mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-17 14:32:34 +08:00
Merge pull request #8485 from aignatov-bio/ai-sci-11858-add-description-to-project-and-experiment-page
Add description buttons to experiments list and tasks list [SCI-11858]
This commit is contained in:
commit
df4d371d17
10 changed files with 195 additions and 8 deletions
|
|
@ -43,6 +43,10 @@ class ExperimentsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def show
|
||||
render json: @experiment, serializer: Lists::ExperimentSerializer, user: current_user
|
||||
end
|
||||
|
||||
def assigned_users
|
||||
render json: User.where(id: @experiment.user_assignments.select(:user_id)),
|
||||
each_serializer: UserSerializer,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ProjectsController < ApplicationController
|
|||
helper_method :current_folder
|
||||
|
||||
before_action :switch_team_with_param, only: :index
|
||||
before_action :load_vars, only: %i(update create_tag assigned_users_list)
|
||||
before_action :load_vars, only: %i(update create_tag assigned_users_list show)
|
||||
before_action :load_current_folder, only: :index
|
||||
before_action :check_read_permissions, except: %i(index create update archive_group restore_group
|
||||
inventory_assigning_project_filter
|
||||
|
|
@ -42,6 +42,10 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def show
|
||||
render json: @project, serializer: ProjectSerializer, user: current_user
|
||||
end
|
||||
|
||||
def inventory_assigning_project_filter
|
||||
viewable_experiments = Experiment.viewable_by_user(current_user, current_team)
|
||||
assignable_my_modules = MyModule.repository_row_assignable_by_user(current_user)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
@archive="archive"
|
||||
@restore="restore"
|
||||
@showDescription="showDescription"
|
||||
@showProjectDescription="showProjectDescription = true"
|
||||
@duplicate="duplicate"
|
||||
@move="move"
|
||||
@edit="edit"
|
||||
|
|
@ -37,6 +38,11 @@
|
|||
:object="descriptionModalObject"
|
||||
@update="updateDescription"
|
||||
@close="descriptionModalObject = null"/>
|
||||
<ProjectDescriptionModal
|
||||
v-if="project && showProjectDescription"
|
||||
:object="project.attributes"
|
||||
@update="updateProjectDescription"
|
||||
@close="showProjectDescription = false"/>
|
||||
<DuplicateModal
|
||||
v-if="duplicateModalObject"
|
||||
:experiment="duplicateModalObject"
|
||||
|
|
@ -70,6 +76,7 @@ import ConfirmationModal from '../shared/confirmation_modal.vue';
|
|||
import CompletedTasksRenderer from './renderers/completed_tasks.vue';
|
||||
import NameRenderer from './renderers/name.vue';
|
||||
import DescriptionModal from '../shared/datatable/modals/description.vue';
|
||||
import ProjectDescriptionModal from '../shared/datatable/modals/description.vue';
|
||||
import DuplicateModal from './modals/duplicate.vue';
|
||||
import MoveModal from './modals/move.vue';
|
||||
import ExperimentFormModal from './modals/form.vue';
|
||||
|
|
@ -85,6 +92,7 @@ export default {
|
|||
DataTable,
|
||||
ConfirmationModal,
|
||||
DescriptionModal,
|
||||
ProjectDescriptionModal,
|
||||
DuplicateModal,
|
||||
MoveModal,
|
||||
ExperimentFormModal,
|
||||
|
|
@ -102,7 +110,8 @@ export default {
|
|||
currentViewMode: { type: String, required: true },
|
||||
createUrl: { type: String, required: true },
|
||||
userRolesUrl: { type: String, required: true },
|
||||
archived: { type: Boolean }
|
||||
archived: { type: Boolean },
|
||||
projectUrl: { type: String, required: true }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -112,6 +121,8 @@ export default {
|
|||
moveModalObject: null,
|
||||
duplicateModalObject: null,
|
||||
descriptionModalObject: null,
|
||||
showProjectDescription: false,
|
||||
project: null,
|
||||
reloadingTable: false,
|
||||
statusesList: [
|
||||
['not_started', this.i18n.t('experiments.table.column.status.not_started')],
|
||||
|
|
@ -230,6 +241,14 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
left.push({
|
||||
name: 'showProjectDescription',
|
||||
icon: 'sn-icon sn-icon-info',
|
||||
label: this.i18n.t('experiments.toolbar.description_button'),
|
||||
type: 'emit',
|
||||
buttonStyle: 'btn btn-light'
|
||||
});
|
||||
|
||||
return {
|
||||
left,
|
||||
right: []
|
||||
|
|
@ -278,7 +297,17 @@ export default {
|
|||
return filters;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadProject();
|
||||
},
|
||||
methods: {
|
||||
loadProject() {
|
||||
axios.get(this.projectUrl).then((response) => {
|
||||
this.project = response.data.data;
|
||||
}).catch((error) => {
|
||||
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
|
||||
});
|
||||
},
|
||||
updateTable() {
|
||||
this.newModalOpen = false;
|
||||
this.editModalObject = null;
|
||||
|
|
@ -308,6 +337,15 @@ export default {
|
|||
this.updateTable();
|
||||
});
|
||||
},
|
||||
updateProjectDescription(description) {
|
||||
axios.put(this.project.attributes.urls.update, {
|
||||
project: {
|
||||
description
|
||||
}
|
||||
}).then(() => {
|
||||
this.loadProject();
|
||||
});
|
||||
},
|
||||
restore(event, rows) {
|
||||
axios.post(event.path, { experiment_ids: rows.map((row) => row.id) }).then((response) => {
|
||||
this.reloadingTable = true;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
@access="access"
|
||||
@archive="archive"
|
||||
@restore="restore"
|
||||
@showExperimentDescription="showExperimentDescription = true"
|
||||
@duplicate="duplicate"
|
||||
@updateDueDate="updateDueDate"
|
||||
@updateStartDate="updateStartDate"
|
||||
|
|
@ -34,6 +35,11 @@
|
|||
:projectName="projectName"
|
||||
:projectTagsUrl="projectTagsUrl"
|
||||
@close="updateTable" />
|
||||
<ExperimentDescriptionModal
|
||||
v-if="experiment && showExperimentDescription"
|
||||
:object="experiment.attributes"
|
||||
@update="updateExperimentDescription"
|
||||
@close="showExperimentDescription = false"/>
|
||||
<NewModal v-if="newModalOpen"
|
||||
:createUrl="createUrl"
|
||||
:projectTagsUrl="projectTagsUrl"
|
||||
|
|
@ -59,6 +65,7 @@
|
|||
import axios from '../../packs/custom_axios.js';
|
||||
import DataTable from '../shared/datatable/table.vue';
|
||||
import ConfirmationModal from '../shared/confirmation_modal.vue';
|
||||
import ExperimentDescriptionModal from '../shared/datatable/modals/description.vue';
|
||||
import NameRenderer from './renderers/name.vue';
|
||||
import ResultsRenderer from './renderers/results.vue';
|
||||
import StatusRenderer from './renderers/status.vue';
|
||||
|
|
@ -79,6 +86,7 @@ export default {
|
|||
DataTable,
|
||||
ConfirmationModal,
|
||||
DueDateRenderer,
|
||||
ExperimentDescriptionModal,
|
||||
StartDateRenderer,
|
||||
DesignatedUsers,
|
||||
TagsModal,
|
||||
|
|
@ -106,7 +114,8 @@ export default {
|
|||
usersFilterUrl: { type: String, required: true },
|
||||
statusesList: { type: Array, required: true },
|
||||
projectName: { type: String },
|
||||
archived: { type: Boolean }
|
||||
archived: { type: Boolean },
|
||||
experimentUrl: { type: String, required: true }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -117,10 +126,14 @@ export default {
|
|||
reloadingTable: false,
|
||||
accessModalParams: null,
|
||||
columnDefs: [],
|
||||
filters: []
|
||||
filters: [],
|
||||
showExperimentDescription: false,
|
||||
experiment: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.loadExperiment();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
field: 'name',
|
||||
|
|
@ -293,6 +306,14 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
left.push({
|
||||
name: 'showExperimentDescription',
|
||||
icon: 'sn-icon sn-icon-info',
|
||||
label: this.i18n.t('experiments.toolbar.description_button'),
|
||||
type: 'emit',
|
||||
buttonStyle: 'btn btn-light'
|
||||
});
|
||||
|
||||
return {
|
||||
left,
|
||||
right: []
|
||||
|
|
@ -300,6 +321,13 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
loadExperiment() {
|
||||
axios.get(this.experimentUrl).then((response) => {
|
||||
this.experiment = response.data.data;
|
||||
}).catch((error) => {
|
||||
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
|
||||
});
|
||||
},
|
||||
updateDueDate(value, params) {
|
||||
axios.put(params.data.urls.update_due_date, {
|
||||
my_module: {
|
||||
|
|
@ -309,6 +337,15 @@ export default {
|
|||
this.updateTable();
|
||||
});
|
||||
},
|
||||
updateExperimentDescription(description) {
|
||||
axios.put(this.experiment.attributes.urls.update, {
|
||||
experiment: {
|
||||
description
|
||||
}
|
||||
}).then(() => {
|
||||
this.loadExperiment();
|
||||
});
|
||||
},
|
||||
updateStartDate(value, params) {
|
||||
axios.put(params.data.urls.update_start_date, {
|
||||
my_module: {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
:data-e2e="`e2e-BT-topToolbar-${action.name}`"
|
||||
@click="doAction(action, $event)">
|
||||
<i :class="action.icon"></i>
|
||||
{{ action.label }}
|
||||
<span class="tw-hidden lg:inline">{{ action.label }}</span>
|
||||
</a>
|
||||
<MenuDropdown
|
||||
v-if="action.type === 'menu'"
|
||||
|
|
|
|||
101
app/serializers/project_serializer.rb
Normal file
101
app/serializers/project_serializer.rb
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ProjectSerializer < ActiveModel::Serializer
|
||||
include Rails.application.routes.url_helpers
|
||||
include Canaid::Helpers::PermissionsHelper
|
||||
include CommentHelper
|
||||
|
||||
attributes :name, :code, :created_at, :archived_on, :users, :urls, :hidden, :default_public_user_role_id, :supervised_by,
|
||||
:comments, :updated_at, :due_date_cell, :start_on_cell, :description, :status, :permissions
|
||||
|
||||
def hidden
|
||||
object.hidden?
|
||||
end
|
||||
|
||||
def supervised_by
|
||||
{
|
||||
id: object.supervised_by&.id,
|
||||
name: object.supervised_by&.name,
|
||||
avatar: (avatar_path(object.supervised_by, :icon_small) if object.supervised_by)
|
||||
}
|
||||
end
|
||||
|
||||
def created_at
|
||||
I18n.l(object.created_at, format: :full_date)
|
||||
end
|
||||
|
||||
def updated_at
|
||||
I18n.l(object.updated_at, format: :full_date)
|
||||
end
|
||||
|
||||
def archived_on
|
||||
I18n.l(object.archived_on, format: :full) if object.archived_on
|
||||
end
|
||||
|
||||
def users
|
||||
object.user_assignments.map do |ua|
|
||||
{
|
||||
avatar: avatar_path(ua.user, :icon_small),
|
||||
full_name: ua.user_name_with_role
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def comments
|
||||
@user = scope[:user] || @instance_options[:user]
|
||||
{
|
||||
count: object.comments.count,
|
||||
count_unseen: count_unseen_comments(object, @user)
|
||||
}
|
||||
end
|
||||
|
||||
def due_date_cell
|
||||
{
|
||||
value: (I18n.l(object.due_date, format: :default) if object.due_date),
|
||||
value_formatted: (I18n.l(object.due_date, format: :full_date) if object.due_date),
|
||||
editable: can_manage_project?(@object),
|
||||
icon: (if object.one_day_prior? && !object.completed?
|
||||
'sn-icon sn-icon-alert-warning text-sn-alert-brittlebush'
|
||||
elsif object.overdue? && !object.completed?
|
||||
'sn-icon sn-icon-alert-warning text-sn-delete-red'
|
||||
end)
|
||||
}
|
||||
end
|
||||
|
||||
def start_on_cell
|
||||
{
|
||||
value: (I18n.l(object.start_on, format: :default) if object.start_on),
|
||||
value_formatted: (I18n.l(object.start_on, format: :full_date) if object.start_on),
|
||||
editable: can_manage_project?(@object)
|
||||
}
|
||||
end
|
||||
|
||||
def permissions
|
||||
{
|
||||
create_comments: can_create_project_comments?(object),
|
||||
manage_users_assignments: can_manage_project_users?(object),
|
||||
manage: can_manage_project?(object)
|
||||
}
|
||||
end
|
||||
|
||||
def urls
|
||||
urls_list = {}
|
||||
|
||||
urls_list[:favorite] = favorite_project_url(object)
|
||||
urls_list[:unfavorite] = unfavorite_project_url(object)
|
||||
urls_list[:show_access] = access_permissions_project_path(object)
|
||||
|
||||
urls_list[:update] = project_path(object) if can_manage_project?(object)
|
||||
|
||||
if can_manage_project_users?(object)
|
||||
urls_list[:assigned_users] = assigned_users_list_project_path(object)
|
||||
urls_list[:update_access] = access_permissions_project_path(object)
|
||||
urls_list[:new_access] = new_access_permissions_project_path(id: object.id)
|
||||
urls_list[:create_access] = access_permissions_projects_path(id: object.id)
|
||||
urls_list[:default_public_user_role_path] =
|
||||
update_default_public_user_role_access_permissions_project_path(object)
|
||||
end
|
||||
|
||||
urls_list
|
||||
end
|
||||
end
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<%= render partial: 'experiments/index/header' %>
|
||||
<div id="ExperimentsList" class="fixed-content-body">
|
||||
<experiments-list
|
||||
project-url="<%= project_path(@project) %>"
|
||||
actions-url="<%= actions_toolbar_experiments_path %>"
|
||||
create-url="<%= project_experiments_path(@project) if can_create_project_experiments?(@project) %>"
|
||||
data-source="<%= experiments_path(project_id: @project, format: :json) %>"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<div id="MyModulesList" class="fixed-content-body">
|
||||
<% view_mode = params[:view_mode] || 'active' %>
|
||||
<my-modules-list
|
||||
experiment-url="<%= experiment_path(@experiment) %>"
|
||||
actions-url="<%= actions_toolbar_my_modules_path %>"
|
||||
create-url="<%= modules_experiment_path(@experiment) if can_manage_experiment?(@experiment) %>"
|
||||
data-source="<%= my_modules_path(experiment_id: @experiment, format: :json) %>"
|
||||
|
|
@ -23,5 +24,6 @@
|
|||
:archived="<%= @experiment.archived_branch?%>"
|
||||
/>
|
||||
</div>
|
||||
<%= render 'shared/tiny_mce_packs' %>
|
||||
<%= javascript_include_tag 'vue_my_modules_list' %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1718,6 +1718,7 @@ en:
|
|||
toolbar:
|
||||
new_button: "New experiment"
|
||||
new_button_tooltip: "Create new experiment"
|
||||
description_button: "Description"
|
||||
edit_button: "Edit details"
|
||||
duplicate_button: "Duplicate"
|
||||
move_button: "Move"
|
||||
|
|
|
|||
|
|
@ -360,7 +360,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :projects, except: [:destroy, :new, :show, :edit] do
|
||||
resources :projects, except: %i(destroy new edit) do
|
||||
# Activities popup (JSON) for individual project in projects index,
|
||||
# as well as all activities page for single project (HTML)
|
||||
resources :project_activities, path: '/activities', only: [:index]
|
||||
|
|
@ -417,9 +417,8 @@ Rails.application.routes.draw do
|
|||
end
|
||||
get 'project_folders/:project_folder_id', to: 'projects#index', as: :project_folder_projects
|
||||
|
||||
get 'projects/:project_id', to: 'experiments#index'
|
||||
get 'projects/:project_id/experiments', to: 'experiments#index', as: :experiments
|
||||
resources :experiments, only: %i(update) do
|
||||
resources :experiments, only: %i(update show) do
|
||||
collection do
|
||||
get 'inventory_assigning_experiment_filter'
|
||||
get 'clone_modal', action: :clone_modal
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue