Remove current workspace member from role assignment picker (#10482)

## Context
Removing the ability to assign yourself from the UI. The backend already
checks that. This is because a member can only have one role for the V1
of permissions
Took the opportunity to move some roles related components in dedicated
folders
This commit is contained in:
Weiko
2025-02-25 17:43:57 +01:00
committed by GitHub
parent 90a390ee33
commit 2331176c53
16 changed files with 42 additions and 36 deletions

View File

@ -14,7 +14,7 @@ export const RecordTableEmptyStateReadOnly = () => {
return ( return (
<RecordTableEmptyStateDisplay <RecordTableEmptyStateDisplay
title={t`No records found`} title={t`No records found`}
subTitle={t`You are not allowed to create records in this object`} subTitle={t`You are not allowed to create records for this object`}
animatedPlaceholderType="noRecord" animatedPlaceholderType="noRecord"
buttonTitle={buttonTitle} buttonTitle={buttonTitle}
ButtonIcon={IconPlus} ButtonIcon={IconPlus}

View File

@ -17,10 +17,10 @@ import { TabList } from '@/ui/layout/tab/components/TabList';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList'; import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { useGetRolesQuery } from '~/generated/graphql'; import { useGetRolesQuery } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { RolePermissions } from '~/pages/settings/roles/components/RolePermissions'; import { RolePermissions } from '~/pages/settings/roles/role-permissions/components/RolePermissions';
import { RoleSettings } from '~/pages/settings/roles/components/RoleSettings'; import { RoleSettings } from '~/pages/settings/roles/role-settings/components/RoleSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath'; import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { RoleAssignment } from './components/RoleAssignment'; import { RoleAssignment } from './role-assignment/components/RoleAssignment';
const StyledContentContainer = styled.div` const StyledContentContainer = styled.div`
flex: 1; flex: 1;

View File

@ -1,4 +1,5 @@
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates'; import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { SettingsPath } from '@/types/SettingsPath'; import { SettingsPath } from '@/types/SettingsPath';
import { TextInput } from '@/ui/input/components/TextInput'; import { TextInput } from '@/ui/input/components/TextInput';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@ -24,11 +25,11 @@ import {
useUpdateWorkspaceMemberRoleMutation, useUpdateWorkspaceMemberRoleMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember'; import { RoleAssignmentTableHeader } from '~/pages/settings/roles/role-assignment/components/RoleAssignmentTableHeader';
import { RoleAssignmentWorkspaceMemberPickerDropdown } from '~/pages/settings/roles/role-assignment/components/RoleAssignmentWorkspaceMemberPickerDropdown';
import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/role-assignment/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember';
import { RoleAssignmentConfirmationModal } from './RoleAssignmentConfirmationModal'; import { RoleAssignmentConfirmationModal } from './RoleAssignmentConfirmationModal';
import { RoleAssignmentTableHeader } from './RoleAssignmentTableHeader';
import { RoleAssignmentTableRow } from './RoleAssignmentTableRow'; import { RoleAssignmentTableRow } from './RoleAssignmentTableRow';
import { RoleWorkspaceMemberPickerDropdown } from './RoleWorkspaceMemberPickerDropdown';
const StyledBottomSection = styled(Section)<{ hasRows: boolean }>` const StyledBottomSection = styled(Section)<{ hasRows: boolean }>`
${({ hasRows, theme }) => ${({ hasRows, theme }) =>
@ -82,6 +83,7 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
const { closeDropdown } = useDropdown('role-member-select'); const { closeDropdown } = useDropdown('role-member-select');
const [searchFilter, setSearchFilter] = useState(''); const [searchFilter, setSearchFilter] = useState('');
const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState); const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const workspaceMemberRoleMap = new Map< const workspaceMemberRoleMap = new Map<
string, string,
@ -108,6 +110,18 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
); );
}); });
const assignedWorkspaceMemberIds = role.workspaceMembers.map(
(workspaceMember) => workspaceMember.id,
);
const assignableWorkspaceMembers = currentWorkspaceMembers.filter(
(member) => member.id !== currentWorkspaceMember?.id,
);
const allWorkspaceMembersHaveThisRole = assignableWorkspaceMembers.every(
(member) => assignedWorkspaceMemberIds.includes(member.id),
);
const handleModalClose = () => { const handleModalClose = () => {
setConfirmationModalIsOpen(false); setConfirmationModalIsOpen(false);
setSelectedWorkspaceMember(null); setSelectedWorkspaceMember(null);
@ -147,9 +161,6 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
setSearchFilter(text); setSearchFilter(text);
}; };
const allWorkspaceMembersHaveThisRole =
role.workspaceMembers.length === currentWorkspaceMembers.length;
return ( return (
<> <>
<Section> <Section>
@ -201,10 +212,11 @@ export const RoleAssignment = ({ role }: RoleAssignmentProps) => {
</> </>
} }
dropdownComponents={ dropdownComponents={
<RoleWorkspaceMemberPickerDropdown <RoleAssignmentWorkspaceMemberPickerDropdown
excludedWorkspaceMemberIds={role.workspaceMembers.map( excludedWorkspaceMemberIds={[
(workspaceMember) => workspaceMember.id, ...assignedWorkspaceMemberIds,
)} currentWorkspaceMember?.id,
]}
onSelect={handleSelectWorkspaceMember} onSelect={handleSelectWorkspaceMember}
/> />
} }

View File

@ -1,7 +1,7 @@
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { RoleAssignmentConfirmationModalSubtitle } from '~/pages/settings/roles/components/RoleAssignmentConfirmationModalSubtitle'; import { RoleAssignmentConfirmationModalSubtitle } from '~/pages/settings/roles/role-assignment/components/RoleAssignmentConfirmationModalSubtitle';
import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember'; import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/role-assignment/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember';
type RoleAssignmentConfirmationModalProps = { type RoleAssignmentConfirmationModalProps = {
selectedWorkspaceMember: RoleAssignmentConfirmationModalSelectedWorkspaceMember; selectedWorkspaceMember: RoleAssignmentConfirmationModalSelectedWorkspaceMember;

View File

@ -2,7 +2,7 @@ import { SettingsCard } from '@/settings/components/SettingsCard';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { IconUser } from 'twenty-ui'; import { IconUser } from 'twenty-ui';
import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember'; import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '~/pages/settings/roles/role-assignment/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember';
const StyledSettingsCardContainer = styled.div` const StyledSettingsCardContainer = styled.div`
margin-top: ${({ theme }) => theme.spacing(2)}; margin-top: ${({ theme }) => theme.spacing(2)};

View File

@ -8,14 +8,8 @@ const StyledTableHeaderRow = styled(Table)`
margin-bottom: ${({ theme }) => theme.spacing(2)}; margin-bottom: ${({ theme }) => theme.spacing(2)};
`; `;
type RoleAssignmentTableHeaderProps = { export const RoleAssignmentTableHeader = () => (
className?: string; <StyledTableHeaderRow>
};
export const RoleAssignmentTableHeader = ({
className,
}: RoleAssignmentTableHeaderProps) => (
<StyledTableHeaderRow className={className}>
<TableRow gridAutoColumns="150px 1fr 1fr"> <TableRow gridAutoColumns="150px 1fr 1fr">
<TableHeader>{t`Name`}</TableHeader> <TableHeader>{t`Name`}</TableHeader>
<TableHeader>{t`Email`}</TableHeader> <TableHeader>{t`Email`}</TableHeader>

View File

@ -6,17 +6,17 @@ import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/Dropdow
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { ChangeEvent, useState } from 'react'; import { ChangeEvent, useState } from 'react';
import { WorkspaceMember } from '~/generated-metadata/graphql'; import { WorkspaceMember } from '~/generated-metadata/graphql';
import { RoleWorkspaceMemberPickerDropdownContent } from './RoleWorkspaceMemberPickerDropdownContent'; import { RoleAssignmentWorkspaceMemberPickerDropdownContent } from '~/pages/settings/roles/role-assignment/components/RoleAssignmentWorkspaceMemberPickerDropdownContent';
type RoleWorkspaceMemberPickerDropdownProps = { type RoleAssignmentWorkspaceMemberPickerDropdownProps = {
excludedWorkspaceMemberIds: string[]; excludedWorkspaceMemberIds: string[];
onSelect: (workspaceMember: WorkspaceMember) => void; onSelect: (workspaceMember: WorkspaceMember) => void;
}; };
export const RoleWorkspaceMemberPickerDropdown = ({ export const RoleAssignmentWorkspaceMemberPickerDropdown = ({
excludedWorkspaceMemberIds, excludedWorkspaceMemberIds,
onSelect, onSelect,
}: RoleWorkspaceMemberPickerDropdownProps) => { }: RoleAssignmentWorkspaceMemberPickerDropdownProps) => {
const [searchFilter, setSearchFilter] = useState(''); const [searchFilter, setSearchFilter] = useState('');
const { loading, records: workspaceMembers } = useSearchRecords({ const { loading, records: workspaceMembers } = useSearchRecords({
@ -42,7 +42,7 @@ export const RoleWorkspaceMemberPickerDropdown = ({
/> />
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItemsContainer> <DropdownMenuItemsContainer>
<RoleWorkspaceMemberPickerDropdownContent <RoleAssignmentWorkspaceMemberPickerDropdownContent
loading={loading} loading={loading}
searchFilter={searchFilter} searchFilter={searchFilter}
filteredWorkspaceMembers={filteredWorkspaceMembers} filteredWorkspaceMembers={filteredWorkspaceMembers}

View File

@ -2,19 +2,19 @@ import { t } from '@lingui/core/macro';
import { MenuItem, MenuItemAvatar } from 'twenty-ui'; import { MenuItem, MenuItemAvatar } from 'twenty-ui';
import { WorkspaceMember } from '~/generated-metadata/graphql'; import { WorkspaceMember } from '~/generated-metadata/graphql';
type RoleWorkspaceMemberPickerDropdownContentProps = { type RoleAssignmentWorkspaceMemberPickerDropdownContentProps = {
loading: boolean; loading: boolean;
searchFilter: string; searchFilter: string;
filteredWorkspaceMembers: WorkspaceMember[]; filteredWorkspaceMembers: WorkspaceMember[];
onSelect: (workspaceMember: WorkspaceMember) => void; onSelect: (workspaceMember: WorkspaceMember) => void;
}; };
export const RoleWorkspaceMemberPickerDropdownContent = ({ export const RoleAssignmentWorkspaceMemberPickerDropdownContent = ({
loading, loading,
searchFilter, searchFilter,
filteredWorkspaceMembers, filteredWorkspaceMembers,
onSelect, onSelect,
}: RoleWorkspaceMemberPickerDropdownContentProps) => { }: RoleAssignmentWorkspaceMemberPickerDropdownContentProps) => {
if (loading) { if (loading) {
return null; return null;
} }

View File

@ -10,9 +10,9 @@ import {
} from 'twenty-ui'; } from 'twenty-ui';
import { Role } from '~/generated-metadata/graphql'; import { Role } from '~/generated-metadata/graphql';
import { SettingsPermissions } from '~/generated/graphql'; import { SettingsPermissions } from '~/generated/graphql';
import { RolePermissionsObjectsTableHeader } from '~/pages/settings/roles/components/RolePermissionsObjectsTableHeader'; import { RolePermissionsObjectsTableHeader } from '~/pages/settings/roles/role-permissions/components/RolePermissionsObjectsTableHeader';
import { RolePermissionsSettingsTableHeader } from '~/pages/settings/roles/components/RolePermissionsSettingsTableHeader'; import { RolePermissionsSettingsTableHeader } from '~/pages/settings/roles/role-permissions/components/RolePermissionsSettingsTableHeader';
import { RolePermissionsSettingsTableRow } from '~/pages/settings/roles/components/RolePermissionsSettingsTableRow'; import { RolePermissionsSettingsTableRow } from '~/pages/settings/roles/role-permissions/components/RolePermissionsSettingsTableRow';
import { RolePermissionsObjectPermission } from '~/pages/settings/roles/types/RolePermissionsObjectPermission'; import { RolePermissionsObjectPermission } from '~/pages/settings/roles/types/RolePermissionsObjectPermission';
import { RolePermissionsObjectsTableRow } from './RolePermissionsObjectsTableRow'; import { RolePermissionsObjectsTableRow } from './RolePermissionsObjectsTableRow';