Skip to content

Commit

Permalink
Merge pull request #6421 from ChrisBr/bootstrap/monitor
Browse files Browse the repository at this point in the history
Bootstrap/monitor
  • Loading branch information
ChrisBr authored Dec 4, 2018
2 parents 9330591 + 0386ddb commit 2861dd2
Show file tree
Hide file tree
Showing 12 changed files with 354 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/api/app/assets/javascripts/webui2/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@
//= require webui2/jquery-ui.min.js
//= require webui2/cm2/use-codemirror.js
//= require webui2/package-view_file.js
//= require webui2/project_monitor.js
3 changes: 2 additions & 1 deletion src/api/app/assets/javascripts/webui2/datatables.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//= require datatables/dataTables.bootstrap4
//= require datatables/extensions/Responsive/dataTables.responsive
//= require datatables/extensions/Responsive/responsive.bootstrap4
//= require datatables/extensions/FixedColumns/fixedColumns.bootstrap4
//= require datatables/extensions/FixedColumns/dataTables.fixedColumns

function initializeDataTable(cssSelector, params){ // jshint ignore:line
var defaultParams = {
Expand All @@ -10,4 +12,3 @@ function initializeDataTable(cssSelector, params){ // jshint ignore:line
var newParams = $.extend(defaultParams, params);
$(cssSelector).DataTable(newParams);
}

105 changes: 105 additions & 0 deletions src/api/app/assets/javascripts/webui2/project_monitor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
function hideRepositoryColumns() {
var table = $('#project-monitor-table').DataTable();

var repositories = [];
$('#project-monitor-repositories-dropdown input:checked').each(function () {
repositories.push($(this).val().trim());
});

if (repositories.length === 0) {
return;
}

var toShowColumns = [];
var offSet = 0;
$('#project-monitor-table thead tr:eq(0) th').each(function () {
var column = $(this);
var colSpan = column.prop('colspan');
if (repositories.includes(column.text().trim())) {
var range = [];
for (var i = offSet; i < offSet + colSpan; i++) {
range.push(i);
}
toShowColumns = toShowColumns.concat(range);
}
offSet += colSpan;
});

table.columns().every(function () {
var index = this.index();
if (index === 0) return;
this.visible(toShowColumns.includes(index));
});
}

function hideArchitectureColumns() {
var table = $('#project-monitor-table').DataTable();

var architectures = [];
$('#project-monitor-architectures-dropdown input:checked').each(function () {
architectures.push($(this).val());
});

if (architectures.length === 0) {
return;
}

table.columns().every(function () {
if (this.index() === 0) return;
if (!this.visible()) return;

var title = $(this.header()).text().trim();
this.visible(architectures.includes(title));
});
}

function updateStatusSearch() {
var table = $('#project-monitor-table').DataTable();
var searchInput = $('#project-monitor_filter input');

var terms = [];
$('#project-monitor-status-dropdown input:checked').each(function () {
terms.push($(this).val());
});

var searchTerm = terms.join("|");
searchInput.val(searchTerm);
table.search(searchTerm).draw();
}

function updateMonitorFilters() {
updateStatusSearch();
var table = $('#project-monitor-table').DataTable();
table.columns().visible(true);
hideRepositoryColumns();
hideArchitectureColumns();
}

function setupProjectMonitor() { // jshint ignore:line
initializeDataTable('#project-monitor-table', { // jshint ignore:line
scrollX: true,
scrollY: "50vh",
fixedColumns: true,
pageLength: 50,
search: {
regex: true,
smart: false,
}
});

$('[data-toggle="popover"]').popover({ trigger: 'hover click' });

$('#project-monitor-status-dropdown input:checkbox').on('change', function () {
updateStatusSearch();
});

$('.monitor-no-filter-link').on('click', function () {
$(this).siblings().children('input:checked').prop('checked', false);
updateMonitorFilters();

});

$('#project-monitor-architectures-dropdown input:checkbox, #project-monitor-repositories-dropdown input:checkbox').on('change', function () {
updateMonitorFilters();
});
}
1 change: 1 addition & 0 deletions src/api/app/assets/stylesheets/webui2/datatables.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import 'datatables/dataTables.bootstrap4';
@import 'datatables/extensions/Responsive/responsive.bootstrap4';
@import 'datatables/extensions/FixedColumns/fixedColumns.bootstrap4';

table.table-fixed {
table-layout: fixed
Expand Down
4 changes: 0 additions & 4 deletions src/api/app/assets/stylesheets/webui2/modals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,3 @@
overflow-x: hidden;
overflow-wrap: break-word;
}

.modal-body p {
white-space: pre-wrap;
}
9 changes: 9 additions & 0 deletions src/api/app/controllers/webui/project_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,14 @@ def move_path
end

def monitor
if params.keys.length < 4
@activate_client_search = true
else
flash[:notice] = "Limited search results, click #{view_context.link_to('here', project_monitor_path(@project))} to remove the filter."
end

@legend = Buildresult::STATUS_DESCRIPTION

@name_filter = params[:pkgname]
@lastbuild_switch = params[:lastbuild]
if params[:defaults]
Expand Down Expand Up @@ -454,6 +462,7 @@ def monitor
@repohash[repo].delete(arch) unless has_packages
end
end
switch_to_webui2
end

# should be in the package controller, but all the helper functions to render the result of a build are in the project
Expand Down
58 changes: 58 additions & 0 deletions src/api/app/views/webui2/webui/project/_monitor_control.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.row
.col-md-12
- if activate_client_search
%span.dropdown#project-monitor-status-dropdown
%button.btn.btn-outline-secondary.dropdown-toggle{ data: { toggle: :dropdown }, type: :button }
%span.caret
Status
.dropdown-menu
%button.btn.btn-link.monitor-no-filter-link No filter
- status.each do |status|
.custom-control.custom-checkbox.dropdown-item.ml-2
%input.custom-control-input{ type: :checkbox, id: "#{status}-checkbox".parameterize, checked: false, value: status }
%label.custom-control-label{ for: "#{status}-checkbox".parameterize }
= status
%span.dropdown#project-monitor-architectures-dropdown
%button.btn.btn-outline-secondary.dropdown-toggle{ data: { toggle: :dropdown }, type: :button }
%span.caret
Architecture
.dropdown-menu
%button.btn.btn-link.monitor-no-filter-link No filter
- architectures.each do |architecture|
.custom-control.custom-checkbox.dropdown-item.ml-2
%input.custom-control-input{ type: :checkbox, id: "#{architecture}-checkbox".parameterize, checked: false, value: architecture }
%label.custom-control-label{ for: "#{architecture}-checkbox".parameterize }
= architecture
%span.dropdown#project-monitor-repositories-dropdown
%button.btn.btn-outline-secondary.dropdown-toggle{ data: { toggle: :dropdown }, type: :button }
%span.caret
Repository
.dropdown-menu
%button.btn.btn-link.monitor-no-filter-link No filter
- repositories.each do |repository|
.custom-control.custom-checkbox.dropdown-item.ml-2
%input.custom-control-input{ type: :checkbox, id: "#{repository}-checkbox".parameterize, checked: false, value: repository }
%label.custom-control-label{ for: "#{repository}-checkbox".parameterize }
= repository
%button.btn.btn-outline-secondary{ data: { toggle: 'modal', target: '#build-monitor-legend' }, title: 'Build status legend' }
Legend
- unless activate_client_search
.float-right
%a.btn.btn-outline-primary{ href: project_monitor_path(project) }
Remove filter

.modal.fade#build-monitor-legend{ tabindex: -1, role: 'dialog', aria: { labelledby: 'confirm-modal-label', hidden: true } }
.modal-dialog.modal-dialog-centered.modal-lg{ role: 'document' }
.modal-content
.modal-header
%h5.modal-title
Build status legend
.modal-body
- @legend.each do |status, description|
%p
%strong
#{status}:
= description
.modal-footer
%button.btn.btn-sm.btn-outline-secondary.px-4{ data: { dismiss: 'modal' } }
Cancel
2 changes: 2 additions & 0 deletions src/api/app/views/webui2/webui/project/_tabs.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
- unless project.defines_remote_instance? || project.is_maintenance?
%li.nav-item
= tab_link('Repositories', repositories_path)
%li.nav-item
= tab_link('Monitor', project_monitor_path(project))
%li.nav-item
= tab_link('Requests', project_requests_path)
- unless project.defines_remote_instance?
Expand Down
37 changes: 37 additions & 0 deletions src/api/app/views/webui2/webui/project/monitor.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
:ruby
@pagetitle = "Show #{@project}"
@layouttype = 'custom'

.card.mb-3
= render partial: 'tabs', locals: { project: @project }
.card-body#project-monitor
= render partial: 'monitor_control',
locals: { project: @project, activate_client_search: @activate_client_search,
status: @avail_status_values, repositories: @avail_repo_values, architectures: @avail_arch_values }
.row.mt-4
.col-md-12.obs-dataTable
%table.table.table-striped.table-bordered.text-nowrap.w-100#project-monitor-table
%thead.header
%tr
%th
- @repohash.sort.each do |repo, archlist|
- next if archlist.empty?
%th.text-center{ colspan: archlist.length }
= repo
%tr
%th
- @repohash.sort.each do |_repo, archlist|
- archlist.sort.each do |arch|
%th
= arch
%tbody
- @packagenames.each do |packname|
%tr
%td
= link_to word_break(packname, 40), controller: :package, action: :show, package: packname, project: @project.to_s
- @repohash.sort.each do |repo, archlist|
- archlist.sort.each do |arch|
%td
= webui2_arch_repo_table_cell(repo, arch, packname, nil, false)
:javascript
setupProjectMonitor();
101 changes: 101 additions & 0 deletions src/api/spec/bootstrap/features/webui/projects/monitor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
require 'browser_helper'
require 'bootstrap/support/page/monitor_page'

RSpec.feature 'Monitor', type: :feature, js: true do
describe 'monitor' do
let(:admin_user) { create(:admin_user) }
let!(:project) { create(:project, name: 'TestProject') }
let!(:package1) { create(:package, project: project, name: 'TestPackage') }
let!(:package2) { create(:package, project: project, name: 'SecondPackage') }
let!(:repository1) { create(:repository, project: project, name: 'openSUSE_Tumbleweed', architectures: ['x86_64', 'i586']) }
let!(:repository2) { create(:repository, project: project, name: 'openSUSE_Leap_42.3', architectures: ['x86_64', 'i586']) }
let!(:repository3) { create(:repository, project: project, name: 'openSUSE_Leap_42.2', architectures: ['x86_64', 'i586']) }

let(:build_results_xml) do
<<-XML
<resultlist state="dc66a487ea4d97b4f157d075a0e747b9">
<result project="TestProject" repository="openSUSE_Tumbleweed" arch="x86_64" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="succeeded">
<details>no source uploaded</details>
</status>
</result>
<result project="TestProject" repository="openSUSE_Leap_42.3" arch="x86_64" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="broken">
<details>no source uploaded</details>
</status>
</result>
<result project="TestProject" repository="openSUSE_Leap_42.2" arch="x86_64" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="broken">
<details>no source uploaded</details>
</status>
</result>
<result project="TestProject" repository="openSUSE_Tumbleweed" arch="i586" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="broken">
<details>no source uploaded</details>
</status>
</result>
<result project="TestProject" repository="openSUSE_Leap_42.3" arch="i586" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="broken">
<details>no source uploaded</details>
</status>
</result>
<result project="TestProject" repository="openSUSE_Leap_42.2" arch="i586" code="published" state="published">
<status package="SecondPackage" code="broken">
<details>no source uploaded</details>
</status>
<status package="TestPackage" code="broken">
<details>no source uploaded</details>
</status>
</result>
</resultlist>
XML
end

before do
login admin_user
allow(Backend::Api::BuildResults::Status).to receive(:result_swiss_knife).and_return(build_results_xml)
visit project_monitor_path(project.name)
end

scenario 'filtering build results by architecture' do
page = Page::MonitorPage.new(:architectures)
page.filter('i586')

expect(page).to have_column('i586')
expect(page).not_to have_column('x86_64')
end

scenario 'filtering build results by repository' do
page = Page::MonitorPage.new(:repositories)
page.filter('openSUSE_Leap_42.2')
page.filter('openSUSE_Leap_42.3')

expect(page).to have_column('openSUSE_Leap_42.2')
expect(page).to have_column('openSUSE_Leap_42.3')
expect(page).not_to have_column('Tumbleweed')
end

scenario 'filtering build results by status' do
page = Page::MonitorPage.new(:status)
page.filter('succeeded')

expect(page).to have_row('TestPackage')
expect(page).not_to have_row('SecondPackage')
end
end
end
Loading

0 comments on commit 2861dd2

Please sign in to comment.