Skip to content

Commit

Permalink
Groups dashboard searching sorting (#733)
Browse files Browse the repository at this point in the history
* chore: Searching and flatten tree when searching

* fix: 🩹 Fixed issue with group policy

* style: 💄 Working on incorporating how the PUID should be displayed

* fix: Ignore parameter list length

* chore: Formatting

* chore: Updated group policy testing

* chore: Fixed line length issue

* chore: Fixed i18n

* test: ✅ Added test for search by name or puid

* chore: Fixed rubocop warning

* chore: Fixed merge i18n conflicts

* chore: Normalized i18n

* chore: Added empty search result state

* test: Added test for empty state

* test: Updated unknown group name

* chore: Updated flat to render_flat_list

* chore: Cleaned up rubocop error

* chore: Removed refreshes_with
  • Loading branch information
joshsadam authored Sep 11, 2024
1 parent 8e3fb3d commit 5153cf4
Show file tree
Hide file tree
Showing 17 changed files with 168 additions and 109 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
path: path,
path_args: path_args,
type: @type,
collapsed: collapsed
collapsed: collapsed,
render_flat_list: render_flat_list,
) %>
</ul>
8 changes: 6 additions & 2 deletions app/components/namespace_tree/namespace_tree_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
module NamespaceTree
# Component to render a namespace tree
class NamespaceTreeComponent < Component
attr_reader :parent, :namespaces, :path, :path_args, :collapsed
attr_reader :parent, :namespaces, :path, :path_args, :collapsed, :render_flat_list

def initialize(namespaces:, type:, parent: nil, path: nil, path_args: {})
# rubocop: disable Metrics/ParameterLists
def initialize(namespaces:, type:, parent: nil, path: nil, path_args: {}, render_flat_list: false)
@parent = parent
@namespaces = namespaces
@path = path
@path_args = path_args
@type = type
@collapsed = true
@render_flat_list = render_flat_list
end

# rubocop: enable Metrics/ParameterLists
end
end
47 changes: 25 additions & 22 deletions app/components/namespace_tree/row/row_contents_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<%= viral_icon(name: :squares_2x2, classes: "h-5 w-5 text-slate-400 mr-2") %>
<%= viral_avatar(
name: @namespace.name,
size: :small,
size: :medium,
colour_string: "#{@namespace.name}-#{@namespace.id}",
data: {
turbo: false,
Expand All @@ -26,27 +26,30 @@
<div class="flex flex-col namespace-text">
<div class="namespace-text grow shrink">
<div class="flex flex-wrap items-center mr-3 font-semibold title">
<% if @namespace.type == "Group" %>
<%= link_to @namespace.name, group_path(@namespace), data: { turbo: false } %>
<% else %>
<%= link_to @namespace.name,
project_samples_path(@namespace.project),
data: {
turbo: false,
} %>
<% end %>
<%= viral_pill(
text:
t(
:"members.access_levels.level_#{Member.effective_access_level(@namespace, Current.user)}",
),
color: "transparent",
border: true,
classes: "ml-2",
) %>
</div>
<div class="description">
<p><%= @namespace.description %></p>
<div class="flex flex-col space-y-1.5">
<div class="space-x-2">
<% if @namespace.type == "Group" %>
<%= link_to @namespace.name, group_path(@namespace), data: { turbo: false } %>
<% else %>
<%= link_to @namespace.name,
project_samples_path(@namespace.project),
data: {
turbo: false,
} %>
<% end %>
<%= viral_pill(
text:
t(
:"members.access_levels.level_#{Member.effective_access_level(@namespace, Current.user)}",
),
color: "transparent",
border: true,
classes: "ml-2",
) %></div>
<span class="text-sm text-gray-500 dark:text-gray-400">
<%= @namespace.puid %>
</span>
</div>
</div>
</div>
</div>
Expand Down
8 changes: 6 additions & 2 deletions app/components/namespace_tree/row_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ class RowComponent < ViewComponent::Base
with_collection_parameter :namespace

erb_template <<~ERB
<% if @namespace.children_of_type?(@type) %>
<% if @namespace.children_of_type?(@type) && !@render_flat_list %>
<%= render NamespaceTree::Row::WithChildrenComponent.new(namespace: @namespace, type: @type, children: Group.none, path: @path, path_args: @path_args, collapsed: @collapsed) %>
<% else %>
<%= render NamespaceTree::Row::WithoutChildrenComponent.new(namespace: @namespace, path: @path, path_args: @path_args) %>
<% end %>
ERB

def initialize(namespace:, type:, path: nil, path_args: {}, collapsed: true)
# rubocop:disable Metrics/ParameterLists
def initialize(namespace:, type:, path: nil, path_args: {}, collapsed: true, render_flat_list: false)
@namespace = namespace
@type = type
@path = path
@path_args = path_args
@collapsed = collapsed
@render_flat_list = render_flat_list
end

# rubocop:enable Metrics/ParameterLists
end
end
5 changes: 3 additions & 2 deletions app/components/namespace_tree_container_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
class NamespaceTreeContainerComponent < ViewComponent::Base
erb_template <<-ERB
<div class="namespace-tree-container">
<%= render NamespaceTree::NamespaceTreeComponent.new(namespaces: @namespaces, path: @path, path_args: @path_args, type: @type) %>
<%= render NamespaceTree::NamespaceTreeComponent.new(namespaces: @namespaces, path: @path, path_args: @path_args, type: @type, render_flat_list: @render_flat_list) %>
</div>
ERB

def initialize(namespaces:, path: nil, path_args: {}, type: Group.sti_name)
def initialize(namespaces:, path: nil, path_args: {}, type: Group.sti_name, render_flat_list: false)
@namespaces = namespaces
@path = path
@path_args = path_args
@type = type
@render_flat_list = render_flat_list
end
end
3 changes: 2 additions & 1 deletion app/components/viral/dropdown_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def default_system_arguments(args)
args.merge({
id: "dd-#{SecureRandom.hex(10)}",
data:,
tag: :button
tag: :button,
type: :button
})
end

Expand Down
2 changes: 1 addition & 1 deletion app/components/viral/pagy/pagination_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<% a = helpers.pagy_anchor(@pagy, anchor_string: 'data-turbo-action="replace"') %>
<% a = helpers.pagy_anchor(@pagy, anchor_string: @data_string) %>
<nav class="pagy nav" aria-label="<%= t(".aria-label")%>">
<ul class="inline-flex h-10 -space-x-px text-base">
<%# Previous page link %>
Expand Down
3 changes: 2 additions & 1 deletion app/components/viral/pagy/pagination_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ module Viral
module Pagy
# Pagy pagination component
class PaginationComponent < Viral::Component
def initialize(pagy)
def initialize(pagy, data_string: 'data-turbo-action="replace"')
@pagy = pagy
@data_string = data_string
end

def active_link_classes
Expand Down
38 changes: 27 additions & 11 deletions app/controllers/dashboard/groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,34 @@ class GroupsController < ApplicationController
before_action :current_page

def index
@q = authorized_groups.ransack(params[:q])
@render_flat_list = flat_list_requested?
@q = build_ransack_query
set_default_sort
@pagy, @groups = pagy(@q.result.include_route)
respond_to_format
end

private

def flat_list_requested?
params.dig(:q, :name_or_puid_cont).present?
end

def build_ransack_query
authorized_groups.ransack(params[:q])
end

def respond_to_format
respond_to do |format|
format.html
format.turbo_stream do
if toggling_group?
toggle_group
render :group
else
@pagy, @groups = pagy(@q.result.include_route)
end
end
format.turbo_stream { handle_turbo_stream }
end
end

private
def handle_turbo_stream
toggle_group if toggling_group?
render :group if toggling_group?
end

def set_default_sort
@q.sorts = 'created_at desc' if @q.sorts.empty?
Expand All @@ -42,7 +54,11 @@ def toggle_group
end

def authorized_groups
authorized_scope(Group, type: :relation).without_descendants
if @render_flat_list
authorized_scope(Group, type: :relation)
else
authorized_scope(Group, type: :relation).without_descendants
end
end

def current_page
Expand Down
2 changes: 1 addition & 1 deletion app/models/namespace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def without_descendants
end

def ransackable_attributes(_auth_object = nil)
%w[created_at deleted_at name updated_at]
%w[created_at deleted_at name puid updated_at]
end

def ransackable_associations(_auth_object = nil)
Expand Down
8 changes: 4 additions & 4 deletions app/policies/group_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,10 @@ def update_sample_metadata?

scope_for :relation do |relation|
relation.with(
user_groups: relation.where(id: user.members.not_expired.select(:namespace_id)).self_and_descendant_ids
.where(type: Group.sti_name),
linked_groups: NamespaceGroupLink.where(Arel.sql('namespace_group_links.group_id in (select * from user_groups)'))
.select(:namespace_id)
user_groups: relation.where(id: user.members.not_expired.select(:namespace_id)).self_and_descendant_ids,
linked_groups: relation.where(id: NamespaceGroupLink.not_expired
.where(Arel.sql('namespace_group_links.group_id in (select * from user_groups)')).select(:namespace_id))
.self_and_descendant_ids
).where(
Arel.sql(
'namespaces.id in (select * from user_groups)
Expand Down
73 changes: 61 additions & 12 deletions app/views/dashboard/groups/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,71 @@
"inline-flex items-center justify-center button button--state-primary button--size-default" %>
<% end %>
<% end %>
<div class="bg-white dark:bg-slate-800">
<div class="flex flex-col">
<div
class="
flex text-sm font-medium text-center border-b text-slate-500 border-slate-200
dark:text-slate-400 dark:border-slate-700
flex text-center border-b border-slate-200 dark:text-slate-400
dark:border-slate-700
"
>
<div class="flex flex-row items-center ml-auto space-x-2 font-normal py-1.5">
<%= turbo_frame_tag "groups_sort_dropdown" %>
<div class="flex flex-row items-center ml-auto space-x-2 font-normal">
<%= search_form_for @q, url: dashboard_groups_url, html: { "data-controller": "filters", "data-turbo-permanent": "true" } do |f| %>
<%= f.hidden_field :format, value: "turbo_stream" %>
<%= f.label :name_cont, "SEARCH", class: "sr-only" %>
<div class="relative lg:w-72">
<div
class="
absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none
"
>
<%= viral_icon(name: "magnifying_glass", classes: "h-5 w-5") %>
</div>
<%= f.search_field :name_or_puid_cont,
"data-action": "filters#submit",
class:
"block w-full p-2.5 pl-10 text-sm text-slate-900 border border-slate-300 rounded-lg bg-slate-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-slate-700 dark:border-slate-600 dark:placeholder-slate-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500",
placeholder: t(:".search.placeholder") %>
</div>
<% end %>
<%= search_form_for @q, url: dashboard_groups_url, method: :post, html: { method: :post, "data-controller": "filters", "data-turbo": false } do %>
<div class="flex flex-row items-center ml-auto space-x-2 font-normal py-1.5">
<%= render Ransack::SortDropdownComponent.new(
@q,
"groups",
[
{ name: "created_at", dir: "desc" },
{ name: "created_at", dir: "asc" },
{ name: "name", dir: "asc" },
{ name: "name", dir: "desc" },
{ name: "updated_at", dir: "desc" },
{ name: "updated_at", dir: "asc" },
],
) %>
</div>
<% end %>
</div>
</div>
<div class="flex flex-col" data-turbo-temporary>
<%= turbo_frame_tag "groups_tree",
src: dashboard_groups_url(format: :turbo_stream, **request.query_parameters) do %>
<%= render partial: "shared/loading/table" %>
<% end %>
<%= turbo_frame_tag "groups_pagination" %>
</div>
<% if @groups.any? %>
<div class="flex flex-col gap-2" id="groups_tree">
<%= render NamespaceTreeContainerComponent.new(
namespaces: @groups,
path: "dashboard_groups_path",
render_flat_list: @render_flat_list,
) %>
<div class="flex flex-row-reverse">
<%= render Viral::Pagy::PaginationComponent.new(
@pagy,
data_string: "data-turbo='false'",
) %>
</div>
</div>
<% else %>
<div class="flex flex-col gap-2">
<%= render Viral::EmptyStateComponent.new(
icon_name: "squares_2x2",
title: t(".no_groups_title"),
description: t(".no_groups_description"),
) %>
</div>
<% end %>
</div>
43 changes: 0 additions & 43 deletions app/views/dashboard/groups/index.turbo_stream.erb

This file was deleted.

4 changes: 4 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ en:
groups:
index:
create_group_button: New group
no_groups_description: No groups found matching your search
no_groups_title: No groups found
row_aria_label: See %{name} subgroups
search:
placeholder: Filter by name or puid
sorting:
created_at_asc: Oldest created
created_at_desc: Last created
Expand Down
4 changes: 4 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,11 @@ fr:
groups:
index:
create_group_button: New group
no_groups_description: No groups found matching your search
no_groups_title: No groups found
row_aria_label: See %{name} subgroups
search:
placeholder: Filter by name or puid
sorting:
created_at_asc: Oldest created
created_at_desc: Last created
Expand Down
Loading

0 comments on commit 5153cf4

Please sign in to comment.