mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-31 04:32:06 +08:00
Add pagination for current tasks on dashboard
This commit is contained in:
parent
73623da02c
commit
52493fd834
5 changed files with 148 additions and 61 deletions
|
@ -1,4 +1,4 @@
|
|||
/* global dropdownSelector I18n animateSpinner PerfectSb */
|
||||
/* global dropdownSelector I18n animateSpinner PerfectSb InfiniteScroll */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
var DasboardCurrentTasksWidget = (function() {
|
||||
|
@ -12,7 +12,58 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
<i class="fas fa-angle-double-down"></i>
|
||||
</div>`;
|
||||
|
||||
function loadCurrentTasksList() {
|
||||
function generateTasksListHtml(json, container) {
|
||||
$.each(json.data, (i, task) => {
|
||||
var currentTaskItem;
|
||||
var stepsPercentage = task.steps_state.percentage + '%';
|
||||
var stateText;
|
||||
var dueDate = (task.due_date !== null) ? '<i class="fas fa-calendar-day"></i>'
|
||||
+ I18n.t('dashboard.current_tasks.due_date', { date: task.due_date }) : '';
|
||||
var overdue = (task.overdue) ? 'overdue' : '';
|
||||
if (task.state === 'completed') {
|
||||
stateText = I18n.t('dashboard.current_tasks.progress_bar.completed');
|
||||
} else {
|
||||
stateText = I18n.t('dashboard.current_tasks.progress_bar.in_progress');
|
||||
if (task.overdue) { stateText = I18n.t('dashboard.current_tasks.progress_bar.overdue'); }
|
||||
if (task.steps_state.all_steps !== 0) {
|
||||
stateText += I18n.t('dashboard.current_tasks.progress_bar.completed_steps',
|
||||
{ steps: task.steps_state.completed_steps, total_steps: task.steps_state.all_steps });
|
||||
}
|
||||
}
|
||||
currentTaskItem = `<a class="current-task-item" href="${task.link}">
|
||||
<div class="current-task-breadcrumbs">${task.project}/${task.experiment}</div>
|
||||
<div class="item-row">
|
||||
<div class="task-name">${task.name}</div>
|
||||
<div class="task-due-date ${overdue}">${dueDate}</div>
|
||||
<div class="task-progress-container ${task.state} ${overdue}">
|
||||
<div class="task-progress" style="padding-left: ${stepsPercentage}"></div>
|
||||
<div class="task-progress-label">${stateText}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>`;
|
||||
$(container).append(currentTaskItem);
|
||||
});
|
||||
}
|
||||
|
||||
function initInfiniteScroll() {
|
||||
InfiniteScroll.init('.current-tasks-list', {
|
||||
url: $('.current-tasks-list').data('tasksListUrl'),
|
||||
customResponse: (json, container) => {
|
||||
generateTasksListHtml(json, container);
|
||||
},
|
||||
customParams: (params) => {
|
||||
params.project_id = dropdownSelector.getValues(projectFilter);
|
||||
params.experiment_id = dropdownSelector.getValues(experimentFilter);
|
||||
params.sort = dropdownSelector.getValues(sortFilter);
|
||||
params.view = dropdownSelector.getValues(viewFilter);
|
||||
params.query = $('.current-tasks-widget .task-search-field').val();
|
||||
params.mode = $('.current-tasks-navbar .active').data('mode');
|
||||
return params;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function loadCurrentTasksList(newList) {
|
||||
var $currentTasksList = $('.current-tasks-list');
|
||||
var params = {
|
||||
project_id: dropdownSelector.getValues(projectFilter),
|
||||
|
@ -24,44 +75,16 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
animateSpinner($currentTasksList, true);
|
||||
$.get($currentTasksList.data('tasksListUrl'), params, function(data) {
|
||||
// Toggle empty state
|
||||
if (data.tasks_list.length === 0) {
|
||||
if (data.data.length === 0) {
|
||||
$currentTasksList.append(emptyState);
|
||||
} else {
|
||||
$currentTasksList.find('.no-tasks').remove();
|
||||
}
|
||||
// Clear the list
|
||||
$currentTasksList.find('.current-task-item').remove();
|
||||
$.each(data.tasks_list, (i, task) => {
|
||||
var currentTaskItem;
|
||||
var stepsPercentage = task.steps_state.percentage + '%';
|
||||
var stateText;
|
||||
var dueDate = (task.due_date !== null) ? '<i class="fas fa-calendar-day"></i>'
|
||||
+ I18n.t('dashboard.current_tasks.due_date', { date: task.due_date }) : '';
|
||||
var overdue = (task.overdue) ? 'overdue' : '';
|
||||
if (task.state === 'completed') {
|
||||
stateText = I18n.t('dashboard.current_tasks.progress_bar.completed');
|
||||
} else {
|
||||
stateText = I18n.t('dashboard.current_tasks.progress_bar.in_progress');
|
||||
if (task.overdue) { stateText = I18n.t('dashboard.current_tasks.progress_bar.overdue'); }
|
||||
if (task.steps_state.all_steps !== 0) {
|
||||
stateText += I18n.t('dashboard.current_tasks.progress_bar.completed_steps',
|
||||
{ steps: task.steps_state.completed_steps, total_steps: task.steps_state.all_steps });
|
||||
}
|
||||
}
|
||||
currentTaskItem = `<a class="current-task-item" href="${task.link}">
|
||||
<div class="current-task-breadcrumbs">${task.project}/${task.experiment}</div>
|
||||
<div class="item-row">
|
||||
<div class="task-name">${task.name}</div>
|
||||
<div class="task-due-date ${overdue}">${dueDate}</div>
|
||||
<div class="task-progress-container ${task.state} ${overdue}">
|
||||
<div class="task-progress" style="padding-left: ${stepsPercentage}"></div>
|
||||
<div class="task-progress-label">${stateText}</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>`;
|
||||
$currentTasksList.append(currentTaskItem);
|
||||
});
|
||||
generateTasksListHtml(data, $currentTasksList);
|
||||
PerfectSb().update_all();
|
||||
if (newList) InfiniteScroll.resetScroll('.current-tasks-list');
|
||||
animateSpinner($currentTasksList, false);
|
||||
});
|
||||
}
|
||||
|
@ -138,7 +161,7 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
$('.curent-tasks-filters').dropdown('toggle');
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
loadCurrentTasksList();
|
||||
loadCurrentTasksList(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -148,7 +171,7 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
e.preventDefault();
|
||||
$('.current-tasks-navbar').find('a').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
loadCurrentTasksList();
|
||||
loadCurrentTasksList(true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -158,6 +181,7 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
initNavbar();
|
||||
initFilters();
|
||||
loadCurrentTasksList();
|
||||
initInfiniteScroll();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
68
app/assets/javascripts/sitewide/infinite_scroll.js
Normal file
68
app/assets/javascripts/sitewide/infinite_scroll.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/* eslint-disable no-unused-vars */
|
||||
|
||||
var InfiniteScroll = (function() {
|
||||
function getScrollHeight($container) {
|
||||
return $container[0].scrollHeight;
|
||||
}
|
||||
|
||||
function scrollNotVisible($container) {
|
||||
return (getScrollHeight($container) - $container.height() - 150 <= 0);
|
||||
}
|
||||
|
||||
function loadData($container, page = 1) {
|
||||
var customParams = $container.data('config').customParams;
|
||||
var params = (customParams ? customParams({ page: page }) : { page: page });
|
||||
|
||||
if ($container.hasClass('loading') || $container.hasClass('last-page')) return;
|
||||
$container.addClass('loading');
|
||||
|
||||
$.get($container.data('config').url, params, function(result) {
|
||||
if ($container.data('config').customResponse) {
|
||||
$container.data('config').customResponse(result, $container);
|
||||
} else {
|
||||
$(result.data).appendTo($container);
|
||||
}
|
||||
|
||||
if (result.next_page) {
|
||||
$container.data('next-page', result.next_page);
|
||||
} else {
|
||||
$container.addClass('last-page');
|
||||
}
|
||||
$container.removeClass('loading');
|
||||
|
||||
if (scrollNotVisible($container)) {
|
||||
loadData($container, $container.data('next-page'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initScroll(object, config = {}) {
|
||||
var $container = $(object);
|
||||
$container.data('next-page', 2);
|
||||
$container.data('config', config);
|
||||
|
||||
if (config.loadFirstPage) {
|
||||
loadData($container, 1);
|
||||
} else if (scrollNotVisible($container)) {
|
||||
loadData($container, $container.data('next-page'));
|
||||
}
|
||||
|
||||
$container.on('scroll', () => {
|
||||
if ($container.scrollTop() + $container.height() > getScrollHeight($container) - 150 && !$container.hasClass('last-page')) {
|
||||
loadData($container, $container.data('next-page'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
init: (object, config) => {
|
||||
initScroll(object, config);
|
||||
},
|
||||
resetScroll: (object) => {
|
||||
$(object).data('next-page', 2).removeClass('last-page');
|
||||
if (scrollNotVisible($(object))) {
|
||||
loadData($(object), $(object).data('next-page'));
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
|
@ -34,28 +34,25 @@ module Dashboard
|
|||
tasks
|
||||
end
|
||||
|
||||
tasks = tasks.with_step_statistics.preload(experiment: :project)
|
||||
page = (params[:page] || 1).to_i
|
||||
tasks_per_page = tasks.page(page).per(Constants::INFINITE_SCROLL_LIMIT)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
render json: {
|
||||
tasks_list: tasks.map do |task|
|
||||
{ id: task.id,
|
||||
link: protocols_my_module_path(task.id),
|
||||
experiment: escape_input(task.experiment.name),
|
||||
project: escape_input(task.experiment.project.name),
|
||||
name: escape_input(task.name),
|
||||
due_date: task.due_date.present? ? I18n.l(task.due_date, format: :full_with_comma) : nil,
|
||||
overdue: task.is_overdue?,
|
||||
state: task.state,
|
||||
steps_state: { completed_steps: task.steps_completed,
|
||||
all_steps: task.steps_total,
|
||||
percentage: task.steps_completed_percentage } }
|
||||
end,
|
||||
status: :ok
|
||||
}
|
||||
end
|
||||
tasks_per_page = tasks_per_page.with_step_statistics.preload(experiment: :project)
|
||||
tasks_list = tasks_per_page.map do |task|
|
||||
{ id: task.id,
|
||||
link: protocols_my_module_path(task.id),
|
||||
experiment: escape_input(task.experiment.name),
|
||||
project: escape_input(task.experiment.project.name),
|
||||
name: escape_input(task.name),
|
||||
due_date: task.due_date.present? ? I18n.l(task.due_date, format: :full_with_comma) : nil,
|
||||
overdue: task.is_overdue?,
|
||||
state: task.state,
|
||||
steps_state: { completed_steps: task.steps_completed,
|
||||
all_steps: task.steps_total,
|
||||
percentage: task.steps_completed_percentage } }
|
||||
end
|
||||
|
||||
render json: { data: tasks_list, next_page: tasks_per_page.next_page }
|
||||
end
|
||||
|
||||
def project_filter
|
||||
|
@ -83,7 +80,7 @@ module Dashboard
|
|||
private
|
||||
|
||||
def task_filters
|
||||
params.permit(:project_id, :experiment_id, :mode, :view, :sort)
|
||||
params.permit(:project_id, :experiment_id, :mode, :view, :sort, :page)
|
||||
end
|
||||
|
||||
def load_project
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
</div>
|
||||
|
||||
<div class="widget-body">
|
||||
<div class="current-tasks-list perfect-scrollbar"
|
||||
<div id="current-tasks-list" class="current-tasks-list perfect-scrollbar"
|
||||
data-tasks-list-url="<%= dashboard_current_tasks_path %>">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,16 +56,14 @@ class Constants
|
|||
COMMENTS_SEARCH_LIMIT = 10
|
||||
# Activity limited query/display elements for pages
|
||||
ACTIVITY_AND_NOTIF_SEARCH_LIMIT = 20
|
||||
|
||||
# Infinite Scroll load limit (elements per page)
|
||||
INFINITE_SCROLL_LIMIT = 20
|
||||
# Maximum number of users that can be invited in a single action
|
||||
INVITE_USERS_LIMIT = 20
|
||||
|
||||
# Maximum nr. of search results for atwho (smart annotations)
|
||||
ATWHO_SEARCH_LIMIT = 5
|
||||
|
||||
# Max characters for repository name in Atwho modal
|
||||
ATWHO_REP_NAME_LIMIT = 16
|
||||
|
||||
# Number of protocols in recent protocol dropdown
|
||||
RECENT_PROTOCOL_LIMIT = 14
|
||||
|
||||
|
|
Loading…
Reference in a new issue