Add filtering for project/experiment filter for assignable tasks [SCI-8442] (#5441)

* Remove object without  edit permission in P/E/T filters [SCI-8442]

* Leave only experiments and projects with active tasks [SCI-8442]
This commit is contained in:
Soufiane 2023-05-24 10:47:27 +02:00 committed by GitHub
parent c7fcd0a52f
commit f21dc998b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 109 additions and 57 deletions

View file

@ -92,6 +92,11 @@
padding: .5em; padding: .5em;
} }
.sn-select__no-options {
color: var(--sn-grey);
padding: .5em;
}
.sn-select__option:hover { .sn-select__option:hover {
background: var(--sn-blue); background: var(--sn-blue);
color: var(--sn-white); color: var(--sn-white);

View file

@ -445,12 +445,23 @@ class ExperimentsController < ApplicationController
end end
def experiment_filter def experiment_filter
project = Project.readable_by_user(current_user).find_by(id: params[:project_id]) readable_experiments = Experiment.readable_by_user(current_user)
managable_active_my_modules = MyModule.managable_by_user(current_user).active
project = Project.readable_by_user(current_user)
.joins(experiments: :my_modules)
.where(experiments: { id: readable_experiments })
.where(my_modules: { id: managable_active_my_modules })
.find_by(id: params[:project_id])
return render_404 if project.blank? return render_404 if project.blank?
experiments = project.experiments experiments = project.experiments
.readable_by_user(current_user) .joins(:my_modules)
.where(experiments: { id: readable_experiments })
.where(my_modules: { id: managable_active_my_modules })
.search(current_user, false, params[:query], 1, current_team) .search(current_user, false, params[:query], 1, current_team)
.distinct
.pluck(:id, :name) .pluck(:id, :name)
return render plain: [].to_json if experiments.blank? return render plain: [].to_json if experiments.blank?

View file

@ -74,13 +74,13 @@ class MyModulesController < ApplicationController
def show def show
respond_to do |format| respond_to do |format|
format.json { format.json do
render :json => { render json: {
:html => render_to_string({ html: render_to_string({
:partial => "show.html.erb" partial: 'show.html.erb'
}) })
} }
} end
end end
end end
@ -88,15 +88,15 @@ class MyModulesController < ApplicationController
def description def description
respond_to do |format| respond_to do |format|
format.html format.html
format.json { format.json do
render json: { render json: {
html: render_to_string({ html: render_to_string({
partial: "description.html.erb" partial: 'description.html.erb'
}), }),
title: t('my_modules.description.title', title: t('my_modules.description.title',
module: escape_input(@my_module.name)) module: escape_input(@my_module.name))
} }
} end
end end
end end
@ -164,13 +164,13 @@ class MyModulesController < ApplicationController
respond_to do |format| respond_to do |format|
format.html format.html
format.json { format.json do
render :json => { render json: {
:html => render_to_string({ html: render_to_string({
:partial => "activities.html.erb" partial: 'activities.html.erb'
}) })
} }
} end
end end
end end
@ -178,15 +178,15 @@ class MyModulesController < ApplicationController
def due_date def due_date
respond_to do |format| respond_to do |format|
format.html format.html
format.json { format.json do
render json: { render json: {
html: render_to_string({ html: render_to_string({
partial: "due_date.html.erb" partial: 'due_date.html.erb'
}), }),
title: t('my_modules.due_date.title', title: t('my_modules.due_date.title',
module: escape_input(@my_module.name)) module: escape_input(@my_module.name))
} }
} end
end end
end end
@ -198,21 +198,13 @@ class MyModulesController < ApplicationController
start_date_changes = @my_module.changes[:started_on] start_date_changes = @my_module.changes[:started_on]
due_date_changes = @my_module.changes[:due_date] due_date_changes = @my_module.changes[:due_date]
if @my_module.completed_on_changed? && !can_complete_my_module?(@my_module) render_403 && return if @my_module.completed_on_changed? && !can_complete_my_module?(@my_module)
render_403 && return
end
if description_changed && !can_update_my_module_description?(@my_module) render_403 && return if description_changed && !can_update_my_module_description?(@my_module)
render_403 && return
end
if start_date_changes.present? && !can_update_my_module_start_date?(@my_module) render_403 && return if start_date_changes.present? && !can_update_my_module_start_date?(@my_module)
render_403 && return
end
if due_date_changes.present? && !can_update_my_module_start_date?(@my_module) render_403 && return if due_date_changes.present? && !can_update_my_module_start_date?(@my_module)
render_403 && return
end
if @my_module.archived_changed?(from: false, to: true) if @my_module.archived_changed?(from: false, to: true)
saved = @my_module.archive(current_user) saved = @my_module.archive(current_user)
@ -273,7 +265,7 @@ class MyModulesController < ApplicationController
else else
format.json do format.json do
render json: @my_module.errors, render json: @my_module.errors,
status: :unprocessable_entity status: :unprocessable_entity
end end
end end
end end
@ -281,6 +273,7 @@ class MyModulesController < ApplicationController
def update_description def update_description
render_403 && return unless can_update_my_module_description?(@my_module) render_403 && return unless can_update_my_module_description?(@my_module)
old_description = @my_module.description old_description = @my_module.description
respond_to do |format| respond_to do |format|
format.json do format.json do
@ -414,7 +407,7 @@ class MyModulesController < ApplicationController
log_activity(:change_status_on_task_flow, @my_module, my_module_status_old: old_status_id, log_activity(:change_status_on_task_flow, @my_module, my_module_status_old: old_status_id,
my_module_status_new: @my_module.my_module_status.id) my_module_status_new: @my_module.my_module_status.id)
return redirect_to protocols_my_module_path(@my_module) redirect_to protocols_my_module_path(@my_module)
else else
render json: { errors: @my_module.errors.messages.values.flatten.join('\n') }, status: :unprocessable_entity render json: { errors: @my_module.errors.messages.values.flatten.join('\n') }, status: :unprocessable_entity
end end
@ -457,11 +450,20 @@ class MyModulesController < ApplicationController
end end
def my_module_filter def my_module_filter
experiment = Experiment.readable_by_user(current_user).find_by(id: params[:experiment_id]) readable_experiments = Experiment.readable_by_user(current_user)
managable_active_my_modules = MyModule.managable_by_user(current_user).active
experiment = Experiment.readable_by_user(current_user)
.joins(:my_modules)
.where(experiments: { id: readable_experiments })
.where(my_modules: { id: managable_active_my_modules })
.find_by(id: params[:experiment_id])
return render_404 if experiment.blank? return render_404 if experiment.blank?
my_modules = experiment.my_modules my_modules = experiment.my_modules
.readable_by_user(current_user) .where(my_modules: { id: managable_active_my_modules })
.distinct
.search(current_user, false, params[:query], 1, current_team) .search(current_user, false, params[:query], 1, current_team)
.pluck(:id, :name) .pluck(:id, :name)

View file

@ -10,6 +10,7 @@ class ProjectsController < ApplicationController
include Breadcrumbs include Breadcrumbs
attr_reader :current_folder attr_reader :current_folder
helper_method :current_folder helper_method :current_folder
before_action :switch_team_with_param, only: :index before_action :switch_team_with_param, only: :index
@ -105,8 +106,15 @@ class ProjectsController < ApplicationController
end end
def project_filter def project_filter
readable_experiments = Experiment.readable_by_user(current_user)
managable_active_my_modules = MyModule.managable_by_user(current_user).active
projects = Project.readable_by_user(current_user) projects = Project.readable_by_user(current_user)
.joins(experiments: :my_modules)
.where(experiments: { id: readable_experiments })
.where(my_modules: { id: managable_active_my_modules })
.search(current_user, false, params[:query], 1, current_team) .search(current_user, false, params[:query], 1, current_team)
.distinct
.pluck(:id, :name) .pluck(:id, :name)
return render plain: [].to_json if projects.blank? return render plain: [].to_json if projects.blank?
@ -211,9 +219,7 @@ class ProjectsController < ApplicationController
# Redirect URL for archive view is different as for other views. # Redirect URL for archive view is different as for other views.
if project_params[:archived] == 'false' if project_params[:archived] == 'false'
# The project should be restored # The project should be restored
unless @project.archived @project.restore(current_user) unless @project.archived
@project.restore(current_user)
end
elsif @project.archived elsif @project.archived
# The project should be archived # The project should be archived
@project.archive(current_user) @project.archive(current_user)
@ -339,17 +345,17 @@ class ProjectsController < ApplicationController
def notifications def notifications
@modules = @project @modules = @project
.assigned_modules(current_user) .assigned_modules(current_user)
.order(due_date: :desc) .order(due_date: :desc)
respond_to do |format| respond_to do |format|
#format.html # format.html
format.json { format.json do
render :json => { render json: {
:html => render_to_string({ html: render_to_string({
:partial => "notifications.html.erb" partial: 'notifications.html.erb'
}) })
} }
} end
end end
end end

View file

@ -95,9 +95,10 @@
ref="tasksSelector" ref="tasksSelector"
@change="changeTask" @change="changeTask"
:options="tasks" :options="tasks"
:placeholder=" :placeholder="tasksSelectorPlaceholder"
:no-options-placeholder="
i18n.t( i18n.t(
'repositories.modal_assign_items_to_task.body.task_select.disabled_placeholder' 'repositories.modal_assign_items_to_task.body.task_select.no_options_placeholder'
) )
" "
:searchPlaceholder=" :searchPlaceholder="
@ -162,8 +163,8 @@ export default {
}); });
}); });
$(this.$refs.modal).on("hidden.bs.modal", () => { $(this.$refs.modal).on("hidden.bs.modal", () => {
this.resetSelectors();
this.$emit("close"); this.$emit("close");
}); });
}, },

View file

@ -7,9 +7,22 @@
<span class="sn-select__caret caret"></span> <span class="sn-select__caret caret"></span>
</slot> </slot>
<div ref="optionsContainer" class="sn-select__options" :style="optionPositionStyle"> <div ref="optionsContainer" class="sn-select__options" :style="optionPositionStyle">
<div v-for="option in options" :key="option[0]" @click="setValue(option[0])" class="sn-select__option"> <template v-if="options.length">
{{ option[1] }} <div
</div> v-for="option in options"
:key="option[0]" @click="setValue(option[0])"
class="sn-select__option"
>
{{ option[1] }}
</div>
</template>
<template v-else>
<div
class="sn-select__no-options"
>
{{ this.noOptionsPlaceholder }}
</div>
</template>
</div> </div>
</div> </div>
</template> </template>
@ -22,6 +35,7 @@
options: { type: Array, default: () => [] }, options: { type: Array, default: () => [] },
initialValue: { type: [String, Number] }, initialValue: { type: [String, Number] },
placeholder: { type: String }, placeholder: { type: String },
noOptionsPlaceholder: { type: String },
disabled: { type: Boolean, default: false } disabled: { type: Boolean, default: false }
}, },
data() { data() {

View file

@ -1,5 +1,16 @@
<template> <template>
<Select class="sn-select--search" :value="value" :options="currentOptions" :placeholder="placeholder" v-bind:disabled="disabled" @change="change" @blur="blur" @open="open" @close="close"> <Select
class="sn-select--search"
:value="value"
:options="currentOptions"
:placeholder="placeholder"
:noOptionsPlaceholder="noOptionsPlaceholder"
v-bind:disabled="disabled"
@change="change"
@blur="blur"
@open="open"
@close="close"
>
<input ref="focusElement" v-model="query" type="text" class="sn-select__search-input" :placeholder="searchPlaceholder" /> <input ref="focusElement" v-model="query" type="text" class="sn-select__search-input" :placeholder="searchPlaceholder" />
<span class="sn-select__value">{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span> <span class="sn-select__value">{{ valueLabel || (placeholder || i18n.t('general.select')) }}</span>
<span class="sn-select__caret caret"></span> <span class="sn-select__caret caret"></span>
@ -17,6 +28,7 @@
optionsUrl: { type: String }, optionsUrl: { type: String },
placeholder: { type: String }, placeholder: { type: String },
searchPlaceholder: { type: String }, searchPlaceholder: { type: String },
noOptionsPlaceholder: { type: String },
disabled: { type: Boolean } disabled: { type: Boolean }
}, },
components: { Select }, components: { Select },

View file

@ -1996,6 +1996,7 @@ en:
label: "Task" label: "Task"
placeholder: "Enter Task name" placeholder: "Enter Task name"
disabled_placeholder: "Select Experiment to enable Task" disabled_placeholder: "Select Experiment to enable Task"
no_options_placeholder: "No tasks available to assign items"
assign: assign:
text: "Assign to this task" text: "Assign to this task"
flash_all_assignments_success: "Successfully assigned %{count} item(s) to the task." flash_all_assignments_success: "Successfully assigned %{count} item(s) to the task."