Skip to content

Commit

Permalink
Details Page Shared projects tab (#227)
Browse files Browse the repository at this point in the history
* chore: Initial tab setup

* chore: Tab setup

* chore: Working on navigation tabs

* chore: Working tabs with turbo and groups namespace tree

* chore: Working query for shared projects

* chore: Working project rows

* chore: Created a shared partial

* chore: Created a no projects shared state

* chore: Made emtpy state view component

* chore: Made LookBook preview

* test: Testing for empty component

* test: Added groups show system test

* chore: Cleaned up empty states

* chore: Updated file comments

* chore: Updated file comments

* test: Added testing for subgroups controller

* test: Added testing for shared projects controller

* chore: Removed old test

* chore: Disabled rubocop Metrics warning

* chore: Code cleanup

* chore: Fixed glaky tests

* style: Removed border around empty state

* chore: Authorize the user to read the subgroup

* chore: Authorize user on group

* test: Moved group show test into groups
  • Loading branch information
joshsadam authored Oct 17, 2023
1 parent fe4473a commit 963ccfc
Show file tree
Hide file tree
Showing 27 changed files with 311 additions and 69 deletions.
5 changes: 5 additions & 0 deletions app/assets/icons/heroicons/document_text.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions app/components/viral/empty_state_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="flex justify-center py-20 mt-4">
<div class="flex items-center inline-block">
<%= viral_icon(name: icon_name, color: :primary, classes: "w-20 h-20 shrink mr-4") %>
<div class="flex flex-col grow">
<h3 class="text-2xl font-bold dark:text-slate-300 text-slate-700">
<%= title %>
</h3>
<% if description.present? %>
<p class="text-slate-600 dark:text-slate-400">
<%= description %>
</p>
<% end %>
</div>
</div>
</div>
14 changes: 14 additions & 0 deletions app/components/viral/empty_state_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

module Viral
# A component for displaying an empty state
class EmptyStateComponent < Viral::Component
attr_reader :title, :description, :icon_name

def initialize(title:, description:, icon_name:)
@title = title
@description = description
@icon_name = icon_name
end
end
end
24 changes: 24 additions & 0 deletions app/controllers/groups/shared_projects_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module Groups
# Controller actions for projects shared with a group
class SharedProjectsController < Groups::ApplicationController
before_action :group, only: %i[index]

def index
authorize! @group, to: :read?
respond_to do |format|
format.html { redirect_to group_path(@group) }
format.turbo_stream do
@shared_projects = @group.shared_projects
end
end
end

private

def group
@group ||= Group.find_by_full_path(request.params[:group_id] || request.params[:id]) # rubocop:disable Rails/DynamicFindBy
end
end
end
44 changes: 44 additions & 0 deletions app/controllers/groups/subgroups_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

module Groups
# Controller actions for group subgroups and projects
class SubgroupsController < ApplicationController
before_action :group, only: %i[index]

def index
authorize! @group, to: :read?
respond_to do |format|
format.html { redirect_to group_path(@group) }
format.turbo_stream do
if params.key? :parent_id
render_subgroup
else
@namespaces = namespace_children
end
end
end
end

private

def render_subgroup
@group = Group.find(params[:parent_id])
@collapsed = params[:collapse] == 'true'
@children = @collapsed ? Namespace.none : namespace_children
@depth = params[:depth].to_i
render :subgroup
end

def group
@group ||= Group.find_by_full_path(request.params[:group_id] || request.params[:id]) # rubocop:disable Rails/DynamicFindBy
end

def namespace_children
@group.children_of_type(
[
Namespaces::ProjectNamespace.sti_name, Group.sti_name
]
)
end
end
end
19 changes: 5 additions & 14 deletions app/controllers/groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class GroupsController < Groups::ApplicationController # rubocop:disable Metrics/ClassLength
layout :resolve_layout
before_action :parent_group, only: %i[new]
before_action :tab, only: %i[show]
before_action :group, only: %i[edit show destroy update transfer]
before_action :authorized_namespaces, except: %i[index show destroy]
before_action :current_page
Expand All @@ -14,20 +15,6 @@ def index

def show
authorize! @group, to: :read?

respond_to do |format|
if params.key? :parent_id
format.turbo_stream do
@group = Group.find(params[:parent_id])
@collapsed = params[:collapse] == 'true'
@children = @collapsed ? Namespace.none : namespace_children
@depth = params[:depth].to_i
end
end
format.html do
@namespaces = namespace_children
end
end
end

def new
Expand Down Expand Up @@ -188,4 +175,8 @@ def namespace
def namespace_path
group_path(@group)
end

def tab
@tab = params[:tab]
end
end
1 change: 1 addition & 0 deletions app/helpers/view_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module ViewHelper
checkbox: 'Viral::Form::CheckboxComponent',
datepicker: 'Viral::Form::DatepickerComponent',
dialog: 'Viral::DialogComponent',
empty: 'Viral::EmptyStateComponent',
dropdown: 'Viral::DropdownComponent',
file_input: 'Viral::Form::FileInputComponent',
flash: 'Viral::FlashComponent',
Expand Down
5 changes: 4 additions & 1 deletion app/models/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Group < Namespace
where(namespace_type: Namespaces::ProjectNamespace.sti_name)
},
foreign_key: :group_id, class_name: 'NamespaceGroupLink', dependent: :destroy

has_many :shared_with_group_links, # rubocop:disable Rails/InverseOf
lambda {
where(namespace_type: Group.sti_name)
Expand All @@ -44,7 +45,9 @@ def of_ancestors_and_self
end
end
has_many :shared_groups, through: :shared_group_links, source: :namespace
has_many :shared_project_namespaces, through: :shared_project_namespace_links, source: :namespace
has_many :shared_project_namespaces, through: :shared_project_namespace_links,
class_name: 'Namespaces::ProjectNamespace', source: :namespace
has_many :shared_projects, through: :shared_project_namespaces, class_name: 'Project', source: :project
has_many :shared_with_groups, through: :shared_with_group_links, source: :group

def self.sti_name
Expand Down
2 changes: 1 addition & 1 deletion app/views/dashboard/projects/index.turbo_stream.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
dark:divide-slate-700
"
>
<%= render partial: "dashboard/projects/project", collection: @projects %>
<%= render partial: "shared/project/row", collection: @projects, as: :project %>
</tbody>
</table>
<% end %>
Expand Down
22 changes: 22 additions & 0 deletions app/views/groups/shared_projects/index.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%= turbo_stream.update "group_show_tab_content" do %>
<% if @shared_projects.length > 0 %>
<table class="min-w-full table-fixed dark:divide-slate-600">
<tbody
class="
bg-white
divide-y
divide-slate-200
dark:bg-slate-800
dark:divide-slate-700
"
>
<%= render partial: "shared/project/row", collection: @shared_projects, as: :project %>
</tbody>
</table>
<% else %>
<%= viral_empty(
title: t(:'groups.show.shared_projects.no_shared.title'),
description: t(:'groups.show.shared_projects.no_shared.description'),
icon_name: :rectangle_stack) %>
<% end %>
<% end %>
65 changes: 49 additions & 16 deletions app/views/groups/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,33 +1,66 @@
<%= render Viral::PageHeaderComponent.new(title: @group.name, subtitle: @group.description) do |component| %>
<%= component.icon do %>
<%= viral_avatar(
name: @group.name,
colour_string: "#{@group.name}-#{@group.id}",
size: :large
) %>
name: @group.name,
colour_string: "#{@group.name}-#{@group.id}",
size: :large
) %>
<% end %>
<%= component.with_buttons do %>
<% if allowed_to?(:new?, @group) %>
<%= link_to t(:"groups.show.create_subgroup_button"),
new_group_path(parent_id: @group.id),
class: "button button--size-default button--state-default" %>
new_group_path(parent_id: @group.id),
class: "button button--size-default button--state-default" %>
<%= link_to t(:"groups.show.create_project_button"),
new_project_path(group_id: @group.id),
class: "button button--size-default button--state-primary ml-2" %>
new_project_path(group_id: @group.id),
class: "button button--size-default button--state-primary ml-2" %>
<% end %>
<% end %>
<% end %>

<%= viral_tabs(id: "group-details", label: t(:'.tabs.label')) do |tabs| %>
<%= tabs.with_tab(url: "#", controls: "group-details", selected: true) do %>
<%= tabs.with_tab(url: group_path(@group), controls: "group-details", selected: @tab != "shared_projects") do %>
<%= t(:".tabs.subgroups_and_projects") %>
<% end %>
<%= tabs.with_tab(url: group_path(@group, tab: "shared_projects"), controls: "group-projects", selected: @tab == "shared_projects") do %>
<%= t(:'.tabs.shared_projects') %>
<% end %>

<%= tabs.with_tab_content do %>
<%= turbo_frame_tag "group_show_tab_content", "data-turbo-temporary": true, src: (
if @tab == "shared_projects"
group_shared_projects_path(@group, format: :turbo_stream)
else
group_subgroups_path(@group, format: :turbo_stream)
end
), loading: :lazy do %>
<table class="min-w-full table-fixed dark:divide-slate-600">
<tbody
class="
bg-white
divide-y
divide-slate-200
dark:bg-slate-800
dark:divide-slate-700
"
>
<% 10.times do %>
<tr>

<td class="p-4 animate-pulse">
<div class="flex-1 py-1 space-y-6">
<div class="space-y-3">
<div class="w-48 h-2 rounded bg-slate-200"></div>
<div class="w-32 h-2 rounded bg-slate-200"></div>
</div>
</div>
</td>

</tr>
<% end %>
</tbody>
</table>
<% end %>
<% end %>
<% end %>

<div class="bg-white dark:bg-gray-800">
<%= render NamespaceTreeContainerComponent.new(
namespaces: @namespaces,
path: "group_path",
type: [Group.sti_name, Namespaces::ProjectNamespace.sti_name]
) %>
</div>
15 changes: 15 additions & 0 deletions app/views/groups/subgroups/index.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%= turbo_stream.update "group_show_tab_content" do %>
<% if @namespaces.length > 0 %>
<%= render NamespaceTreeContainerComponent.new(
namespaces: @namespaces,
path: "group_subgroups_path",
path_args: { group_id: @group.full_path },
type: [Group.sti_name, Namespaces::ProjectNamespace.sti_name]
) %>
<% else %>
<%= viral_empty(
title: t(:"groups.show.subgroups.no_subgroups.title"),
description: t(:'groups.show.subgroups.no_subgroups.description'),
icon_name: :squares_2x2) %>
<% end %>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
namespace: @group,
children: @children,
collapsed: @collapsed,
path: "group_path",
path: "group_subgroups_path",
path_args: { group_id: @group.full_path },
type: [Group.sti_name, Namespaces::ProjectNamespace.sti_name]
) %>
<% end %>
9 changes: 0 additions & 9 deletions app/views/layouts/partials/_empty_content.html.erb

This file was deleted.

10 changes: 4 additions & 6 deletions app/views/projects/samples/attachments/_table.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@
</tbody>
</table>
<div class="empty_state_message">
<%= render partial: "layouts/partials/empty_content",
locals: {
text_title: t("projects.samples.show.no_files"),
text_note: t("projects.samples.show.no_associated_files"),
btn_icon: :document_plus
} %>
<%= viral_empty(
title: t(:'projects.samples.show.no_files'),
description: t(:'projects.samples.show.no_associated_files'),
icon_name: :document_text) %>
</div>
</div>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
>
<td class="w-16 p-2 whitespace-nowrap">
<%= viral_avatar(
name: project.name,
colour_string: "#{project.name}-#{project.id}",
data: {
turbo: false
},
url: namespace_project_path(project.namespace.parent, project)
) %>
name: project.name,
colour_string: "#{project.name}-#{project.id}",
data: {
turbo: false
},
url: namespace_project_path(project.namespace.parent, project)
) %>

</td>
<td class="p-4 whitespace-nowrap">
<%= link_to namespace_project_path(project.namespace.parent, project),
data: {
turbo: false
},
data: {
turbo: false
},
class: "text-slate-800 dark:text-slate-300 hover:underline" do %>
<span><%= project.namespace.parent.full_name %>
/
Expand Down
9 changes: 9 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,15 @@ en:
tabs:
label: Group project details navigation
subgroups_and_projects: Subgroups and projects
shared_projects: Shared projects
subgroups:
no_subgroups:
title: No subgroups
description: Create a subgroup to manage projects and members
shared_projects:
no_shared:
title: No projects have been shared with this group.
description: Other groups can share projects directly with this group through the project settings page.
new_subgroup:
title: Create subgroup
subtitle: Groups allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects
Expand Down
2 changes: 2 additions & 0 deletions config/routes/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
resources :members, only: %i[create destroy index new update]
resources :group_links, only: %i[create destroy update index new]
resources :samples, only: %i[index]
resources :subgroups, only: %i[index]
resources :shared_projects, only: %i[index]
end

scope(path: '*id',
Expand Down
Loading

0 comments on commit 963ccfc

Please sign in to comment.