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:
Alex Kriuchykhin 2020-08-24 11:09:57 +02:00 committed by GitHub
commit 5006173d59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 177 deletions

View file

@ -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);

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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"