Skip to content

Commit

Permalink
Merge pull request #14170 from opf/implementation/50255-add-user-stat…
Browse files Browse the repository at this point in the history
…us-to-shares-list

[#50255] Add User Details to the Share Modal List
  • Loading branch information
aaron-contreras committed Nov 23, 2023
2 parents 1c93185 + b21d7b4 commit 8c0af70
Show file tree
Hide file tree
Showing 12 changed files with 737 additions and 10 deletions.
8 changes: 4 additions & 4 deletions app/components/work_packages/share/modal_body_component.sass
@@ -1,14 +1,14 @@
.op-share-wp-modal-body
&--user-row
display: grid
grid-template-columns: 1fr
grid-template-areas: "user"
grid-template-columns: minmax(31px, auto) 1fr // 31px is the width needed to display a group avatar
grid-template-areas: "avatar user_details"
grid-column-gap: 10px

&_manageable
display: grid
grid-template-columns: 20px 1fr auto auto
grid-template-areas: "selection user button remove"
grid-template-columns: 20px minmax(31px, auto) 1fr auto auto
grid-template-areas: "selection avatar user_details button remove"
grid-column-gap: 10px

&--header
Expand Down
Expand Up @@ -12,8 +12,12 @@
end
end

user_row_grid.with_area(:user, tag: :div, classes: 'ellipsis') do
render(Users::AvatarComponent.new(user: principal, size: :medium))
user_row_grid.with_area(:avatar, tag: :div) do
render(Users::AvatarComponent.new(user: principal, show_name: false, size: :medium))
end

user_row_grid.with_area(:user_details, tag: :div, classes: 'ellipsis') do
render(WorkPackages::Share::UserDetailsComponent.new(share:, manager_mode: share_editable?))
end

if share_editable?
Expand Down
67 changes: 67 additions & 0 deletions app/components/work_packages/share/user_details_component.html.erb
@@ -0,0 +1,67 @@
<%=
component_wrapper do
flex_layout do |flex|
flex.with_row do
render(Primer::Beta::Link.new(font_weight: :semibold, href: principal_show_path)) { user.name }
end

flex.with_row(classes: 'ellipsis') do
if manager_mode?
if user_is_a_group?
if project_group?
render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.project_group")}
else
render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.not_project_group")}
end
else
if user_in_non_active_status?
if user.locked?
concat(render(Primer::Beta::Octicon.new(icon: :lock, color: :muted, mr: 1)))
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.locked") })
elsif user.invited?
if invite_resent?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.invite_resent") })
else
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t('work_package.sharing.user_details.invited') })
concat(
form_with(url: resend_invite_path, method: :post) do
render(Primer::Beta::Button.new(type: :submit, px: 0, scheme: :link)) { I18n.t('work_package.sharing.user_details.resend_invite') }
end
)
end
end
else
if part_of_a_group?
if part_of_a_shared_group?
if project_member?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.additional_privileges_project_or_group") })
else
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.additional_privileges_group") })
end
else
if inherited_project_member?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.additional_privileges_project_or_group") })
elsif project_member?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.additional_privileges_project") })
else
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.not_project_member") })
end
end
else
if project_member?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.additional_privileges_project") })
else
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.not_project_member") })
end
end
end
end
else
if user.invited?
concat(render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("work_package.sharing.user_details.invited")})
end
end
end
end
end
%>
131 changes: 131 additions & 0 deletions app/components/work_packages/share/user_details_component.rb
@@ -0,0 +1,131 @@
# frozen_string_literal: true

# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2023 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
# ++

module WorkPackages
module Share
# rubocop:disable OpenProject/AddPreviewForViewComponent
class UserDetailsComponent < ApplicationComponent
# rubocop:enable OpenProject/AddPreviewForViewComponent
include OpTurbo::Streamable
include OpPrimer::ComponentHelpers
include WorkPackages::Share::Concerns::DisplayableRoles

def initialize(share:,
manager_mode: User.current.allowed_in_project?(:share_work_packages, share.project),
invite_resent: false)
super

@share = share
@user = share.principal
@manager_mode = manager_mode
@invite_resent = invite_resent
end

private

attr_reader :user, :share

def manager_mode? = @manager_mode

def invite_resent? = @invite_resent

def wrapper_uniq_by
share.id
end

def authoritative_work_package_role_name
@authoritative_work_package_role_name = options.find do |option|
option[:value] == share.roles.first.builtin
end[:label]
end

def principal_show_path
case user
when User
user_path(user)
when Group
show_group_path(user)
else
placeholder_user_path(user)
end
end

def resend_invite_path
resend_invite_work_package_share_path(share.entity, share)
end

def user_is_a_group?
@user_is_a_group ||= user.is_a?(Group)
end

def user_in_non_active_status?
user.locked? || user.invited?
end

# Is a user member of a project no matter whether inherited or directly assigned
def project_member?
Member.exists?(project: share.project,
principal: user,
entity: nil)
end

# Explicitly check whether the project membership was inherited by a group
def inherited_project_member?
Member.includes(:roles)
.references(:member_roles)
.where(project: share.project, principal: user, entity: nil) # membership in the project
.merge(MemberRole.only_inherited) # that was inherited
.any?
end

def project_group?
user_is_a_group? && project_member?
end

def part_of_a_shared_group?
share.member_roles.where.not(inherited_from: nil).any?
end

def part_of_a_group?
GroupUser.where(user_id: user.id).any?
end

def project_role_name
Member.where(project: share.project,
principal: user,
entity: nil)
.first
.roles
.first
.name
end
end
end
end
21 changes: 19 additions & 2 deletions app/controllers/work_packages/shares_controller.rb
Expand Up @@ -30,8 +30,8 @@ class WorkPackages::SharesController < ApplicationController
include OpTurbo::ComponentStream
include MemberHelper

before_action :find_work_package, only: %i[index create]
before_action :find_share, only: %i[destroy update]
before_action :find_work_package, only: %i[index create resend_invite]
before_action :find_share, only: %i[destroy update resend_invite]
before_action :find_project
before_action :authorize
before_action :enterprise_check, only: %i[index]
Expand Down Expand Up @@ -94,6 +94,14 @@ def destroy
end
end

def resend_invite
OpenProject::Notifications.send(OpenProject::Events::WORK_PACKAGE_SHARED,
work_package_member: @share,
send_notifications: true)

respond_with_update_user_details
end

private

def enterprise_check
Expand Down Expand Up @@ -150,6 +158,15 @@ def respond_with_remove_share
respond_with_turbo_streams
end

def respond_with_update_user_details
update_via_turbo_stream(
component: WorkPackages::Share::UserDetailsComponent.new(share: @share,
invite_resent: true)
)

respond_with_turbo_streams
end

def find_work_package
@work_package = WorkPackage.find(params[:work_package_id])
end
Expand Down
2 changes: 1 addition & 1 deletion config/initializers/permissions.rb
Expand Up @@ -118,7 +118,7 @@

map.permission :share_work_packages,
{
'work_packages/shares': %i[index create destroy update],
'work_packages/shares': %i[index create destroy update resend_invite],
'work_packages/shares/bulk': %i[update destroy]
},
permissible_on: :project,
Expand Down
11 changes: 11 additions & 0 deletions config/locales/en.yml
Expand Up @@ -3281,6 +3281,17 @@ en:
Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this work package.
warning_user_limit_reached_admin: >
Adding additional users will exceed the current limit. Please <a href="%{upgrade_url}">upgrade your plan</a> to be able to ensure external users are able to access this work package.
user_details:
locked: "Locked user"
invited: "Invite sent. "
resend_invite: "Resend."
invite_resent: "Invite has been resent"
not_project_member: "Not a project member"
project_group: "Group members might have additional privileges (as project members)"
not_project_group: "Group (shared with all members)"
additional_privileges_project: "Might have additional privileges (as project member)"
additional_privileges_group: "Might have additional privileges (as group member)"
additional_privileges_project_or_group: "Might have additional privileges (as project or group member)"

working_days:
info: >
Expand Down
3 changes: 3 additions & 0 deletions config/routes.rb
Expand Up @@ -471,6 +471,9 @@

# Rails managed sharing route
resources :shares, controller: 'work_packages/shares', only: %i[index create] do
member do
post 'resend_invite' => 'work_packages/shares#resend_invite'
end
collection do
resource :bulk, controller: 'work_packages/shares/bulk', only: %i[update destroy], as: :shares_bulk
end
Expand Down
@@ -1,5 +1,5 @@
<div
class="spot-modal op-share-wp-modal"
class="spot-modal spot-modal_wide op-share-wp-modal"
>
<div
class="spot-modal--header"
Expand Down

0 comments on commit 8c0af70

Please sign in to comment.