From 473af6da3ee0831db42313b796af6e403ab123ae Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Mon, 11 Dec 2023 11:58:24 +0100 Subject: [PATCH 01/37] Pass filter via url params and tweak message threads table title based on filter or query --- .../layout/filter_list_component.html.erb | 2 +- .../layout/filter_list_component.rb | 2 ++ ...ge_threads_bulk_actions_component.html.erb | 2 +- .../message_threads_bulk_actions_component.rb | 12 +++++++++- .../message_threads_table_component.html.erb | 2 +- .../message_threads_table_component.rb | 7 ++++++ .../t_w/top_navigation_component.html.erb | 6 ++--- .../t_w/top_navigation_component.rb | 13 ++++++++++ app/controllers/filters_controller.rb | 4 ++-- app/controllers/message_threads_controller.rb | 10 +++++++- app/helpers/message_thread_helper.rb | 10 ++++++++ app/models/searchable/query_builder.rb | 24 +++++++++++++++++++ app/views/message_threads/index.html.erb | 2 +- 13 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 app/helpers/message_thread_helper.rb create mode 100644 app/models/searchable/query_builder.rb diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index 0c3bfe5bf..b3c000b3b 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -4,7 +4,7 @@

Filtre

<% @filters.each do |filter| %> - <% url = message_threads_path(q: filter.query) %> + <% url = filtered_message_threads_path(filter:) %> <%= link_to url, class: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group w-72 flex gap-x-3 rounded-md p-2 px-4 text-sm leading-6 font-semibold data-[active=true]:bg-gray-50 data-[active=true]:text-indigo-600", data: { active: current_page?(url) } do %> <%= render Icons::BookmarkComponent.new %>

<%= filter.name %>

diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index d3ba8594b..7c533a03d 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -1,4 +1,6 @@ class Layout::FilterListComponent < ViewComponent::Base + include MessageThreadHelper + def initialize(filters:) @filters = filters end diff --git a/app/components/message_threads_bulk_actions_component.html.erb b/app/components/message_threads_bulk_actions_component.html.erb index 6241eff2e..53dc61e5b 100644 --- a/app/components/message_threads_bulk_actions_component.html.erb +++ b/app/components/message_threads_bulk_actions_component.html.erb @@ -1,7 +1,7 @@ <%= tag.turbo_frame id: "bulk_actions" do %>
<%= check_box_tag("", nil, false, { class: "hidden sm:block h-4 w-4 rounded border-gray-300 text-blue-500 focus:ring-0", type: "checkbox", id: "checkbox-all", data: { action: "all-checkboxes#toggle", "all-checkboxes-target": "checkbox" } }) %> - <%= @ids.present? ? t(:selected_message, count: @ids.count) : "Správy v schránke" %> + <%= title %> <% if @ids.present? %> <%= form_with url: bulk_merge_message_threads_path, data: { turbo_frame: "_top" } do %> <% @ids.each do |id| %> diff --git a/app/components/message_threads_bulk_actions_component.rb b/app/components/message_threads_bulk_actions_component.rb index 9d4b31a26..de85bbee2 100644 --- a/app/components/message_threads_bulk_actions_component.rb +++ b/app/components/message_threads_bulk_actions_component.rb @@ -1,5 +1,15 @@ class MessageThreadsBulkActionsComponent < ViewComponent::Base - def initialize(ids:) + def initialize(ids: nil, filter: nil, query: nil) @ids = ids + @filter = filter + @query = query + end + + def title + return t(:selected_message, count: @ids.count) if @ids.present? + return "Správy z filtra '#{@filter.name}'" if @filter.present? + return "Správy vyhovujúce hľadanému výrazu '#{@query}'" if @query.present? + + "Správy v schránke" end end diff --git a/app/components/message_threads_table_component.html.erb b/app/components/message_threads_table_component.html.erb index 989c5dd24..aa9bdd7f2 100644 --- a/app/components/message_threads_table_component.html.erb +++ b/app/components/message_threads_table_component.html.erb @@ -1,6 +1,6 @@
- <%= render MessageThreadsBulkActionsComponent.new(ids: []) %> + <%= render MessageThreadsBulkActionsComponent.new(ids: [], filter:, query:) %> <%= form_with url: bulk_actions_message_threads_path, data: { "form-target": "form", "all-checkboxes-target": "form" } do %>
    <% message_threads.each do |message_thread| %> diff --git a/app/components/message_threads_table_component.rb b/app/components/message_threads_table_component.rb index f058a2dbf..5ff59080b 100644 --- a/app/components/message_threads_table_component.rb +++ b/app/components/message_threads_table_component.rb @@ -1,4 +1,11 @@ class MessageThreadsTableComponent < ViewComponent::Base renders_many :message_threads renders_one :next_page_area + + attr_reader :filter, :query + + def initialize(filter: nil, query: nil) + @filter = filter + @query = query + end end diff --git a/app/components/t_w/top_navigation_component.html.erb b/app/components/t_w/top_navigation_component.html.erb index ce0893e60..e79b5ce71 100644 --- a/app/components/t_w/top_navigation_component.html.erb +++ b/app/components/t_w/top_navigation_component.html.erb @@ -10,10 +10,10 @@
    <%= form_with url: message_threads_path, method: :get, html: { class: 'relative flex flex-1' } do |f| %> <%= render Icons::MagnifyingGlassComponent.gray %> - <%= f.search_field :q, id: "search", value: params[:q], placeholder: 'Vyhľadaj správu', class: 'block h-full w-full border-0 py-0 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-base' %> + <%= f.search_field :q, id: "search", value: query, placeholder: 'Vyhľadaj správu', class: 'block h-full w-full border-0 py-0 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-base' %> <% end %> - <% if params[:q].present? %> - <%= link_to new_filter_path(query: params[:q]), data: { turbo_frame: "modal" }, class: "flex items-center gap-2 text-gray-500 hover:text-gray-900", title: "Pridať filter" do %> + <% if query.present? %> + <%= link_to new_filter_path(query:), data: { turbo_frame: "modal" }, class: "flex items-center gap-2 text-gray-500 hover:text-gray-900", title: "Pridať filter" do %> <%= render Icons::BookmarkComponent.new %> <% end %> <% end %> diff --git a/app/components/t_w/top_navigation_component.rb b/app/components/t_w/top_navigation_component.rb index 6e66e11d3..97358fb25 100644 --- a/app/components/t_w/top_navigation_component.rb +++ b/app/components/t_w/top_navigation_component.rb @@ -1,5 +1,18 @@ class TW::TopNavigationComponent < ViewComponent::Base + include MessageThreadHelper + def initialize(current_tenant_boxes_count) @current_tenant_boxes_count = current_tenant_boxes_count end + + def query + query_params = params + .permit(:filter_id, :q) + .slice(:filter_id, :q) + + Searchable::QueryBuilder.new( + filter_id: query_params[:filter_id], + query: query_params[:q], + ).build + end end diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index f8d0b806b..6fc987479 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -26,13 +26,13 @@ def create if @filter.save flash[:notice] = 'Filter bol úspešne vytvorený' if params[:to] == 'search' - redirect_to message_threads_path(q: @filter.query) + redirect_to helpers.filtered_message_threads_path(filter: @filter) else redirect_to filters_path end else if params[:to] == 'search' - redirect_to message_threads_path(q: @filter.query), alert: 'Filter sa nepodarilo vytvoriť :(' + redirect_to helpers.filtered_message_threads_path(query: @filter.query), alert: 'Filter sa nepodarilo vytvoriť :(' else render :new end diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index ce6695b20..ae873fbd9 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -27,6 +27,9 @@ def update def index authorize MessageThread + + @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: params[:filter_id]) if params[:filter_id].present? + @query = search_params[:q] end def scroll @@ -62,13 +65,18 @@ def merge_threads(message_thread_ids) end def load_threads + query = Searchable::QueryBuilder.new( + filter_id: params[:filter_id], + query: search_params[:q], + ).build + cursor = MessageThreadCollection.init_cursor(search_params[:cursor]) result = MessageThreadCollection.all( scope: message_thread_policy_scope.includes(:tags, :box), search_permissions: search_permissions, - query: search_params[:q], + query:, cursor: cursor ) diff --git a/app/helpers/message_thread_helper.rb b/app/helpers/message_thread_helper.rb new file mode 100644 index 000000000..091cfdcee --- /dev/null +++ b/app/helpers/message_thread_helper.rb @@ -0,0 +1,10 @@ +module MessageThreadHelper + def filtered_message_threads_path(filter: nil, query: nil) + args = { + filter_id: filter&.id, + q: query + }.compact + + message_threads_path(args) + end +end diff --git a/app/models/searchable/query_builder.rb b/app/models/searchable/query_builder.rb new file mode 100644 index 000000000..a984f3ce6 --- /dev/null +++ b/app/models/searchable/query_builder.rb @@ -0,0 +1,24 @@ +class Searchable::QueryBuilder + attr_reader :filter, :filter_id, :query, :user + + def initialize(filter: nil, filter_id: nil, query: nil, user: nil) + @filter = filter + @filter_id = filter_id + @query = query + @user = user + end + + def build + if filter.nil? && filter_id.present? + @filter = FilterPolicy::ScopeShowable.new(user, Filter).resolve.find_by(id: filter_id) + end + + [ + filter&.query, + query, + ] + .compact + .map(&:strip) + .join(' ') + end +end \ No newline at end of file diff --git a/app/views/message_threads/index.html.erb b/app/views/message_threads/index.html.erb index c93243d35..e1ef3f8ea 100644 --- a/app/views/message_threads/index.html.erb +++ b/app/views/message_threads/index.html.erb @@ -1,5 +1,5 @@ <%= render TW::FlashComponent.new %> -<%= render MessageThreadsTableComponent.new do |component| %> +<%= render MessageThreadsTableComponent.new(filter: @filter, query: @query) do |component| %> <% component.with_message_thread do %> <%= render MessageThreadsTableRowComponent.with_collection(@message_threads) %> <% end %> From 914d2fb9c0414e230e41f58837496dfdd6020794 Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Mon, 11 Dec 2023 14:16:04 +0100 Subject: [PATCH 02/37] Tweak title text --- app/components/message_threads_bulk_actions_component.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/message_threads_bulk_actions_component.rb b/app/components/message_threads_bulk_actions_component.rb index de85bbee2..048ad381c 100644 --- a/app/components/message_threads_bulk_actions_component.rb +++ b/app/components/message_threads_bulk_actions_component.rb @@ -8,7 +8,7 @@ def initialize(ids: nil, filter: nil, query: nil) def title return t(:selected_message, count: @ids.count) if @ids.present? return "Správy z filtra '#{@filter.name}'" if @filter.present? - return "Správy vyhovujúce hľadanému výrazu '#{@query}'" if @query.present? + return "Hľadaný výraz '#{@query}'" if @query.present? "Správy v schránke" end From 0a03182530fe94e5110cb75558486ff2f5a7a02f Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Mon, 11 Dec 2023 23:44:12 +0100 Subject: [PATCH 03/37] Implement pinning and unpinning filters in sidebar --- app/components/icons/star_component.html.erb | 7 ++++ app/components/icons/star_component.rb | 15 ++++++++ .../layout/filter_list_component.html.erb | 35 ++++++++++++++----- .../layout/filter_list_component.rb | 10 +++++- .../t_w/sidebar_menu_item_component.html.erb | 21 ++++++++--- .../t_w/sidebar_menu_item_component.rb | 13 ++++++- app/controllers/application_controller.rb | 2 +- app/controllers/filters_controller.rb | 16 +++++++-- app/lib/sidebar_menu.rb | 31 +++++++++++++--- app/models/filter.rb | 9 +++-- app/models/fulltext_filter.rb | 22 ++++++++++++ app/models/tag_filter.rb | 22 ++++++++++++ app/policies/filter_policy.rb | 8 +++++ config/routes.rb | 7 +++- config/tailwind.config.js | 3 ++ .../20231211132422_add_type_to_filters.rb | 17 +++++++++ .../20231211133725_add_tag_to_filters.rb | 5 +++ ...1211134125_change_query_null_on_filters.rb | 5 +++ ...20231211140731_add_is_pinned_to_filters.rb | 6 ++++ db/schema.rb | 11 ++++-- package.json | 1 + yarn.lock | 5 +++ 22 files changed, 243 insertions(+), 28 deletions(-) create mode 100644 app/components/icons/star_component.html.erb create mode 100644 app/components/icons/star_component.rb create mode 100644 app/models/fulltext_filter.rb create mode 100644 app/models/tag_filter.rb create mode 100644 db/migrate/20231211132422_add_type_to_filters.rb create mode 100644 db/migrate/20231211133725_add_tag_to_filters.rb create mode 100644 db/migrate/20231211134125_change_query_null_on_filters.rb create mode 100644 db/migrate/20231211140731_add_is_pinned_to_filters.rb diff --git a/app/components/icons/star_component.html.erb b/app/components/icons/star_component.html.erb new file mode 100644 index 000000000..bdd75645c --- /dev/null +++ b/app/components/icons/star_component.html.erb @@ -0,0 +1,7 @@ +" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" stroke-width="<%= @stroke_width %>" stroke="currentColor"> + <% if solid? %> + + <% elsif light? %> + + <% end %> + \ No newline at end of file diff --git a/app/components/icons/star_component.rb b/app/components/icons/star_component.rb new file mode 100644 index 000000000..35832232a --- /dev/null +++ b/app/components/icons/star_component.rb @@ -0,0 +1,15 @@ +class Icons::StarComponent < ViewComponent::Base + def initialize(css_classes: nil, stroke_width: 1.5, variant: :solid) + @css_classes = css_classes + @stroke_width = stroke_width + @variant = variant + end + + def solid? + @variant == :solid + end + + def light? + @variant == :light + end +end diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index b3c000b3b..1ca24a0f8 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -1,14 +1,31 @@ <% if @filters.present? %> -
    -
    -

    Filtre

    -
    +
    + <% if @label.present? %> +
    +

    <%= @label %>

    +
    + <% end %> <% @filters.each do |filter| %> - <% url = filtered_message_threads_path(filter:) %> - <%= link_to url, class: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50 group w-72 flex gap-x-3 rounded-md p-2 px-4 text-sm leading-6 font-semibold data-[active=true]:bg-gray-50 data-[active=true]:text-indigo-600", data: { active: current_page?(url) } do %> - <%= render Icons::BookmarkComponent.new %> -

    <%= filter.name %>

    + <%= render TW::SidebarMenuItemComponent.new( + name: filter.name, + url: filtered_message_threads_path(filter:), + icon: icon_for(filter), + variant: :light, + ) do |menu_item| %> + <% menu_item.with_accessory do %> + <% if filter.is_pinned %> + <%= link_to unpin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group-one p-4", data: { turbo_method: :patch } do %> + <%= render Icons::StarComponent.new(css_classes: 'hidden group-one-hover:inline w-6 h-6', variant: :light) %> + <%= render Icons::StarComponent.new(css_classes: 'inline group-one-hover:hidden w-6 h-6', variant: :solid) %> + <% end %> + <% else %> + <%= link_to pin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group-one p-4", data: { turbo_method: :patch } do %> + <%= render Icons::StarComponent.new(css_classes: 'inline group-one-hover:hidden w-6 h-6', variant: :light) %> + <%= render Icons::StarComponent.new(css_classes: 'hidden group-one-hover:inline w-6 h-6', variant: :solid) %> + <% end %> + <% end %> + <% end %> <% end %> <% end %>
    -<% end %> +<% end %> \ No newline at end of file diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index 7c533a03d..e917a3d27 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -1,7 +1,15 @@ class Layout::FilterListComponent < ViewComponent::Base include MessageThreadHelper - def initialize(filters:) + def initialize(label: nil, filters:) + @label = label @filters = filters end + + def icon_for(filter) + case filter + when TagFilter then Icons::TagComponent.new + else Icons::BookmarkComponent.new + end + end end diff --git a/app/components/t_w/sidebar_menu_item_component.html.erb b/app/components/t_w/sidebar_menu_item_component.html.erb index a5888f916..fc8991b64 100644 --- a/app/components/t_w/sidebar_menu_item_component.html.erb +++ b/app/components/t_w/sidebar_menu_item_component.html.erb @@ -1,6 +1,17 @@ -<%= link_to @url, class: "items-center text-gray-700 hover:text-indigo-600 hover:bg-gray-50 w-full group flex gap-x-3 rounded-md p-4 leading-6 font-semibold data-[active=true]:bg-gray-50 data-[active=true]:text-indigo-600", data: { active: current_page?(@url, check_parameters: true) } do %> - <% if @icon_component %> - <%= render @icon_component %> +
    + <%= link_to \ + @url, + class: "w-full flex gap-x-3 p-4", + data: { active: current_page?(@url, check_parameters: true) } \ + do %> + <% if @icon_component %> + <%= render @icon_component %> + <% end %> + <%= @name %> <% end %> - <%= @name %> -<% end %> + <% if accessory %> + <%= accessory %> + <% end %> +
    diff --git a/app/components/t_w/sidebar_menu_item_component.rb b/app/components/t_w/sidebar_menu_item_component.rb index 868c2e347..1e62457f5 100644 --- a/app/components/t_w/sidebar_menu_item_component.rb +++ b/app/components/t_w/sidebar_menu_item_component.rb @@ -1,7 +1,18 @@ class TW::SidebarMenuItemComponent < ViewComponent::Base - def initialize(name:, url:, icon:) + renders_one :accessory + + def initialize(name:, url:, icon:, variant: :regular) @name = name @url = url @icon_component = icon + @variant = variant + end + + def regular? + @variant == :regular + end + + def light? + @variant == :light end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 90ae21fb2..f45e6e05b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,7 +14,7 @@ def set_menu_context @tags = policy_scope(Tag, policy_scope_class: TagPolicy::ScopeListable).where(visible: true).order(:name) @filters = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).order(:position) - @menu = SidebarMenu.new(controller_name, action_name, { tags: @tags, filters: @filters }).menu + @menu = SidebarMenu.new(controller_name, action_name, filters: @filters).menu @current_tenant_boxes_count = Current.tenant.boxes.count end end diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index 6fc987479..2b0ddfe5a 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -1,5 +1,5 @@ class FiltersController < ApplicationController - before_action :set_filter, only: [:edit, :update, :destroy] + before_action :set_filter, only: [:edit, :update, :destroy, :pin, :unpin] def index authorize Filter @@ -22,7 +22,7 @@ def new def create authorize Filter - @filter = Current.tenant.filters.build(filter_params.merge({author_id: Current.user.id})) + @filter = Current.tenant.filters.build(filter_params.merge({ author_id: Current.user.id })) if @filter.save flash[:notice] = 'Filter bol úspešne vytvorený' if params[:to] == 'search' @@ -59,6 +59,18 @@ def destroy redirect_to filters_path, notice: 'Filter bol úspešne odstránený' end + def pin + authorize @filter + @filter.update(is_pinned: true) + redirect_back fallback_location: filters_path + end + + def unpin + authorize @filter + @filter.update(is_pinned: false) + redirect_back fallback_location: filters_path + end + private def filter_params diff --git a/app/lib/sidebar_menu.rb b/app/lib/sidebar_menu.rb index 4409f1346..fff231846 100644 --- a/app/lib/sidebar_menu.rb +++ b/app/lib/sidebar_menu.rb @@ -1,8 +1,8 @@ class SidebarMenu include Rails.application.routes.url_helpers - def initialize(controller, action, parameters = nil) - @parameters = parameters + def initialize(controller, action, filters: []) + @filters = filters @menu = initial_structure(controller, action) end @@ -19,8 +19,9 @@ def initial_structure(controller, _action) def default_main_menu [ TW::SidebarMenuItemComponent.new(name: 'Všetky správy', url: message_threads_path, icon: Icons::EnvelopeComponent.new), - Layout::FilterListComponent.new(filters: @parameters[:filters]), - Layout::TagListComponent.new(tags: @parameters[:tags]), + Layout::FilterListComponent.new(filters: pinned_filters), + Layout::FilterListComponent.new(label: 'Filtre', filters: fulltext_filters), + Layout::FilterListComponent.new(label: 'Štítky', filters: tag_filters), TW::SidebarMenuItemComponent.new(name: 'Nastavenia', url: filters_path, icon: Icons::CogSixToothComponent.new) ] end @@ -51,4 +52,26 @@ def site_admin_menu TW::SidebarMenuItemComponent.new(name: 'Good Job Dashboard', url: good_job_path, icon: Icons::CogSixToothComponent.new) ] end + + private + + def pinned_filters + @filters + .pinned + .order(position: :asc) + end + + def fulltext_filters + @filters + .not_pinned + .where(type: 'FulltextFilter') + .order(position: :asc) + end + + def tag_filters + @filters + .not_pinned + .where(type: 'TagFilter') + .order(position: :asc) + end end diff --git a/app/models/filter.rb b/app/models/filter.rb index e64e2e8ef..e78374548 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -5,10 +5,12 @@ # id :bigint not null, primary key # name :string not null # position :integer not null -# query :string not null +# query :string +# type :string # created_at :datetime not null # updated_at :datetime not null # author_id :bigint not null +# tag_id :bigint # tenant_id :bigint not null # class Filter < ApplicationRecord @@ -17,10 +19,13 @@ class Filter < ApplicationRecord belongs_to :author, class_name: 'User' belongs_to :tenant - validates :tenant_id, :author_id, :name, :query, presence: true + validates :tenant_id, :author_id, :name, presence: true before_create :fill_position + scope :pinned, -> { where(is_pinned: true) } + scope :not_pinned, -> { where(is_pinned: false) } + def fill_position return if position.present? diff --git a/app/models/fulltext_filter.rb b/app/models/fulltext_filter.rb new file mode 100644 index 000000000..26e336157 --- /dev/null +++ b/app/models/fulltext_filter.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: filters +# +# id :bigint not null, primary key +# name :string not null +# position :integer not null +# query :string +# type :string +# created_at :datetime not null +# updated_at :datetime not null +# author_id :bigint not null +# tag_id :bigint +# tenant_id :bigint not null +# +class FulltextFilter < Filter + validates :query, presence: true + + def self.model_name + Filter.model_name + end +end diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb new file mode 100644 index 000000000..81c6a4563 --- /dev/null +++ b/app/models/tag_filter.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: filters +# +# id :bigint not null, primary key +# name :string not null +# position :integer not null +# query :string +# type :string +# created_at :datetime not null +# updated_at :datetime not null +# author_id :bigint not null +# tag_id :bigint +# tenant_id :bigint not null +# +class TagFilter < Filter + belongs_to :tag, optional: false + + def self.model_name + Filter.model_name + end +end diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb index 2fe871ffd..d2b635166 100644 --- a/app/policies/filter_policy.rb +++ b/app/policies/filter_policy.rb @@ -54,6 +54,14 @@ def destroy? is_author_current_user? end + def pin? + is_author_current_user? + end + + def unpin? + pin? + end + private def is_author_current_user? diff --git a/config/routes.rb b/config/routes.rb index 65e013405..a5b4a0673 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -101,7 +101,12 @@ end end - resources :filters + resources :filters do + member do + patch :pin + patch :unpin + end + end resources :message_drafts do member do diff --git a/config/tailwind.config.js b/config/tailwind.config.js index cc80e93df..1f5cb6171 100644 --- a/config/tailwind.config.js +++ b/config/tailwind.config.js @@ -20,5 +20,8 @@ module.exports = { require('@tailwindcss/aspect-ratio'), require('@tailwindcss/typography'), require('@tailwindcss/container-queries'), + require("tailwindcss-scoped-groups")({ + groups: ["one", "two"], + }), ] } diff --git a/db/migrate/20231211132422_add_type_to_filters.rb b/db/migrate/20231211132422_add_type_to_filters.rb new file mode 100644 index 000000000..68b31f28b --- /dev/null +++ b/db/migrate/20231211132422_add_type_to_filters.rb @@ -0,0 +1,17 @@ +class AddTypeToFilters < ActiveRecord::Migration[7.1] + def up + add_column :filters, :type, :string, null: true + + Filter.where(type: nil).update_all(type: 'FulltextFilter') + + change_column_null :filters, :name, false + + add_index :filters, :type + end + + def down + Filter.where.not(type: 'FulltextFilter').delete_all + + remove_column :filters, :type + end +end diff --git a/db/migrate/20231211133725_add_tag_to_filters.rb b/db/migrate/20231211133725_add_tag_to_filters.rb new file mode 100644 index 000000000..30c564abe --- /dev/null +++ b/db/migrate/20231211133725_add_tag_to_filters.rb @@ -0,0 +1,5 @@ +class AddTagToFilters < ActiveRecord::Migration[7.1] + def change + add_reference :filters, :tag, null: true, foreign_key: true + end +end diff --git a/db/migrate/20231211134125_change_query_null_on_filters.rb b/db/migrate/20231211134125_change_query_null_on_filters.rb new file mode 100644 index 000000000..af7943c92 --- /dev/null +++ b/db/migrate/20231211134125_change_query_null_on_filters.rb @@ -0,0 +1,5 @@ +class ChangeQueryNullOnFilters < ActiveRecord::Migration[7.1] + def change + change_column_null :filters, :query, true + end +end diff --git a/db/migrate/20231211140731_add_is_pinned_to_filters.rb b/db/migrate/20231211140731_add_is_pinned_to_filters.rb new file mode 100644 index 000000000..73bf7e13d --- /dev/null +++ b/db/migrate/20231211140731_add_is_pinned_to_filters.rb @@ -0,0 +1,6 @@ +class AddIsPinnedToFilters < ActiveRecord::Migration[7.1] + def change + add_column :filters, :is_pinned, :boolean, null: false, default: false + add_index :filters, :is_pinned + end +end diff --git a/db/schema.rb b/db/schema.rb index 4f5650be2..aebca8022 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_12_06_200814) do +ActiveRecord::Schema[7.1].define(version: 2023_12_11_140731) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -135,13 +135,19 @@ t.bigint "tenant_id", null: false t.bigint "author_id", null: false t.string "name", null: false - t.string "query", null: false + t.string "query" t.integer "position", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "type" + t.bigint "tag_id" + t.boolean "is_pinned", default: false, null: false t.index ["author_id"], name: "index_filters_on_author_id" + t.index ["is_pinned"], name: "index_filters_on_is_pinned" + t.index ["tag_id"], name: "index_filters_on_tag_id" t.index ["tenant_id", "position"], name: "index_filters_on_tenant_id_and_position", unique: true t.index ["tenant_id"], name: "index_filters_on_tenant_id" + t.index ["type"], name: "index_filters_on_type" end create_table "folders", force: :cascade do |t| @@ -491,6 +497,7 @@ add_foreign_key "automation_rules", "users" add_foreign_key "boxes", "api_connections" add_foreign_key "boxes", "tenants" + add_foreign_key "filters", "tags" add_foreign_key "filters", "tenants", on_delete: :cascade add_foreign_key "filters", "users", column: "author_id", on_delete: :cascade add_foreign_key "folders", "boxes" diff --git a/package.json b/package.json index e8894a76f..d947ce61a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@hotwired/turbo-rails": "^7.0.0", "@rails/request.js": "^0.0.9", "esbuild": "^0.19.8", + "tailwindcss-scoped-groups": "^2.0.0", "tailwindcss-stimulus-components": "^4.0.4" }, "scripts": { diff --git a/yarn.lock b/yarn.lock index d2f0df489..63b8048ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -703,6 +703,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +tailwindcss-scoped-groups@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tailwindcss-scoped-groups/-/tailwindcss-scoped-groups-2.0.0.tgz#0a60ec02c9d6aaad16d6d78b080637ebe3a19ca2" + integrity sha512-uE9PJzfjqzsKlZ0dUjG5yPwBmkEZ/qmrXMLjykRs0otolUHAIclbtV49JQGyeYLo8YA7WPMgzKOg2e4snVyHqw== + tailwindcss-stimulus-components@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/tailwindcss-stimulus-components/-/tailwindcss-stimulus-components-4.0.4.tgz#1df5f2a488aa89365561bb33357095cd59ed831a" From a6b44f0602e42ac68247b50798a1f7b6cfaf3b2c Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Tue, 12 Dec 2023 14:25:20 +0100 Subject: [PATCH 04/37] Remove dependency on tailwindcss-scoped-groups since it is a native tailwind functionality --- app/components/layout/filter_list_component.html.erb | 12 ++++++------ config/tailwind.config.js | 3 --- package.json | 1 - yarn.lock | 5 ----- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index 1ca24a0f8..4ceee9420 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -14,14 +14,14 @@ ) do |menu_item| %> <% menu_item.with_accessory do %> <% if filter.is_pinned %> - <%= link_to unpin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group-one p-4", data: { turbo_method: :patch } do %> - <%= render Icons::StarComponent.new(css_classes: 'hidden group-one-hover:inline w-6 h-6', variant: :light) %> - <%= render Icons::StarComponent.new(css_classes: 'inline group-one-hover:hidden w-6 h-6', variant: :solid) %> + <%= link_to unpin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group/icon p-4", data: { turbo_method: :patch } do %> + <%= render Icons::StarComponent.new(css_classes: 'hidden group-hover/icon:inline w-6 h-6', variant: :light) %> + <%= render Icons::StarComponent.new(css_classes: 'inline group-hover/icon:hidden w-6 h-6', variant: :solid) %> <% end %> <% else %> - <%= link_to pin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group-one p-4", data: { turbo_method: :patch } do %> - <%= render Icons::StarComponent.new(css_classes: 'inline group-one-hover:hidden w-6 h-6', variant: :light) %> - <%= render Icons::StarComponent.new(css_classes: 'hidden group-one-hover:inline w-6 h-6', variant: :solid) %> + <%= link_to pin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group/icon p-4", data: { turbo_method: :patch } do %> + <%= render Icons::StarComponent.new(css_classes: 'inline group-hover/icon:hidden w-6 h-6', variant: :light) %> + <%= render Icons::StarComponent.new(css_classes: 'hidden group-hover/icon:inline w-6 h-6', variant: :solid) %> <% end %> <% end %> <% end %> diff --git a/config/tailwind.config.js b/config/tailwind.config.js index 1f5cb6171..cc80e93df 100644 --- a/config/tailwind.config.js +++ b/config/tailwind.config.js @@ -20,8 +20,5 @@ module.exports = { require('@tailwindcss/aspect-ratio'), require('@tailwindcss/typography'), require('@tailwindcss/container-queries'), - require("tailwindcss-scoped-groups")({ - groups: ["one", "two"], - }), ] } diff --git a/package.json b/package.json index d947ce61a..e8894a76f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "@hotwired/turbo-rails": "^7.0.0", "@rails/request.js": "^0.0.9", "esbuild": "^0.19.8", - "tailwindcss-scoped-groups": "^2.0.0", "tailwindcss-stimulus-components": "^4.0.4" }, "scripts": { diff --git a/yarn.lock b/yarn.lock index 63b8048ab..d2f0df489 100644 --- a/yarn.lock +++ b/yarn.lock @@ -703,11 +703,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -tailwindcss-scoped-groups@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tailwindcss-scoped-groups/-/tailwindcss-scoped-groups-2.0.0.tgz#0a60ec02c9d6aaad16d6d78b080637ebe3a19ca2" - integrity sha512-uE9PJzfjqzsKlZ0dUjG5yPwBmkEZ/qmrXMLjykRs0otolUHAIclbtV49JQGyeYLo8YA7WPMgzKOg2e4snVyHqw== - tailwindcss-stimulus-components@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/tailwindcss-stimulus-components/-/tailwindcss-stimulus-components-4.0.4.tgz#1df5f2a488aa89365561bb33357095cd59ed831a" From be94fbe81f4ebad50ce702bd23d7972eb3e4547e Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Wed, 13 Dec 2023 12:48:13 +0100 Subject: [PATCH 05/37] Implement filter sorting --- app/components/icons/bars_component.html.erb | 3 ++ app/components/icons/bars_component.rb | 6 ++++ .../layout/filter_list_component.html.erb | 24 ++++++++++++-- .../layout/filter_list_component.rb | 3 +- .../t_w/sidebar_menu_item_component.html.erb | 11 ++++--- .../t_w/sidebar_menu_item_component.rb | 6 ++-- app/controllers/filters_controller.rb | 19 +++++++++++ app/javascript/controllers/index.js | 3 ++ .../controllers/sortable_controller.js | 33 +++++++++++++++++++ app/lib/sidebar_menu.rb | 2 +- app/models/filter.rb | 1 + app/models/fulltext_filter.rb | 1 + app/models/tag_filter.rb | 1 + app/policies/filter_policy.rb | 4 +++ config/routes.rb | 4 +++ ...index_filters_on_tenant_id_and_position.rb | 5 +++ db/schema.rb | 3 +- package.json | 1 + yarn.lock | 5 +++ 19 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 app/components/icons/bars_component.html.erb create mode 100644 app/components/icons/bars_component.rb create mode 100644 app/javascript/controllers/sortable_controller.js create mode 100644 db/migrate/20231213100122_remove_index_filters_on_tenant_id_and_position.rb diff --git a/app/components/icons/bars_component.html.erb b/app/components/icons/bars_component.html.erb new file mode 100644 index 000000000..09c9bb355 --- /dev/null +++ b/app/components/icons/bars_component.html.erb @@ -0,0 +1,3 @@ +" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" stroke-width="<%= @stroke_width %>" stroke="currentColor" style="aspect-ratio: 1.14285714;"> + + \ No newline at end of file diff --git a/app/components/icons/bars_component.rb b/app/components/icons/bars_component.rb new file mode 100644 index 000000000..8f83e721e --- /dev/null +++ b/app/components/icons/bars_component.rb @@ -0,0 +1,6 @@ +class Icons::BarsComponent < ViewComponent::Base + def initialize(css_classes: nil, stroke_width: 1.5) + @css_classes = css_classes + @stroke_width = stroke_width + end +end diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index 4ceee9420..0697b8077 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -1,5 +1,17 @@ <% if @filters.present? %> -
    +
    + data-controller="sortable" + data-sortable-url-value="<%= sort_filters_path %>" + data-sortable-draggable-class=".item" + data-sortable-handle-class=".handle" + <% end %> + class="w-full flex flex-col justify-start items-start gap-2" + data-test="filters" + > + <% if @sortable %> + <%= link_to 'Sort', '', class: 'hidden', data: { turbo_method: :patch, sortable_target: 'submit', url: sort_filters_path } %> + <% end %> <% if @label.present? %>

    <%= @label %>

    @@ -11,8 +23,16 @@ url: filtered_message_threads_path(filter:), icon: icon_for(filter), variant: :light, + classes: 'item', ) do |menu_item| %> - <% menu_item.with_accessory do %> + <% if @sortable %> + <% menu_item.with_leading do %> + + <% end %> + <% end %> + <% menu_item.with_trailing do %> <% if filter.is_pinned %> <%= link_to unpin_filter_path(filter), class: "invisible group-hover:visible fill-yellow-400 group/icon p-4", data: { turbo_method: :patch } do %> <%= render Icons::StarComponent.new(css_classes: 'hidden group-hover/icon:inline w-6 h-6', variant: :light) %> diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index e917a3d27..305b27ca8 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -1,9 +1,10 @@ class Layout::FilterListComponent < ViewComponent::Base include MessageThreadHelper - def initialize(label: nil, filters:) + def initialize(label: nil, filters:, sortable: false) @label = label @filters = filters + @sortable = sortable end def icon_for(filter) diff --git a/app/components/t_w/sidebar_menu_item_component.html.erb b/app/components/t_w/sidebar_menu_item_component.html.erb index fc8991b64..d74576ab2 100644 --- a/app/components/t_w/sidebar_menu_item_component.html.erb +++ b/app/components/t_w/sidebar_menu_item_component.html.erb @@ -1,9 +1,12 @@
    + <% if leading %> + <%= leading %> + <% end %> <%= link_to \ @url, - class: "w-full flex gap-x-3 p-4", + class: "w-full flex gap-x-3 p-4 grow", data: { active: current_page?(@url, check_parameters: true) } \ do %> <% if @icon_component %> @@ -11,7 +14,7 @@ <% end %> <%= @name %> <% end %> - <% if accessory %> - <%= accessory %> + <% if trailing %> + <%= trailing %> <% end %>
    diff --git a/app/components/t_w/sidebar_menu_item_component.rb b/app/components/t_w/sidebar_menu_item_component.rb index 1e62457f5..de2d224ba 100644 --- a/app/components/t_w/sidebar_menu_item_component.rb +++ b/app/components/t_w/sidebar_menu_item_component.rb @@ -1,11 +1,13 @@ class TW::SidebarMenuItemComponent < ViewComponent::Base - renders_one :accessory + renders_one :leading + renders_one :trailing - def initialize(name:, url:, icon:, variant: :regular) + def initialize(name:, url:, icon:, variant: :regular, classes: '') @name = name @url = url @icon_component = icon @variant = variant + @classes = classes end def regular? diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index 2b0ddfe5a..2c9b2a0b1 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -71,6 +71,25 @@ def unpin redirect_back fallback_location: filters_path end + def sort + filters = filter_scope + .where(id: params[:filter_ids]) + .reorder('') + .in_order_of(:id, params[:filter_ids]) + + filters.map do |filter| + authorize filter + end + + Filter.transaction do + filters.map.with_index do |filter, i| + filter.update!(position: i + 1) + end + end + + redirect_back fallback_location: filters_path + end + private def filter_params diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index cedf3e19f..d1ce4ebf7 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -25,6 +25,9 @@ application.register("form", FormController) import MessageDraftsController from "./message_drafts_controller" application.register("message-drafts", MessageDraftsController) +import SortableController from "./sortable_controller" +application.register("sortable", SortableController) + import TriStateCheckboxController from "./tri_state_checkbox_controller" application.register("tri-state-checkbox", TriStateCheckboxController) diff --git a/app/javascript/controllers/sortable_controller.js b/app/javascript/controllers/sortable_controller.js new file mode 100644 index 000000000..21317f1ac --- /dev/null +++ b/app/javascript/controllers/sortable_controller.js @@ -0,0 +1,33 @@ +import {Controller} from "@hotwired/stimulus" +import {Sortable} from "@shopify/draggable"; +import {post} from '@rails/request.js' + +export default class extends Controller { + static classes = ["draggable", "handle"] + static targets = ["item", "submit"] + static values = {url: String} + + connect() { + this.sortable = new Sortable(this.element, { + draggable: this.draggableClass, + handle: this.handleClass, + classes: { + "source:dragging": "invisible", + } + }) + + this.sortable.on('drag:stopped', async (e) => { + // As of now, this is the only way to submit a PATCH request with Rails so Turbo updates the pages without a full reload + + const link = this.submitTarget; + + const urlSearchParams = new URLSearchParams({_method: 'patch'}); + this.itemTargets.map((item) => { + urlSearchParams.append('filter_ids[]', item.dataset.id); + }); + link.href = this.urlValue + '?' + urlSearchParams.toString(); + + link.click() + }); + } +} diff --git a/app/lib/sidebar_menu.rb b/app/lib/sidebar_menu.rb index fff231846..7a81efefb 100644 --- a/app/lib/sidebar_menu.rb +++ b/app/lib/sidebar_menu.rb @@ -19,7 +19,7 @@ def initial_structure(controller, _action) def default_main_menu [ TW::SidebarMenuItemComponent.new(name: 'Všetky správy', url: message_threads_path, icon: Icons::EnvelopeComponent.new), - Layout::FilterListComponent.new(filters: pinned_filters), + Layout::FilterListComponent.new(filters: pinned_filters, sortable: true), Layout::FilterListComponent.new(label: 'Filtre', filters: fulltext_filters), Layout::FilterListComponent.new(label: 'Štítky', filters: tag_filters), TW::SidebarMenuItemComponent.new(name: 'Nastavenia', url: filters_path, icon: Icons::CogSixToothComponent.new) diff --git a/app/models/filter.rb b/app/models/filter.rb index e78374548..b6bc6a65f 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -3,6 +3,7 @@ # Table name: filters # # id :bigint not null, primary key +# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/app/models/fulltext_filter.rb b/app/models/fulltext_filter.rb index 26e336157..490a770be 100644 --- a/app/models/fulltext_filter.rb +++ b/app/models/fulltext_filter.rb @@ -3,6 +3,7 @@ # Table name: filters # # id :bigint not null, primary key +# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index 81c6a4563..754b09831 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -3,6 +3,7 @@ # Table name: filters # # id :bigint not null, primary key +# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb index d2b635166..4d2b690ec 100644 --- a/app/policies/filter_policy.rb +++ b/app/policies/filter_policy.rb @@ -62,6 +62,10 @@ def unpin? pin? end + def sort? + is_author_current_user? + end + private def is_author_current_user? diff --git a/config/routes.rb b/config/routes.rb index a5b4a0673..21d1f7e9c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -106,6 +106,10 @@ patch :pin patch :unpin end + + collection do + patch :sort + end end resources :message_drafts do diff --git a/db/migrate/20231213100122_remove_index_filters_on_tenant_id_and_position.rb b/db/migrate/20231213100122_remove_index_filters_on_tenant_id_and_position.rb new file mode 100644 index 000000000..d28127e87 --- /dev/null +++ b/db/migrate/20231213100122_remove_index_filters_on_tenant_id_and_position.rb @@ -0,0 +1,5 @@ +class RemoveIndexFiltersOnTenantIdAndPosition < ActiveRecord::Migration[7.1] + def change + remove_index :filters, [:tenant_id, :position], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index aebca8022..6a446d77b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_12_11_140731) do +ActiveRecord::Schema[7.1].define(version: 2023_12_13_100122) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -145,7 +145,6 @@ t.index ["author_id"], name: "index_filters_on_author_id" t.index ["is_pinned"], name: "index_filters_on_is_pinned" t.index ["tag_id"], name: "index_filters_on_tag_id" - t.index ["tenant_id", "position"], name: "index_filters_on_tenant_id_and_position", unique: true t.index ["tenant_id"], name: "index_filters_on_tenant_id" t.index ["type"], name: "index_filters_on_type" end diff --git a/package.json b/package.json index e8894a76f..93550d7b1 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@hotwired/stimulus": "^3.2.1", "@hotwired/turbo-rails": "^7.0.0", "@rails/request.js": "^0.0.9", + "@shopify/draggable": "^1.1.3", "esbuild": "^0.19.8", "tailwindcss-stimulus-components": "^4.0.4" }, diff --git a/yarn.lock b/yarn.lock index d2f0df489..9546758b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -198,6 +198,11 @@ resolved "https://registry.yarnpkg.com/@rails/request.js/-/request.js-0.0.9.tgz#89e2a575405dc07eb8a9b3d2fe04289e1f057cd0" integrity sha512-VleYUyrA3rwKMvYnz7MI9Ada85Vekjb/WVz7NuGgDO24Y3Zy9FFSpDMQW+ea/tlftD+CdX/W/sUosRA9/HkDOQ== +"@shopify/draggable@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@shopify/draggable/-/draggable-1.1.3.tgz#4c1d0415629198ec11d27b776dda0fc89eb5efa2" + integrity sha512-okZG6FTOX1HpfToN2uFVXTicum+NtHFGEY+0MFkZsdChP5qvLSlkffQormMxoDQVIDsK+jso3yz03tteIJ/A0w== + "@tailwindcss/aspect-ratio@^0.4.2": version "0.4.2" resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz#9ffd52fee8e3c8b20623ff0dcb29e5c21fb0a9ba" From d8e29fffaf959847baf64cd1d52a80cf8befd9ac Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Wed, 13 Dec 2023 13:12:45 +0100 Subject: [PATCH 06/37] Replace bars icon with grip icon --- app/components/icons/bars_component.html.erb | 3 --- app/components/icons/grip_component.html.erb | 3 +++ app/components/icons/{bars_component.rb => grip_component.rb} | 2 +- app/components/layout/filter_list_component.html.erb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 app/components/icons/bars_component.html.erb create mode 100644 app/components/icons/grip_component.html.erb rename app/components/icons/{bars_component.rb => grip_component.rb} (72%) diff --git a/app/components/icons/bars_component.html.erb b/app/components/icons/bars_component.html.erb deleted file mode 100644 index 09c9bb355..000000000 --- a/app/components/icons/bars_component.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" stroke-width="<%= @stroke_width %>" stroke="currentColor" style="aspect-ratio: 1.14285714;"> - - \ No newline at end of file diff --git a/app/components/icons/grip_component.html.erb b/app/components/icons/grip_component.html.erb new file mode 100644 index 000000000..d3459f4b4 --- /dev/null +++ b/app/components/icons/grip_component.html.erb @@ -0,0 +1,3 @@ +" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" stroke-width="<%= @stroke_width %>" stroke="currentColor" style="aspect-ratio: 1.6;"> + + \ No newline at end of file diff --git a/app/components/icons/bars_component.rb b/app/components/icons/grip_component.rb similarity index 72% rename from app/components/icons/bars_component.rb rename to app/components/icons/grip_component.rb index 8f83e721e..d2b374863 100644 --- a/app/components/icons/bars_component.rb +++ b/app/components/icons/grip_component.rb @@ -1,4 +1,4 @@ -class Icons::BarsComponent < ViewComponent::Base +class Icons::GripComponent < ViewComponent::Base def initialize(css_classes: nil, stroke_width: 1.5) @css_classes = css_classes @stroke_width = stroke_width diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index 0697b8077..3f168b6a8 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -28,7 +28,7 @@ <% if @sortable %> <% menu_item.with_leading do %> <% end %> <% end %> From 5b0b7a31410c3ccb01b26defb30457ce8937443d Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Thu, 4 Jan 2024 09:22:41 +0100 Subject: [PATCH 07/37] Tweak styles --- app/components/layout/filter_list_component.html.erb | 4 ++-- app/components/t_w/sidebar_menu_item_component.html.erb | 2 +- app/components/t_w/sidebar_menu_item_component.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/layout/filter_list_component.html.erb b/app/components/layout/filter_list_component.html.erb index 3f168b6a8..385364c18 100644 --- a/app/components/layout/filter_list_component.html.erb +++ b/app/components/layout/filter_list_component.html.erb @@ -23,11 +23,11 @@ url: filtered_message_threads_path(filter:), icon: icon_for(filter), variant: :light, - classes: 'item', + classes: "item #{!@sortable ? 'pl-4' : ''}", ) do |menu_item| %> <% if @sortable %> <% menu_item.with_leading do %> -
    - <%= render Settings::UserHiddenItems::UserHiddenItemsListRowComponent.with_collection(@items, type: @type) %> + <%= render Settings::UserItemVisibilities::ListRowComponent.with_collection(@visibilities) %>
    diff --git a/app/components/settings/user_item_visibilities/list_component.rb b/app/components/settings/user_item_visibilities/list_component.rb new file mode 100644 index 000000000..e5cc40f6f --- /dev/null +++ b/app/components/settings/user_item_visibilities/list_component.rb @@ -0,0 +1,6 @@ +class Settings::UserItemVisibilities::ListComponent < ViewComponent::Base + def initialize(type, visibilities) + @type = type + @visibilities = visibilities + end +end diff --git a/app/components/settings/user_item_visibilities/list_row_component.html.erb b/app/components/settings/user_item_visibilities/list_row_component.html.erb new file mode 100644 index 000000000..ea13f8419 --- /dev/null +++ b/app/components/settings/user_item_visibilities/list_row_component.html.erb @@ -0,0 +1,37 @@ +
    +
    +
    + <%= render Common::TagComponent.new(@item) if @item.is_a?(Tag) %> + <%= @item.name if @item.is_a?(Filter) %> +
    +
    + <% if @visibility.new_record? %> + <%= form_with model: [:settings, Current.user.user_item_visibilities.new(user_item: @item)], method: :post do |form| %> + <%= form.hidden_field :user_item_type, value: @item.class %> + <%= form.hidden_field :user_item_id, value: @item.id %> + <%= form.hidden_field :visible, value: !@visibility.visible %> + <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> + Use setting + + <% end %> + <% end %> + <% else %> + <%= form_with model: [:move_higher, :settings, @visibility], method: :post do |form| %> + <%= form.button do %> + Up + <% end %> + <% end %> + <%= form_with model: [:move_lower, :settings, @visibility], method: :post do |form| %> + <%= form.button do %> + Down + <% end %> + <% end %> + <%= form_with model: [:settings, @visibility], method: :patch do |form| %> + <%= form.hidden_field :visible, value: !@visibility.visible %> + <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> + Use setting + + <% end %> + <% end %> + <% end %> +
    diff --git a/app/components/settings/user_item_visibilities/list_row_component.rb b/app/components/settings/user_item_visibilities/list_row_component.rb new file mode 100644 index 000000000..23d69f61f --- /dev/null +++ b/app/components/settings/user_item_visibilities/list_row_component.rb @@ -0,0 +1,7 @@ +class Settings::UserItemVisibilities::ListRowComponent < ViewComponent::Base + with_collection_parameter :visibility + def initialize(visibility:) + @visibility = visibility + @item = visibility.user_item + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 550cc717f..cc05bd630 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,13 +13,8 @@ def pundit_user def set_menu_context return unless Current.user - @tags = policy_scope(Tag, policy_scope_class: TagPolicy::ScopeListable) - .where(visible: true) - .where.not(id: UserHiddenItem.where(user: Current.user, user_hideable_type: "Tag").select(:user_hideable_id)) - .order(:name) - @filters = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable) - .where.not(id: UserHiddenItem.where(user: Current.user, user_hideable_type: "Filter").select(:user_hideable_id)) - .order(:position) + @tags = Current.user.build_tag_visibilities!.where(visible: true).map(&:user_item) + @filters = Current.user.build_filter_visibilities!.where(visible: true).map(&:user_item) @menu = SidebarMenu.new(controller_name, action_name, tags: @tags, filters: @filters).menu @current_tenant_boxes_count = Current.tenant.boxes.count end diff --git a/app/controllers/settings/filter_visibilities_controller.rb b/app/controllers/settings/filter_visibilities_controller.rb new file mode 100644 index 000000000..8a908e390 --- /dev/null +++ b/app/controllers/settings/filter_visibilities_controller.rb @@ -0,0 +1,11 @@ +class Settings::FilterVisibilitiesController < Settings::UserItemVisibilitiesController + private + + def set_type + @type = 'Filter' + end + + def set_user_item_visibilities + @user_item_visibilities = Current.user.build_filter_visibilities! + end +end diff --git a/app/controllers/settings/tag_visibilities_controller.rb b/app/controllers/settings/tag_visibilities_controller.rb new file mode 100644 index 000000000..d61c6c4f5 --- /dev/null +++ b/app/controllers/settings/tag_visibilities_controller.rb @@ -0,0 +1,11 @@ +class Settings::TagVisibilitiesController < Settings::UserItemVisibilitiesController + private + + def set_type + @type = 'Tag' + end + + def set_user_item_visibilities + @user_item_visibilities = Current.user.build_tag_visibilities! + end +end diff --git a/app/controllers/settings/user_hidden_items_controller.rb b/app/controllers/settings/user_hidden_items_controller.rb deleted file mode 100644 index bf1c5dacc..000000000 --- a/app/controllers/settings/user_hidden_items_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -class Settings::UserHiddenItemsController < ApplicationController - before_action :set_user_hidden_item, only: [:destroy] - - def index - authorize UserHiddenItem - if params[:type] == 'Tag' - set_tag_items - elsif params[:type] == 'Filter' - set_filter_items - end - end - - def create - authorize UserHiddenItem - Current.user.user_hidden_items.create(user_hidden_item_params) - redirect_back fallback_location: settings_user_hidden_items_path - end - - def destroy - authorize @user_hidden_item - @user_hidden_item.destroy - redirect_back fallback_location: settings_user_hidden_items_path - end - - private - - def set_tag_items - @items = policy_scope(Tag, policy_scope_class: TagPolicy::ScopeListable) - .where(visible: true) - .order(:name) - .select("tags.*, (select exists (select id from user_hidden_items where user_hideable_type='Tag' and user_hideable_id = tags.id and user_id = #{Current.user.id})) as user_hidden") - end - - def set_filter_items - @items = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable) - .order(:position) - .select("filters.*, (select exists (select id from user_hidden_items where user_hideable_type='Filter' and user_hideable_id = filters.id and user_id = #{Current.user.id})) as user_hidden") - end - - def set_user_hidden_item - @user_hidden_item = policy_scope(UserHiddenItem).find(params[:id]) - end - - def user_hidden_item_params - params.require(:user_hidden_item).permit(:user_hideable_type, :user_hideable_id) - end -end diff --git a/app/controllers/settings/user_item_visibilities_controller.rb b/app/controllers/settings/user_item_visibilities_controller.rb new file mode 100644 index 000000000..71ce58731 --- /dev/null +++ b/app/controllers/settings/user_item_visibilities_controller.rb @@ -0,0 +1,60 @@ +class Settings::UserItemVisibilitiesController < ApplicationController + before_action :set_user_item_visibility, only: [:update, :move_higher, :move_lower, :destroy] + + def index + authorize UserItemVisibility + + set_type + set_user_item_visibilities + end + + def create + authorize UserItemVisibility + Current.user.user_item_visibilities.create(user_item_visibility_params).tap do |visibility| + visibility.move_to_bottom + end + redirect_back fallback_location: request.referer + end + + def update + authorize @user_item_visibility + @user_item_visibility.update(user_item_visibility_params) + redirect_back fallback_location: request.referer + end + + def move_higher + authorize @user_item_visibility + @user_item_visibility.move_higher + redirect_back fallback_location: request.referer + end + + def move_lower + authorize @user_item_visibility + @user_item_visibility.move_lower + redirect_back fallback_location: request.referer + end + + def destroy + authorize @user_item_visibility + @user_item_visibility.destroy + redirect_back fallback_location: request.referer + end + + private + + def set_type + raise NotImplementedError + end + + def set_user_item_visibilities + raise NotImplementedError + end + + def set_user_item_visibility + @user_item_visibility = policy_scope(UserItemVisibility).find(params[:id]) + end + + def user_item_visibility_params + params.require(:user_item_visibility).permit(:user_item_type, :user_item_id, :visible) + end +end diff --git a/app/lib/sidebar_menu.rb b/app/lib/sidebar_menu.rb index 77e81699f..905ee3662 100644 --- a/app/lib/sidebar_menu.rb +++ b/app/lib/sidebar_menu.rb @@ -13,8 +13,8 @@ def initialize(controller, _action, parameters = nil, filters: [], tags: []) private def current_menu(controller) - return admin_menu + site_admin_menu if Current.user.admin? && controller.in?(%w[groups users tags tag_groups automation_rules boxes filters user_hidden_items]) - return settings_menu if controller.in? %w[filters tags user_hidden_items] + return admin_menu + site_admin_menu if Current.user.admin? && controller.in?(%w[groups users tags tag_groups automation_rules boxes filters filter_visibilities tag_visibilities]) + return settings_menu if controller.in? %w[filters tags filter_visibilities tag_visibilities] default_main_menu end @@ -34,8 +34,8 @@ def settings_menu TW::SidebarMenuDividerComponent.new(name: 'Nastavenia'), TW::SidebarMenuItemComponent.new(name: 'Filtre', url: filters_path, icon: Icons::BookmarkComponent.new), TW::SidebarMenuItemComponent.new(name: 'Pravidlá', url: settings_automation_rules_path, icon: Icons::FunnelComponent.new), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_user_hidden_items_path(type: "Tag"), icon: Common::IconComponent.new("tag")), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_user_hidden_items_path(type: "Filter"), icon: Common::IconComponent.new("bookmark")) + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_tag_visibilities_path, icon: Common::IconComponent.new("tag")), + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_filter_visibilities_path, icon: Common::IconComponent.new("bookmark")) ] end @@ -47,8 +47,8 @@ def admin_menu TW::SidebarMenuDividerComponent.new(name: 'Nastavenia'), TW::SidebarMenuItemComponent.new(name: 'Filtre', url: filters_path, icon: Icons::BookmarkComponent.new), TW::SidebarMenuItemComponent.new(name: 'Pravidlá', url: settings_automation_rules_path, icon: Icons::FunnelComponent.new), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_user_hidden_items_path(type: Tag), icon: Common::IconComponent.new("bookmark")), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_user_hidden_items_path(type: "Filter"), icon: Common::IconComponent.new("tag")), + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_tag_visibilities_path, icon: Common::IconComponent.new("bookmark")), + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_filter_visibilities_path, icon: Common::IconComponent.new("tag")), TW::SidebarMenuDividerComponent.new(name: 'Administrácia'), TW::SidebarMenuItemComponent.new(name: 'Používatelia', url: admin_tenant_users_path(Current.tenant), icon: Icons::UsersComponent.new), TW::SidebarMenuItemComponent.new(name: 'Prístup', url: admin_tenant_tag_groups_path(Current.tenant), icon: Icons::LockClosedComponent.new), diff --git a/app/models/filter.rb b/app/models/filter.rb index b6bc6a65f..931b403d6 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -19,6 +19,7 @@ class Filter < ApplicationRecord belongs_to :author, class_name: 'User' belongs_to :tenant + has_many :user_item_visibilities, inverse_of: :user_item, dependent: :destroy validates :tenant_id, :author_id, :name, presence: true diff --git a/app/models/tag.rb b/app/models/tag.rb index 727a62ddb..c8930ab81 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -30,7 +30,7 @@ class Tag < ApplicationRecord has_many :automation_actions, class_name: "Automation::Action", as: :action_object, dependent: :restrict_with_error has_many :message_objects_tags, dependent: :destroy has_many :message_objects, through: :message_objects_tags - has_many :user_hidden_items, as: :user_hideable, dependent: :destroy + has_many :user_item_visibilities, as: :user_item, dependent: :destroy validates :name, presence: true validates :name, uniqueness: { scope: :tenant_id, case_sensitive: false } diff --git a/app/models/user.rb b/app/models/user.rb index 86624a3ab..3941fd10b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -13,6 +13,7 @@ # tenant_id :bigint # class User < ApplicationRecord + include Pundit include AuditableEvents belongs_to :tenant @@ -26,7 +27,7 @@ class User < ApplicationRecord has_many :filters, foreign_key: :author_id has_many :filter_subscriptions has_many :notifications - has_many :user_hidden_items, dependent: :destroy + has_many :user_item_visibilities, dependent: :destroy validates_presence_of :name, :email validates_uniqueness_of :name, :email, scope: :tenant_id, case_sensitive: false @@ -49,10 +50,10 @@ def user_group def accessible_tags Tag.where( TagGroup.select(1) - .joins(:group_memberships) - .where("tag_groups.tag_id = tags.id") - .where(group_memberships: { user_id: id }) - .arel.exists + .joins(:group_memberships) + .where("tag_groups.tag_id = tags.id") + .where(group_memberships: { user_id: id }) + .arel.exists ) end @@ -79,8 +80,37 @@ def update_notifications_retention end end + def build_filter_visibilities! + user_items = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).order(:position) + visibilities = user_item_visibilities.where(user_item_type: "Filter").order(:position) + build_user_item_visibilities(user_items, visibilities) + end + + def build_tag_visibilities! + user_items = policy_scope(Tag, policy_scope_class: TagPolicy::ScopeListable).where(visible: true).order(:name) + visibilities = user_item_visibilities.where(user_item_type: "Tag").order(:position) + build_user_item_visibilities(user_items, visibilities) + end + + def pundit_user + self + end + private + def build_user_item_visibilities(user_items, visibilities) + user_items_without_visibilities = user_items.where.not(id: visibilities.pluck(:user_item_id)) + new_visibilities = user_items_without_visibilities.map.with_index do |user_item, i| + last_position = visibilities.last&.position || 0 + user_item_visibilities.new(user_item: user_item, visible: true, position: last_position + 1 + i) + end + + all_visibilities = visibilities.to_a + new_visibilities + all_visibilities.map(&:save!) + user_item_visibilities.where(id: all_visibilities).order(:position) + end + + def delete_user_group user_group.destroy end diff --git a/app/models/user_hidden_item.rb b/app/models/user_hidden_item.rb deleted file mode 100644 index 38bcd7254..000000000 --- a/app/models/user_hidden_item.rb +++ /dev/null @@ -1,15 +0,0 @@ -# == Schema Information -# -# Table name: user_hidden_items -# -# id :bigint not null, primary key -# user_hideable_type :string not null -# created_at :datetime not null -# updated_at :datetime not null -# user_hideable_id :bigint -# user_id :bigint not null -# -class UserHiddenItem < ApplicationRecord - belongs_to :user - belongs_to :user_hideable, polymorphic: true -end diff --git a/app/models/user_item_visibility.rb b/app/models/user_item_visibility.rb new file mode 100644 index 000000000..2ffe68125 --- /dev/null +++ b/app/models/user_item_visibility.rb @@ -0,0 +1,23 @@ +# == Schema Information +# +# Table name: user_item_visibilities +# +# id :bigint not null, primary key +# position :integer +# user_item_type :string not null +# visible :boolean default(TRUE), not null +# created_at :datetime not null +# updated_at :datetime not null +# user_id :bigint not null +# user_item_id :bigint +# +class UserItemVisibility < ApplicationRecord + belongs_to :user + belongs_to :user_item, polymorphic: true + + acts_as_list scope: [:user_id, :user_item_type] + + def hidden + !visible + end +end diff --git a/app/policies/user_hidden_item_policy.rb b/app/policies/user_hidden_item_policy.rb deleted file mode 100644 index ae32b3eb2..000000000 --- a/app/policies/user_hidden_item_policy.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -class UserHiddenItemPolicy < ApplicationPolicy - attr_reader :user, :user_hidden_item - - def initialize(user, user_hidden_item) - @user = user - @user_hidden_item = user_hidden_item - end - - class Scope < Scope - def resolve - scope.where(user: Current.user) - end - end - - def index? - true - end - - def destroy? - @user_hidden_item.user == Current.user - end - - def create? - true - end -end diff --git a/app/policies/user_item_visibility_policy.rb b/app/policies/user_item_visibility_policy.rb new file mode 100644 index 000000000..75384f44c --- /dev/null +++ b/app/policies/user_item_visibility_policy.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +class UserItemVisibilityPolicy < ApplicationPolicy + attr_reader :user, :user_item_visible + + def initialize(user, user_item_visible) + @user = user + @user_item_visible = user_item_visible + end + + class Scope < Scope + def resolve + scope.where(user: Current.user) + end + end + + def index? + true + end + + def destroy? + owner? + end + + def create? + true + end + + def update? + owner? + end + + def move_higher? + update? + end + + def move_lower? + update? + end + + private + + def owner? + @user_item_visible.user == Current.user + end +end diff --git a/app/views/settings/user_hidden_items/index.html.erb b/app/views/settings/user_hidden_items/index.html.erb deleted file mode 100644 index 2c69fbcfd..000000000 --- a/app/views/settings/user_hidden_items/index.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render Settings::UserHiddenItems::UserHiddenItemsListComponent.new(params[:type], @items) %> diff --git a/app/views/settings/user_item_visibilities/index.html.erb b/app/views/settings/user_item_visibilities/index.html.erb new file mode 100644 index 000000000..871616726 --- /dev/null +++ b/app/views/settings/user_item_visibilities/index.html.erb @@ -0,0 +1 @@ +<%= render Settings::UserItemVisibilities::ListComponent.new(@type, @user_item_visibilities) %> diff --git a/config/routes.rb b/config/routes.rb index 484586bec..ffb83c2a2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,7 +22,14 @@ end resources :tags resource :profile - resources :user_hidden_items + resources :filter_visibilities + resources :tag_visibilities + resources :user_item_visibilities do + member do + post :move_higher + post :move_lower + end + end end namespace :admin do diff --git a/db/migrate/20240523122734_rename_user_hidden_item_to_user_item_visibility.rb b/db/migrate/20240523122734_rename_user_hidden_item_to_user_item_visibility.rb new file mode 100644 index 000000000..967807a6c --- /dev/null +++ b/db/migrate/20240523122734_rename_user_hidden_item_to_user_item_visibility.rb @@ -0,0 +1,5 @@ +class RenameUserHiddenItemToUserItemVisibility < ActiveRecord::Migration[7.1] + def change + rename_table :user_hidden_items, :user_item_visibilities + end +end diff --git a/db/migrate/20240523123256_rename_user_item_visibilities_user_hideable_to_user_item.rb b/db/migrate/20240523123256_rename_user_item_visibilities_user_hideable_to_user_item.rb new file mode 100644 index 000000000..035c6f24c --- /dev/null +++ b/db/migrate/20240523123256_rename_user_item_visibilities_user_hideable_to_user_item.rb @@ -0,0 +1,6 @@ +class RenameUserItemVisibilitiesUserHideableToUserItem < ActiveRecord::Migration[7.1] + def change + rename_column :user_item_visibilities, :user_hideable_type, :user_item_type + rename_column :user_item_visibilities, :user_hideable_id, :user_item_id + end +end diff --git a/db/migrate/20240523123432_add_visible_and_position_to_user_item_visibilities.rb b/db/migrate/20240523123432_add_visible_and_position_to_user_item_visibilities.rb new file mode 100644 index 000000000..5cfa349c5 --- /dev/null +++ b/db/migrate/20240523123432_add_visible_and_position_to_user_item_visibilities.rb @@ -0,0 +1,6 @@ +class AddVisibleAndPositionToUserItemVisibilities < ActiveRecord::Migration[7.1] + def change + add_column :user_item_visibilities, :visible, :boolean, null: false, default: true + add_column :user_item_visibilities, :position, :integer, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 53e89471a..9abf9c8d7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_17_131624) do +ActiveRecord::Schema[7.1].define(version: 2024_05_23_123432) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -583,13 +583,15 @@ t.datetime "updated_at", null: false end - create_table "user_hidden_items", force: :cascade do |t| + create_table "user_item_visibilities", force: :cascade do |t| t.bigint "user_id", null: false - t.string "user_hideable_type", null: false - t.bigint "user_hideable_id" + t.string "user_item_type", null: false + t.bigint "user_item_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["user_id"], name: "index_user_hidden_items_on_user_id" + t.boolean "visible", default: true, null: false + t.integer "position" + t.index ["user_id"], name: "index_user_item_visibilities_on_user_id" end create_table "users", force: :cascade do |t| @@ -661,6 +663,6 @@ add_foreign_key "tags", "tenants" add_foreign_key "tags", "users", column: "owner_id" add_foreign_key "upvs_form_related_documents", "upvs_forms" - add_foreign_key "user_hidden_items", "users" + add_foreign_key "user_item_visibilities", "users" add_foreign_key "users", "tenants" end From 87c0bd82c9bfd85e5f162131c9e6a34c380ebfea Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Mon, 24 Jun 2024 13:50:13 +0200 Subject: [PATCH 17/37] Reorganize filtering and enable TagFilter usage --- .../list_component.html.erb | 6 +- .../list_component.rb | 5 ++ .../list_row_component.html.erb | 8 +-- .../list_row_component.rb | 7 +++ .../user_item_visibilities/list_component.rb | 6 -- .../list_row_component.rb | 7 --- app/controllers/application_controller.rb | 3 +- .../filter_visibilities_controller.rb | 11 ---- .../settings/tag_visibilities_controller.rb | 11 ---- .../user_filter_visibilities_controller.rb | 55 +++++++++++++++++ .../user_item_visibilities_controller.rb | 60 ------------------- app/lib/sidebar_menu.rb | 13 ++-- app/models/everything_filter.rb | 30 ++++++++++ app/models/filter.rb | 6 +- app/models/fulltext_filter.rb | 2 +- app/models/tag.rb | 10 +++- app/models/tag_filter.rb | 4 +- app/models/user.rb | 28 ++++----- app/models/user_filter_visibility.rb | 22 +++++++ app/models/user_item_visibility.rb | 23 ------- ...cy.rb => user_filter_visibility_policy.rb} | 10 ++-- .../user_filter_visibilities/index.html.erb | 1 + .../user_item_visibilities/index.html.erb | 1 - config/routes.rb | 4 +- ...isibilities_to_user_filter_visibilities.rb | 5 ++ ...m_to_filter_on_user_filter_visibilities.rb | 28 +++++++++ ...40619084104_change_type_null_on_filters.rb | 14 +++++ ...0624114024_create_tag_filters_from_tags.rb | 29 +++++++++ db/schema.rb | 15 ++--- 29 files changed, 251 insertions(+), 173 deletions(-) rename app/components/settings/{user_item_visibilities => user_filter_visibilities}/list_component.html.erb (61%) create mode 100644 app/components/settings/user_filter_visibilities/list_component.rb rename app/components/settings/{user_item_visibilities => user_filter_visibilities}/list_row_component.html.erb (85%) create mode 100644 app/components/settings/user_filter_visibilities/list_row_component.rb delete mode 100644 app/components/settings/user_item_visibilities/list_component.rb delete mode 100644 app/components/settings/user_item_visibilities/list_row_component.rb delete mode 100644 app/controllers/settings/filter_visibilities_controller.rb delete mode 100644 app/controllers/settings/tag_visibilities_controller.rb create mode 100644 app/controllers/settings/user_filter_visibilities_controller.rb delete mode 100644 app/controllers/settings/user_item_visibilities_controller.rb create mode 100644 app/models/everything_filter.rb create mode 100644 app/models/user_filter_visibility.rb delete mode 100644 app/models/user_item_visibility.rb rename app/policies/{user_item_visibility_policy.rb => user_filter_visibility_policy.rb} (60%) create mode 100644 app/views/settings/user_filter_visibilities/index.html.erb delete mode 100644 app/views/settings/user_item_visibilities/index.html.erb create mode 100644 db/migrate/20240617090128_rename_user_item_visibilities_to_user_filter_visibilities.rb create mode 100644 db/migrate/20240617090456_rename_user_item_to_filter_on_user_filter_visibilities.rb create mode 100644 db/migrate/20240619084104_change_type_null_on_filters.rb create mode 100644 db/migrate/20240624114024_create_tag_filters_from_tags.rb diff --git a/app/components/settings/user_item_visibilities/list_component.html.erb b/app/components/settings/user_filter_visibilities/list_component.html.erb similarity index 61% rename from app/components/settings/user_item_visibilities/list_component.html.erb rename to app/components/settings/user_filter_visibilities/list_component.html.erb index 36422e477..86362c676 100644 --- a/app/components/settings/user_item_visibilities/list_component.html.erb +++ b/app/components/settings/user_filter_visibilities/list_component.html.erb @@ -1,11 +1,11 @@
    -
    <%= @type == "Tag" ? "Štítky" : "Filtre" %>
    - Nastavte si osobnú preferenciu viditeľnosti <%= @type == "Tag" ? "štítkov" : "filtrov" %> v ľavom menu +
    Filtre
    + Nastavte si osobnú preferenciu viditeľnosti filtrov v ľavom menu
    - <%= render Settings::UserItemVisibilities::ListRowComponent.with_collection(@visibilities) %> + <%= render Settings::UserFilterVisibilities::ListRowComponent.with_collection(@visibilities) %>
    diff --git a/app/components/settings/user_filter_visibilities/list_component.rb b/app/components/settings/user_filter_visibilities/list_component.rb new file mode 100644 index 000000000..b21ad237e --- /dev/null +++ b/app/components/settings/user_filter_visibilities/list_component.rb @@ -0,0 +1,5 @@ +class Settings::UserFilterVisibilities::ListComponent < ViewComponent::Base + def initialize(visibilities) + @visibilities = visibilities + end +end diff --git a/app/components/settings/user_item_visibilities/list_row_component.html.erb b/app/components/settings/user_filter_visibilities/list_row_component.html.erb similarity index 85% rename from app/components/settings/user_item_visibilities/list_row_component.html.erb rename to app/components/settings/user_filter_visibilities/list_row_component.html.erb index ea13f8419..ae3a5c9e9 100644 --- a/app/components/settings/user_item_visibilities/list_row_component.html.erb +++ b/app/components/settings/user_filter_visibilities/list_row_component.html.erb @@ -1,14 +1,12 @@
    - <%= render Common::TagComponent.new(@item) if @item.is_a?(Tag) %> - <%= @item.name if @item.is_a?(Filter) %> + <%= @filter.name %>
    <% if @visibility.new_record? %> - <%= form_with model: [:settings, Current.user.user_item_visibilities.new(user_item: @item)], method: :post do |form| %> - <%= form.hidden_field :user_item_type, value: @item.class %> - <%= form.hidden_field :user_item_id, value: @item.id %> + <%= form_with model: [:settings, Current.user.user_filter_visibilities.new(filter: @filter)], method: :post do |form| %> + <%= form.hidden_field :filter_id, value: @filter.id %> <%= form.hidden_field :visible, value: !@visibility.visible %> <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> Use setting diff --git a/app/components/settings/user_filter_visibilities/list_row_component.rb b/app/components/settings/user_filter_visibilities/list_row_component.rb new file mode 100644 index 000000000..99cf8ca6e --- /dev/null +++ b/app/components/settings/user_filter_visibilities/list_row_component.rb @@ -0,0 +1,7 @@ +class Settings::UserFilterVisibilities::ListRowComponent < ViewComponent::Base + with_collection_parameter :visibility + def initialize(visibility:) + @visibility = visibility + @filter = visibility.filter + end +end diff --git a/app/components/settings/user_item_visibilities/list_component.rb b/app/components/settings/user_item_visibilities/list_component.rb deleted file mode 100644 index e5cc40f6f..000000000 --- a/app/components/settings/user_item_visibilities/list_component.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Settings::UserItemVisibilities::ListComponent < ViewComponent::Base - def initialize(type, visibilities) - @type = type - @visibilities = visibilities - end -end diff --git a/app/components/settings/user_item_visibilities/list_row_component.rb b/app/components/settings/user_item_visibilities/list_row_component.rb deleted file mode 100644 index 23d69f61f..000000000 --- a/app/components/settings/user_item_visibilities/list_row_component.rb +++ /dev/null @@ -1,7 +0,0 @@ -class Settings::UserItemVisibilities::ListRowComponent < ViewComponent::Base - with_collection_parameter :visibility - def initialize(visibility:) - @visibility = visibility - @item = visibility.user_item - end -end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index cc05bd630..7ec65e093 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -13,8 +13,7 @@ def pundit_user def set_menu_context return unless Current.user - @tags = Current.user.build_tag_visibilities!.where(visible: true).map(&:user_item) - @filters = Current.user.build_filter_visibilities!.where(visible: true).map(&:user_item) + @filters = Current.user.visible_filters @menu = SidebarMenu.new(controller_name, action_name, tags: @tags, filters: @filters).menu @current_tenant_boxes_count = Current.tenant.boxes.count end diff --git a/app/controllers/settings/filter_visibilities_controller.rb b/app/controllers/settings/filter_visibilities_controller.rb deleted file mode 100644 index 8a908e390..000000000 --- a/app/controllers/settings/filter_visibilities_controller.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Settings::FilterVisibilitiesController < Settings::UserItemVisibilitiesController - private - - def set_type - @type = 'Filter' - end - - def set_user_item_visibilities - @user_item_visibilities = Current.user.build_filter_visibilities! - end -end diff --git a/app/controllers/settings/tag_visibilities_controller.rb b/app/controllers/settings/tag_visibilities_controller.rb deleted file mode 100644 index d61c6c4f5..000000000 --- a/app/controllers/settings/tag_visibilities_controller.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Settings::TagVisibilitiesController < Settings::UserItemVisibilitiesController - private - - def set_type - @type = 'Tag' - end - - def set_user_item_visibilities - @user_item_visibilities = Current.user.build_tag_visibilities! - end -end diff --git a/app/controllers/settings/user_filter_visibilities_controller.rb b/app/controllers/settings/user_filter_visibilities_controller.rb new file mode 100644 index 000000000..1dcaf1895 --- /dev/null +++ b/app/controllers/settings/user_filter_visibilities_controller.rb @@ -0,0 +1,55 @@ +class Settings::UserFilterVisibilitiesController < ApplicationController + before_action :set_user_filter_visibility, only: [:update, :move_higher, :move_lower, :destroy] + + def index + authorize UserFilterVisibility + + set_user_filter_visibilities + end + + def create + authorize UserFilterVisibility + Current.user.user_filter_visibilities.create(user_filter_visibility_params).tap do |visibility| + visibility.move_to_bottom + end + redirect_back fallback_location: request.referer + end + + def update + authorize @user_filter_visibility + @user_filter_visibility.update(user_filter_visibility_params) + redirect_back fallback_location: request.referer + end + + def move_higher + authorize @user_filter_visibility + @user_filter_visibility.move_higher + redirect_back fallback_location: request.referer + end + + def move_lower + authorize @user_filter_visibility + @user_filter_visibility.move_lower + redirect_back fallback_location: request.referer + end + + def destroy + authorize @user_filter_visibility + @user_filter_visibility.destroy + redirect_back fallback_location: request.referer + end + + private + + def set_user_filter_visibilities + @user_filter_visibilities = Current.user.build_filter_visibilities! + end + + def set_user_filter_visibility + @user_filter_visibility = policy_scope(UserFilterVisibility).find(params[:id]) + end + + def user_filter_visibility_params + params.require(:user_filter_visibility).permit(:filter_id, :visible) + end +end diff --git a/app/controllers/settings/user_item_visibilities_controller.rb b/app/controllers/settings/user_item_visibilities_controller.rb deleted file mode 100644 index 71ce58731..000000000 --- a/app/controllers/settings/user_item_visibilities_controller.rb +++ /dev/null @@ -1,60 +0,0 @@ -class Settings::UserItemVisibilitiesController < ApplicationController - before_action :set_user_item_visibility, only: [:update, :move_higher, :move_lower, :destroy] - - def index - authorize UserItemVisibility - - set_type - set_user_item_visibilities - end - - def create - authorize UserItemVisibility - Current.user.user_item_visibilities.create(user_item_visibility_params).tap do |visibility| - visibility.move_to_bottom - end - redirect_back fallback_location: request.referer - end - - def update - authorize @user_item_visibility - @user_item_visibility.update(user_item_visibility_params) - redirect_back fallback_location: request.referer - end - - def move_higher - authorize @user_item_visibility - @user_item_visibility.move_higher - redirect_back fallback_location: request.referer - end - - def move_lower - authorize @user_item_visibility - @user_item_visibility.move_lower - redirect_back fallback_location: request.referer - end - - def destroy - authorize @user_item_visibility - @user_item_visibility.destroy - redirect_back fallback_location: request.referer - end - - private - - def set_type - raise NotImplementedError - end - - def set_user_item_visibilities - raise NotImplementedError - end - - def set_user_item_visibility - @user_item_visibility = policy_scope(UserItemVisibility).find(params[:id]) - end - - def user_item_visibility_params - params.require(:user_item_visibility).permit(:user_item_type, :user_item_id, :visible) - end -end diff --git a/app/lib/sidebar_menu.rb b/app/lib/sidebar_menu.rb index 905ee3662..89c619982 100644 --- a/app/lib/sidebar_menu.rb +++ b/app/lib/sidebar_menu.rb @@ -4,7 +4,6 @@ class SidebarMenu def initialize(controller, _action, parameters = nil, filters: [], tags: []) @parameters = parameters @filters = filters - @tags = tags @menu = current_menu(controller) end @@ -13,17 +12,15 @@ def initialize(controller, _action, parameters = nil, filters: [], tags: []) private def current_menu(controller) - return admin_menu + site_admin_menu if Current.user.admin? && controller.in?(%w[groups users tags tag_groups automation_rules boxes filters filter_visibilities tag_visibilities]) - return settings_menu if controller.in? %w[filters tags filter_visibilities tag_visibilities] + return admin_menu + site_admin_menu if Current.user.admin? && controller.in?(%w[groups users tags tag_groups automation_rules boxes filters user_filter_visibilities]) + return settings_menu if controller.in? %w[filters tags user_filter_visibilities] default_main_menu end def default_main_menu [ - TW::SidebarMenuItemComponent.new(name: 'Všetky správy', url: message_threads_path, icon: Common::IconComponent.new("envelope")), Layout::FilterListComponent.new(filters: @filters), - Layout::TagListComponent.new(tags: @tags), TW::SidebarMenuItemComponent.new(name: 'Nastavenia', url: filters_path, icon: Icons::CogSixToothComponent.new) ] end @@ -34,8 +31,7 @@ def settings_menu TW::SidebarMenuDividerComponent.new(name: 'Nastavenia'), TW::SidebarMenuItemComponent.new(name: 'Filtre', url: filters_path, icon: Icons::BookmarkComponent.new), TW::SidebarMenuItemComponent.new(name: 'Pravidlá', url: settings_automation_rules_path, icon: Icons::FunnelComponent.new), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_tag_visibilities_path, icon: Common::IconComponent.new("tag")), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_filter_visibilities_path, icon: Common::IconComponent.new("bookmark")) + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_user_filter_visibilities_path, icon: Common::IconComponent.new("bookmark")) ] end @@ -47,8 +43,7 @@ def admin_menu TW::SidebarMenuDividerComponent.new(name: 'Nastavenia'), TW::SidebarMenuItemComponent.new(name: 'Filtre', url: filters_path, icon: Icons::BookmarkComponent.new), TW::SidebarMenuItemComponent.new(name: 'Pravidlá', url: settings_automation_rules_path, icon: Icons::FunnelComponent.new), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť štítkov', url: settings_tag_visibilities_path, icon: Common::IconComponent.new("bookmark")), - TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_filter_visibilities_path, icon: Common::IconComponent.new("tag")), + TW::SidebarMenuItemComponent.new(name: 'Viditeľnosť filtrov', url: settings_user_filter_visibilities_path, icon: Common::IconComponent.new("tag")), TW::SidebarMenuDividerComponent.new(name: 'Administrácia'), TW::SidebarMenuItemComponent.new(name: 'Používatelia', url: admin_tenant_users_path(Current.tenant), icon: Icons::UsersComponent.new), TW::SidebarMenuItemComponent.new(name: 'Prístup', url: admin_tenant_tag_groups_path(Current.tenant), icon: Icons::LockClosedComponent.new), diff --git a/app/models/everything_filter.rb b/app/models/everything_filter.rb new file mode 100644 index 000000000..f46d8a722 --- /dev/null +++ b/app/models/everything_filter.rb @@ -0,0 +1,30 @@ +# == Schema Information +# +# Table name: filters +# +# id :bigint not null, primary key +# is_pinned :boolean default(FALSE), not null +# name :string not null +# position :integer not null +# query :string +# type :string not null +# created_at :datetime not null +# updated_at :datetime not null +# author_id :bigint not null +# tag_id :bigint +# tenant_id :bigint not null +# +class EverythingFilter < TagFilter + before_validation :set_everything_tag + after_create :move_to_top + + def self.model_name + Filter.model_name + end + + private + + def set_everything_tag + self.tag = tenant.everything_tag + end +end diff --git a/app/models/filter.rb b/app/models/filter.rb index 931b403d6..f9b099b5d 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -7,7 +7,7 @@ # name :string not null # position :integer not null # query :string -# type :string +# type :string not null # created_at :datetime not null # updated_at :datetime not null # author_id :bigint not null @@ -19,7 +19,7 @@ class Filter < ApplicationRecord belongs_to :author, class_name: 'User' belongs_to :tenant - has_many :user_item_visibilities, inverse_of: :user_item, dependent: :destroy + has_many :user_filter_visibilities, inverse_of: :filter, dependent: :destroy validates :tenant_id, :author_id, :name, presence: true @@ -28,6 +28,8 @@ class Filter < ApplicationRecord scope :pinned, -> { where(is_pinned: true) } scope :not_pinned, -> { where(is_pinned: false) } + acts_as_list scope: :tenant_id + def fill_position return if position.present? diff --git a/app/models/fulltext_filter.rb b/app/models/fulltext_filter.rb index 490a770be..a068f711e 100644 --- a/app/models/fulltext_filter.rb +++ b/app/models/fulltext_filter.rb @@ -7,7 +7,7 @@ # name :string not null # position :integer not null # query :string -# type :string +# type :string not null # created_at :datetime not null # updated_at :datetime not null # author_id :bigint not null diff --git a/app/models/tag.rb b/app/models/tag.rb index c8930ab81..200dec47b 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -30,7 +30,7 @@ class Tag < ApplicationRecord has_many :automation_actions, class_name: "Automation::Action", as: :action_object, dependent: :restrict_with_error has_many :message_objects_tags, dependent: :destroy has_many :message_objects, through: :message_objects_tags - has_many :user_item_visibilities, as: :user_item, dependent: :destroy + has_many :user_filter_visibilities, as: :user_item, dependent: :destroy validates :name, presence: true validates :name, uniqueness: { scope: :tenant_id, case_sensitive: false } @@ -41,6 +41,14 @@ class Tag < ApplicationRecord scope :archived, -> { where(type: ArchivedTag.to_s) } after_update_commit ->(tag) { EventBus.publish(:tag_renamed, tag) if previous_changes.key?("name") } + after_create ->(tag) do + TagFilter.create!( + tenant: tag.tenant, + author: tag.owner, + name: tag.name, + tag:, + ) + end def assign_to_message_object(message_object) message_object.assign_tag(self) diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index 754b09831..d9b3a7f17 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -7,7 +7,7 @@ # name :string not null # position :integer not null # query :string -# type :string +# type :string not null # created_at :datetime not null # updated_at :datetime not null # author_id :bigint not null @@ -17,6 +17,8 @@ class TagFilter < Filter belongs_to :tag, optional: false + delegate :name, to: :tag + def self.model_name Filter.model_name end diff --git a/app/models/user.rb b/app/models/user.rb index 3941fd10b..165f8e347 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -13,7 +13,7 @@ # tenant_id :bigint # class User < ApplicationRecord - include Pundit + include Pundit::Authorization include AuditableEvents belongs_to :tenant @@ -27,7 +27,7 @@ class User < ApplicationRecord has_many :filters, foreign_key: :author_id has_many :filter_subscriptions has_many :notifications - has_many :user_item_visibilities, dependent: :destroy + has_many :user_filter_visibilities, dependent: :destroy validates_presence_of :name, :email validates_uniqueness_of :name, :email, scope: :tenant_id, case_sensitive: false @@ -80,16 +80,14 @@ def update_notifications_retention end end - def build_filter_visibilities! - user_items = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).order(:position) - visibilities = user_item_visibilities.where(user_item_type: "Filter").order(:position) - build_user_item_visibilities(user_items, visibilities) + def visible_filters + build_filter_visibilities!.where(visible: true).map(&:filter) end - def build_tag_visibilities! - user_items = policy_scope(Tag, policy_scope_class: TagPolicy::ScopeListable).where(visible: true).order(:name) - visibilities = user_item_visibilities.where(user_item_type: "Tag").order(:position) - build_user_item_visibilities(user_items, visibilities) + def build_filter_visibilities! + filters = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).order(:position) + visibilities = user_filter_visibilities.order(:position) + build_user_filter_visibilities(filters, visibilities) end def pundit_user @@ -98,16 +96,16 @@ def pundit_user private - def build_user_item_visibilities(user_items, visibilities) - user_items_without_visibilities = user_items.where.not(id: visibilities.pluck(:user_item_id)) - new_visibilities = user_items_without_visibilities.map.with_index do |user_item, i| + def build_user_filter_visibilities(filters, visibilities) + user_filters_without_visibilities = filters.where.not(id: visibilities.pluck(:filter_id)) + new_visibilities = user_filters_without_visibilities.map.with_index do |filter, i| last_position = visibilities.last&.position || 0 - user_item_visibilities.new(user_item: user_item, visible: true, position: last_position + 1 + i) + user_filter_visibilities.new(filter: filter, visible: true, position: last_position + 1 + i) end all_visibilities = visibilities.to_a + new_visibilities all_visibilities.map(&:save!) - user_item_visibilities.where(id: all_visibilities).order(:position) + user_filter_visibilities.where(id: all_visibilities).order(:position) end diff --git a/app/models/user_filter_visibility.rb b/app/models/user_filter_visibility.rb new file mode 100644 index 000000000..d6519dce2 --- /dev/null +++ b/app/models/user_filter_visibility.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: user_filter_visibilities +# +# id :bigint not null, primary key +# position :integer +# visible :boolean default(TRUE), not null +# created_at :datetime not null +# updated_at :datetime not null +# filter_id :bigint not null +# user_id :bigint not null +# +class UserFilterVisibility < ApplicationRecord + belongs_to :user + belongs_to :filter + + acts_as_list scope: :user_id + + def hidden + !visible + end +end diff --git a/app/models/user_item_visibility.rb b/app/models/user_item_visibility.rb deleted file mode 100644 index 2ffe68125..000000000 --- a/app/models/user_item_visibility.rb +++ /dev/null @@ -1,23 +0,0 @@ -# == Schema Information -# -# Table name: user_item_visibilities -# -# id :bigint not null, primary key -# position :integer -# user_item_type :string not null -# visible :boolean default(TRUE), not null -# created_at :datetime not null -# updated_at :datetime not null -# user_id :bigint not null -# user_item_id :bigint -# -class UserItemVisibility < ApplicationRecord - belongs_to :user - belongs_to :user_item, polymorphic: true - - acts_as_list scope: [:user_id, :user_item_type] - - def hidden - !visible - end -end diff --git a/app/policies/user_item_visibility_policy.rb b/app/policies/user_filter_visibility_policy.rb similarity index 60% rename from app/policies/user_item_visibility_policy.rb rename to app/policies/user_filter_visibility_policy.rb index 75384f44c..a3885a313 100644 --- a/app/policies/user_item_visibility_policy.rb +++ b/app/policies/user_filter_visibility_policy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -class UserItemVisibilityPolicy < ApplicationPolicy - attr_reader :user, :user_item_visible +class UserFilterVisibilityPolicy < ApplicationPolicy + attr_reader :user, :user_filter_visibility - def initialize(user, user_item_visible) + def initialize(user, user_filter_visibility) @user = user - @user_item_visible = user_item_visible + @user_filter_visibility = user_filter_visibility end class Scope < Scope @@ -41,6 +41,6 @@ def move_lower? private def owner? - @user_item_visible.user == Current.user + @user_filter_visibility.user == Current.user end end diff --git a/app/views/settings/user_filter_visibilities/index.html.erb b/app/views/settings/user_filter_visibilities/index.html.erb new file mode 100644 index 000000000..10e38a30b --- /dev/null +++ b/app/views/settings/user_filter_visibilities/index.html.erb @@ -0,0 +1 @@ +<%= render Settings::UserFilterVisibilities::ListComponent.new(@user_filter_visibilities) %> diff --git a/app/views/settings/user_item_visibilities/index.html.erb b/app/views/settings/user_item_visibilities/index.html.erb deleted file mode 100644 index 871616726..000000000 --- a/app/views/settings/user_item_visibilities/index.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render Settings::UserItemVisibilities::ListComponent.new(@type, @user_item_visibilities) %> diff --git a/config/routes.rb b/config/routes.rb index ffb83c2a2..9bfd070eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -22,9 +22,7 @@ end resources :tags resource :profile - resources :filter_visibilities - resources :tag_visibilities - resources :user_item_visibilities do + resources :user_filter_visibilities do member do post :move_higher post :move_lower diff --git a/db/migrate/20240617090128_rename_user_item_visibilities_to_user_filter_visibilities.rb b/db/migrate/20240617090128_rename_user_item_visibilities_to_user_filter_visibilities.rb new file mode 100644 index 000000000..703544f46 --- /dev/null +++ b/db/migrate/20240617090128_rename_user_item_visibilities_to_user_filter_visibilities.rb @@ -0,0 +1,5 @@ +class RenameUserItemVisibilitiesToUserFilterVisibilities < ActiveRecord::Migration[7.1] + def change + rename_table :user_item_visibilities, :user_filter_visibilities + end +end diff --git a/db/migrate/20240617090456_rename_user_item_to_filter_on_user_filter_visibilities.rb b/db/migrate/20240617090456_rename_user_item_to_filter_on_user_filter_visibilities.rb new file mode 100644 index 000000000..081affd61 --- /dev/null +++ b/db/migrate/20240617090456_rename_user_item_to_filter_on_user_filter_visibilities.rb @@ -0,0 +1,28 @@ +class RenameUserItemToFilterOnUserFilterVisibilities < ActiveRecord::Migration[7.1] + def change + add_reference :user_filter_visibilities, :filter, foreign_key: true, null: true + + reversible do |dir| + dir.up do + UserFilterVisibility.reset_column_information + UserFilterVisibility.find_each do |visibility| + if visibility.user_item_type == 'Filter' + visibility.update!(filter_id: visibility.user_item_id) + else + visibility.destroy! + end + end + end + + dir.down do + UserFilterVisibility.reset_column_information + UserFilterVisibility.find_each do |visibility| + visibility.update!(user_item_id: visibility.filter_id, user_item_type: visibility.filter.class.name) + end + end + end + + change_column_null :user_filter_visibilities, :filter_id, false + remove_reference :user_filter_visibilities, :user_item, polymorphic: true, index: true + end +end diff --git a/db/migrate/20240619084104_change_type_null_on_filters.rb b/db/migrate/20240619084104_change_type_null_on_filters.rb new file mode 100644 index 000000000..f7f241c01 --- /dev/null +++ b/db/migrate/20240619084104_change_type_null_on_filters.rb @@ -0,0 +1,14 @@ +class ChangeTypeNullOnFilters < ActiveRecord::Migration[7.1] + def change + reversible do |dir| + dir.up do + Filter.find_each do |filter| + if filter.type.nil? + filter.update!(type: 'FulltextFilter') + end + end + end + end + change_column_null :filters, :type, false + end +end diff --git a/db/migrate/20240624114024_create_tag_filters_from_tags.rb b/db/migrate/20240624114024_create_tag_filters_from_tags.rb new file mode 100644 index 000000000..0e892e3ff --- /dev/null +++ b/db/migrate/20240624114024_create_tag_filters_from_tags.rb @@ -0,0 +1,29 @@ +class CreateTagFiltersFromTags < ActiveRecord::Migration[7.1] + def up + Tenant.find_each do |tenant| + tenant.tags.visible.find_each do |tag| + TagFilter.create!( + tenant:, + author: tag.owner, + name: tag.name, + tag:, + ) + end + + tenant.everything_tag.tap do |tag| + EverythingFilter.create!( + tenant:, + author: tag.owner, + name: tag.name, + tag:, + ).tap do |filter| + filter.move_to_top + end + end + end + end + + def down + TagFilter.destroy_all + end +end diff --git a/db/schema.rb b/db/schema.rb index 9abf9c8d7..a91d36d75 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_23_123432) do +ActiveRecord::Schema[7.1].define(version: 2024_06_24_114024) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -187,7 +187,7 @@ t.integer "position", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.string "type" + t.string "type", null: false t.bigint "tag_id" t.boolean "is_pinned", default: false, null: false t.index ["author_id"], name: "index_filters_on_author_id" @@ -583,15 +583,15 @@ t.datetime "updated_at", null: false end - create_table "user_item_visibilities", force: :cascade do |t| + create_table "user_filter_visibilities", force: :cascade do |t| t.bigint "user_id", null: false - t.string "user_item_type", null: false - t.bigint "user_item_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "visible", default: true, null: false t.integer "position" - t.index ["user_id"], name: "index_user_item_visibilities_on_user_id" + t.bigint "filter_id", null: false + t.index ["filter_id"], name: "index_user_filter_visibilities_on_filter_id" + t.index ["user_id"], name: "index_user_filter_visibilities_on_user_id" end create_table "users", force: :cascade do |t| @@ -663,6 +663,7 @@ add_foreign_key "tags", "tenants" add_foreign_key "tags", "users", column: "owner_id" add_foreign_key "upvs_form_related_documents", "upvs_forms" - add_foreign_key "user_item_visibilities", "users" + add_foreign_key "user_filter_visibilities", "filters" + add_foreign_key "user_filter_visibilities", "users" add_foreign_key "users", "tenants" end From 7cc68016942532a7aaffa40b35f9c89445a07bbe Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Sat, 6 Jul 2024 15:41:14 +0200 Subject: [PATCH 18/37] Make first filter default --- app/controllers/message_threads_controller.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index d10a3ae5c..b600e2be8 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -32,7 +32,12 @@ def update def index authorize MessageThread - @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: params[:filter_id]) if params[:filter_id].present? + if params[:filter_id].present? + @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: params[:filter_id]) + else + @filter = Current.user.visible_filters.first + end + @query = search_params[:q] end From 3783ec47f86696c2a58bb5f1693d929a304049d9 Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Sat, 6 Jul 2024 15:54:35 +0200 Subject: [PATCH 19/37] Redirect to default filter and fix active sidebar item tracking --- app/components/t_w/sidebar_menu_item_component.html.erb | 5 ++--- app/controllers/message_threads_controller.rb | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/components/t_w/sidebar_menu_item_component.html.erb b/app/components/t_w/sidebar_menu_item_component.html.erb index 83c9332a9..d68d22672 100644 --- a/app/components/t_w/sidebar_menu_item_component.html.erb +++ b/app/components/t_w/sidebar_menu_item_component.html.erb @@ -1,14 +1,13 @@
    > <% if leading %> <%= leading %> <% end %> <%= link_to \ @url, - class: "w-full flex gap-x-3 py-4 grow", - data: { active: current_page?(@url, check_parameters: true) } \ - do %> + class: "w-full flex gap-x-3 py-4 grow" do %> <% if @icon_component %> <%= render @icon_component %> <% end %> diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index b600e2be8..a94024803 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -35,7 +35,9 @@ def index if params[:filter_id].present? @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: params[:filter_id]) else - @filter = Current.user.visible_filters.first + if Current.user.visible_filters.any? + redirect_to message_threads_path(filter_id: Current.user.visible_filters.first.id) + end end @query = search_params[:q] From 5935dd457ae6e379584b0cc69224c1658754b607 Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Sat, 6 Jul 2024 16:00:20 +0200 Subject: [PATCH 20/37] Add buttons with icons for up down --- .../common/down_button_component.html.erb | 3 +++ app/components/common/down_button_component.rb | 4 ++++ .../common/up_button_component.html.erb | 3 +++ app/components/common/up_button_component.rb | 4 ++++ .../list_row_component.html.erb | 18 +++++++++--------- 5 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 app/components/common/down_button_component.html.erb create mode 100644 app/components/common/down_button_component.rb create mode 100644 app/components/common/up_button_component.html.erb create mode 100644 app/components/common/up_button_component.rb diff --git a/app/components/common/down_button_component.html.erb b/app/components/common/down_button_component.html.erb new file mode 100644 index 000000000..653b30946 --- /dev/null +++ b/app/components/common/down_button_component.html.erb @@ -0,0 +1,3 @@ +
    + <%= render Icons::ChevronDownComponent.new %> +
    diff --git a/app/components/common/down_button_component.rb b/app/components/common/down_button_component.rb new file mode 100644 index 000000000..b1d36031b --- /dev/null +++ b/app/components/common/down_button_component.rb @@ -0,0 +1,4 @@ +module Common + class DownButtonComponent < ViewComponent::Base + end +end diff --git a/app/components/common/up_button_component.html.erb b/app/components/common/up_button_component.html.erb new file mode 100644 index 000000000..d2bb7975d --- /dev/null +++ b/app/components/common/up_button_component.html.erb @@ -0,0 +1,3 @@ +
    + <%= render Icons::ChevronUpComponent.new %> +
    diff --git a/app/components/common/up_button_component.rb b/app/components/common/up_button_component.rb new file mode 100644 index 000000000..71d156a8f --- /dev/null +++ b/app/components/common/up_button_component.rb @@ -0,0 +1,4 @@ +module Common + class UpButtonComponent < ViewComponent::Base + end +end diff --git a/app/components/settings/user_filter_visibilities/list_row_component.html.erb b/app/components/settings/user_filter_visibilities/list_row_component.html.erb index ae3a5c9e9..9d21c0d53 100644 --- a/app/components/settings/user_filter_visibilities/list_row_component.html.erb +++ b/app/components/settings/user_filter_visibilities/list_row_component.html.erb @@ -14,21 +14,21 @@ <% end %> <% end %> <% else %> + <%= form_with model: [:settings, @visibility], method: :patch do |form| %> + <%= form.hidden_field :visible, value: !@visibility.visible %> + <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> + Use setting + + <% end %> + <% end %> <%= form_with model: [:move_higher, :settings, @visibility], method: :post do |form| %> <%= form.button do %> - Up + <%= render Common::UpButtonComponent.new %> <% end %> <% end %> <%= form_with model: [:move_lower, :settings, @visibility], method: :post do |form| %> <%= form.button do %> - Down - <% end %> - <% end %> - <%= form_with model: [:settings, @visibility], method: :patch do |form| %> - <%= form.hidden_field :visible, value: !@visibility.visible %> - <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> - Use setting - + <%= render Common::DownButtonComponent.new %> <% end %> <% end %> <% end %> From cf6ebfa2d1831c942d76740cfefd1a7471872d1b Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Tue, 10 Sep 2024 13:26:25 +0200 Subject: [PATCH 21/37] Make Filter author nullable --- app/models/everything_filter.rb | 2 +- app/models/filter.rb | 6 +++--- app/models/fulltext_filter.rb | 2 +- app/models/tag_filter.rb | 2 +- app/models/tenant.rb | 2 ++ .../20240910112424_change_author_id_null_on_filters.rb | 5 +++++ db/schema.rb | 4 ++-- 7 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20240910112424_change_author_id_null_on_filters.rb diff --git a/app/models/everything_filter.rb b/app/models/everything_filter.rb index f46d8a722..03a5e0fdd 100644 --- a/app/models/everything_filter.rb +++ b/app/models/everything_filter.rb @@ -10,7 +10,7 @@ # type :string not null # created_at :datetime not null # updated_at :datetime not null -# author_id :bigint not null +# author_id :bigint # tag_id :bigint # tenant_id :bigint not null # diff --git a/app/models/filter.rb b/app/models/filter.rb index f9b099b5d..3a6ac3426 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -10,18 +10,18 @@ # type :string not null # created_at :datetime not null # updated_at :datetime not null -# author_id :bigint not null +# author_id :bigint # tag_id :bigint # tenant_id :bigint not null # class Filter < ApplicationRecord include AuditableEvents - belongs_to :author, class_name: 'User' + belongs_to :author, class_name: 'User', optional: true belongs_to :tenant has_many :user_filter_visibilities, inverse_of: :filter, dependent: :destroy - validates :tenant_id, :author_id, :name, presence: true + validates :tenant_id, :name, presence: true before_create :fill_position diff --git a/app/models/fulltext_filter.rb b/app/models/fulltext_filter.rb index a068f711e..52f3d67c2 100644 --- a/app/models/fulltext_filter.rb +++ b/app/models/fulltext_filter.rb @@ -10,7 +10,7 @@ # type :string not null # created_at :datetime not null # updated_at :datetime not null -# author_id :bigint not null +# author_id :bigint # tag_id :bigint # tenant_id :bigint not null # diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index d9b3a7f17..10d426944 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -10,7 +10,7 @@ # type :string not null # created_at :datetime not null # updated_at :datetime not null -# author_id :bigint not null +# author_id :bigint # tag_id :bigint # tenant_id :bigint not null # diff --git a/app/models/tenant.rb b/app/models/tenant.rb index 28e5faf1c..764693813 100644 --- a/app/models/tenant.rb +++ b/app/models/tenant.rb @@ -112,5 +112,7 @@ def create_default_objects create_signed_externally_tag!(name: "Externe podpísané", visible: false, color: "purple", icon: "shield-check") make_admins_see_everything! + rescue => ex + binding.pry end end diff --git a/db/migrate/20240910112424_change_author_id_null_on_filters.rb b/db/migrate/20240910112424_change_author_id_null_on_filters.rb new file mode 100644 index 000000000..b9a89d10f --- /dev/null +++ b/db/migrate/20240910112424_change_author_id_null_on_filters.rb @@ -0,0 +1,5 @@ +class ChangeAuthorIdNullOnFilters < ActiveRecord::Migration[7.1] + def change + change_column_null :filters, :author_id, true + end +end diff --git a/db/schema.rb b/db/schema.rb index a91d36d75..1d1454e23 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_24_114024) do +ActiveRecord::Schema[7.1].define(version: 2024_09_10_112424) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -181,7 +181,7 @@ create_table "filters", force: :cascade do |t| t.bigint "tenant_id", null: false - t.bigint "author_id", null: false + t.bigint "author_id" t.string "name", null: false t.string "query" t.integer "position", null: false From 6c4313f8be80ec946b3cc053d4b43a350a8c75cd Mon Sep 17 00:00:00 2001 From: Ahmed Al Hafoudh Date: Tue, 10 Sep 2024 13:31:03 +0200 Subject: [PATCH 22/37] Remove binding.pry --- app/models/tenant.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/models/tenant.rb b/app/models/tenant.rb index 764693813..28e5faf1c 100644 --- a/app/models/tenant.rb +++ b/app/models/tenant.rb @@ -112,7 +112,5 @@ def create_default_objects create_signed_externally_tag!(name: "Externe podpísané", visible: false, color: "purple", icon: "shield-check") make_admins_see_everything! - rescue => ex - binding.pry end end From 41f947ab6aaaee3577b45eb1dcdf72bb38ffd9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 13 Sep 2024 14:14:12 +0200 Subject: [PATCH 23/37] Update filters and tags views, forms, icons, .. --- .../admin/tags/tag_form_component.html.erb | 5 ++++- .../filters/filter_form_component.html.erb | 15 +++++++++++++-- .../filters/filters_list_row_component.html.erb | 12 ++++++++++-- app/components/layout/filter_list_component.rb | 10 +++++++--- .../t_w/create_filter_component.html.erb | 1 + .../t_w/top_navigation_component.html.erb | 1 + app/components/t_w/top_navigation_component.rb | 10 ++++++---- app/controllers/filters_controller.rb | 8 ++++---- app/controllers/message_threads_controller.rb | 11 +++++------ app/models/filter.rb | 2 ++ app/models/tag.rb | 3 ++- app/models/user.rb | 2 +- db/migrate/20240730110824_add_icon_to_filters.rb | 5 +++++ 13 files changed, 61 insertions(+), 24 deletions(-) create mode 100644 db/migrate/20240730110824_add_icon_to_filters.rb diff --git a/app/components/admin/tags/tag_form_component.html.erb b/app/components/admin/tags/tag_form_component.html.erb index b0761ddd1..64584441b 100644 --- a/app/components/admin/tags/tag_form_component.html.erb +++ b/app/components/admin/tags/tag_form_component.html.erb @@ -14,16 +14,19 @@
    - <%= form.text_field :name, placeholder: "Názov štítku", class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %> + <%= form.label :name, "Názov štítku" %> + <%= form.text_field :name, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    + <%= form.label :color, "Farba" %> <%= form.select :color, helpers.color_select_options, {}, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    + <%= form.label :icon, "Icona" %> <%= form.select :icon, helpers.icon_select_options, {}, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    diff --git a/app/components/filters/filter_form_component.html.erb b/app/components/filters/filter_form_component.html.erb index 76b3d5a19..c98fbe623 100644 --- a/app/components/filters/filter_form_component.html.erb +++ b/app/components/filters/filter_form_component.html.erb @@ -10,15 +10,26 @@ <%= render Common::CloseButtonComponent.new(link_to: filters_path) %>
    <%= form_with model: @filter, data: { turbo_frame: "_top" } do |form| %> + <%= form.hidden_field :type %>
    - <%= form.text_field :name, placeholder: "Názov filtra", class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %> + <%= form.label :name, "Názov filtra" %> + <%= form.text_field :name, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    + <% if @filter.is_a? FulltextFilter %> +
    +
    + <%= form.label :query, "Dopyt na vyhľadávanie" %> + <%= form.text_field :query, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %> +
    +
    + <% end %>
    - <%= form.text_field :query, placeholder: "Dopyt na vyhľadávanie", class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %> + <%= form.label :icon, "Icona" %> + <%= form.select :icon, helpers.icon_select_options, {}, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    diff --git a/app/components/filters/filters_list_row_component.html.erb b/app/components/filters/filters_list_row_component.html.erb index a83295cdd..9c5866484 100644 --- a/app/components/filters/filters_list_row_component.html.erb +++ b/app/components/filters/filters_list_row_component.html.erb @@ -1,13 +1,21 @@
    - <%= @filter.name[0] %> + <% if (@filter.icon || @filter.tag&.icon).presence %> + <%= render Common::IconComponent.new(@filter.icon || @filter.tag.icon, classes: "w-6 h-6 stroke-gray-300", stroke_width: 2) %> + <% else %> + <%= @filter.name[0] %> + <% end %>
    <%= render Common::InlineRenameComponent.new(name: @filter.name, model: @filter) %>
    - <%= @filter.query %> + <% if @filter.is_a? TagFilter %> + <%= render Common::TagComponent.new(@filter.tag) %> + <% else %> + <%= @filter.query %> + <% end %>
    diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index 305b27ca8..253fb2af6 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -8,9 +8,13 @@ def initialize(label: nil, filters:, sortable: false) end def icon_for(filter) - case filter - when TagFilter then Icons::TagComponent.new - else Icons::BookmarkComponent.new + return Common::IconComponent.new(filter.icon) if filter.icon.present? + + if filter.is_a?(TagFilter) + return Common::IconComponent.new(filter.tag.icon) if filter.tag.icon.present? + return Icons::TagComponent.new end + + Icons::BookmarkComponent.new end end diff --git a/app/components/t_w/create_filter_component.html.erb b/app/components/t_w/create_filter_component.html.erb index 60fe2fa46..23ce9a2cc 100644 --- a/app/components/t_w/create_filter_component.html.erb +++ b/app/components/t_w/create_filter_component.html.erb @@ -11,6 +11,7 @@
    + <%= f.hidden_field :type %> <%= f.hidden_field :query %> <%= render Common::ModalActionsComponent.new do |actions| %> diff --git a/app/components/t_w/top_navigation_component.html.erb b/app/components/t_w/top_navigation_component.html.erb index 5d8c673e7..586a3885f 100644 --- a/app/components/t_w/top_navigation_component.html.erb +++ b/app/components/t_w/top_navigation_component.html.erb @@ -10,6 +10,7 @@
    <%= form_with url: message_threads_path, method: :get, html: { class: 'relative flex flex-1' } do |f| %> <%= render Icons::MagnifyingGlassComponent.gray %> + <%= f.hidden_field :filter_id, value: query_params[:filter_id] %> <%= f.search_field :q, id: "search", value: query, placeholder: 'Vyhľadaj správu', class: 'block h-full w-full border-0 py-0 pr-0 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-base' %> <% end %> <% if query.present? %> diff --git a/app/components/t_w/top_navigation_component.rb b/app/components/t_w/top_navigation_component.rb index 72c55d052..cc478eb51 100644 --- a/app/components/t_w/top_navigation_component.rb +++ b/app/components/t_w/top_navigation_component.rb @@ -2,13 +2,15 @@ class TW::TopNavigationComponent < ViewComponent::Base include MessageThreadHelper def query - query_params = params - .permit(:filter_id, :q) - .slice(:filter_id, :q) - Searchable::QueryBuilder.new( filter_id: query_params[:filter_id], query: query_params[:q], ).build end + + def query_params + params + .permit(:filter_id, :q) + .slice(:filter_id, :q) + end end diff --git a/app/controllers/filters_controller.rb b/app/controllers/filters_controller.rb index 7e3417fd0..42d759e90 100644 --- a/app/controllers/filters_controller.rb +++ b/app/controllers/filters_controller.rb @@ -11,10 +11,10 @@ def new authorize Filter if params[:query].present? - @filter = Filter.new(query: params[:query]) + @filter = FulltextFilter.new(query: params[:query]) render :new_in_modal else - @filter = Filter.new + @filter = FulltextFilter.new render :new end end @@ -81,7 +81,7 @@ def sort private def filter_params - params.require(:filter).permit(:name, :query) + params.require(:filter).permit(:name, :query, :icon, :type) end def set_filter @@ -89,6 +89,6 @@ def set_filter end def filter_scope - policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeEditable).order(:position) + policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeEditable).includes(:tag).order(:position) end end diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index a94024803..8161a3235 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -31,12 +31,11 @@ def update def index authorize MessageThread - - if params[:filter_id].present? - @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: params[:filter_id]) + if search_params[:filter_id].present? + @filter = policy_scope(Filter, policy_scope_class: FilterPolicy::ScopeShowable).find_by(id: search_params[:filter_id]) else if Current.user.visible_filters.any? - redirect_to message_threads_path(filter_id: Current.user.visible_filters.first.id) + redirect_to message_threads_path(search_params.merge(filter_id: Current.user.visible_filters.first.id)) end end @@ -81,7 +80,7 @@ def merge_threads(message_thread_ids) def load_threads query = Searchable::QueryBuilder.new( - filter_id: params[:filter_id], + filter_id: search_params[:filter_id], query: search_params[:q], ).build @@ -148,7 +147,7 @@ def message_thread_params end def search_params - params.permit(:q, :format, cursor: MessageThreadCollection::CURSOR_PARAMS) + params.permit(:q, :format, :filter_id, cursor: MessageThreadCollection::CURSOR_PARAMS) end def set_thread_tags diff --git a/app/models/filter.rb b/app/models/filter.rb index 6c2364167..b1b19302e 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -17,9 +17,11 @@ # class Filter < ApplicationRecord include AuditableEvents + include Iconized belongs_to :author, class_name: 'User', optional: true belongs_to :tenant + belongs_to :tag, optional: true has_many :user_filter_visibilities, inverse_of: :filter, dependent: :destroy validates :tenant_id, :name, presence: true diff --git a/app/models/tag.rb b/app/models/tag.rb index 200dec47b..2efedae03 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -30,7 +30,8 @@ class Tag < ApplicationRecord has_many :automation_actions, class_name: "Automation::Action", as: :action_object, dependent: :restrict_with_error has_many :message_objects_tags, dependent: :destroy has_many :message_objects, through: :message_objects_tags - has_many :user_filter_visibilities, as: :user_item, dependent: :destroy + has_many :filters, dependent: :destroy + has_many :user_filter_visibilities, through: :filters validates :name, presence: true validates :name, uniqueness: { scope: :tenant_id, case_sensitive: false } diff --git a/app/models/user.rb b/app/models/user.rb index 165f8e347..94a1befa8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -105,7 +105,7 @@ def build_user_filter_visibilities(filters, visibilities) all_visibilities = visibilities.to_a + new_visibilities all_visibilities.map(&:save!) - user_filter_visibilities.where(id: all_visibilities).order(:position) + user_filter_visibilities.where(id: all_visibilities).includes(filter: :tag).order(:position) end diff --git a/db/migrate/20240730110824_add_icon_to_filters.rb b/db/migrate/20240730110824_add_icon_to_filters.rb new file mode 100644 index 000000000..15a5c3878 --- /dev/null +++ b/db/migrate/20240730110824_add_icon_to_filters.rb @@ -0,0 +1,5 @@ +class AddIconToFilters < ActiveRecord::Migration[7.1] + def change + add_column :filters, :icon, :string + end +end From ab4b919ee1afe1c791dfdd8d9ec736f3fee68af8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 13 Sep 2024 14:49:37 +0200 Subject: [PATCH 24/37] Refactor routes --- config/routes.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index e56075dbd..1dcdb4dd9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -153,9 +153,7 @@ patch :unpin end - collection do - patch :sort - end + patch :sort, on: :collection resources :filter_subscriptions end From 6afd34130cb152ffd399654e8a95d3d540ef2a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Mon, 16 Sep 2024 10:46:09 +0200 Subject: [PATCH 25/37] Update filter editable scope --- app/models/filter.rb | 3 +++ app/policies/filter_policy.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/filter.rb b/app/models/filter.rb index b1b19302e..76fb0fd9d 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -30,6 +30,9 @@ class Filter < ApplicationRecord scope :pinned, -> { where(is_pinned: true) } scope :not_pinned, -> { where(is_pinned: false) } + scope :visible_for, -> (user) { joins(:user_filter_visibilities) + .where(user_filter_visibilities: { visible: true, user: user}) + .where(is_pinned: false) } acts_as_list scope: :tenant_id diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb index 9fe412074..46ae43fed 100644 --- a/app/policies/filter_policy.rb +++ b/app/policies/filter_policy.rb @@ -10,7 +10,7 @@ def initialize(user, filter) class ScopeEditable < Scope def resolve - scoped = scope.where(tenant_id: Current.tenant) + scoped = scope.where(tenant_id: Current.tenant).visible_for(@user) return scoped if @user.admin? From 01240ecf390132b956493785b82ece794ebf8c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Mon, 16 Sep 2024 11:03:33 +0200 Subject: [PATCH 26/37] Fix filter fixtures --- test/fixtures/filters.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml index df801de55..8e19d2522 100644 --- a/test/fixtures/filters.yml +++ b/test/fixtures/filters.yml @@ -6,6 +6,7 @@ one: name: With General text query: general position: 1 + type: 'FulltextFilter' two: tenant: ssd @@ -13,6 +14,7 @@ two: name: With Legal text query: Legal position: 2 + type: 'FulltextFilter' solver_one: tenant: solver @@ -20,3 +22,4 @@ solver_one: name: Urgent query: urgent position: 3 + type: 'FulltextFilter' From c845d7bc0206d35311d8f18910e5a3c8518d3a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Mon, 16 Sep 2024 14:51:51 +0200 Subject: [PATCH 27/37] FGRA-9973: Update tests --- test/fixtures/filters.yml | 16 ++++++++++++---- test/helpers/auth_helper.rb | 8 +++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml index 8e19d2522..4d5da8dd9 100644 --- a/test/fixtures/filters.yml +++ b/test/fixtures/filters.yml @@ -4,16 +4,24 @@ one: tenant: ssd author: basic name: With General text - query: general position: 1 - type: 'FulltextFilter' + type: 'TagFilter' + tag: solver_everything two: + tenant: ssd + author: basic + name: With General text + query: general + position: 2 + type: 'FulltextFilter' + +three: tenant: ssd author: admin name: With Legal text query: Legal - position: 2 + position: 3 type: 'FulltextFilter' solver_one: @@ -21,5 +29,5 @@ solver_one: author: solver_other name: Urgent query: urgent - position: 3 + position: 4 type: 'FulltextFilter' diff --git a/test/helpers/auth_helper.rb b/test/helpers/auth_helper.rb index 657e576a3..0d412214c 100644 --- a/test/helpers/auth_helper.rb +++ b/test/helpers/auth_helper.rb @@ -6,7 +6,13 @@ def sign_in_as(user_fixture_name) click_on "Prihlásiť cez Google" - assert_text "Správy v schránke" + filter = Filter.where(tenant_id: users(user_fixture_name).tenant).order(:position).first + + if filter + assert_text "Správy z filtra '#{filter.name}'" + else + assert_text "Správy v schránke" + end end def mock_omni_auth_with_user(user_fixture_name) From 715141c353ace3a7cdd6e118609f612fb7909a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 20 Sep 2024 12:20:20 +0200 Subject: [PATCH 28/37] Update filters creation, scope, components --- .../filters_list_row_component.html.erb | 2 +- .../layout/filter_list_component.rb | 2 +- .../message_threads_bulk_actions_component.rb | 1 + .../t_w/top_navigation_component.rb | 1 + app/controllers/message_threads_controller.rb | 1 + app/models/tag.rb | 6 ++ app/models/tag_filter.rb | 4 +- app/models/user.rb | 3 +- app/policies/filter_policy.rb | 14 ++++- .../20231211132422_add_type_to_filters.rb | 2 + ...0624114024_create_tag_filters_from_tags.rb | 1 + .../20240730110824_add_icon_to_filters.rb | 5 -- ...x_on_uuid_message_thread_id_to_messages.rb | 4 ++ db/schema.rb | 2 +- test/fixtures/filters.yml | 55 ++++++++++++++++--- test/helpers/auth_helper.rb | 2 +- test/system/filters_test.rb | 4 +- test/system/message_threads_test.rb | 16 ++---- 18 files changed, 90 insertions(+), 35 deletions(-) delete mode 100644 db/migrate/20240730110824_add_icon_to_filters.rb diff --git a/app/components/filters/filters_list_row_component.html.erb b/app/components/filters/filters_list_row_component.html.erb index 9c5866484..c85612097 100644 --- a/app/components/filters/filters_list_row_component.html.erb +++ b/app/components/filters/filters_list_row_component.html.erb @@ -22,7 +22,7 @@ <%= link_to edit_filter_path(@filter), title: "Upraviť filter" do %> <%= render Common::EditButtonComponent.new %> <% end %> - <%= link_to filter_path(@filter), title: "Zmazať filter", data: { turbo_confirm: "Naozaj?", turbo_method: :delete } do %> + <%= button_to filter_path(@filter), title: "Zmazať filter", method: :delete, data: { turbo_confirm: "Naozaj chcete zmazať filter?" } do %> <%= render Common::DeleteButtonComponent.new %> <% end %>
    diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index 253fb2af6..5459d81ae 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -10,7 +10,7 @@ def initialize(label: nil, filters:, sortable: false) def icon_for(filter) return Common::IconComponent.new(filter.icon) if filter.icon.present? - if filter.is_a?(TagFilter) + if filter.tag_id.present? return Common::IconComponent.new(filter.tag.icon) if filter.tag.icon.present? return Icons::TagComponent.new end diff --git a/app/components/message_threads_bulk_actions_component.rb b/app/components/message_threads_bulk_actions_component.rb index 7cf61258d..7b847f216 100644 --- a/app/components/message_threads_bulk_actions_component.rb +++ b/app/components/message_threads_bulk_actions_component.rb @@ -9,6 +9,7 @@ def initialize(ids: nil, signable:, filter: nil, query: nil, filter_subscription def title return t(:selected_message, count: @ids.count) if @ids.present? + return @filter.name if @filter.present? && @filter.is_a?(EverythingFilter) return "Správy z filtra '#{@filter.name}'" if @filter.present? return "Hľadaný výraz '#{@query}'" if @query.present? diff --git a/app/components/t_w/top_navigation_component.rb b/app/components/t_w/top_navigation_component.rb index cc478eb51..3f9bb2f77 100644 --- a/app/components/t_w/top_navigation_component.rb +++ b/app/components/t_w/top_navigation_component.rb @@ -5,6 +5,7 @@ def query Searchable::QueryBuilder.new( filter_id: query_params[:filter_id], query: query_params[:q], + user: Current.user ).build end diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index 8161a3235..ab3292778 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -82,6 +82,7 @@ def load_threads query = Searchable::QueryBuilder.new( filter_id: search_params[:filter_id], query: search_params[:q], + user: Current.user, ).build cursor = MessageThreadCollection.init_cursor(search_params[:cursor]) diff --git a/app/models/tag.rb b/app/models/tag.rb index 2efedae03..42cc78eb0 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -42,6 +42,12 @@ class Tag < ApplicationRecord scope :archived, -> { where(type: ArchivedTag.to_s) } after_update_commit ->(tag) { EventBus.publish(:tag_renamed, tag) if previous_changes.key?("name") } + after_update_commit ->(tag) do + tag.filters.each do |filter| + filter.user_filter_visibilities.update_all(visible: false) + end if previous_changes.key?("visible") && !tag.visible + end + after_create ->(tag) do TagFilter.create!( tenant: tag.tenant, diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index 0315142bb..0fe9fa08e 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -18,7 +18,9 @@ class TagFilter < Filter belongs_to :tag, optional: false - delegate :name, to: :tag + def name + self[:name] || tag.name + end def self.model_name Filter.model_name diff --git a/app/models/user.rb b/app/models/user.rb index 94a1befa8..5d76ab068 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -100,7 +100,8 @@ def build_user_filter_visibilities(filters, visibilities) user_filters_without_visibilities = filters.where.not(id: visibilities.pluck(:filter_id)) new_visibilities = user_filters_without_visibilities.map.with_index do |filter, i| last_position = visibilities.last&.position || 0 - user_filter_visibilities.new(filter: filter, visible: true, position: last_position + 1 + i) + visible = filter.is_a?(FulltextFilter) || filter.author_id.nil? + user_filter_visibilities.new(filter:, visible:, position: last_position + 1 + i) end all_visibilities = visibilities.to_a + new_visibilities diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb index 46ae43fed..183a3a3b1 100644 --- a/app/policies/filter_policy.rb +++ b/app/policies/filter_policy.rb @@ -20,7 +20,19 @@ def resolve class ScopeShowable < Scope def resolve - scope.where(tenant_id: Current.tenant) + scoped = scope.where(tenant_id: Current.tenant) + + return scoped if @user.admin? + + scoped.left_joins(:tag) + .where( + TagGroup + .select(1) + .joins(:group_memberships) + .where("tag_groups.tag_id = tags.id") + .where(group_memberships: { user_id: @user.id }) + .arel.exists) + .or(scoped.where(author_id: [nil, @user.id])) end end diff --git a/db/migrate/20231211132422_add_type_to_filters.rb b/db/migrate/20231211132422_add_type_to_filters.rb index 68b31f28b..6d3a884e6 100644 --- a/db/migrate/20231211132422_add_type_to_filters.rb +++ b/db/migrate/20231211132422_add_type_to_filters.rb @@ -1,5 +1,6 @@ class AddTypeToFilters < ActiveRecord::Migration[7.1] def up + add_column :filters, :icon, :string, null: true add_column :filters, :type, :string, null: true Filter.where(type: nil).update_all(type: 'FulltextFilter') @@ -12,6 +13,7 @@ def up def down Filter.where.not(type: 'FulltextFilter').delete_all + remove_column :filters, :icon remove_column :filters, :type end end diff --git a/db/migrate/20240624114024_create_tag_filters_from_tags.rb b/db/migrate/20240624114024_create_tag_filters_from_tags.rb index 0e892e3ff..e534fa493 100644 --- a/db/migrate/20240624114024_create_tag_filters_from_tags.rb +++ b/db/migrate/20240624114024_create_tag_filters_from_tags.rb @@ -25,5 +25,6 @@ def up def down TagFilter.destroy_all + EverythingFilter.destroy_all end end diff --git a/db/migrate/20240730110824_add_icon_to_filters.rb b/db/migrate/20240730110824_add_icon_to_filters.rb deleted file mode 100644 index 15a5c3878..000000000 --- a/db/migrate/20240730110824_add_icon_to_filters.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddIconToFilters < ActiveRecord::Migration[7.1] - def change - add_column :filters, :icon, :string - end -end diff --git a/db/migrate/20240814102352_add_unique_index_on_uuid_message_thread_id_to_messages.rb b/db/migrate/20240814102352_add_unique_index_on_uuid_message_thread_id_to_messages.rb index 95e651bf0..f1a19578f 100644 --- a/db/migrate/20240814102352_add_unique_index_on_uuid_message_thread_id_to_messages.rb +++ b/db/migrate/20240814102352_add_unique_index_on_uuid_message_thread_id_to_messages.rb @@ -2,5 +2,9 @@ class AddUniqueIndexOnUuidMessageThreadIdToMessages < ActiveRecord::Migration[7. def up add_index :messages, [:uuid, :message_thread_id], unique: true end + + def down + remove_index :messages, [:uuid, :message_thread_id], unique: true + end end diff --git a/db/schema.rb b/db/schema.rb index 0a8fd272e..fbf09a397 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -198,10 +198,10 @@ t.integer "position", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "icon" t.string "type", null: false t.bigint "tag_id" t.boolean "is_pinned", default: false, null: false - t.string "icon" t.index ["author_id"], name: "index_filters_on_author_id" t.index ["is_pinned"], name: "index_filters_on_is_pinned" t.index ["tag_id"], name: "index_filters_on_tag_id" diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml index 4d5da8dd9..56ac41f19 100644 --- a/test/fixtures/filters.yml +++ b/test/fixtures/filters.yml @@ -1,14 +1,13 @@ # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html -one: +ssd_all: tenant: ssd - author: basic - name: With General text + name: Everything position: 1 - type: 'TagFilter' - tag: solver_everything + type: 'EverythingFilter' + tag: ssd_everything -two: +ssd_general: tenant: ssd author: basic name: With General text @@ -16,15 +15,53 @@ two: position: 2 type: 'FulltextFilter' -three: +ssd_legal: tenant: ssd - author: admin + author: basic name: With Legal text query: Legal position: 3 type: 'FulltextFilter' -solver_one: +ssd_without_author: + tenant: ssd + name: Other + position: 4 + tag: ssd_other + type: 'TagFilter' + +ssd_hidden: + tenant: ssd + author: basic + name: Hidden + position: 5 + tag: ssd_construction + type: 'TagFilter' + +ssd_external: + tenant: ssd + author: basic + name: External + position: 6 + tag: ssd_external + type: 'TagFilter' + +ssd_general_two: + tenant: ssd + author: ssd_signer + name: With General text + query: general + position: 6 + type: 'FulltextFilter' + +solver_all: + tenant: solver + name: Everything + position: 1 + type: 'EverythingFilter' + tag: solver_everything + +solver_urgent: tenant: solver author: solver_other name: Urgent diff --git a/test/helpers/auth_helper.rb b/test/helpers/auth_helper.rb index 0d412214c..644b47837 100644 --- a/test/helpers/auth_helper.rb +++ b/test/helpers/auth_helper.rb @@ -9,7 +9,7 @@ def sign_in_as(user_fixture_name) filter = Filter.where(tenant_id: users(user_fixture_name).tenant).order(:position).first if filter - assert_text "Správy z filtra '#{filter.name}'" + assert_text filter.name else assert_text "Správy v schránke" end diff --git a/test/system/filters_test.rb b/test/system/filters_test.rb index 1166cfb5b..c0d562dad 100644 --- a/test/system/filters_test.rb +++ b/test/system/filters_test.rb @@ -3,7 +3,7 @@ class FiltersTest < ApplicationSystemTestCase setup do Searchable::MessageThread.reindex_all - sign_in_as(:basic) + sign_in_as(:ssd_signer) end test "user can create a filter" do @@ -41,7 +41,7 @@ class FiltersTest < ApplicationSystemTestCase assert_text "General" accept_alert do - click_link "Zmazať filter" + click_button "Zmazať filter" end assert_no_text "General" diff --git a/test/system/message_threads_test.rb b/test/system/message_threads_test.rb index 81ea09313..0297294c0 100644 --- a/test/system/message_threads_test.rb +++ b/test/system/message_threads_test.rb @@ -32,7 +32,6 @@ class MessageThreadsTest < ApplicationSystemTestCase within_tags do assert_text "Finance" - assert_text "Legal" assert_text "Other" end end @@ -42,31 +41,24 @@ class MessageThreadsTest < ApplicationSystemTestCase assert_text "SD Services" within_tags do + assert_text "Archivovane" assert_text "Finance" end end within_sidebar do within_filters do + assert_text "Everything" assert_text "With General text" assert_text "With Legal text" + assert_text "Other" # other tenant refute_text "Urgent" - end - - within_tags do - assert_text "Finance" - assert_text "Legal" - assert_text "ExtVisible" - assert_text "Print" # non visible refute_text "Hidden" refute_text "External" - - # other tenant - refute_text "Special" end end end @@ -99,7 +91,7 @@ class MessageThreadsTest < ApplicationSystemTestCase assert_no_selector "#next_page_area" within_sidebar do - within_tags do + within_filters do click_link "Legal" end end From 15dfcdd91551e6f75f7d5f54823f64530657b1a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 20 Sep 2024 12:29:30 +0200 Subject: [PATCH 29/37] Update tests --- test/models/filter_subscription_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/models/filter_subscription_test.rb b/test/models/filter_subscription_test.rb index 134d1df36..adb896a1d 100644 --- a/test/models/filter_subscription_test.rb +++ b/test/models/filter_subscription_test.rb @@ -3,7 +3,7 @@ class FilterSubscriptionTest < ActiveSupport::TestCase test "new thread matching subscription fires event" do user = users(:admin) - filter = filters(:one) + filter = filters(:ssd_general) s = FilterSubscription.create!(tenant: user.tenant, user: user, filter: filter, events: ["Notifications::NewMessageThread", "Notifications::NewMessage"]) m = Govbox::Message.create_message_with_thread!(govbox_messages(:one)) From 901e0183860efcedb0a5f27b2f7ce83d5f33690e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 20 Sep 2024 14:02:05 +0200 Subject: [PATCH 30/37] Try fix random failing notifications_test --- test/system/notifications_test.rb | 5 +++-- test/test_helper.rb | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/test/system/notifications_test.rb b/test/system/notifications_test.rb index cf2dca43c..b2fc66dbd 100644 --- a/test/system/notifications_test.rb +++ b/test/system/notifications_test.rb @@ -10,8 +10,9 @@ class NotificationsTest < ApplicationSystemTestCase visit message_threads_path click_link "With General text" - - click_link "Nastaviť notifikácie" + safe_click do + click_link "Nastaviť notifikácie" + end check "Nová konverzácia" check "Nová správa" diff --git a/test/test_helper.rb b/test/test_helper.rb index 001840a8c..f7b89afe0 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -22,6 +22,13 @@ def generate_api_token(sub: 'site_admin', exp: 5.minutes.since(Time.now).to_i, j JWT.encode(payload.merge(sub: sub, exp: exp, jti: jti).compact, key_pair, 'RS256') end +def safe_click + 5.times do + element = yield.inspect + break if element != "Obsolete #" + end +end + private def default_key_pair From d0bf1181b510e7a15092f89d9783c3d534b27c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 20 Sep 2024 14:51:00 +0200 Subject: [PATCH 31/37] Change default_max_wait_time for Capybara --- test/test_helper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test_helper.rb b/test/test_helper.rb index f7b89afe0..4817bc90d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,6 +8,10 @@ Rails.application.eager_load! # see https://github.com/simplecov-ruby/simplecov?tab=readme-ov-file#want-to-use-spring-with-simplecov +Capybara.configure do |config| + config.default_max_wait_time = 5 +end + class ActiveSupport::TestCase # Run tests in parallel with specified workers parallelize(workers: :number_of_processors) From 699fc2f2d975fb8515dda2e037b832cb75f473cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 20 Sep 2024 15:57:56 +0200 Subject: [PATCH 32/37] Update notifications_test --- test/system/notifications_test.rb | 5 ++--- test/test_helper.rb | 11 ----------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/test/system/notifications_test.rb b/test/system/notifications_test.rb index b2fc66dbd..8deda7473 100644 --- a/test/system/notifications_test.rb +++ b/test/system/notifications_test.rb @@ -10,9 +10,8 @@ class NotificationsTest < ApplicationSystemTestCase visit message_threads_path click_link "With General text" - safe_click do - click_link "Nastaviť notifikácie" - end + assert_text "General agenda SSD" + click_link "Nastaviť notifikácie" if page.has_link?("Nastaviť notifikácie") check "Nová konverzácia" check "Nová správa" diff --git a/test/test_helper.rb b/test/test_helper.rb index 4817bc90d..001840a8c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,10 +8,6 @@ Rails.application.eager_load! # see https://github.com/simplecov-ruby/simplecov?tab=readme-ov-file#want-to-use-spring-with-simplecov -Capybara.configure do |config| - config.default_max_wait_time = 5 -end - class ActiveSupport::TestCase # Run tests in parallel with specified workers parallelize(workers: :number_of_processors) @@ -26,13 +22,6 @@ def generate_api_token(sub: 'site_admin', exp: 5.minutes.since(Time.now).to_i, j JWT.encode(payload.merge(sub: sub, exp: exp, jti: jti).compact, key_pair, 'RS256') end -def safe_click - 5.times do - element = yield.inspect - break if element != "Obsolete #" - end -end - private def default_key_pair From 6f5ba246004f0e164e8e1ea747dc56599bc0bca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Wed, 25 Sep 2024 15:38:18 +0200 Subject: [PATCH 33/37] Fix migration and filtering by tag filters --- app/components/t_w/top_navigation_component.rb | 2 +- app/controllers/message_threads_controller.rb | 1 + app/models/everything_filter.rb | 4 ++++ app/models/tag_filter.rb | 4 ++++ app/models/tenant.rb | 2 +- ....rb => 20240624114023_change_author_id_null_on_filters.rb} | 0 db/schema.rb | 2 +- 7 files changed, 12 insertions(+), 3 deletions(-) rename db/migrate/{20240910112424_change_author_id_null_on_filters.rb => 20240624114023_change_author_id_null_on_filters.rb} (100%) diff --git a/app/components/t_w/top_navigation_component.rb b/app/components/t_w/top_navigation_component.rb index 3f9bb2f77..2898fc7e5 100644 --- a/app/components/t_w/top_navigation_component.rb +++ b/app/components/t_w/top_navigation_component.rb @@ -3,7 +3,7 @@ class TW::TopNavigationComponent < ViewComponent::Base def query Searchable::QueryBuilder.new( - filter_id: query_params[:filter_id], + filter_id: nil, query: query_params[:q], user: Current.user ).build diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index ab3292778..f6f857ea7 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -80,6 +80,7 @@ def merge_threads(message_thread_ids) def load_threads query = Searchable::QueryBuilder.new( + filter: @filter, filter_id: search_params[:filter_id], query: search_params[:q], user: Current.user, diff --git a/app/models/everything_filter.rb b/app/models/everything_filter.rb index ea8430bcd..032894685 100644 --- a/app/models/everything_filter.rb +++ b/app/models/everything_filter.rb @@ -23,6 +23,10 @@ def self.model_name Filter.model_name end + def query + nil + end + private def set_everything_tag diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index 0fe9fa08e..ec7ea46e6 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -22,6 +22,10 @@ def name self[:name] || tag.name end + def query + "label:(#{tag.name})" + end + def self.model_name Filter.model_name end diff --git a/app/models/tenant.rb b/app/models/tenant.rb index 1b33c4ddf..9320d2112 100644 --- a/app/models/tenant.rb +++ b/app/models/tenant.rb @@ -106,8 +106,8 @@ def create_default_objects create_admin_group!(name: "admins") create_signer_group!(name: "signers") - create_draft_tag!(name: "Rozpracované", visible: true) create_everything_tag!(name: "Všetky správy", visible: false) + create_draft_tag!(name: "Rozpracované", visible: true) create_archived_tag!(name: "Archivované", color: "green", icon: "archive-box", visible: true) create_signature_requested_tag!(name: "Na podpis", visible: true, color: "yellow", icon: "pencil") create_signed_tag!(name: "Podpísané", visible: true, color: "green", icon: "fingerprint") diff --git a/db/migrate/20240910112424_change_author_id_null_on_filters.rb b/db/migrate/20240624114023_change_author_id_null_on_filters.rb similarity index 100% rename from db/migrate/20240910112424_change_author_id_null_on_filters.rb rename to db/migrate/20240624114023_change_author_id_null_on_filters.rb diff --git a/db/schema.rb b/db/schema.rb index fbf09a397..552a2fe48 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_09_10_112424) do +ActiveRecord::Schema[7.1].define(version: 2024_08_20_143244) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" From 29cc35801b76a28fe2ef7e8114dda7ed14f04791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Wed, 25 Sep 2024 15:49:10 +0200 Subject: [PATCH 34/37] Remove is_pinned from filters --- app/models/everything_filter.rb | 1 - app/models/filter.rb | 6 +----- app/models/fulltext_filter.rb | 1 - app/models/tag_filter.rb | 1 - .../20240925134557_remove_is_pinned_from_filters.rb | 10 ++++++++++ db/schema.rb | 4 +--- 6 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20240925134557_remove_is_pinned_from_filters.rb diff --git a/app/models/everything_filter.rb b/app/models/everything_filter.rb index 032894685..e1522cf78 100644 --- a/app/models/everything_filter.rb +++ b/app/models/everything_filter.rb @@ -4,7 +4,6 @@ # # id :bigint not null, primary key # icon :string -# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/app/models/filter.rb b/app/models/filter.rb index 76fb0fd9d..5ccdf02a6 100644 --- a/app/models/filter.rb +++ b/app/models/filter.rb @@ -4,7 +4,6 @@ # # id :bigint not null, primary key # icon :string -# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string @@ -28,11 +27,8 @@ class Filter < ApplicationRecord before_create :fill_position - scope :pinned, -> { where(is_pinned: true) } - scope :not_pinned, -> { where(is_pinned: false) } scope :visible_for, -> (user) { joins(:user_filter_visibilities) - .where(user_filter_visibilities: { visible: true, user: user}) - .where(is_pinned: false) } + .where(user_filter_visibilities: { visible: true, user: user}) } acts_as_list scope: :tenant_id diff --git a/app/models/fulltext_filter.rb b/app/models/fulltext_filter.rb index fe71655a7..b9589760a 100644 --- a/app/models/fulltext_filter.rb +++ b/app/models/fulltext_filter.rb @@ -4,7 +4,6 @@ # # id :bigint not null, primary key # icon :string -# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/app/models/tag_filter.rb b/app/models/tag_filter.rb index ec7ea46e6..5109feaa4 100644 --- a/app/models/tag_filter.rb +++ b/app/models/tag_filter.rb @@ -4,7 +4,6 @@ # # id :bigint not null, primary key # icon :string -# is_pinned :boolean default(FALSE), not null # name :string not null # position :integer not null # query :string diff --git a/db/migrate/20240925134557_remove_is_pinned_from_filters.rb b/db/migrate/20240925134557_remove_is_pinned_from_filters.rb new file mode 100644 index 000000000..87b1976e5 --- /dev/null +++ b/db/migrate/20240925134557_remove_is_pinned_from_filters.rb @@ -0,0 +1,10 @@ +class RemoveIsPinnedFromFilters < ActiveRecord::Migration[7.1] + def up + remove_column :filters, :is_pinned + end + + def down + add_column :filters, :is_pinned, :boolean, null: false, default: false + add_index :filters, :is_pinned + end +end diff --git a/db/schema.rb b/db/schema.rb index 552a2fe48..0bd99f3da 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_08_20_143244) do +ActiveRecord::Schema[7.1].define(version: 2024_09_25_134557) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -201,9 +201,7 @@ t.string "icon" t.string "type", null: false t.bigint "tag_id" - t.boolean "is_pinned", default: false, null: false t.index ["author_id"], name: "index_filters_on_author_id" - t.index ["is_pinned"], name: "index_filters_on_is_pinned" t.index ["tag_id"], name: "index_filters_on_tag_id" t.index ["tenant_id"], name: "index_filters_on_tenant_id" t.index ["type"], name: "index_filters_on_type" From 0776ad3977dc55032a33265d40e9aaef2f45ef42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Mon, 30 Sep 2024 08:00:48 +0200 Subject: [PATCH 35/37] Refactoring after review --- .../admin/tags/tag_form_component.html.erb | 2 +- .../filters/filter_form_component.html.erb | 2 +- app/components/icons/grip_component.html.erb | 3 --- app/components/icons/grip_component.rb | 6 ------ app/components/icons/star_component.html.erb | 7 ------- app/components/icons/star_component.rb | 15 --------------- 6 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 app/components/icons/grip_component.html.erb delete mode 100644 app/components/icons/grip_component.rb delete mode 100644 app/components/icons/star_component.html.erb delete mode 100644 app/components/icons/star_component.rb diff --git a/app/components/admin/tags/tag_form_component.html.erb b/app/components/admin/tags/tag_form_component.html.erb index 64584441b..1201aaec4 100644 --- a/app/components/admin/tags/tag_form_component.html.erb +++ b/app/components/admin/tags/tag_form_component.html.erb @@ -26,7 +26,7 @@
    - <%= form.label :icon, "Icona" %> + <%= form.label :icon, "Ikona" %> <%= form.select :icon, helpers.icon_select_options, {}, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    diff --git a/app/components/filters/filter_form_component.html.erb b/app/components/filters/filter_form_component.html.erb index c98fbe623..d0782ce07 100644 --- a/app/components/filters/filter_form_component.html.erb +++ b/app/components/filters/filter_form_component.html.erb @@ -28,7 +28,7 @@ <% end %>
    - <%= form.label :icon, "Icona" %> + <%= form.label :icon, "Ikona" %> <%= form.select :icon, helpers.icon_select_options, {}, class: "block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" %>
    diff --git a/app/components/icons/grip_component.html.erb b/app/components/icons/grip_component.html.erb deleted file mode 100644 index d3459f4b4..000000000 --- a/app/components/icons/grip_component.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" stroke-width="<%= @stroke_width %>" stroke="currentColor" style="aspect-ratio: 1.6;"> - - \ No newline at end of file diff --git a/app/components/icons/grip_component.rb b/app/components/icons/grip_component.rb deleted file mode 100644 index d2b374863..000000000 --- a/app/components/icons/grip_component.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Icons::GripComponent < ViewComponent::Base - def initialize(css_classes: nil, stroke_width: 1.5) - @css_classes = css_classes - @stroke_width = stroke_width - end -end diff --git a/app/components/icons/star_component.html.erb b/app/components/icons/star_component.html.erb deleted file mode 100644 index bdd75645c..000000000 --- a/app/components/icons/star_component.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" stroke-width="<%= @stroke_width %>" stroke="currentColor"> - <% if solid? %> - - <% elsif light? %> - - <% end %> - \ No newline at end of file diff --git a/app/components/icons/star_component.rb b/app/components/icons/star_component.rb deleted file mode 100644 index 35832232a..000000000 --- a/app/components/icons/star_component.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Icons::StarComponent < ViewComponent::Base - def initialize(css_classes: nil, stroke_width: 1.5, variant: :solid) - @css_classes = css_classes - @stroke_width = stroke_width - @variant = variant - end - - def solid? - @variant == :solid - end - - def light? - @variant == :light - end -end From 84646a6cc13953f6444719fc74aec9cc1b22020e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Fri, 15 Nov 2024 20:38:46 +0100 Subject: [PATCH 36/37] Refactoring after review --- Gemfile | 2 +- Gemfile.lock | 2 +- .../common/down_button_component.html.erb | 3 -- .../common/down_button_component.rb | 4 --- app/components/common/icon_component.rb | 1 + .../common/up_button_component.html.erb | 3 -- app/components/common/up_button_component.rb | 4 --- .../layout/filter_list_component.rb | 2 +- .../message_options_component.html.erb | 4 +-- ...ge_threads_bulk_actions_component.html.erb | 4 +-- .../list_row_component.html.erb | 28 +++++++++++++++---- app/policies/filter_policy.rb | 8 ------ 12 files changed, 30 insertions(+), 35 deletions(-) delete mode 100644 app/components/common/down_button_component.html.erb delete mode 100644 app/components/common/down_button_component.rb delete mode 100644 app/components/common/up_button_component.html.erb delete mode 100644 app/components/common/up_button_component.rb diff --git a/Gemfile b/Gemfile index 07e845b52..3146f6c5e 100644 --- a/Gemfile +++ b/Gemfile @@ -39,7 +39,7 @@ gem 'jwt' gem 'stimulus-rails' gem 'jsbundling-rails' gem 'pdf-reader' -gem "acts_as_list", "~> 1.1" +gem "acts_as_list" # Monitoring gem 'rollbar' diff --git a/Gemfile.lock b/Gemfile.lock index 2d3924f10..bc6aad9e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -504,7 +504,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - acts_as_list (~> 1.1) + acts_as_list annotate bootsnap (>= 1.4.4) brakeman diff --git a/app/components/common/down_button_component.html.erb b/app/components/common/down_button_component.html.erb deleted file mode 100644 index 653b30946..000000000 --- a/app/components/common/down_button_component.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -
    - <%= render Icons::ChevronDownComponent.new %> -
    diff --git a/app/components/common/down_button_component.rb b/app/components/common/down_button_component.rb deleted file mode 100644 index b1d36031b..000000000 --- a/app/components/common/down_button_component.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Common - class DownButtonComponent < ViewComponent::Base - end -end diff --git a/app/components/common/icon_component.rb b/app/components/common/icon_component.rb index e295b6b99..06e2d11ea 100644 --- a/app/components/common/icon_component.rb +++ b/app/components/common/icon_component.rb @@ -16,6 +16,7 @@ class IconComponent < ViewComponent::Base "bell-slash" => "M9.143 17.082a24.248 24.248 0 003.844.148m-3.844-.148a23.856 23.856 0 01-5.455-1.31 8.964 8.964 0 002.3-5.542m3.155 6.852a3 3 0 005.667 1.97m1.965-2.277L21 21m-4.225-4.225a23.81 23.81 0 003.536-1.003A8.967 8.967 0 0118 9.75V9A6 6 0 006.53 6.53m10.245 10.245L6.53 6.53M3 3l3.53 3.53", "chat-bubble-left-right" => "M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 01-.825-.242m9.345-8.334a2.126 2.126 0 00-.476-.095 48.64 48.64 0 00-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0011.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155", "chevron-down" => "m19.5 8.25-7.5 7.5-7.5-7.5", + "chevron-up" => "M4.5 15.75l7.5-7.5 7.5 7.5", "archive-box" => "M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z", "archive-box-x-mark" => "m20.25 7.5-.625 10.632a2.25 2.25 0 0 1-2.247 2.118H6.622a2.25 2.25 0 0 1-2.247-2.118L3.75 7.5m6 4.125 2.25 2.25m0 0 2.25 2.25M12 13.875l2.25-2.25M12 13.875l-2.25 2.25M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z", "trash" => "M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0", diff --git a/app/components/common/up_button_component.html.erb b/app/components/common/up_button_component.html.erb deleted file mode 100644 index d2bb7975d..000000000 --- a/app/components/common/up_button_component.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -
    - <%= render Icons::ChevronUpComponent.new %> -
    diff --git a/app/components/common/up_button_component.rb b/app/components/common/up_button_component.rb deleted file mode 100644 index 71d156a8f..000000000 --- a/app/components/common/up_button_component.rb +++ /dev/null @@ -1,4 +0,0 @@ -module Common - class UpButtonComponent < ViewComponent::Base - end -end diff --git a/app/components/layout/filter_list_component.rb b/app/components/layout/filter_list_component.rb index 5459d81ae..a77931d34 100644 --- a/app/components/layout/filter_list_component.rb +++ b/app/components/layout/filter_list_component.rb @@ -10,7 +10,7 @@ def initialize(label: nil, filters:, sortable: false) def icon_for(filter) return Common::IconComponent.new(filter.icon) if filter.icon.present? - if filter.tag_id.present? + if filter.tag.present? return Common::IconComponent.new(filter.tag.icon) if filter.tag.icon.present? return Icons::TagComponent.new end diff --git a/app/components/message_options_component.html.erb b/app/components/message_options_component.html.erb index 06127ebd5..0a36d3c43 100644 --- a/app/components/message_options_component.html.erb +++ b/app/components/message_options_component.html.erb @@ -32,12 +32,12 @@ <% if @mode == :thread_view && @message.collapsible? %> <% if @message.collapsed %> <%= button_to message_path(@message), params: { collapsed: false }, method: :patch, class: 'whitespace-nowrap flex gap-3', role: 'menu-item', tabindex: -1 do %> - <%= render Icons::ChevronDownComponent.new(css_classes: "w-5 h-5") %> + <%= render Common::IconComponent.new("chevron-down", classes: "w-5 h-5") %> Vždy zobrazovať <% end %> <% else %> <%= button_to message_path(@message), params: { collapsed: true }, method: :patch, class: 'whitespace-nowrap flex gap-3', role: 'menu-item', tabindex: -1 do %> - <%= render Icons::ChevronUpComponent.new(css_classes: "w-5 h-5") %> + <%= render Common::IconComponent.new("chevron-up", classes: "w-5 h-5") %> Zbaliť a už nerozbaľovať <% end %> <% end %> diff --git a/app/components/message_threads_bulk_actions_component.html.erb b/app/components/message_threads_bulk_actions_component.html.erb index 245dd9947..fc5f9d4ab 100644 --- a/app/components/message_threads_bulk_actions_component.html.erb +++ b/app/components/message_threads_bulk_actions_component.html.erb @@ -24,7 +24,7 @@
    @@ -126,7 +126,7 @@
    diff --git a/app/components/settings/user_filter_visibilities/list_row_component.html.erb b/app/components/settings/user_filter_visibilities/list_row_component.html.erb index 9d21c0d53..b60639d1a 100644 --- a/app/components/settings/user_filter_visibilities/list_row_component.html.erb +++ b/app/components/settings/user_filter_visibilities/list_row_component.html.erb @@ -8,27 +8,43 @@ <%= form_with model: [:settings, Current.user.user_filter_visibilities.new(filter: @filter)], method: :post do |form| %> <%= form.hidden_field :filter_id, value: @filter.id %> <%= form.hidden_field :visible, value: !@visibility.visible %> - <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> + <%= form.button class: class_names('relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2', { "bg-gray-200": @visibility.hidden, "bg-indigo-600": @visibility.visible }), role: :switch, aria: { checked: @visibility.hidden.to_s } do %> Use setting - + <% end %> <% end %> <% else %> <%= form_with model: [:settings, @visibility], method: :patch do |form| %> <%= form.hidden_field :visible, value: !@visibility.visible %> - <%= form.button class: "#{@visibility.hidden ? "bg-gray-200" : "bg-indigo-600"} relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2", role: :switch, aria: { checked: @visibility.hidden.to_s } do %> + <%= form.button class: class_names('relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2', { "bg-gray-200": @visibility.hidden, "bg-indigo-600": @visibility.visible }), role: :switch, aria: { checked: @visibility.hidden.to_s } do %> Use setting - + <% end %> <% end %> <%= form_with model: [:move_higher, :settings, @visibility], method: :post do |form| %> <%= form.button do %> - <%= render Common::UpButtonComponent.new %> +
    + <%= render Common::IconComponent.new("chevron-up") %> +
    <% end %> <% end %> <%= form_with model: [:move_lower, :settings, @visibility], method: :post do |form| %> <%= form.button do %> - <%= render Common::DownButtonComponent.new %> +
    + <%= render Common::IconComponent.new("chevron-down") %> +
    <% end %> <% end %> <% end %> diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb index 183a3a3b1..02312a42d 100644 --- a/app/policies/filter_policy.rb +++ b/app/policies/filter_policy.rb @@ -60,14 +60,6 @@ def destroy? @user.admin? || is_author_current_user? end - def pin? - is_author_current_user? - end - - def unpin? - pin? - end - def sort? is_author_current_user? end From 8824a1fc8ebd7c03902356ac9294f66b5d889616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Durc=CC=8Ca=CC=81k?= Date: Sun, 17 Nov 2024 18:47:13 +0100 Subject: [PATCH 37/37] Basic fix --- app/components/message_threads_bulk_actions_component.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/message_threads_bulk_actions_component.html.erb b/app/components/message_threads_bulk_actions_component.html.erb index fc5f9d4ab..b73c25a4a 100644 --- a/app/components/message_threads_bulk_actions_component.html.erb +++ b/app/components/message_threads_bulk_actions_component.html.erb @@ -24,7 +24,7 @@