From c2aee2b4fe9ab24287c293f64d50a059e2d003fc Mon Sep 17 00:00:00 2001 From: Oleksii Kriuchykhin Date: Wed, 3 Sep 2025 15:42:14 +0200 Subject: [PATCH] Add tag filtering to task table [SCI-12289] --- app/controllers/tags_controller.rb | 7 ++++++- app/controllers/teams_controller.rb | 12 +----------- app/javascript/vue/my_modules/list.vue | 18 +++++++++++++++++- .../shared/filters/inputs/select_filter.vue | 2 ++ app/services/lists/my_modules_service.rb | 4 ++++ app/views/my_modules/index.html.erb | 1 + app/views/shared/navigation/_top.html.erb | 2 +- config/locales/en.yml | 2 ++ 8 files changed, 34 insertions(+), 14 deletions(-) diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index c68feefca..be5b59d7b 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -2,6 +2,11 @@ class TagsController < ApplicationController def index - @tags = current_team.tags.order(:name) + @tags = if params[:teams].present? + Tag.where(team: current_user.teams.where(id: params[:teams])).order(:name) + else + current_team.tags.order(:name) + end + @tags = @tags.where_attributes_like(['tags.name'], params[:query]) if params[:query].present? end end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 495c07fb8..1b67ceeb1 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -9,7 +9,7 @@ class TeamsController < ApplicationController before_action :load_vars, only: %i(sidebar export_projects export_projects_modal disable_tasks_sharing_modal shared_tasks_toggle) before_action :load_current_folder, only: :sidebar - before_action :check_read_permissions, except: %i(view_type visible_teams visible_users visible_tags current_team_users) + before_action :check_read_permissions, except: %i(view_type visible_teams visible_users current_team_users) before_action :check_export_projects_permissions, only: %i(export_projects_modal export_projects) def visible_teams @@ -26,16 +26,6 @@ class TeamsController < ApplicationController render json: users, each_serializer: UserSerializer, user: current_user end - def visible_tags - teams = if params[:teams].present? - current_user.teams.where(id: params[:teams]) - else - current_team - end - tags = Tag.where(team: teams) - render json: tags, each_serializer: TagSerializer - end - def current_team_users users = current_team.users.order(:full_name) render json: users, each_serializer: UserSerializer, user: current_user diff --git a/app/javascript/vue/my_modules/list.vue b/app/javascript/vue/my_modules/list.vue index 180d2d9b0..022c75295 100644 --- a/app/javascript/vue/my_modules/list.vue +++ b/app/javascript/vue/my_modules/list.vue @@ -64,6 +64,7 @@ /* global HelperModule */ import axios from '../../packs/custom_axios.js'; +import escapeHtml from '../shared/escape_html.js'; import DataTable from '../shared/datatable/table.vue'; import ConfirmationModal from '../shared/confirmation_modal.vue'; import ExperimentDescriptionModal from '../shared/datatable/modals/description.vue'; @@ -113,6 +114,7 @@ export default { canvasUrl: { type: String, required: true }, tagsColors: { type: Array, required: true }, projectTagsUrl: { type: String, required: true }, + teamTagsUrl: { type: String, required: true }, assignedUsersUrl: { type: String, required: true }, usersFilterUrl: { type: String, required: true }, statusesList: { type: Array, required: true }, @@ -288,6 +290,17 @@ export default { placeholder: this.i18n.t('experiments.table.filters.status_placeholder') }); + filters.push({ + key: 'tags', + type: 'Select', + searchable: true, + optionsUrl: this.teamTagsUrl, + optionRenderer: this.tagsFilterRenderer, + labelRenderer: this.tagsFilterRenderer, + label: this.i18n.t('experiments.table.filters.tags'), + placeholder: this.i18n.t('experiments.table.filters.tags_placeholder') + }); + this.columnDefs = columns; this.filters = filters; }, @@ -426,9 +439,12 @@ export default { usersFilterRenderer(option) { return `
- ${option[1]} + ${escapeHtml(option[1])}
`; }, + tagsFilterRenderer(option) { + return `
${escapeHtml(option[1])}
`; + }, updateFavorite(value, params) { const url = value ? params.data.urls.favorite : params.data.urls.unfavorite; axios.post(url).then(() => { diff --git a/app/javascript/vue/shared/filters/inputs/select_filter.vue b/app/javascript/vue/shared/filters/inputs/select_filter.vue index 413b9c125..c568ce98b 100644 --- a/app/javascript/vue/shared/filters/inputs/select_filter.vue +++ b/app/javascript/vue/shared/filters/inputs/select_filter.vue @@ -10,6 +10,8 @@ :placeholder="filter.placeholder" :optionRenderer="filter.optionRenderer" :labelRenderer="filter.labelRenderer" + :tagsView="filter.tagsView" + :searchable="filter.searchable" @change="change" > diff --git a/app/services/lists/my_modules_service.rb b/app/services/lists/my_modules_service.rb index d75d3e8ad..39b9efe2b 100644 --- a/app/services/lists/my_modules_service.rb +++ b/app/services/lists/my_modules_service.rb @@ -158,5 +158,9 @@ module Lists def statuses_filter(statuses) @records = @records.where(my_module_status_id: statuses.values) end + + def tags_filter(tags) + @records = @records.joins(:tags).where(tags: { id: tags.values }) + end end end diff --git a/app/views/my_modules/index.html.erb b/app/views/my_modules/index.html.erb index ae1e376e1..6a0962744 100644 --- a/app/views/my_modules/index.html.erb +++ b/app/views/my_modules/index.html.erb @@ -19,6 +19,7 @@ project-name="<%= @experiment.project.name %>" :statuses-list="<%= MyModuleStatus.all.order(:id).map{ |i| [i.id, i.name] }.to_json %>" project-tags-url="" + team-tags-url="<%= tags_path %>" canvas-url="<%= view_mode == 'active' ? canvas_experiment_path(@experiment) : module_archive_experiment_path(@experiment) %>" :archived="<%= @experiment.archived_branch?%>" /> diff --git a/app/views/shared/navigation/_top.html.erb b/app/views/shared/navigation/_top.html.erb index 88b730466..c1303fcf0 100644 --- a/app/views/shared/navigation/_top.html.erb +++ b/app/views/shared/navigation/_top.html.erb @@ -8,7 +8,7 @@ unseen-notifications-url="<%= unseen_counter_user_notifications_path %>" teams-url="<%= visible_teams_teams_path %>" users-url="<%= visible_users_teams_path %>" - tags-url="<%= visible_tags_teams_path %>" + tags-url="<%= tags_path %>" logo-url="<%= application_logo_url %>" /> diff --git a/config/locales/en.yml b/config/locales/en.yml index c04a5df23..b3724e2d0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1972,6 +1972,8 @@ en: due_date: 'Due date' status: 'Status' status_placeholder: 'Select task status' + tags: 'Tags' + tags_placeholder: 'Select task tags' assigned: 'Assigned to' assigned_placeholder: 'Select a person assigned to a task' view: