mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-19 18:26:06 +08:00
Implement sorting for experiment table view [SCI-7451] [SCI-7497] (#4659)
* Implement experiment table sort flyout [SCI-7451] * Implement archive sort options for experiment table [SCI-7497] * Fix hound [SCI-7451] * Clean code for experiment table view sorting [SCI-7497] * Fix hound [SCI-7451]
This commit is contained in:
parent
fdf13f822e
commit
02f039ffed
8 changed files with 134 additions and 26 deletions
|
@ -8,6 +8,7 @@ var ExperimnetTable = {
|
|||
selectedMyModules: [],
|
||||
activeFilters: {},
|
||||
filters: [], // Filter {name: '', init(), closeFilter(), apply(), active(), clearFilter()}
|
||||
myModulesCurrentSort: '',
|
||||
pageSize: GLOBAL_CONSTANTS.DEFAULT_ELEMENTS_PER_PAGE,
|
||||
getUrls: function(id) {
|
||||
return $(`.table-row[data-id="${id}"]`).data('urls');
|
||||
|
@ -20,7 +21,7 @@ var ExperimnetTable = {
|
|||
$(placeholder).insertAfter($(this.table).find('.table-body'));
|
||||
},
|
||||
appendRows: function(result) {
|
||||
$.each(result, (id, data) => {
|
||||
$.each(result, (_j, data) => {
|
||||
let row;
|
||||
|
||||
// Checkbox selector
|
||||
|
@ -28,7 +29,7 @@ var ExperimnetTable = {
|
|||
<div class="table-body-cell">
|
||||
<div class="sci-checkbox-container">
|
||||
<div class="loading-overlay"></div>
|
||||
<input type="checkbox" class="sci-checkbox my-module-selector" data-my-module="${id}">
|
||||
<input type="checkbox" class="sci-checkbox my-module-selector" data-my-module="${data.id}">
|
||||
<span class="sci-checkbox-label"></span>
|
||||
</div>
|
||||
</div>`;
|
||||
|
@ -59,7 +60,7 @@ var ExperimnetTable = {
|
|||
</div>`;
|
||||
|
||||
let tableRowClass = `table-row ${data.provisioning_status === 'in_progress' ? 'table-row-provisioning' : ''}`;
|
||||
$(`<div class="${tableRowClass}" data-urls='${JSON.stringify(data.urls)}' data-id="${id}">${row}</div>`)
|
||||
$(`<div class="${tableRowClass}" data-urls='${JSON.stringify(data.urls)}' data-id="${data.id}">${row}</div>`)
|
||||
.appendTo(`${this.table} .table-body`);
|
||||
});
|
||||
},
|
||||
|
@ -430,6 +431,18 @@ var ExperimnetTable = {
|
|||
table.loadTable();
|
||||
});
|
||||
},
|
||||
initSorting: function(table) {
|
||||
$('#sortMenuDropdown a').click(function() {
|
||||
if (table.myModulesCurrentSort !== $(this).data('sort')) {
|
||||
$('#sortMenuDropdown a').removeClass('selected');
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
table.myModulesCurrentSort = $(this).data('sort');
|
||||
table.loadTable();
|
||||
$(this).addClass('selected');
|
||||
$('#sortMenu').dropdown('toggle');
|
||||
}
|
||||
});
|
||||
},
|
||||
initFilters: function() {
|
||||
this.filterDropdown = filterDropdown.init();
|
||||
let $experimentFilter = $('#experimentTable .my-modules-filters');
|
||||
|
@ -466,9 +479,13 @@ var ExperimnetTable = {
|
|||
});
|
||||
},
|
||||
loadTable: function() {
|
||||
var tableParams = {
|
||||
filters: this.activeFilters,
|
||||
sort: this.myModulesCurrentSort
|
||||
};
|
||||
var dataUrl = $(this.table).data('my-modules-url');
|
||||
this.loadPlaceholder();
|
||||
$.get(dataUrl, { filters: this.activeFilters }, (result) => {
|
||||
$.get(dataUrl, tableParams, (result) => {
|
||||
$(this.table).find('.table-row').remove();
|
||||
this.appendRows(result.data);
|
||||
this.initDueDatePicker(result.data);
|
||||
|
@ -484,7 +501,7 @@ var ExperimnetTable = {
|
|||
this.initDueDatePicker(response.data);
|
||||
},
|
||||
customParams: (params) => {
|
||||
return { ...params, ...{ filters: this.activeFilters } };
|
||||
return { ...params, ...tableParams };
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -529,6 +546,7 @@ var ExperimnetTable = {
|
|||
this.initSelector();
|
||||
this.initSelectAllCheckbox();
|
||||
this.initFilters();
|
||||
this.initSorting(this);
|
||||
this.loadTable();
|
||||
this.initRenameModal();
|
||||
this.initAccessModal();
|
||||
|
|
|
@ -5,6 +5,22 @@
|
|||
--toolbar-height: 4.5em;
|
||||
position: relative;
|
||||
|
||||
.title-row {
|
||||
.header-actions {
|
||||
&.experiment-header {
|
||||
column-gap: .25em;
|
||||
}
|
||||
|
||||
.sort-task-menu {
|
||||
&:not(.archived) {
|
||||
[data-view-mode="archived"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.experiment-table-container {
|
||||
height: calc(100vh - var(--content-header-size) - var(--navbar-height) - var(--toolbar-height));
|
||||
overflow: auto;
|
||||
|
|
|
@ -49,10 +49,6 @@
|
|||
display: flex;
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
|
||||
&.experiment-header {
|
||||
column-gap: .25em;
|
||||
}
|
||||
}
|
||||
|
||||
.view-switch {
|
||||
|
|
|
@ -90,6 +90,10 @@ class ExperimentsController < ApplicationController
|
|||
|
||||
def table
|
||||
redirect_to module_archive_experiment_path(@experiment) if @experiment.archived_branch?
|
||||
view_state = @experiment.current_view_state(current_user)
|
||||
view_mode = params[:view_mode] || 'active'
|
||||
@current_sort = view_state.state.dig('my_modules', view_mode, 'sort') || 'atoz'
|
||||
|
||||
@project = @experiment.project
|
||||
@active_modules = @experiment.my_modules.active.order(:name)
|
||||
end
|
||||
|
@ -97,7 +101,7 @@ class ExperimentsController < ApplicationController
|
|||
def load_table
|
||||
my_modules = @experiment.my_modules.readable_by_user(current_user)
|
||||
my_modules = params[:view_mode] == 'archived' ? my_modules.archived : my_modules.active
|
||||
render json: Experiments::TableViewService.new(my_modules, current_user, params).call
|
||||
render json: Experiments::TableViewService.new(@experiment, my_modules, current_user, params).call
|
||||
end
|
||||
|
||||
def edit
|
||||
|
|
|
@ -9,6 +9,7 @@ class Experiment < ApplicationRecord
|
|||
include ArchivableModel
|
||||
include SearchableModel
|
||||
include SearchableByNameModel
|
||||
include ViewableModel
|
||||
include PermissionCheckableModel
|
||||
include Assignable
|
||||
include Cloneable
|
||||
|
@ -94,6 +95,23 @@ class Experiment < ApplicationRecord
|
|||
joins(:project).where(project: { team: teams })
|
||||
end
|
||||
|
||||
def default_view_state
|
||||
{
|
||||
my_modules: {
|
||||
active: { sort: 'atoz' },
|
||||
archived: { sort: 'atoz' }
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def validate_view_state(view_state)
|
||||
if %w(atoz ztoa due_first due_last).exclude?(view_state.state.dig('my_modules', 'active', 'sort')) ||
|
||||
%w(atoz ztoa due_first due_last
|
||||
archived_old archived_new).exclude?(view_state.state.dig('my_modules', 'archived', 'sort'))
|
||||
view_state.errors.add(:state, :wrong_state)
|
||||
end
|
||||
end
|
||||
|
||||
def connections
|
||||
Connection.joins(
|
||||
'LEFT JOIN my_modules AS inputs ON input_id = inputs.id'
|
||||
|
|
|
@ -35,20 +35,24 @@ module Experiments
|
|||
experiment: :project
|
||||
}
|
||||
|
||||
def initialize(my_modules, user, params)
|
||||
def initialize(experiment, my_modules, user, params)
|
||||
@my_modules = my_modules
|
||||
@page = params[:page] || 1
|
||||
@user = user
|
||||
@filters = params[:filters] || []
|
||||
@params = params
|
||||
initialize_table_sorting(experiment)
|
||||
end
|
||||
|
||||
def call
|
||||
result = {}
|
||||
result = []
|
||||
my_module_list = @my_modules
|
||||
@filters.each do |name, value|
|
||||
my_module_list = __send__("#{name}_filter", my_module_list, value) if value.present?
|
||||
end
|
||||
|
||||
my_module_list = sort_records(my_module_list)
|
||||
|
||||
my_module_list = my_module_list.includes(PRELOAD)
|
||||
.select('my_modules.*')
|
||||
.group('my_modules.id')
|
||||
|
@ -67,20 +71,20 @@ module Experiments
|
|||
experiment = my_module.experiment
|
||||
project = experiment.project
|
||||
|
||||
result[my_module.id] = {
|
||||
columns: prepared_my_module,
|
||||
provisioning_status: my_module.provisioning_status,
|
||||
urls: {
|
||||
permissions: permissions_my_module_path(my_module),
|
||||
actions_dropdown: actions_dropdown_my_module_path(my_module),
|
||||
name_update: my_module_path(my_module),
|
||||
restore: restore_my_modules_experiment_path(experiment),
|
||||
provisioning_status:
|
||||
my_module.provisioning_status == 'in_progress' && provisioning_status_my_module_url(my_module),
|
||||
access: edit_access_permissions_project_experiment_my_module_path(project, experiment, my_module)
|
||||
|
||||
}
|
||||
}
|
||||
result.push({ id: my_module.id,
|
||||
columns: prepared_my_module,
|
||||
provisioning_status: my_module.provisioning_status,
|
||||
urls: {
|
||||
permissions: permissions_my_module_path(my_module),
|
||||
actions_dropdown: actions_dropdown_my_module_path(my_module),
|
||||
name_update: my_module_path(my_module),
|
||||
restore: restore_my_modules_experiment_path(experiment),
|
||||
provisioning_status:
|
||||
my_module.provisioning_status == 'in_progress' &&
|
||||
provisioning_status_my_module_url(my_module),
|
||||
access: edit_access_permissions_project_experiment_my_module_path(project,
|
||||
experiment, my_module)
|
||||
} })
|
||||
end
|
||||
|
||||
{
|
||||
|
@ -193,5 +197,36 @@ module Experiments
|
|||
def statuses_filter(my_modules, value)
|
||||
my_modules.where(my_module_status_id: value)
|
||||
end
|
||||
|
||||
def initialize_table_sorting(experiment)
|
||||
@view_state = experiment.current_view_state(@user)
|
||||
@view_mode = @params[:view_mode] || 'active'
|
||||
@sort = @view_state.state.dig('my_modules', @view_mode, 'sort') || 'atoz'
|
||||
if @params[:sort] && @sort != @params[:sort] && %w(due_first due_last atoz ztoa
|
||||
archived_old archived_new).include?(@params[:sort])
|
||||
@view_state.state['my_modules'].merge!(Hash[@view_mode, { 'sort': @params[:sort] }.stringify_keys])
|
||||
@view_state.save!
|
||||
@sort = @view_state.state.dig('my_modules', @view_mode, 'sort')
|
||||
end
|
||||
end
|
||||
|
||||
def sort_records(records)
|
||||
case @sort
|
||||
when 'due_first'
|
||||
records.order(:due_date)
|
||||
when 'due_last'
|
||||
records.order(Arel.sql("COALESCE(due_date, DATE '1900-01-01') DESC"))
|
||||
when 'atoz'
|
||||
records.order(:name)
|
||||
when 'ztoa'
|
||||
records.order(name: :desc)
|
||||
when 'archived_old'
|
||||
records.order(Arel.sql('COALESCE(my_modules.archived_on, my_modules.archived_on) ASC'))
|
||||
when 'archived_new'
|
||||
records.order(Arel.sql('COALESCE(my_modules.archived_on, my_modules.archived_on) DESC'))
|
||||
else
|
||||
records
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,6 +63,25 @@
|
|||
<% end %>
|
||||
<% if action_name == 'table' %>
|
||||
<%= render partial: 'table_filters.html.erb' %>
|
||||
|
||||
<div class="dropdown sort-menu">
|
||||
<button class="btn btn-light icon-btn dropdown-toggle" type="button" id="sortMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
|
||||
<i class="fas fa-sort-amount-up"></i>
|
||||
</button>
|
||||
<ul id="sortMenuDropdown" class="dropdown-menu sort-task-menu <%= params[:view_mode] %> dropdown-menu-right" aria-labelledby="sortMenu">
|
||||
<% %w(atoz ztoa due_first due_last archived_old archived_new).each_with_index do |sort, i| %>
|
||||
<% if i.even? && i.positive? %>
|
||||
<li class="divider" <%= i > 3 ? 'data-view-mode=archived' : '' %>></li>
|
||||
<% end %>
|
||||
<li <%= %w(archived_new archived_old).include?(sort) ? 'data-view-mode=archived' : '' %>>
|
||||
<a class="<%= 'selected' if @current_sort == sort %>"
|
||||
data-sort="<%= sort %>" >
|
||||
<%= t("general.sort.#{sort}_html") %>
|
||||
</a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3224,6 +3224,8 @@ en:
|
|||
ztoa_html: "<i class=\"fas fa-sort-alpha-up\"></i> Name Z to A"
|
||||
archived_new_html: "<span class=\"fa-stack\"><i class=\"fas fa-long-arrow-alt-up\"></i><i class=\"fas fa-archive\"></i></span>Archived last"
|
||||
archived_old_html: "<span class=\"fa-stack\"><i class=\"fas fa-long-arrow-alt-down\"></i><i class=\"fas fa-archive\"></i></span>Archived first"
|
||||
due_first_html: "<i class=\"fas fa-sort-numeric-up\"></i> Due first"
|
||||
due_last_html: "<i class=\"fas fa-sort-numeric-up\"></i> Due last"
|
||||
sort_new:
|
||||
new: "Newest"
|
||||
old: "Oldest"
|
||||
|
|
Loading…
Add table
Reference in a new issue