Skip to content

Commit

Permalink
Add reverse sorting.
Browse files Browse the repository at this point in the history
  • Loading branch information
drgrice1 committed Oct 23, 2023
1 parent cda2ad5 commit d492a23
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 73 deletions.
15 changes: 14 additions & 1 deletion htdocs/js/JobManager/jobmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
toggle_filter_elements();
}

// Submit the job list form when a sort header is clicked or enter or space is pressed when it has focus.
// Submit the form when a sort header is clicked or enter or space is pressed when it has focus.
const currentAction = document.getElementById('current_action');
if (currentAction) {
for (const header of document.querySelectorAll('.sort-header')) {
Expand All @@ -33,6 +33,19 @@
header.addEventListener('keydown', (e) => {
if (e.key === ' ' || e.key === 'Enter') submitSortMethod(e);
});

const orderToggleButton = header.parentElement.querySelector('button.sort-order');
orderToggleButton?.addEventListener('click', () => {
currentAction.value = 'sort';

const sortOrderInput = document.createElement('input');
sortOrderInput.name = 'labelSortOrder';
sortOrderInput.value = orderToggleButton.dataset.sortPriority;
sortOrderInput.type = 'hidden';
currentAction.form.append(sortOrderInput);

currentAction.form.submit();
});
}
}

Expand Down
72 changes: 52 additions & 20 deletions lib/WeBWorK/ContentGenerator/Instructor/JobManager.pm
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ use constant FIELDS => [
];

use constant SORT_SUBS => {
id => \&byJobID,
courseID => \&byCourseID,
task => \&byTask,
created => \&byCreatedTime,
started => \&byStartedTime,
finished => \&byFinishedTime,
state => \&byState
id => { ASC => \&byJobID, DESC => \&byDescJobID },
courseID => { ASC => \&byCourseID, DESC => \&byDescCourseID },
task => { ASC => \&byTask, DESC => \&byDescTask },
created => { ASC => \&byCreatedTime, DESC => \&byDescCreatedTime },
started => { ASC => \&byStartedTime, DESC => \&byDescStartedTime },
finished => { ASC => \&byFinishedTime, DESC => \&byDescFinishedTime },
state => { ASC => \&byState, DESC => \&byDescState }
};

sub initialize ($c) {
Expand All @@ -64,8 +64,11 @@ sub initialize ($c) {
$c->stash->{selectedJobs} = {};
$c->stash->{sortedJobs} = [];
$c->stash->{primarySortField} = $c->param('primarySortField') || 'created';
$c->stash->{primarySortOrder} = $c->param('primarySortOrder') || 'ASC';
$c->stash->{secondarySortField} = $c->param('secondarySortField') || 'task';
$c->stash->{secondarySortOrder} = $c->param('secondarySortOrder') || 'ASC';
$c->stash->{ternarySortField} = $c->param('ternarySortField') || 'state';
$c->stash->{ternarySortOrder} = $c->param('ternarySortOrder') || 'ASC';

return unless $c->authz->hasPermissions($c->param('user'), 'access_instructor_tools');

Expand Down Expand Up @@ -108,9 +111,9 @@ sub initialize ($c) {
}

# Sort jobs
my $primarySortSub = SORT_SUBS()->{ $c->stash->{primarySortField} };
my $secondarySortSub = SORT_SUBS()->{ $c->stash->{secondarySortField} };
my $ternarySortSub = SORT_SUBS()->{ $c->stash->{ternarySortField} };
my $primarySortSub = SORT_SUBS()->{ $c->stash->{primarySortField} }{ $c->stash->{primarySortOrder} };
my $secondarySortSub = SORT_SUBS()->{ $c->stash->{secondarySortField} }{ $c->stash->{secondarySortOrder} };
my $ternarySortSub = SORT_SUBS()->{ $c->stash->{ternarySortField} }{ $c->stash->{ternarySortOrder} };

# byJobID is included to ensure a definite sort order in case the
# first three sorts do not determine a proper order.
Expand Down Expand Up @@ -148,26 +151,47 @@ sub filter_handler ($c) {
}

sub sort_handler ($c) {
if (defined $c->param('labelSortMethod')) {
$c->stash->{ternarySortField} = $c->stash->{secondarySortField};
$c->stash->{secondarySortField} = $c->stash->{primarySortField};
$c->stash->{primarySortField} = $c->param('labelSortMethod');
$c->param('action.sort.primary', $c->stash->{primarySortField});
$c->param('action.sort.secondary', $c->stash->{secondarySortField});
$c->param('action.sort.ternary', $c->stash->{ternarySortField});
if (defined $c->param('labelSortMethod') || defined $c->param('labelSortOrder')) {
if (defined $c->param('labelSortOrder')) {
$c->stash->{ $c->param('labelSortOrder') . 'SortOrder' } =
$c->stash->{ $c->param('labelSortOrder') . 'SortOrder' } eq 'ASC' ? 'DESC' : 'ASC';
} elsif ($c->param('labelSortMethod') eq $c->stash->{primarySortField}) {
$c->stash->{primarySortOrder} = $c->stash->{primarySortOrder} eq 'ASC' ? 'DESC' : 'ASC';
} else {
$c->stash->{ternarySortField} = $c->stash->{secondarySortField};
$c->stash->{ternarySortOrder} = $c->stash->{secondarySortOrder};
$c->stash->{secondarySortField} = $c->stash->{primarySortField};
$c->stash->{secondarySortOrder} = $c->stash->{primarySortOrder};
$c->stash->{primarySortField} = $c->param('labelSortMethod');
$c->stash->{primarySortOrder} = 'ASC';
}

$c->param('action.sort.primary', $c->stash->{primarySortField});
$c->param('action.sort.primary.order', $c->stash->{primarySortOrder});
$c->param('action.sort.secondary', $c->stash->{secondarySortField});
$c->param('action.sort.secondary.order', $c->stash->{secondarySortOrder});
$c->param('action.sort.ternary', $c->stash->{ternarySortField});
$c->param('action.sort.ternary.order', $c->stash->{ternarySortOrder});
} else {
$c->stash->{primarySortField} = $c->param('action.sort.primary');
$c->stash->{primarySortOrder} = $c->param('action.sort.primary.order');
$c->stash->{secondarySortField} = $c->param('action.sort.secondary');
$c->stash->{secondarySortOrder} = $c->param('action.sort.secondary.order');
$c->stash->{ternarySortField} = $c->param('action.sort.ternary');
$c->stash->{ternarySortOrder} = $c->param('action.sort.ternary.order');
}

return $c->maketext(
'Users sorted by [_1], then by [_2], then by [_3]',
'Jobs sorted by [_1] in [plural,_2,ascending,descending] order, '
. 'then by [_3] in [plural,_4,ascending,descending] order,'
. 'and then by [_5] in [plural,_6,ascending,descending] order.',
$c->maketext((grep { $_->[0] eq $c->stash->{primarySortField} } @{ FIELDS() })[0][1]),
$c->stash->{primarySortOrder} eq 'ASC' ? 1 : 2,
$c->maketext((grep { $_->[0] eq $c->stash->{secondarySortField} } @{ FIELDS() })[0][1]),
$c->maketext((grep { $_->[0] eq $c->stash->{ternarySortField} } @{ FIELDS() })[0][1])
$c->stash->{secondarySortOrder} eq 'ASC' ? 1 : 2,
$c->maketext((grep { $_->[0] eq $c->stash->{ternarySortField} } @{ FIELDS() })[0][1]),
$c->stash->{ternarySortOrder} eq 'ASC' ? 1 : 2
);

}

sub delete_handler ($c) {
Expand Down Expand Up @@ -202,4 +226,12 @@ sub byStartedTime { return ($a->{started} || 0) <=> ($b->{started} || 0) }
sub byFinishedTime { return ($a->{finished} || 0) <=> ($b->{finished} || 0) }
sub byState { return $a->{state} cmp $b->{state} }

sub byDescJobID { local ($b, $a) = ($a, $b); return byJobID(); }
sub byDescCourseID { local ($b, $a) = ($a, $b); return byCourseID(); }
sub byDescTask { local ($b, $a) = ($a, $b); return byTask(); }
sub byDescCreatedTime { local ($b, $a) = ($a, $b); return byCreatedTime(); }
sub byDescStartedTime { local ($b, $a) = ($a, $b); return byStartedTime(); }
sub byDescFinishedTime { local ($b, $a) = ($a, $b); return byFinishedTime(); }
sub byDescState { local ($b, $a) = ($a, $b); return byState(); }

1;
71 changes: 52 additions & 19 deletions templates/ContentGenerator/Instructor/JobManager.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@
% }
%
<%= hidden_field primarySortField => $primarySortField =%>
<%= hidden_field primarySortOrder => $primarySortOrder =%>
<%= hidden_field secondarySortField => $secondarySortField =%>
<%= hidden_field secondarySortOrder => $secondarySortOrder =%>
<%= hidden_field ternarySortField => $ternarySortField =%>
<%= hidden_field ternarySortOrder => $ternarySortOrder =%>
%
% # Output action forms
% for my $form (@$actionForms) {
Expand Down Expand Up @@ -74,41 +77,71 @@
<table class="table table-sm table-bordered caption-top font-sm">
<thead class="table-group-divider">
<tr>
<th>
<%= check_box 'select-all' => 'on', id => 'select-all',
'aria-label' => maketext('Select all jobs'),
data => { select_group => 'selected_jobs' },
class => 'select-all form-check-input' =%>
<th class="text-nowrap">
<%= label_for 'select-all', begin =%>
<%= check_box 'select-all' => 'on', id => 'select-all',
class => 'select-all form-check-input set-id-tooltip',
'aria-label' => maketext('Select all jobs'),
data => {
select_group => 'selected_jobs',
bs_toggle => 'tooltip',
bs_placement => 'right',
bs_title => maketext('Select all jobs')
} =%>
<i class="fa-solid fa-check-double" aria-hidden="true"></i>
<% end =%>
</th>
<th>
<%= label_for 'select-all' =>
link_to maketext('Id') => '#', class => 'sort-header', data => { sort_field => 'id' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Id') => '#', class => 'sort-header',
data => { sort_field => 'id' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'id' =%>
</div>
</th>
% if ($courseID eq 'admin') {
<th>
<%= link_to maketext('Course Id') => '#', class => 'sort-header',
data => { sort_field => 'courseID' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Course Id') => '#', class => 'sort-header',
data => { sort_field => 'courseID' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button',
field => 'course_id' =%>
</div>
</th>
% }
<th>
<%= link_to maketext('Task') => '#', class => 'sort-header',
data => { sort_field => 'task' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Task') => '#', class => 'sort-header',
data => { sort_field => 'task' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'task' =%>
</div>
</th>
<th>
<%= link_to maketext('Created') => '#', class => 'sort-header',
data => { sort_field => 'created' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Created') => '#', class => 'sort-header',
data => { sort_field => 'created' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'created' =%>
</div>
</th>
<th>
<%= link_to maketext('Started') => '#', class => 'sort-header',
data => { sort_field => 'started' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Started') => '#', class => 'sort-header',
data => { sort_field => 'started' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'started' =%>
</div>
</th>
<th>
<%= link_to maketext('Finished') => '#', class => 'sort-header',
data => { sort_field => 'finished' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('Finished') => '#', class => 'sort-header',
data => { sort_field => 'finished' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'finished' =%>
</div>
</th>
<th>
<%= link_to maketext('State') => '#', class => 'sort-header',
data => { sort_field => 'state' } =%>
<div class="d-flex justify-content-between align-items-end gap-1">
<%= link_to maketext('State') => '#', class => 'sort-header',
data => { sort_field => 'state' } =%>
<%= include 'ContentGenerator/Instructor/JobManager/sort_button', field => 'state' =%>
</div>
</th>
</tr>
</thead>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
% if ($primarySortField eq $field) {
<button type="button" data-sort-priority="primary"
class="sort-order btn btn-secondary rounded-pill btn-sm py-0 fw-bold text-nowrap font-xs">
1
% if ($primarySortOrder eq 'ASC') {
<i class="fa-solid fa-chevron-down"></i>
<span class="visually-hidden"><%= maketext('ascending') %></span>
% } else {
<i class="fa-solid fa-chevron-up"></i>
<span class="visually-hidden"><%= maketext('descending') %></span>
% }
</button>
% } elsif ($secondarySortField eq $field) {
<button type="button" data-sort-priority="secondary"
class="sort-order btn btn-secondary rounded-pill btn-sm py-0 fw-bold text-nowrap font-xs">
2
% if ($secondarySortOrder eq 'ASC') {
<i class="fa-solid fa-chevron-down"></i>
<span class="visually-hidden"><%= maketext('ascending') %></span>
% } else {
<i class="fa-solid fa-chevron-up"></i>
<span class="visually-hidden"><%= maketext('descending') %></span>
% }
</button>
% } elsif ($ternarySortField eq $field) {
<button type="button" data-sort-priority="ternary"
class="sort-order btn btn-secondary rounded-pill btn-sm py-0 fw-bold text-nowrap font-xs">
3
% if ($ternarySortOrder eq 'ASC') {
<i class="fa-solid fa-chevron-down"></i>
<span class="visually-hidden"><%= maketext('ascending') %></span>
% } else {
<i class="fa-solid fa-chevron-up"></i>
<span class="visually-hidden"><%= maketext('descending') %></span>
% }
</button>
% }
Loading

0 comments on commit d492a23

Please sign in to comment.