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 */
|
/* 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() {
|
var MyModuleRepositories = (function() {
|
||||||
const FULL_VIEW_MODAL = $('#myModuleRepositoryFullViewModal');
|
const FULL_VIEW_MODAL = $('#myModuleRepositoryFullViewModal');
|
||||||
|
@ -59,7 +58,10 @@ var MyModuleRepositories = (function() {
|
||||||
targets: 1,
|
targets: 1,
|
||||||
searchable: false,
|
searchable: false,
|
||||||
className: 'assigned-column',
|
className: 'assigned-column',
|
||||||
sWidth: '1%'
|
sWidth: '1%',
|
||||||
|
render: function(data) {
|
||||||
|
return $.fn.dataTable.render.AssignedTasksValue(data);
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
targets: 3,
|
targets: 3,
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
|
@ -158,6 +160,7 @@ var MyModuleRepositories = (function() {
|
||||||
} else {
|
} else {
|
||||||
$('.table-container .toolbar').html($('#repositoryToolbarButtonsTemplate').html());
|
$('.table-container .toolbar').html($('#repositoryToolbarButtonsTemplate').html());
|
||||||
}
|
}
|
||||||
|
initAssignedTasksDropdown(tableContainer);
|
||||||
},
|
},
|
||||||
|
|
||||||
drawCallback: function() {
|
drawCallback: function() {
|
||||||
|
|
|
@ -154,3 +154,26 @@ $.fn.dataTable.render.RepositoryNumberValue = function(data) {
|
||||||
${data.value}
|
${data.value}
|
||||||
</span>`;
|
</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
|
globals I18n _ SmartAnnotation FilePreviewModal animateSpinner Promise DataTableHelpers
|
||||||
HelperModule animateLoading hideAssignUnasignModal RepositoryDatatableRowEditor
|
HelperModule animateLoading hideAssignUnasignModal RepositoryDatatableRowEditor
|
||||||
|
initAssignedTasksDropdown
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//= require jquery-ui/widgets/sortable
|
//= require jquery-ui/widgets/sortable
|
||||||
|
@ -442,7 +443,7 @@ var RepositoryDatatable = (function(global) {
|
||||||
className: 'assigned-column',
|
className: 'assigned-column',
|
||||||
sWidth: '1%',
|
sWidth: '1%',
|
||||||
render: function(data, type, row) {
|
render: function(data, type, row) {
|
||||||
let content = data;
|
let content = $.fn.dataTable.render.AssignedTasksValue(data);
|
||||||
let icon;
|
let icon;
|
||||||
if (!row.recordEditable) {
|
if (!row.recordEditable) {
|
||||||
icon = `<i class="repository-row-lock-icon fas fa-lock" title="${I18n.t('repositories.table.locked_item')}"></i>`;
|
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) {
|
$(TABLE_ID).find('tr[data-editable=false]').each(function(_, e) {
|
||||||
rowsLocked.push(parseInt($(e).attr('id'), 10));
|
rowsLocked.push(parseInt($(e).attr('id'), 10));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initAssignedTasksDropdown(TABLE_ID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,28 @@
|
||||||
|
|
||||||
initUnsavedWorkDialog();
|
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);
|
width: calc(100% - 16px);
|
||||||
|
|
||||||
.assign-counter {
|
.assign-counter {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&.has-assigned {
|
&.has-assigned {
|
||||||
color: $brand-primary;
|
color: $brand-primary;
|
||||||
}
|
}
|
||||||
|
@ -275,6 +279,11 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $color-alto;
|
background-color: $color-alto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
min-width: 320px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
|
|
||||||
.assign-counter-container {
|
.assign-counter-container {
|
||||||
border-radius: $border-radius-tag;
|
border-radius: $border-radius-tag;
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -49,7 +48,16 @@
|
||||||
width: calc(100% - 40px);
|
width: calc(100% - 40px);
|
||||||
|
|
||||||
.assign-counter {
|
.assign-counter {
|
||||||
margin-left: 5px;
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
padding-left: 5px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:visited,
|
||||||
|
&:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
&.has-assigned {
|
&.has-assigned {
|
||||||
color: $brand-primary;
|
color: $brand-primary;
|
||||||
|
@ -59,6 +67,11 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $color-alto;
|
background-color: $color-alto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
min-width: 320px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.circle-icon {
|
.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
|
module Dashboard
|
||||||
class CalendarsController < ApplicationController
|
class CalendarsController < ApplicationController
|
||||||
include IconsHelper
|
include IconsHelper
|
||||||
|
include MyModulesHelper
|
||||||
|
|
||||||
def show
|
def show
|
||||||
date = DateTime.parse(params[:date])
|
date = DateTime.parse(params[:date])
|
||||||
|
@ -26,9 +27,10 @@ module Dashboard
|
||||||
.where(projects: { archived: false })
|
.where(projects: { archived: false })
|
||||||
.where('DATE(my_modules.due_date) = DATE(?)', date)
|
.where('DATE(my_modules.due_date) = DATE(?)', date)
|
||||||
.where(projects: { team_id: current_team.id })
|
.where(projects: { team_id: current_team.id })
|
||||||
.my_modules_list_partial
|
|
||||||
render json: {
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,9 @@ class RepositoryRowsController < ApplicationController
|
||||||
include InputSanitizeHelper
|
include InputSanitizeHelper
|
||||||
include ActionView::Helpers::TextHelper
|
include ActionView::Helpers::TextHelper
|
||||||
include ApplicationHelper
|
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_vars, only: %i(edit update)
|
||||||
before_action :load_repository,
|
before_action :load_repository,
|
||||||
only: %i(create
|
only: %i(create
|
||||||
|
@ -180,6 +181,16 @@ class RepositoryRowsController < ApplicationController
|
||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
include StringUtility
|
include StringUtility
|
||||||
|
|
|
@ -55,4 +55,22 @@ module MyModulesHelper
|
||||||
def is_results_page?
|
def is_results_page?
|
||||||
action_name == 'results'
|
action_name == 'results'
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -67,17 +67,12 @@ module RepositoryDatatableHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigned_row(record)
|
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,
|
experiments: record.assigned_experiments_count,
|
||||||
projects: record.assigned_projects_count)
|
projects: record.assigned_projects_count,
|
||||||
|
task_list_url: assigned_task_list_repository_repository_row_path(record.repository, record)
|
||||||
"<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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_perform_repository_actions(repository)
|
def can_perform_repository_actions(repository)
|
||||||
|
|
|
@ -523,21 +523,6 @@ class MyModule < ApplicationRecord
|
||||||
self.completed_on = nil
|
self.completed_on = nil
|
||||||
end
|
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)
|
def assign_user(user, assigned_by = nil)
|
||||||
user_my_modules.create(
|
user_my_modules.create(
|
||||||
assigned_by: assigned_by || user,
|
assigned_by: assigned_by || user,
|
||||||
|
|
|
@ -1,16 +1,29 @@
|
||||||
<div class="my-modules-list-partial">
|
<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="task-group">
|
||||||
<div class="header">
|
<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="project" title="<%= task_group[:project_name] %>"><%= task_group[:project_name] %></span>
|
||||||
<span class="slash">/</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>
|
<span class="experiment" title="<%= task_group[:experiment_name] %>"><%= task_group[:experiment_name] %></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tasks">
|
<div class="tasks">
|
||||||
<% task_group[:tasks].each do |task| %>
|
<% task_group[:tasks].each do |task| %>
|
||||||
<div class="task">
|
<div class="task">
|
||||||
<%= draw_custom_icon('task-icon') %>
|
<%= 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>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1100,6 +1100,7 @@ en:
|
||||||
table:
|
table:
|
||||||
id: 'ID'
|
id: 'ID'
|
||||||
assigned: "Assigned"
|
assigned: "Assigned"
|
||||||
|
assigned_search: 'Search...'
|
||||||
assigned_tooltip: "%{tasks} tasks in %{experiments} experiments, %{projects} projects"
|
assigned_tooltip: "%{tasks} tasks in %{experiments} experiments, %{projects} projects"
|
||||||
row_name: "Name"
|
row_name: "Name"
|
||||||
added_on: "Added on"
|
added_on: "Added on"
|
||||||
|
@ -2202,6 +2203,7 @@ en:
|
||||||
more_comments: "More comments"
|
more_comments: "More comments"
|
||||||
comment_placeholder: "Your Message"
|
comment_placeholder: "Your Message"
|
||||||
comment_placeholder_new: "Add new comment…"
|
comment_placeholder_new: "Add new comment…"
|
||||||
|
archived: "Archived"
|
||||||
sort:
|
sort:
|
||||||
new_html: "Newest first ↓"
|
new_html: "Newest first ↓"
|
||||||
old_html: "Oldest first ↑"
|
old_html: "Oldest first ↑"
|
||||||
|
|
|
@ -633,7 +633,11 @@ Rails.application.routes.draw do
|
||||||
defaults: { format: 'json' }
|
defaults: { format: 'json' }
|
||||||
|
|
||||||
resources :repository_columns, only: %i(create edit update destroy)
|
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
|
member do
|
||||||
post 'parse_sheet', defaults: { format: 'json' }
|
post 'parse_sheet', defaults: { format: 'json' }
|
||||||
post 'import_records'
|
post 'import_records'
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"required": ["DT_RowId", "1", "2", "3", "4", "5", "recordEditUrl", "recordUpdateUrl", "recordInfoUrl"],
|
"required": ["DT_RowId", "1", "2", "3", "4", "5", "recordEditUrl", "recordUpdateUrl", "recordInfoUrl"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"DT_RowId": { "type": "integer" },
|
"DT_RowId": { "type": "integer" },
|
||||||
"1": { "type": "string" },
|
"1": { "type": "object" },
|
||||||
"2": { "type": "integer" },
|
"2": { "type": "integer" },
|
||||||
"3": { "type": "string" },
|
"3": { "type": "string" },
|
||||||
"4": { "type": "string" },
|
"4": { "type": "string" },
|
||||||
|
|
Loading…
Reference in a new issue