Merge pull request #2526 from aignatov-bio/ai-sci-4559-add-assigned-tasks-dropdown-to-inventory

Add assigned task dropdown to repository and task page [SCI-4559][SCI-4565]
This commit is contained in:
aignatov-bio 2020-05-08 12:39:28 +02:00 committed by GitHub
commit d2a479c2e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 154 additions and 38 deletions

View file

@ -1,6 +1,5 @@
/* eslint-disable no-param-reassign, no-use-before-define */
/* global DataTableHelpers PerfectScrollbar FilePreviewModal animateSpinner HelperModule */
/* global DataTableHelpers PerfectScrollbar FilePreviewModal animateSpinner HelperModule initAssignedTasksDropdown */
var MyModuleRepositories = (function() {
const FULL_VIEW_MODAL = $('#myModuleRepositoryFullViewModal');
@ -59,7 +58,10 @@ var MyModuleRepositories = (function() {
targets: 1,
searchable: false,
className: 'assigned-column',
sWidth: '1%'
sWidth: '1%',
render: function(data) {
return $.fn.dataTable.render.AssignedTasksValue(data);
}
}, {
targets: 3,
render: function(data, type, row) {
@ -158,6 +160,7 @@ var MyModuleRepositories = (function() {
} else {
$('.table-container .toolbar').html($('#repositoryToolbarButtonsTemplate').html());
}
initAssignedTasksDropdown(tableContainer);
},
drawCallback: function() {

View file

@ -154,3 +154,26 @@ $.fn.dataTable.render.RepositoryNumberValue = function(data) {
${data.value}
</span>`;
};
$.fn.dataTable.render.AssignedTasksValue = function(data) {
if (data.tasks > 0) {
let tooltip = I18n.t('repositories.table.assigned_tooltip', {
tasks: data.tasks,
experiments: data.experiments,
projects: data.projects
});
return `<div class="assign-counter-container dropdown" title="${tooltip}"
data-task-list-url="${data.task_list_url}">
<a href="#" class="assign-counter has-assigned"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">${data.tasks}</a>
<div class="dropdown-menu" role="menu">
<div class="sci-input-container">
<input type="text" class="sci-input-field search-tasks"
placeholder="${I18n.t('repositories.table.assigned_search')}"></input>
</div>
<div class="tasks"></div>
</div>
</div>`;
}
return "<div class='assign-counter-container'><span class='assign-counter'>0</span></div>";
};

View file

@ -1,6 +1,7 @@
/*
globals I18n _ SmartAnnotation FilePreviewModal animateSpinner Promise DataTableHelpers
HelperModule animateLoading hideAssignUnasignModal RepositoryDatatableRowEditor
initAssignedTasksDropdown
*/
//= require jquery-ui/widgets/sortable
@ -442,7 +443,7 @@ var RepositoryDatatable = (function(global) {
className: 'assigned-column',
sWidth: '1%',
render: function(data, type, row) {
let content = data;
let content = $.fn.dataTable.render.AssignedTasksValue(data);
let icon;
if (!row.recordEditable) {
icon = `<i class="repository-row-lock-icon fas fa-lock" title="${I18n.t('repositories.table.locked_item')}"></i>`;
@ -582,6 +583,8 @@ var RepositoryDatatable = (function(global) {
$(TABLE_ID).find('tr[data-editable=false]').each(function(_, e) {
rowsLocked.push(parseInt($(e).attr('id'), 10));
});
initAssignedTasksDropdown(TABLE_ID);
}
});

View file

@ -18,3 +18,28 @@
initUnsavedWorkDialog();
}());
function initAssignedTasksDropdown(table) {
function loadTasks(counterContainer) {
var tasksContainer = counterContainer.find('.tasks');
var tasksUrl = counterContainer.data('task-list-url');
var searchQuery = counterContainer.find('.search-tasks').val();
$.get(tasksUrl, { query: searchQuery }, function(result) {
tasksContainer.html(result.html);
});
}
$(table).on('show.bs.dropdown', '.assign-counter-container', function() {
var cell = $(this);
loadTasks(cell);
});
$(table).on('click', '.assign-counter-container .dropdown-menu', function(e) {
e.stopPropagation();
});
$(table).on('change', '.assign-counter-container .search-tasks', function() {
var cell = $(this).closest('.assign-counter-container');
loadTasks(cell);
});
}

View file

@ -267,6 +267,10 @@
width: calc(100% - 16px);
.assign-counter {
display: inline-block;
height: 100%;
width: 100%;
&.has-assigned {
color: $brand-primary;
}
@ -275,6 +279,11 @@
&:hover {
background-color: $color-alto;
}
.dropdown-menu {
min-width: 320px;
padding: 8px;
}
}
}
}

View file

@ -41,7 +41,6 @@
.assign-counter-container {
border-radius: $border-radius-tag;
cursor: pointer;
display: inline-block;
line-height: 35px;
position: absolute;
@ -49,7 +48,16 @@
width: calc(100% - 40px);
.assign-counter {
margin-left: 5px;
display: inline-block;
height: 100%;
padding-left: 5px;
width: 100%;
&:hover,
&:visited,
&:focus {
text-decoration: none;
}
&.has-assigned {
color: $brand-primary;
@ -59,6 +67,11 @@
&:hover {
background-color: $color-alto;
}
.dropdown-menu {
min-width: 320px;
padding: 8px;
}
}
.circle-icon {

View file

@ -56,4 +56,14 @@
}
}
}
.archived {
@include font-small;
background: $brand-warning;
border-radius: $border-radius-tag;
color: $color-white;
line-height: 14px;
margin-right: 3px;
padding: 2px 3px;
}
}

View file

@ -3,6 +3,7 @@
module Dashboard
class CalendarsController < ApplicationController
include IconsHelper
include MyModulesHelper
def show
date = DateTime.parse(params[:date])
@ -26,9 +27,10 @@ module Dashboard
.where(projects: { archived: false })
.where('DATE(my_modules.due_date) = DATE(?)', date)
.where(projects: { team_id: current_team.id })
.my_modules_list_partial
render json: {
html: render_to_string(partial: 'shared/my_modules_list_partial.html.erb', locals: { task_groups: my_modules })
html: render_to_string(partial: 'shared/my_modules_list_partial.html.erb', locals: {
my_modules: my_modules
})
}
end
end

View file

@ -2,8 +2,9 @@ class RepositoryRowsController < ApplicationController
include InputSanitizeHelper
include ActionView::Helpers::TextHelper
include ApplicationHelper
include MyModulesHelper
before_action :load_info_modal_vars, only: :show
before_action :load_info_modal_vars, only: %i(show assigned_task_list)
before_action :load_vars, only: %i(edit update)
before_action :load_repository,
only: %i(create
@ -180,6 +181,16 @@ class RepositoryRowsController < ApplicationController
end
end
def assigned_task_list
my_modules = @repository_row.my_modules.joins(experiment: :project)
.search_by_name(current_user, current_team, params[:query])
render json: {
html: render_to_string(partial: 'shared/my_modules_list_partial.html.erb', locals: {
my_modules: my_modules
})
}
end
private
include StringUtility

View file

@ -55,4 +55,22 @@ module MyModulesHelper
def is_results_page?
action_name == 'results'
end
def grouped_by_prj_exp(my_modules)
ungrouped_tasks = my_modules.joins(experiment: :project)
.select('experiments.name as experiment_name,
experiments.archived as experiment_archived,
projects.name as project_name,
projects.archived as project_archived,
my_modules.*')
ungrouped_tasks.group_by { |i| [i[:project_name], i[:experiment_name]] }.map do |group, tasks|
{
project_name: group[0],
project_archived: tasks[0]&.project_archived,
experiment_name: group[1],
experiment_archived: tasks[0]&.experiment_archived,
tasks: tasks
}
end
end
end

View file

@ -67,17 +67,12 @@ module RepositoryDatatableHelper
end
def assigned_row(record)
if record.assigned_my_modules_count.positive?
tooltip = t('repositories.table.assigned_tooltip',
tasks: record.assigned_my_modules_count,
{
tasks: record.assigned_my_modules_count,
experiments: record.assigned_experiments_count,
projects: record.assigned_projects_count)
"<div class='assign-counter-container' title='#{tooltip}'>"\
"<span class='assign-counter has-assigned'>#{record.assigned_my_modules_count}</span></div>"
else
"<div class='assign-counter-container'><span class='assign-counter'>0</span></div>"
end
projects: record.assigned_projects_count,
task_list_url: assigned_task_list_repository_repository_row_path(record.repository, record)
}
end
def can_perform_repository_actions(repository)

View file

@ -523,21 +523,6 @@ class MyModule < ApplicationRecord
self.completed_on = nil
end
def self.my_modules_list_partial
ungrouped_tasks = joins(experiment: :project)
.select('experiments.name as experiment_name,
projects.name as project_name,
my_modules.name as task_name,
my_modules.id')
ungrouped_tasks.group_by { |i| [i[:project_name], i[:experiment_name]] }.map do |group, tasks|
{
project_name: group[0],
experiment_name: group[1],
tasks: tasks.map { |task| { id: task.id, task_name: task.task_name } }
}
end
end
def assign_user(user, assigned_by = nil)
user_my_modules.create(
assigned_by: assigned_by || user,

View file

@ -1,16 +1,29 @@
<div class="my-modules-list-partial">
<% task_groups.each do |task_group| %>
<% grouped_by_prj_exp(my_modules).each do |task_group| %>
<div class="task-group">
<div class="header">
<% if task_group[:project_archived]%>
<span class="archived"><%= t('general.archived') %></span>
<% end %>
<span class="project" title="<%= task_group[:project_name] %>"><%= task_group[:project_name] %></span>
<span class="slash">/</span>
<% if task_group[:experiment_archived] %>
<span class="archived"><%= t('general.archived') %></span>
<% end %>
<span class="experiment" title="<%= task_group[:experiment_name] %>"><%= task_group[:experiment_name] %></span>
</div>
<div class="tasks">
<% task_group[:tasks].each do |task| %>
<div class="task">
<%= draw_custom_icon('task-icon') %>
<%= link_to(task[:task_name], protocols_my_module_path(task[:id]), {class: "task-link", title: task[:task_name]}) %>
<% if task.archived %>
<span class="archived"><%= t('general.archived') %></span>
<% end %>
<% if can_read_experiment?(current_user, task.experiment) %>
<%= link_to(task.name, protocols_my_module_path(task.id), {class: "task-link", title: task.name, target: "_blank"}) %>
<% else %>
<%= task.name %>
<% end %>
</div>
<% end %>
</div>

View file

@ -1100,6 +1100,7 @@ en:
table:
id: 'ID'
assigned: "Assigned"
assigned_search: 'Search...'
assigned_tooltip: "%{tasks} tasks in &#10;%{experiments} experiments,&#10;%{projects} projects"
row_name: "Name"
added_on: "Added on"
@ -2202,6 +2203,7 @@ en:
more_comments: "More comments"
comment_placeholder: "Your Message"
comment_placeholder_new: "Add new comment…"
archived: "Archived"
sort:
new_html: "Newest first &#8595;"
old_html: "Oldest first &#8593;"

View file

@ -633,7 +633,11 @@ Rails.application.routes.draw do
defaults: { format: 'json' }
resources :repository_columns, only: %i(create edit update destroy)
resources :repository_rows, only: %i(create edit update)
resources :repository_rows, only: %i(create edit update) do
member do
get :assigned_task_list
end
end
member do
post 'parse_sheet', defaults: { format: 'json' }
post 'import_records'

View file

@ -11,7 +11,7 @@
"required": ["DT_RowId", "1", "2", "3", "4", "5", "recordEditUrl", "recordUpdateUrl", "recordInfoUrl"],
"properties": {
"DT_RowId": { "type": "integer" },
"1": { "type": "string" },
"1": { "type": "object" },
"2": { "type": "integer" },
"3": { "type": "string" },
"4": { "type": "string" },