mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-03-03 19:24:48 +08:00
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:
commit
d2a479c2e8
16 changed files with 154 additions and 38 deletions
|
@ -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() {
|
||||
|
|
|
@ -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>";
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1100,6 +1100,7 @@ en:
|
|||
table:
|
||||
id: 'ID'
|
||||
assigned: "Assigned"
|
||||
assigned_search: 'Search...'
|
||||
assigned_tooltip: "%{tasks} tasks in %{experiments} experiments, %{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 ↓"
|
||||
old_html: "Oldest first ↑"
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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" },
|
||||
|
|
Loading…
Reference in a new issue