Add tabs to team page [SCI-11954]

This commit is contained in:
Anton 2025-06-09 14:19:28 +02:00
parent 8367bf868e
commit 2f555b57d1
10 changed files with 193 additions and 110 deletions

View file

@ -15,6 +15,7 @@ module Users
create
show
users_datatable
members
)
before_action :load_team, only: %i(
@ -24,12 +25,13 @@ module Users
description_html
update
destroy
members
)
before_action :check_create_team_permission,
only: %i(new create)
before_action :set_breadcrumbs_items, only: %i(index show)
before_action :set_breadcrumbs_items, only: %i(index show members)
layout 'fluid'
@ -57,7 +59,13 @@ module Users
end
end
def show; end
def show
@active_tab = :details
end
def members
@active_tab = :members
end
def users_datatable
render json: ::TeamUsersDatatable.new(view_context, @team, @user)

View file

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Users
module Settings
class UserGroupsController < ApplicationController
before_action :load_team
before_action :set_breadcrumbs_items
def index
@active_tab = :user_groups
end
private
def load_team
@team = Team.find_by(id: params[:team_id])
render_403 unless can_manage_team?(@team)
end
def set_breadcrumbs_items
@breadcrumbs_items = []
@breadcrumbs_items.push({
label: t('breadcrumbs.teams'),
url: teams_path
})
if @team
@breadcrumbs_items.push({
label: @team.name,
url: team_path(@team)
})
end
end
end
end
end

View file

@ -2,7 +2,7 @@ class TeamsDatatable < CustomDatatable
include InputSanitizeHelper
def_delegator :@view, :link_to
def_delegator :@view, :team_path
def_delegator :@view, :members_users_settings_team_path
def_delegator :@view, :leave_user_team_html_path
MEMEBERS_SORT_COL = 'members'.freeze
@ -28,7 +28,7 @@ class TeamsDatatable < CustomDatatable
{
'DT_RowId': record.id,
'0': if current_user_team_role(record)&.owner?
link_to(escape_input(record.name), team_path(record))
link_to(escape_input(record.name), members_users_settings_team_path(record))
else
escape_input(record.name)
end,

View file

@ -0,0 +1,24 @@
<div class="content-header">
<div class="title-row">
<h1 id="team-name" class="settings-team-name" data-current-team="<%= current_team == @team %>">
<% if can_manage_team?(@team) %>
<%= render partial: "shared/inline_editing",
locals: {
initial_value: @team.name,
config: {
field_to_udpate: 'name',
params_group: 'team',
path_to_update: update_team_path(@team, format: :json)
}
} %>
<% else %>
<span class="view-mode"><%= @team.name %></span>
<% end %>
</h1>
</div>
</div>
<div class="flex items-center gap-4 p-2 mb-4 bg-white">
<%= link_to t("users.settings.teams.navigation.details"), team_path(@team), class: "p-2.5 hover:no-underline #{ @active_tab == :details ? "text-sn-blue" : "text-sn-grey" }"%>
<%= link_to t("users.settings.teams.navigation.members"), members_users_settings_team_path(@team), class: "p-2.5 hover:no-underline #{ @active_tab == :members ? "text-sn-blue" : "text-sn-grey" }"%>
<%= link_to t("users.settings.teams.navigation.groups"), users_settings_team_user_groups_path(@team), class: "p-2.5 hover:no-underline #{ @active_tab == :user_groups ? "text-sn-blue" : "text-sn-grey" }"%>
</div>

View file

@ -0,0 +1,47 @@
<% provide(:head_title, t("users.settings.teams.head_title")) %>
<% provide(:container_class, "no-second-nav-container") %>
<% content_for :head do %>
<meta id="cache-directive" name="turbolinks-cache-control" content="no-cache">
<% end %>
<div class="content-pane flexible team-settings-pane with-grey-background">
<%= render partial: 'header' %>
<!-- USERS TABLE -->
<div class="users-datatable">
<% if can_invite_team_users?(@team) %>
<div id="add-new-team-members-button" class="hidden">
<a href="#" class="btn btn-primary" data-trigger="invite-users" data-turbolinks="false" data-modal-id="team-invite-users-modal">
<span class="sn-icon sn-icon-new-task"></span>
<%= I18n.t('users.settings.teams.edit.add_user') %>
</a>
</div>
<%= render(partial: 'shared/invite_users_modal',
locals: { modal_id: 'team-invite-users-modal',
type: 'invite_to_team_with_role',
team: @team } ) %>
<% end %>
<table id="users-table" class="table" data-source="<%= team_users_datatable_path(@team, format: :json) %>">
<thead>
<tr>
<th id="user-name"><%= t("users.settings.teams.edit.thead_user_name") %></th>
<th id="email"><%= t("users.settings.teams.edit.thead_email") %></th>
<th id="user-role"><%= t("users.settings.teams.edit.thead_role") %></th>
<th id="joined-on"><%= t("users.settings.teams.edit.thead_joined_on") %></th>
<th id="status"><%= t("users.settings.teams.edit.thead_status") %></th>
<th id="options"><%= t("users.settings.teams.edit.thead_actions") %></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<!-- End of USERS TABLE -->
</div>
<%= render partial: 'users/settings/teams/description_modal' %>
<%= render partial: 'users/settings/teams/destroy_modal', locals: { team: @team } %>
<%= render partial: 'users/settings/user_teams/destroy_user_team_modal' %>
<%= stylesheet_link_tag 'datatables' %>
<%= javascript_include_tag 'users/settings/teams/show' %>
<span data-hook="team-bottom"></span>

View file

@ -7,120 +7,67 @@
<div data-hook="team-beginning"></div>
<%= render partial: "users/settings/sidebar" %>
<div class="tab-content">
<div class="tab-pane content-pane" role="tabpanel"></div>
<div class="tab-pane content-pane active team-settings-pane" role="tabpanel">
<!-- TITLE -->
<h1 id="team-name" class="settings-team-name" data-current-team="<%= current_team == @team %>">
<% if can_manage_team?(@team) %>
<%= render partial: "shared/inline_editing",
locals: {
initial_value: @team.name,
config: {
field_to_udpate: 'name',
params_group: 'team',
path_to_update: update_team_path(@team, format: :json)
}
} %>
<% else %>
<span class="view-mode"><%= @team.name %></span>
<% end %>
</h1>
<!-- End of TITLE -->
<div class="content-pane flexible team-settings-pane with-grey-background">
<%= render partial: 'header' %>
<!-- HEADER -->
<div class="team-metadata">
<!-- HEADER -->
<div class="team-metadata">
<div class="created-at grid-block">
<span class="sn-icon sn-icon-calendar"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_created_at") %></span>
<b><%= l(@team.created_at, format: :full_date) %></b>
</div>
<div class="created-by grid-block">
<span class="sn-icon sn-icon-user-menu fa-lg"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_created_by") %></span>
<b>
<%= t('users.settings.teams.edit.header_created_by_name_email', name: @team.created_by.full_name, email: @team.created_by.email) if @team.created_by %>
</b>
</div>
<div class="space-usage grid-block">
<span class="fas fa-hdd"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_space_taken") %></span>
<b data-hook="team-space-taken"><%= "#{number_to_human_size(@team.storage_used)}" %></b>
</div>
<div class="created-at grid-block">
<span class="sn-icon sn-icon-calendar"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_created_at") %></span>
<b><%= l(@team.created_at, format: :full_date) %></b>
</div>
<div class="flex items-center py-4 leading-6 gap-6">
<span><%= t("users.settings.teams.show.tasks_share.enable_label") %></span>
<span class="sci-toggle-checkbox-container">
<%= check_box_tag 'select_team_share_permission', 0, @team.shareable_links_enabled?, { class: 'sci-toggle-checkbox team-share-permission',
data: { disable_url: disable_tasks_sharing_modal_team_path(),
enable_url: shared_tasks_toggle_team_path()
},
disabled: !can_manage_team?(@team) } %>
<span class="sci-toggle-checkbox-label"></span>
</span>
<div class="created-by grid-block">
<span class="sn-icon sn-icon-user-menu fa-lg"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_created_by") %></span>
<b>
<%= t('users.settings.teams.edit.header_created_by_name_email', name: @team.created_by.full_name, email: @team.created_by.email) if @team.created_by %>
</b>
</div>
<div class="team-description inline-editing-container">
<% if can_manage_team?(@team) %>
<div
class="inline-init-handler"
data-field-to-update="description"
data-params-group="team"
data-path-to-update="<%= update_team_path(@team, format: :json) %>"
data-original-name="<%= @team.description %>"
>
<div class="view-mode" data-placeholder="<%= t("users.settings.teams.show.enter_description") %>"><%= @team.description %></div>
<textarea placeholder="<%= t("users.settings.teams.show.enter_description") %>" class="hidden input-field smart-text-area" type="text" value="<%= @team.description %>" disabled><%= @team.description %></textarea>
<div class="button-container">
<span class="cancel-button inline-field-button"><i class="sn-icon sn-icon-close"></i></span>
<span class="save-button inline-field-button"><i class="sn-icon sn-icon-check"></i></span>
</div>
</div>
<% else %>
<span class="view-mode disable-select"><%= @team.description.blank? ? t('users.settings.teams.edit.header_no_description') : @team.description %></span>
<% end %>
<div class="space-usage grid-block">
<span class="fas fa-hdd"></span>
<span class="hidden-xs hidden-sm"><%= t("users.settings.teams.edit.header_space_taken") %></span>
<b data-hook="team-space-taken"><%= "#{number_to_human_size(@team.storage_used)}" %></b>
</div>
<!-- End of HEADER -->
<!-- USERS TABLE -->
<div class="users-datatable">
<% if can_invite_team_users?(@team) %>
<div id="add-new-team-members-button" class="hidden">
<a href="#" class="btn btn-primary" data-trigger="invite-users" data-turbolinks="false" data-modal-id="team-invite-users-modal">
<span class="sn-icon sn-icon-new-task"></span>
<%= I18n.t('users.settings.teams.edit.add_user') %>
</a>
</div>
<%= render(partial: 'shared/invite_users_modal',
locals: { modal_id: 'team-invite-users-modal',
type: 'invite_to_team_with_role',
team: @team } ) %>
<% end %>
<table id="users-table" class="table" data-source="<%= team_users_datatable_path(@team, format: :json) %>">
<thead>
<tr>
<th id="user-name"><%= t("users.settings.teams.edit.thead_user_name") %></th>
<th id="email"><%= t("users.settings.teams.edit.thead_email") %></th>
<th id="user-role"><%= t("users.settings.teams.edit.thead_role") %></th>
<th id="joined-on"><%= t("users.settings.teams.edit.thead_joined_on") %></th>
<th id="status"><%= t("users.settings.teams.edit.thead_status") %></th>
<th id="options"><%= t("users.settings.teams.edit.thead_actions") %></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<!-- End of USERS TABLE -->
<div data-hook="team-the-end"></div>
</div>
<div class="flex items-center py-4 leading-6 gap-6">
<span><%= t("users.settings.teams.show.tasks_share.enable_label") %></span>
<span class="sci-toggle-checkbox-container">
<%= check_box_tag 'select_team_share_permission', 0, @team.shareable_links_enabled?, { class: 'sci-toggle-checkbox team-share-permission',
data: { disable_url: disable_tasks_sharing_modal_team_path(),
enable_url: shared_tasks_toggle_team_path()
},
disabled: !can_manage_team?(@team) } %>
<span class="sci-toggle-checkbox-label"></span>
</span>
</div>
<div class="team-description inline-editing-container">
<% if can_manage_team?(@team) %>
<div
class="inline-init-handler"
data-field-to-update="description"
data-params-group="team"
data-path-to-update="<%= update_team_path(@team, format: :json) %>"
data-original-name="<%= @team.description %>"
>
<div class="view-mode bg-white !px-4" data-placeholder="<%= t("users.settings.teams.show.enter_description") %>"><%= @team.description %></div>
<textarea placeholder="<%= t("users.settings.teams.show.enter_description") %>" class="hidden input-field smart-text-area !px-4" type="text" value="<%= @team.description %>" disabled><%= @team.description %></textarea>
<div class="button-container">
<span class="cancel-button inline-field-button"><i class="sn-icon sn-icon-close"></i></span>
<span class="save-button inline-field-button"><i class="sn-icon sn-icon-check"></i></span>
</div>
</div>
<% else %>
<span class="view-mode disable-select"><%= @team.description.blank? ? t('users.settings.teams.edit.header_no_description') : @team.description %></span>
<% end %>
</div>
<!-- End of HEADER -->
<div data-hook="team-the-end"></div>
</div>
<%= render partial: 'users/settings/teams/description_modal' %>

View file

@ -0,0 +1,10 @@
<% provide(:head_title, t("users.settings.teams.head_title")) %>
<% provide(:container_class, "no-second-nav-container") %>
<% content_for :head do %>
<meta id="cache-directive" name="turbolinks-cache-control" content="no-cache">
<% end %>
<div class="content-pane flexible with-grey-background">
<%= render partial: 'users/settings/teams/header' %>
</div>

View file

@ -754,6 +754,9 @@ class Extends
storage_locations/index
storage_locations/show
forms/show
teams/show
teams/members
user_groups/index
)
DEFAULT_USER_NOTIFICATION_SETTINGS = {

View file

@ -3599,6 +3599,10 @@ en:
breadcrumbs:
all: "All teams"
new_team: "New team"
navigation:
details: "Details"
members: "Members"
groups: "Groups"
show:
enter_description: "Enter Team description"
tasks_share:

View file

@ -149,6 +149,10 @@ Rails.application.routes.draw do
resource :user_settings, only: %i(show update)
resources :teams, only: [] do
resources :user_groups
member do
get :members
end
collection do
post :switch
end