Role page various fixes 2 (#12416)
- Fix: AvatarURL signedPath for workspace members were not consistent when queried multiple times and it was causing the frontend to wrongly interpret this as a change in the deepEqual condition - Use SaveAndCancel button to be consistent with data model page - When applying all object permission changes, a "smarter" logic applies and removes all permissions if read is unchecked for example - Hide settings permissions when Settings All Access is toggled
This commit is contained in:
@ -28,11 +28,21 @@ export const SettingsRolesQueryEffect = () => {
|
|||||||
snapshot,
|
snapshot,
|
||||||
settingsPersistedRoleFamilyState(role.id),
|
settingsPersistedRoleFamilyState(role.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const currentDraftRole = getSnapshotValue(
|
||||||
|
snapshot,
|
||||||
|
settingsDraftRoleFamilyState(role.id),
|
||||||
|
);
|
||||||
|
|
||||||
if (isDeeplyEqual(role, persistedRole)) {
|
if (isDeeplyEqual(role, persistedRole)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
set(settingsDraftRoleFamilyState(role.id), role);
|
|
||||||
set(settingsPersistedRoleFamilyState(role.id), role);
|
set(settingsPersistedRoleFamilyState(role.id), role);
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(currentDraftRole, role)) {
|
||||||
|
set(settingsDraftRoleFamilyState(role.id), role);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import {
|
import {
|
||||||
AppTooltip,
|
AppTooltip,
|
||||||
Avatar,
|
Avatar,
|
||||||
@ -62,6 +65,16 @@ export const SettingsRolesTableRow = ({ role }: SettingsRolesTableRowProps) => {
|
|||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const Icon = getIcon(role.icon ?? 'IconUser');
|
const Icon = getIcon(role.icon ?? 'IconUser');
|
||||||
|
|
||||||
|
const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState);
|
||||||
|
|
||||||
|
const enrichedWorkspaceMembers = role.workspaceMembers
|
||||||
|
.map((workspaceMember) =>
|
||||||
|
currentWorkspaceMembers.find(
|
||||||
|
(member) => member.id === workspaceMember.id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(isDefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledTableRow
|
<StyledTableRow
|
||||||
key={role.id}
|
key={role.id}
|
||||||
@ -85,7 +98,7 @@ export const SettingsRolesTableRow = ({ role }: SettingsRolesTableRowProps) => {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell align={'right'}>
|
<TableCell align={'right'}>
|
||||||
<StyledAvatarGroup>
|
<StyledAvatarGroup>
|
||||||
{role.workspaceMembers.slice(0, 5).map((workspaceMember) => (
|
{enrichedWorkspaceMembers.slice(0, 5).map((workspaceMember) => (
|
||||||
<React.Fragment key={workspaceMember.id}>
|
<React.Fragment key={workspaceMember.id}>
|
||||||
<div id={`avatar-${workspaceMember.id}`}>
|
<div id={`avatar-${workspaceMember.id}`}>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import {
|
||||||
|
CurrentWorkspaceMember,
|
||||||
|
currentWorkspaceMemberState,
|
||||||
|
} from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWorkspaceMemberRole';
|
import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWorkspaceMemberRole';
|
||||||
import { SettingsRoleAssignmentConfirmationModal } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentConfirmationModal';
|
import { SettingsRoleAssignmentConfirmationModal } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentConfirmationModal';
|
||||||
@ -28,11 +31,7 @@ import {
|
|||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { Button } from 'twenty-ui/input';
|
import { Button } from 'twenty-ui/input';
|
||||||
import { Section } from 'twenty-ui/layout';
|
import { Section } from 'twenty-ui/layout';
|
||||||
import {
|
import { Role, WorkspaceMember } from '~/generated-metadata/graphql';
|
||||||
Role,
|
|
||||||
SearchRecord,
|
|
||||||
WorkspaceMember,
|
|
||||||
} from '~/generated-metadata/graphql';
|
|
||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
import { ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID } from '../constants/RoleAssignmentConfirmationModalId';
|
import { ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID } from '../constants/RoleAssignmentConfirmationModalId';
|
||||||
import { SettingsRoleAssignmentTableRow } from './SettingsRoleAssignmentTableRow';
|
import { SettingsRoleAssignmentTableRow } from './SettingsRoleAssignmentTableRow';
|
||||||
@ -142,17 +141,14 @@ export const SettingsRoleAssignment = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectWorkspaceMember = (
|
const handleSelectWorkspaceMember = (
|
||||||
workspaceMemberSearchRecord: SearchRecord,
|
workspaceMember: CurrentWorkspaceMember,
|
||||||
) => {
|
) => {
|
||||||
const existingRole = workspaceMemberRoleMap.get(
|
const existingRole = workspaceMemberRoleMap.get(workspaceMember.id);
|
||||||
workspaceMemberSearchRecord.recordId,
|
|
||||||
);
|
|
||||||
|
|
||||||
setSelectedWorkspaceMember({
|
setSelectedWorkspaceMember({
|
||||||
id: workspaceMemberSearchRecord.recordId,
|
id: workspaceMember.id,
|
||||||
name: `${workspaceMemberSearchRecord.label}`,
|
name: `${workspaceMember.name.firstName} ${workspaceMember.name.lastName}`,
|
||||||
role: existingRole,
|
role: existingRole,
|
||||||
avatarUrl: workspaceMemberSearchRecord.imageUrl,
|
|
||||||
});
|
});
|
||||||
openModal(ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID);
|
openModal(ROLE_ASSIGNMENT_CONFIRMATION_MODAL_ID);
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
import { SettingsCard } from '@/settings/components/SettingsCard';
|
import { SettingsCard } from '@/settings/components/SettingsCard';
|
||||||
import { SettingsRoleAssignmentConfirmationModalSelectedWorkspaceMember } from '@/settings/roles/role-assignment/types/SettingsRoleAssignmentConfirmationModalSelectedWorkspaceMember';
|
import { SettingsRoleAssignmentConfirmationModalSelectedWorkspaceMember } from '@/settings/roles/role-assignment/types/SettingsRoleAssignmentConfirmationModalSelectedWorkspaceMember';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Avatar } from 'twenty-ui/display';
|
import { Avatar } from 'twenty-ui/display';
|
||||||
|
|
||||||
const StyledSettingsCardContainer = styled.div`
|
const StyledSettingsCardContainer = styled.div`
|
||||||
@ -17,7 +19,13 @@ export const SettingsRoleAssignmentConfirmationModalSubtitle = ({
|
|||||||
selectedWorkspaceMember,
|
selectedWorkspaceMember,
|
||||||
onRoleClick,
|
onRoleClick,
|
||||||
}: SettingsRoleAssignmentConfirmationModalSubtitleProps) => {
|
}: SettingsRoleAssignmentConfirmationModalSubtitleProps) => {
|
||||||
const workspaceMemberName = selectedWorkspaceMember.name;
|
const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState);
|
||||||
|
|
||||||
|
const enrichedSelectedWorkspaceMember = currentWorkspaceMembers.find(
|
||||||
|
(member) => member.id === selectedWorkspaceMember.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
const workspaceMemberName = `${enrichedSelectedWorkspaceMember?.name.firstName} ${enrichedSelectedWorkspaceMember?.name.lastName}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -27,9 +35,9 @@ export const SettingsRoleAssignmentConfirmationModalSubtitle = ({
|
|||||||
title={selectedWorkspaceMember.role?.label || ''}
|
title={selectedWorkspaceMember.role?.label || ''}
|
||||||
Icon={
|
Icon={
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarUrl={selectedWorkspaceMember.avatarUrl}
|
avatarUrl={enrichedSelectedWorkspaceMember?.avatarUrl}
|
||||||
placeholderColorSeed={selectedWorkspaceMember.id}
|
placeholderColorSeed={enrichedSelectedWorkspaceMember?.id}
|
||||||
placeholder={selectedWorkspaceMember.name}
|
placeholder={workspaceMemberName}
|
||||||
size="md"
|
size="md"
|
||||||
type="rounded"
|
type="rounded"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
import { TableCell } from '@/ui/layout/table/components/TableCell';
|
||||||
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
import { TableRow } from '@/ui/layout/table/components/TableRow';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Avatar, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
import { Avatar, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||||
import { WorkspaceMember } from '~/generated-metadata/graphql';
|
import { WorkspaceMember } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -35,15 +37,20 @@ type SettingsRoleAssignmentTableRowProps = {
|
|||||||
export const SettingsRoleAssignmentTableRow = ({
|
export const SettingsRoleAssignmentTableRow = ({
|
||||||
workspaceMember,
|
workspaceMember,
|
||||||
}: SettingsRoleAssignmentTableRowProps) => {
|
}: SettingsRoleAssignmentTableRowProps) => {
|
||||||
|
const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState);
|
||||||
|
const enrichedWorkspaceMember = currentWorkspaceMembers.find(
|
||||||
|
(member) => member.id === workspaceMember.id,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow gridAutoColumns="2fr 4fr">
|
<TableRow gridAutoColumns="2fr 4fr">
|
||||||
<StyledTableCell>
|
<StyledTableCell>
|
||||||
<StyledNameContainer>
|
<StyledNameContainer>
|
||||||
<StyledIconWrapper>
|
<StyledIconWrapper>
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarUrl={workspaceMember.avatarUrl}
|
avatarUrl={enrichedWorkspaceMember?.avatarUrl}
|
||||||
placeholderColorSeed={workspaceMember.id}
|
placeholderColorSeed={enrichedWorkspaceMember?.id}
|
||||||
placeholder={workspaceMember.name.firstName ?? ''}
|
placeholder={enrichedWorkspaceMember?.name.firstName ?? ''}
|
||||||
type="rounded"
|
type="rounded"
|
||||||
size="md"
|
size="md"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useObjectRecordSearchRecords } from '@/object-record/hooks/useObjectRecordSearchRecords';
|
import { useObjectRecordSearchRecords } from '@/object-record/hooks/useObjectRecordSearchRecords';
|
||||||
import { SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent';
|
import { SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent } from '@/settings/roles/role-assignment/components/SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent';
|
||||||
@ -7,11 +8,10 @@ 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 { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { ChangeEvent, useState } from 'react';
|
import { ChangeEvent, useState } from 'react';
|
||||||
import { SearchRecord } from '~/generated-metadata/graphql';
|
|
||||||
|
|
||||||
type SettingsRoleAssignmentWorkspaceMemberPickerDropdownProps = {
|
type SettingsRoleAssignmentWorkspaceMemberPickerDropdownProps = {
|
||||||
excludedWorkspaceMemberIds: string[];
|
excludedWorkspaceMemberIds: string[];
|
||||||
onSelect: (workspaceMemberSearchRecord: SearchRecord) => void;
|
onSelect: (workspaceMember: CurrentWorkspaceMember) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsRoleAssignmentWorkspaceMemberPickerDropdown = ({
|
export const SettingsRoleAssignmentWorkspaceMemberPickerDropdown = ({
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
|
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { MenuItem, MenuItemAvatar } from 'twenty-ui/navigation';
|
import { MenuItem, MenuItemAvatar } from 'twenty-ui/navigation';
|
||||||
import { SearchRecord } from '~/generated-metadata/graphql';
|
import { SearchRecord } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
@ -6,7 +10,7 @@ type SettingsRoleAssignmentWorkspaceMemberPickerDropdownContentProps = {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
searchFilter: string;
|
searchFilter: string;
|
||||||
filteredWorkspaceMembers: SearchRecord[];
|
filteredWorkspaceMembers: SearchRecord[];
|
||||||
onSelect: (workspaceMemberSearchRecord: SearchRecord) => void;
|
onSelect: (workspaceMember: CurrentWorkspaceMember) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent = ({
|
export const SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent = ({
|
||||||
@ -15,6 +19,8 @@ export const SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent = ({
|
|||||||
filteredWorkspaceMembers,
|
filteredWorkspaceMembers,
|
||||||
onSelect,
|
onSelect,
|
||||||
}: SettingsRoleAssignmentWorkspaceMemberPickerDropdownContentProps) => {
|
}: SettingsRoleAssignmentWorkspaceMemberPickerDropdownContentProps) => {
|
||||||
|
const currentWorkspaceMembers = useRecoilValue(currentWorkspaceMembersState);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -23,20 +29,28 @@ export const SettingsRoleAssignmentWorkspaceMemberPickerDropdownContent = ({
|
|||||||
return <MenuItem disabled text={t`No Results`} />;
|
return <MenuItem disabled text={t`No Results`} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enrichedWorkspaceMembers = filteredWorkspaceMembers
|
||||||
|
.map((workspaceMember) =>
|
||||||
|
currentWorkspaceMembers.find(
|
||||||
|
(member) => member.id === workspaceMember.recordId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(isDefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{filteredWorkspaceMembers.map((workspaceMember) => (
|
{enrichedWorkspaceMembers.map((workspaceMember) => (
|
||||||
<MenuItemAvatar
|
<MenuItemAvatar
|
||||||
key={workspaceMember.recordId}
|
key={workspaceMember.id}
|
||||||
onClick={() => onSelect(workspaceMember)}
|
onClick={() => onSelect(workspaceMember)}
|
||||||
avatar={{
|
avatar={{
|
||||||
type: 'rounded',
|
type: 'rounded',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
placeholder: workspaceMember.label ?? '',
|
placeholder: workspaceMember?.name.firstName ?? '',
|
||||||
placeholderColorSeed: workspaceMember.recordId,
|
placeholderColorSeed: workspaceMember?.id,
|
||||||
avatarUrl: workspaceMember.imageUrl,
|
avatarUrl: workspaceMember?.avatarUrl,
|
||||||
}}
|
}}
|
||||||
text={workspaceMember.label}
|
text={workspaceMember?.name.firstName ?? ''}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -2,7 +2,6 @@ export type SettingsRoleAssignmentConfirmationModalSelectedWorkspaceMember = {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
role?: { id: string; label: string };
|
role?: { id: string; label: string };
|
||||||
avatarUrl?: string | null;
|
|
||||||
colorScheme?: string;
|
colorScheme?: string;
|
||||||
userEmail?: string;
|
userEmail?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -82,7 +82,13 @@ export const SettingsRolePermissionsObjectLevelSection = ({
|
|||||||
...(draftRole.objectPermissions ?? []).filter(
|
...(draftRole.objectPermissions ?? []).filter(
|
||||||
(permission) => permission.objectMetadataId !== objectMetadataId,
|
(permission) => permission.objectMetadataId !== objectMetadataId,
|
||||||
),
|
),
|
||||||
{ objectMetadataId, roleId },
|
{
|
||||||
|
objectMetadataId,
|
||||||
|
canReadObjectRecords: null,
|
||||||
|
canUpdateObjectRecords: null,
|
||||||
|
canSoftDeleteObjectRecords: null,
|
||||||
|
canDestroyObjectRecords: null,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
navigate(SettingsPath.RoleObjectLevel, {
|
navigate(SettingsPath.RoleObjectLevel, {
|
||||||
|
|||||||
@ -47,6 +47,13 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
setSettingsDraftRole({
|
setSettingsDraftRole({
|
||||||
...settingsDraftRole,
|
...settingsDraftRole,
|
||||||
canReadAllObjectRecords: value,
|
canReadAllObjectRecords: value,
|
||||||
|
...(value === false
|
||||||
|
? {
|
||||||
|
canUpdateAllObjectRecords: value,
|
||||||
|
canSoftDeleteAllObjectRecords: value,
|
||||||
|
canDestroyAllObjectRecords: value,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -64,6 +71,11 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
setSettingsDraftRole({
|
setSettingsDraftRole({
|
||||||
...settingsDraftRole,
|
...settingsDraftRole,
|
||||||
canUpdateAllObjectRecords: value,
|
canUpdateAllObjectRecords: value,
|
||||||
|
...(value === true
|
||||||
|
? {
|
||||||
|
canReadAllObjectRecords: value,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -81,6 +93,11 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
setSettingsDraftRole({
|
setSettingsDraftRole({
|
||||||
...settingsDraftRole,
|
...settingsDraftRole,
|
||||||
canSoftDeleteAllObjectRecords: value,
|
canSoftDeleteAllObjectRecords: value,
|
||||||
|
...(value === true
|
||||||
|
? {
|
||||||
|
canReadAllObjectRecords: value,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -98,6 +115,11 @@ export const SettingsRolePermissionsObjectsSection = ({
|
|||||||
setSettingsDraftRole({
|
setSettingsDraftRole({
|
||||||
...settingsDraftRole,
|
...settingsDraftRole,
|
||||||
canDestroyAllObjectRecords: value,
|
canDestroyAllObjectRecords: value,
|
||||||
|
...(value === true
|
||||||
|
? {
|
||||||
|
canReadAllObjectRecords: value,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import {
|
|||||||
IconSettings,
|
IconSettings,
|
||||||
IconUsers,
|
IconUsers,
|
||||||
} from 'twenty-ui/display';
|
} from 'twenty-ui/display';
|
||||||
import { Card, Section } from 'twenty-ui/layout';
|
import { AnimatedExpandableContainer, Card, Section } from 'twenty-ui/layout';
|
||||||
import {
|
import {
|
||||||
FeatureFlagKey,
|
FeatureFlagKey,
|
||||||
SettingPermissionType,
|
SettingPermissionType,
|
||||||
@ -112,19 +112,30 @@ export const SettingsRolePermissionsSettingsSection = ({
|
|||||||
/>
|
/>
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
)}
|
)}
|
||||||
<StyledTable>
|
<AnimatedExpandableContainer
|
||||||
<SettingsRolePermissionsSettingsTableHeader />
|
isExpanded={!settingsDraftRole.canUpdateAllSettings}
|
||||||
<StyledTableRows>
|
dimension="height"
|
||||||
{settingsPermissionsConfig.map((permission) => (
|
animationDurations={{
|
||||||
<SettingsRolePermissionsSettingsTableRow
|
opacity: 0.2,
|
||||||
key={permission.key}
|
size: 0.4,
|
||||||
roleId={roleId}
|
}}
|
||||||
permission={permission}
|
mode="scroll-height"
|
||||||
isEditable={isEditable}
|
containAnimation={false}
|
||||||
/>
|
>
|
||||||
))}
|
<StyledTable>
|
||||||
</StyledTableRows>
|
<SettingsRolePermissionsSettingsTableHeader />
|
||||||
</StyledTable>
|
<StyledTableRows>
|
||||||
|
{settingsPermissionsConfig.map((permission) => (
|
||||||
|
<SettingsRolePermissionsSettingsTableRow
|
||||||
|
key={permission.key}
|
||||||
|
roleId={roleId}
|
||||||
|
permission={permission}
|
||||||
|
isEditable={isEditable}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</StyledTableRows>
|
||||||
|
</StyledTable>
|
||||||
|
</AnimatedExpandableContainer>
|
||||||
</Section>
|
</Section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery';
|
import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery';
|
||||||
import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWorkspaceMemberRole';
|
import { useUpdateWorkspaceMemberRole } from '@/settings/roles/hooks/useUpdateWorkspaceMemberRole';
|
||||||
@ -22,7 +23,6 @@ import { t } from '@lingui/core/macro';
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconLockOpen, IconSettings, IconUserPlus } from 'twenty-ui/display';
|
import { IconLockOpen, IconSettings, IconUserPlus } from 'twenty-ui/display';
|
||||||
import { Button } from 'twenty-ui/input';
|
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import {
|
import {
|
||||||
FeatureFlagKey,
|
FeatureFlagKey,
|
||||||
@ -281,16 +281,11 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
actionButton={
|
actionButton={
|
||||||
isDirty && (
|
<SaveAndCancelButtons
|
||||||
<Button
|
onSave={handleSave}
|
||||||
title={isCreateMode ? t`Create` : t`Save`}
|
onCancel={() => navigateSettings(SettingsPath.Roles)}
|
||||||
variant="primary"
|
isSaveDisabled={!isRoleEditable || !isDirty}
|
||||||
size="small"
|
/>
|
||||||
accent="blue"
|
|
||||||
onClick={handleSave}
|
|
||||||
disabled={!isRoleEditable}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SettingsPageContainer>
|
<SettingsPageContainer>
|
||||||
|
|||||||
@ -188,17 +188,6 @@ export class RoleResolver {
|
|||||||
workspace.id,
|
workspace.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
workspaceMembers.map(async (workspaceMember) => {
|
|
||||||
if (workspaceMember && workspaceMember.avatarUrl) {
|
|
||||||
workspaceMember.avatarUrl = this.fileService.signFileUrl({
|
|
||||||
url: workspaceMember.avatarUrl,
|
|
||||||
workspaceId: workspace.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return workspaceMembers;
|
return workspaceMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user