mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-12-27 02:04:33 +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 */
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
var DasboardCurrentTasksWidget = (function() {
|
var DasboardCurrentTasksWidget = (function() {
|
||||||
|
@ -11,15 +11,14 @@ var DasboardCurrentTasksWidget = (function() {
|
||||||
$.each(json.data, (i, task) => {
|
$.each(json.data, (i, task) => {
|
||||||
var currentTaskItem = ` <a class="current-task-item" href="${task.link}">
|
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="current-task-breadcrumbs">${task.project}<span class="slash">/</span>${task.experiment}</div>
|
||||||
<div class="item-row">
|
<div class="task-name row-border">${task.name}</div>
|
||||||
<div class="task-name">${task.name}</div>
|
<div class="task-due-date row-border ${task.due_date.state}">
|
||||||
<div class="task-due-date ${task.state.class} ${task.due_date ? '' : 'hidden'}">
|
<span class="${task.due_date.text ? '' : 'hidden'}">
|
||||||
<i class="fas fa-calendar-day"></i> ${I18n.t('dashboard.current_tasks.due_date', { date: task.due_date })}
|
<i class="fas fa-calendar-day"></i> ${task.due_date.text}
|
||||||
</div>
|
</span>
|
||||||
<div class="task-progress-container ${task.state.class}">
|
</div>
|
||||||
<div class="task-progress" style="padding-left: ${task.steps_precentage}%"></div>
|
<div class="task-status-container row-border">
|
||||||
<div class="task-progress-label">${task.state.text}</div>
|
<span class="task-status" style="background:${task.status_color}">${task.status_name}</span>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</a>`;
|
</a>`;
|
||||||
$(container).append(currentTaskItem);
|
$(container).append(currentTaskItem);
|
||||||
|
|
|
@ -133,28 +133,33 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-tasks-list {
|
.current-tasks-list-wrapper {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0 10px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-tasks-list {
|
||||||
|
align-items: center;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto max-content max-content;
|
||||||
|
padding: 0 1em;
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-task-item {
|
.current-task-item {
|
||||||
border-bottom: $border-tertiary;
|
|
||||||
color: $color-volcano;
|
color: $color-volcano;
|
||||||
padding: 6px;
|
display: contents;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
.current-task-breadcrumbs {
|
.current-task-breadcrumbs {
|
||||||
@include font-small;
|
@include font-small;
|
||||||
color: $color-silver-chalice;
|
color: $color-silver-chalice;
|
||||||
|
grid-column: 1 / span 3;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
|
margin-top: .5em;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -166,39 +171,54 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-row {
|
.row-border {
|
||||||
display: flex;
|
border-bottom: $border-tertiary;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.task-name {
|
.task-name {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-right: 10px;
|
text-overflow: ellipsis;
|
||||||
text-overflow: ellipsis;
|
white-space: nowrap;
|
||||||
white-space: nowrap;
|
}
|
||||||
|
|
||||||
|
.task-due-date {
|
||||||
|
flex-basis: 280px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0 2em 0 1em;
|
||||||
|
|
||||||
|
.fas {
|
||||||
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-due-date {
|
&.overdue {
|
||||||
flex-basis: 280px;
|
color: $brand-danger;
|
||||||
flex-shrink: 0;
|
}
|
||||||
font-size: 14px;
|
|
||||||
|
|
||||||
.fas {
|
&.day-prior {
|
||||||
padding: 4px;
|
color: $brand-warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.overdue {
|
&.completed {
|
||||||
color: $brand-danger;
|
color: $brand-success;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.day-prior {
|
.task-status-container {
|
||||||
color: $brand-warning;
|
grid-column: 3;
|
||||||
}
|
text-align: right;
|
||||||
|
|
||||||
&.completed {
|
.task-status {
|
||||||
color: $brand-success;
|
@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) {
|
@media (max-width: 1500px) {
|
||||||
|
@ -370,22 +303,33 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.current-tasks-list {
|
.current-tasks-list {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
|
||||||
.current-task-item {
|
.current-task-item {
|
||||||
.item-row {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
.task-due-date {
|
.current-task-breadcrumbs {
|
||||||
@include font-small;
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.fas {
|
.task-name {
|
||||||
display: none;
|
border: 0;
|
||||||
}
|
padding: 0;
|
||||||
|
height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-due-date {
|
||||||
|
@include font-small;
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
|
.fas {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.task-progress-container {
|
.task-status-container {
|
||||||
flex-basis: 100%;
|
grid-column: 1;
|
||||||
max-width: none;
|
text-align: left;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,9 @@ module Dashboard
|
||||||
end
|
end
|
||||||
|
|
||||||
page = (params[:page] || 1).to_i
|
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)
|
.preload(experiment: :project).page(page).per(Constants::INFINITE_SCROLL_LIMIT)
|
||||||
|
|
||||||
tasks_list = tasks.map do |task|
|
tasks_list = tasks.map do |task|
|
||||||
|
@ -50,9 +52,9 @@ module Dashboard
|
||||||
experiment: escape_input(task.experiment.name),
|
experiment: escape_input(task.experiment.name),
|
||||||
project: escape_input(task.experiment.project.name),
|
project: escape_input(task.experiment.project.name),
|
||||||
name: escape_input(task.name),
|
name: escape_input(task.name),
|
||||||
due_date: task.due_date.present? ? I18n.l(task.due_date, format: :full_date) : nil,
|
due_date: prepare_due_date(task),
|
||||||
state: task_state(task),
|
status_color: task.status_color,
|
||||||
steps_precentage: task.steps_completed_percentage }
|
status_name: task.status_name }
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: { data: tasks_list, next_page: tasks.next_page }
|
render json: { data: tasks_list, next_page: tasks.next_page }
|
||||||
|
@ -90,29 +92,26 @@ module Dashboard
|
||||||
|
|
||||||
private
|
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)
|
def filter_by_state(tasks)
|
||||||
tasks.where(my_modules: { state: task_filters[:view] })
|
tasks.where(my_modules: { state: task_filters[:view] })
|
||||||
end
|
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
|
def task_filters
|
||||||
params.permit(:project_id, :experiment_id, :mode, :view, :sort, :query, :page)
|
params.permit(:project_id, :experiment_id, :mode, :view, :sort, :query, :page)
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,16 +83,6 @@ class MyModule < ApplicationRecord
|
||||||
end)
|
end)
|
||||||
scope :workflow_ordered, -> { order(workflow_order: :asc) }
|
scope :workflow_ordered, -> { order(workflow_order: :asc) }
|
||||||
scope :uncomplete, -> { where(state: 'uncompleted') }
|
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
|
# A module takes this much space in canvas (x, y) in database
|
||||||
WIDTH = 30
|
WIDTH = 30
|
||||||
|
|
|
@ -59,8 +59,10 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="widget-body">
|
<div class="widget-body">
|
||||||
<div class="current-tasks-list perfect-scrollbar"
|
<div class="current-tasks-list-wrapper perfect-scrollbar">
|
||||||
data-tasks-list-url="<%= dashboard_current_tasks_path %>">
|
<div class="current-tasks-list "
|
||||||
|
data-tasks-list-url="<%= dashboard_current_tasks_path %>">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,4 +82,4 @@
|
||||||
<div class="widget-placeholder">
|
<div class="widget-placeholder">
|
||||||
<p class="widget-placeholder-title"><%= I18n.t('dashboard.current_tasks.no_tasks.search_result.title') %></p>
|
<p class="widget-placeholder-title"><%= I18n.t('dashboard.current_tasks.no_tasks.search_result.title') %></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -30,7 +30,8 @@ en:
|
||||||
title: "Your Team has no tasks at the moment."
|
title: "Your Team has no tasks at the moment."
|
||||||
search_result:
|
search_result:
|
||||||
title: "No results."
|
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:
|
progress_bar:
|
||||||
in_progress: "In progress"
|
in_progress: "In progress"
|
||||||
overdue: "Overdue"
|
overdue: "Overdue"
|
||||||
|
|
Loading…
Reference in a new issue