mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-26 09:42:46 +08:00
Merge pull request #2780 from aignatov-bio/ai-sci-4856-add-new-statuses-to-dashboard
Add new statuses to dashboard [SCI-4856]
This commit is contained in:
commit
5006173d59
6 changed files with 112 additions and 177 deletions
|
@ -1,4 +1,4 @@
|
|||
/* global dropdownSelector I18n animateSpinner PerfectSb InfiniteScroll */
|
||||
/* global dropdownSelector animateSpinner PerfectSb InfiniteScroll */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
var DasboardCurrentTasksWidget = (function() {
|
||||
|
@ -11,15 +11,14 @@ var DasboardCurrentTasksWidget = (function() {
|
|||
$.each(json.data, (i, task) => {
|
||||
var currentTaskItem = ` <a class="current-task-item" href="${task.link}">
|
||||
<div class="current-task-breadcrumbs">${task.project}<span class="slash">/</span>${task.experiment}</div>
|
||||
<div class="item-row">
|
||||
<div class="task-name">${task.name}</div>
|
||||
<div class="task-due-date ${task.state.class} ${task.due_date ? '' : 'hidden'}">
|
||||
<i class="fas fa-calendar-day"></i> ${I18n.t('dashboard.current_tasks.due_date', { date: task.due_date })}
|
||||
</div>
|
||||
<div class="task-progress-container ${task.state.class}">
|
||||
<div class="task-progress" style="padding-left: ${task.steps_precentage}%"></div>
|
||||
<div class="task-progress-label">${task.state.text}</div>
|
||||
</div>
|
||||
<div class="task-name row-border">${task.name}</div>
|
||||
<div class="task-due-date row-border ${task.due_date.state}">
|
||||
<span class="${task.due_date.text ? '' : 'hidden'}">
|
||||
<i class="fas fa-calendar-day"></i> ${task.due_date.text}
|
||||
</span>
|
||||
</div>
|
||||
<div class="task-status-container row-border">
|
||||
<span class="task-status" style="background:${task.status_color}">${task.status_name}</span>
|
||||
</div>
|
||||
</a>`;
|
||||
$(container).append(currentTaskItem);
|
||||
|
|
|
@ -133,28 +133,33 @@
|
|||
}
|
||||
}
|
||||
|
||||
.current-tasks-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.current-tasks-list-wrapper {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: 0 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.current-tasks-list {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: auto max-content max-content;
|
||||
padding: 0 1em;
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.current-task-item {
|
||||
border-bottom: $border-tertiary;
|
||||
color: $color-volcano;
|
||||
padding: 6px;
|
||||
display: contents;
|
||||
text-decoration: none;
|
||||
|
||||
.current-task-breadcrumbs {
|
||||
@include font-small;
|
||||
color: $color-silver-chalice;
|
||||
grid-column: 1 / span 3;
|
||||
line-height: 14px;
|
||||
margin-top: .5em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
@ -166,39 +171,54 @@
|
|||
}
|
||||
}
|
||||
|
||||
.item-row {
|
||||
display: flex;
|
||||
.row-border {
|
||||
border-bottom: $border-tertiary;
|
||||
height: 32px;
|
||||
line-height: 24px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.task-name {
|
||||
flex-grow: 1;
|
||||
font-size: $font-size-base;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
padding-right: 10px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
.task-name {
|
||||
flex-grow: 1;
|
||||
font-size: $font-size-base;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-due-date {
|
||||
flex-basis: 280px;
|
||||
flex-shrink: 0;
|
||||
padding: 0 2em 0 1em;
|
||||
|
||||
.fas {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.task-due-date {
|
||||
flex-basis: 280px;
|
||||
flex-shrink: 0;
|
||||
font-size: 14px;
|
||||
&.overdue {
|
||||
color: $brand-danger;
|
||||
}
|
||||
|
||||
.fas {
|
||||
padding: 4px;
|
||||
}
|
||||
&.day-prior {
|
||||
color: $brand-warning;
|
||||
}
|
||||
|
||||
&.overdue {
|
||||
color: $brand-danger;
|
||||
}
|
||||
&.completed {
|
||||
color: $brand-success;
|
||||
}
|
||||
}
|
||||
|
||||
&.day-prior {
|
||||
color: $brand-warning;
|
||||
}
|
||||
.task-status-container {
|
||||
grid-column: 3;
|
||||
text-align: right;
|
||||
|
||||
&.completed {
|
||||
color: $brand-success;
|
||||
}
|
||||
.task-status {
|
||||
@include font-small;
|
||||
border-radius: $border-radius-tag;
|
||||
color: $color-white;
|
||||
font-weight: bold;
|
||||
padding: .25em .5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,93 +227,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.task-progress-container {
|
||||
height: 20px;
|
||||
max-width: 250px;
|
||||
min-width: 150px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&::after {
|
||||
@include font-small;
|
||||
@include font-awesome;
|
||||
content: "";
|
||||
line-height: 18px;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.task-progress {
|
||||
background: $brand-focus-light;
|
||||
border: $border-tertiary;
|
||||
border-radius: $border-radius-tag;
|
||||
display: flex;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
background: $color-white;
|
||||
content: "";
|
||||
height: 18px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.task-progress-label {
|
||||
@include font-small;
|
||||
font-weight: bold;
|
||||
height: 20px;
|
||||
left: 0;
|
||||
line-height: 20px;
|
||||
padding-left: 8px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
|
||||
&.overdue {
|
||||
.task-progress {
|
||||
background: $brand-danger-light;
|
||||
}
|
||||
|
||||
.task-progress-label {
|
||||
color: $brand-danger;
|
||||
}
|
||||
|
||||
&::after {
|
||||
color: $brand-danger;
|
||||
content: $font-fas-exclamation-triangle;
|
||||
}
|
||||
}
|
||||
|
||||
&.day-prior {
|
||||
.task-progress-label {
|
||||
color: $brand-warning;
|
||||
}
|
||||
}
|
||||
|
||||
&.completed {
|
||||
.task-progress {
|
||||
outline: $border-success;
|
||||
}
|
||||
|
||||
.task-progress,
|
||||
.task-progress::after {
|
||||
background: $brand-success-light;
|
||||
}
|
||||
|
||||
.task-progress-label {
|
||||
color: $brand-success;
|
||||
}
|
||||
|
||||
&::after {
|
||||
color: $brand-success;
|
||||
content: $font-fas-check;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1500px) {
|
||||
|
@ -370,22 +303,33 @@
|
|||
}
|
||||
|
||||
.current-tasks-list {
|
||||
grid-template-columns: auto;
|
||||
|
||||
.current-task-item {
|
||||
.item-row {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.task-due-date {
|
||||
@include font-small;
|
||||
.current-task-breadcrumbs {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.fas {
|
||||
display: none;
|
||||
}
|
||||
.task-name {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.task-due-date {
|
||||
@include font-small;
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
|
||||
.fas {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.task-progress-container {
|
||||
flex-basis: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
.task-status-container {
|
||||
grid-column: 1;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,9 @@ module Dashboard
|
|||
end
|
||||
|
||||
page = (params[:page] || 1).to_i
|
||||
tasks = tasks.with_step_statistics.search_by_name(current_user, current_team, task_filters[:query])
|
||||
tasks = tasks.search_by_name(current_user, current_team, task_filters[:query])
|
||||
.joins(:my_module_status)
|
||||
.select('my_modules.*', 'my_module_statuses.name as status_name', 'my_module_statuses.color as status_color')
|
||||
.preload(experiment: :project).page(page).per(Constants::INFINITE_SCROLL_LIMIT)
|
||||
|
||||
tasks_list = tasks.map do |task|
|
||||
|
@ -50,9 +52,9 @@ module Dashboard
|
|||
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_date) : nil,
|
||||
state: task_state(task),
|
||||
steps_precentage: task.steps_completed_percentage }
|
||||
due_date: prepare_due_date(task),
|
||||
status_color: task.status_color,
|
||||
status_name: task.status_name }
|
||||
end
|
||||
|
||||
render json: { data: tasks_list, next_page: tasks.next_page }
|
||||
|
@ -90,29 +92,26 @@ module Dashboard
|
|||
|
||||
private
|
||||
|
||||
def task_state(task)
|
||||
if task.state == 'completed'
|
||||
task_state_class = task.state
|
||||
task_state_text = t('dashboard.current_tasks.progress_bar.completed')
|
||||
else
|
||||
task_state_text = t('dashboard.current_tasks.progress_bar.in_progress')
|
||||
task_state_class = 'day-prior' if task.is_one_day_prior?
|
||||
if task.is_overdue?
|
||||
task_state_text = t('dashboard.current_tasks.progress_bar.overdue')
|
||||
task_state_class = 'overdue'
|
||||
end
|
||||
if task.steps_total.positive?
|
||||
task_state_text += t('dashboard.current_tasks.progress_bar.completed_steps',
|
||||
steps: task.steps_completed, total_steps: task.steps_total)
|
||||
end
|
||||
end
|
||||
{ text: task_state_text, class: task_state_class }
|
||||
end
|
||||
|
||||
def filter_by_state(tasks)
|
||||
tasks.where(my_modules: { state: task_filters[:view] })
|
||||
end
|
||||
|
||||
def prepare_due_date(task)
|
||||
if task.due_date.present?
|
||||
due_date_formatted = I18n.l(task.due_date, format: :full_date)
|
||||
if task.is_overdue?
|
||||
return { state: 'overdue', text: I18n.t('dashboard.current_tasks.due_date_overdue_html',
|
||||
date: due_date_formatted) }
|
||||
elsif task.is_one_day_prior?
|
||||
return { state: 'day-prior', text: I18n.t('dashboard.current_tasks.due_date_html',
|
||||
date: due_date_formatted) }
|
||||
end
|
||||
|
||||
return { state: '', text: I18n.t('dashboard.current_tasks.due_date_html', date: due_date_formatted) }
|
||||
end
|
||||
{ state: nil, text: nil }
|
||||
end
|
||||
|
||||
def task_filters
|
||||
params.permit(:project_id, :experiment_id, :mode, :view, :sort, :query, :page)
|
||||
end
|
||||
|
|
|
@ -83,16 +83,6 @@ class MyModule < ApplicationRecord
|
|||
end)
|
||||
scope :workflow_ordered, -> { order(workflow_order: :asc) }
|
||||
scope :uncomplete, -> { where(state: 'uncompleted') }
|
||||
scope :with_step_statistics, (lambda do
|
||||
left_outer_joins(protocols: :steps)
|
||||
.group(:id)
|
||||
.select('my_modules.*')
|
||||
.select('COUNT(steps.id) AS steps_total')
|
||||
.select('COUNT(steps.id) FILTER (where steps.completed = true) AS steps_completed')
|
||||
.select('CASE COUNT(steps.id) WHEN 0 THEN 0 ELSE'\
|
||||
'((COUNT(steps.id) FILTER (where steps.completed = true)) * 100 / COUNT(steps.id)) '\
|
||||
'END AS steps_completed_percentage')
|
||||
end)
|
||||
|
||||
# A module takes this much space in canvas (x, y) in database
|
||||
WIDTH = 30
|
||||
|
|
|
@ -59,8 +59,10 @@
|
|||
</div>
|
||||
|
||||
<div class="widget-body">
|
||||
<div class="current-tasks-list perfect-scrollbar"
|
||||
data-tasks-list-url="<%= dashboard_current_tasks_path %>">
|
||||
<div class="current-tasks-list-wrapper perfect-scrollbar">
|
||||
<div class="current-tasks-list "
|
||||
data-tasks-list-url="<%= dashboard_current_tasks_path %>">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,4 +82,4 @@
|
|||
<div class="widget-placeholder">
|
||||
<p class="widget-placeholder-title"><%= I18n.t('dashboard.current_tasks.no_tasks.search_result.title') %></p>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
|
|
@ -30,7 +30,8 @@ en:
|
|||
title: "Your Team has no tasks at the moment."
|
||||
search_result:
|
||||
title: "No results."
|
||||
due_date: "Due date: %{date}"
|
||||
due_date_html: "Due date: <b>%{date}</b>"
|
||||
due_date_overdue_html: "Due date: <b>%{date} (overdue)</b>"
|
||||
progress_bar:
|
||||
in_progress: "In progress"
|
||||
overdue: "Overdue"
|
||||
|
|
Loading…
Reference in a new issue