Add object level form to role creation (#12826)
## Context - Add object-level form to role creation - Add isSaving props for save button isLoading state <img width="594" alt="Screenshot 2025-06-24 at 15 03 59" src="https://github.com/user-attachments/assets/77d9d399-4e1a-4e35-be45-c19100ef06c1" /> --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -3,10 +3,9 @@ import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDr
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { PENDING_ROLE_ID } from '~/pages/settings/roles/SettingsRoleCreate';
|
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { getRolesMock } from '~/testing/mock-data/roles';
|
import { getRolesMock } from '~/testing/mock-data/roles';
|
||||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
|
||||||
|
|
||||||
const SettingsRoleAssignmentWrapper = (
|
const SettingsRoleAssignmentWrapper = (
|
||||||
args: React.ComponentProps<typeof SettingsRoleAssignment>,
|
args: React.ComponentProps<typeof SettingsRoleAssignment>,
|
||||||
@ -41,6 +40,6 @@ export const Default: Story = {
|
|||||||
|
|
||||||
export const PendingRole: Story = {
|
export const PendingRole: Story = {
|
||||||
args: {
|
args: {
|
||||||
roleId: PENDING_ROLE_ID,
|
roleId: 'newRoleId',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,13 +12,11 @@ const StyledRolePermissionsContainer = styled.div`
|
|||||||
type SettingsRolePermissionsProps = {
|
type SettingsRolePermissionsProps = {
|
||||||
roleId: string;
|
roleId: string;
|
||||||
isEditable: boolean;
|
isEditable: boolean;
|
||||||
isCreateMode: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SettingsRolePermissions = ({
|
export const SettingsRolePermissions = ({
|
||||||
roleId,
|
roleId,
|
||||||
isEditable,
|
isEditable,
|
||||||
isCreateMode,
|
|
||||||
}: SettingsRolePermissionsProps) => {
|
}: SettingsRolePermissionsProps) => {
|
||||||
return (
|
return (
|
||||||
<StyledRolePermissionsContainer>
|
<StyledRolePermissionsContainer>
|
||||||
@ -26,12 +24,10 @@ export const SettingsRolePermissions = ({
|
|||||||
roleId={roleId}
|
roleId={roleId}
|
||||||
isEditable={isEditable}
|
isEditable={isEditable}
|
||||||
/>
|
/>
|
||||||
{!isCreateMode && (
|
<SettingsRolePermissionsObjectLevelSection
|
||||||
<SettingsRolePermissionsObjectLevelSection
|
roleId={roleId}
|
||||||
roleId={roleId}
|
isEditable={isEditable}
|
||||||
isEditable={isEditable}
|
/>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<SettingsRolePermissionsSettingsSection
|
<SettingsRolePermissionsSettingsSection
|
||||||
roleId={roleId}
|
roleId={roleId}
|
||||||
isEditable={isEditable}
|
isEditable={isEditable}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||||
import { PENDING_ROLE_ID } from '~/pages/settings/roles/SettingsRoleCreate';
|
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { getRolesMock } from '~/testing/mock-data/roles';
|
import { getRolesMock } from '~/testing/mock-data/roles';
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export const ReadOnly: Story = {
|
|||||||
|
|
||||||
export const PendingRole: Story = {
|
export const PendingRole: Story = {
|
||||||
args: {
|
args: {
|
||||||
roleId: PENDING_ROLE_ID,
|
roleId: 'newRoleId',
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
isCreateMode: true,
|
isCreateMode: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { Meta, StoryObj } from '@storybook/react';
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||||
import { PENDING_ROLE_ID } from '~/pages/settings/roles/SettingsRoleCreate';
|
|
||||||
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
||||||
import { getRolesMock } from '~/testing/mock-data/roles';
|
import { getRolesMock } from '~/testing/mock-data/roles';
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export const ReadOnly: Story = {
|
|||||||
|
|
||||||
export const PendingRole: Story = {
|
export const PendingRole: Story = {
|
||||||
args: {
|
args: {
|
||||||
roleId: PENDING_ROLE_ID,
|
roleId: 'newRoleId',
|
||||||
isEditable: true,
|
isEditable: true,
|
||||||
isCreateMode: false,
|
isCreateMode: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -20,10 +20,10 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab
|
|||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
|
import { useState } from 'react';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, 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 { v4 } from 'uuid';
|
|
||||||
import {
|
import {
|
||||||
Role,
|
Role,
|
||||||
useCreateOneRoleMutation,
|
useCreateOneRoleMutation,
|
||||||
@ -65,6 +65,8 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
const [upsertSettingPermissions] = useUpsertSettingPermissionsMutation();
|
const [upsertSettingPermissions] = useUpsertSettingPermissionsMutation();
|
||||||
const [upsertObjectPermissions] = useUpsertObjectPermissionsMutation();
|
const [upsertObjectPermissions] = useUpsertObjectPermissionsMutation();
|
||||||
|
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
const { addWorkspaceMembersToRole } = useUpdateWorkspaceMemberRole(roleId);
|
const { addWorkspaceMembersToRole } = useUpdateWorkspaceMemberRole(roleId);
|
||||||
|
|
||||||
const settingsRolesIsLoading = useRecoilValue(settingsRolesIsLoadingState);
|
const settingsRolesIsLoading = useRecoilValue(settingsRolesIsLoadingState);
|
||||||
@ -114,6 +116,8 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
setIsSaving(true);
|
||||||
|
|
||||||
const dirtyFields = getDirtyFields(
|
const dirtyFields = getDirtyFields(
|
||||||
settingsDraftRole,
|
settingsDraftRole,
|
||||||
settingsPersistedRole,
|
settingsPersistedRole,
|
||||||
@ -126,151 +130,156 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCreateMode) {
|
try {
|
||||||
const roleId = v4();
|
if (isCreateMode) {
|
||||||
|
const { data } = await createRole({
|
||||||
const { data } = await createRole({
|
|
||||||
variables: {
|
|
||||||
createRoleInput: {
|
|
||||||
id: roleId,
|
|
||||||
label: settingsDraftRole.label,
|
|
||||||
description: settingsDraftRole.description,
|
|
||||||
icon: settingsDraftRole.icon,
|
|
||||||
canUpdateAllSettings: settingsDraftRole.canUpdateAllSettings,
|
|
||||||
canReadAllObjectRecords: settingsDraftRole.canReadAllObjectRecords,
|
|
||||||
canUpdateAllObjectRecords:
|
|
||||||
settingsDraftRole.canUpdateAllObjectRecords,
|
|
||||||
canSoftDeleteAllObjectRecords:
|
|
||||||
settingsDraftRole.canSoftDeleteAllObjectRecords,
|
|
||||||
canDestroyAllObjectRecords:
|
|
||||||
settingsDraftRole.canDestroyAllObjectRecords,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(dirtyFields.workspaceMembers)) {
|
|
||||||
await addWorkspaceMembersToRole({
|
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
workspaceMemberIds: settingsDraftRole.workspaceMembers.map(
|
|
||||||
(member) => member.id,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(dirtyFields.settingPermissions)) {
|
|
||||||
await upsertSettingPermissions({
|
|
||||||
variables: {
|
variables: {
|
||||||
upsertSettingPermissionsInput: {
|
createRoleInput: {
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
settingPermissionKeys:
|
|
||||||
settingsDraftRole.settingPermissions?.map(
|
|
||||||
(settingPermission) => settingPermission.setting,
|
|
||||||
) ?? [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(dirtyFields.objectPermissions)) {
|
|
||||||
await upsertObjectPermissions({
|
|
||||||
variables: {
|
|
||||||
upsertObjectPermissionsInput: {
|
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
objectPermissions:
|
|
||||||
settingsDraftRole.objectPermissions?.map(
|
|
||||||
(objectPermission) => ({
|
|
||||||
objectMetadataId: objectPermission.objectMetadataId,
|
|
||||||
canReadObjectRecords: objectPermission.canReadObjectRecords,
|
|
||||||
canUpdateObjectRecords:
|
|
||||||
objectPermission.canUpdateObjectRecords,
|
|
||||||
canSoftDeleteObjectRecords:
|
|
||||||
objectPermission.canSoftDeleteObjectRecords,
|
|
||||||
canDestroyObjectRecords:
|
|
||||||
objectPermission.canDestroyObjectRecords,
|
|
||||||
}),
|
|
||||||
) ?? [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
navigateSettings(SettingsPath.RoleDetail, {
|
|
||||||
roleId: data.createOneRole.id,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (isDefined(dirtyFields.settingPermissions)) {
|
|
||||||
await upsertSettingPermissions({
|
|
||||||
variables: {
|
|
||||||
upsertSettingPermissionsInput: {
|
|
||||||
roleId: roleId,
|
|
||||||
settingPermissionKeys:
|
|
||||||
settingsDraftRole.settingPermissions?.map(
|
|
||||||
(settingPermission) => settingPermission.setting,
|
|
||||||
) ?? [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ROLE_BASIC_KEYS.some((key) => key in dirtyFields)) {
|
|
||||||
await updateRole({
|
|
||||||
variables: {
|
|
||||||
updateRoleInput: {
|
|
||||||
id: roleId,
|
id: roleId,
|
||||||
update: {
|
label: settingsDraftRole.label,
|
||||||
label: settingsDraftRole.label,
|
description: settingsDraftRole.description,
|
||||||
description: settingsDraftRole.description,
|
icon: settingsDraftRole.icon,
|
||||||
icon: settingsDraftRole.icon,
|
canUpdateAllSettings: settingsDraftRole.canUpdateAllSettings,
|
||||||
canUpdateAllSettings: settingsDraftRole.canUpdateAllSettings,
|
canReadAllObjectRecords:
|
||||||
canReadAllObjectRecords:
|
settingsDraftRole.canReadAllObjectRecords,
|
||||||
settingsDraftRole.canReadAllObjectRecords,
|
canUpdateAllObjectRecords:
|
||||||
canUpdateAllObjectRecords:
|
settingsDraftRole.canUpdateAllObjectRecords,
|
||||||
settingsDraftRole.canUpdateAllObjectRecords,
|
canSoftDeleteAllObjectRecords:
|
||||||
canSoftDeleteAllObjectRecords:
|
settingsDraftRole.canSoftDeleteAllObjectRecords,
|
||||||
settingsDraftRole.canSoftDeleteAllObjectRecords,
|
canDestroyAllObjectRecords:
|
||||||
canDestroyAllObjectRecords:
|
settingsDraftRole.canDestroyAllObjectRecords,
|
||||||
settingsDraftRole.canDestroyAllObjectRecords,
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(dirtyFields.settingPermissions)) {
|
||||||
|
await upsertSettingPermissions({
|
||||||
|
variables: {
|
||||||
|
upsertSettingPermissionsInput: {
|
||||||
|
roleId: data.createOneRole.id,
|
||||||
|
settingPermissionKeys:
|
||||||
|
settingsDraftRole.settingPermissions?.map(
|
||||||
|
(settingPermission) => settingPermission.setting,
|
||||||
|
) ?? [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(dirtyFields.objectPermissions)) {
|
if (isDefined(dirtyFields.objectPermissions)) {
|
||||||
await upsertObjectPermissions({
|
await upsertObjectPermissions({
|
||||||
variables: {
|
variables: {
|
||||||
upsertObjectPermissionsInput: {
|
upsertObjectPermissionsInput: {
|
||||||
roleId: roleId,
|
roleId: data.createOneRole.id,
|
||||||
objectPermissions:
|
objectPermissions:
|
||||||
settingsDraftRole.objectPermissions?.map(
|
settingsDraftRole.objectPermissions?.map(
|
||||||
(objectPermission) => ({
|
(objectPermission) => ({
|
||||||
objectMetadataId: objectPermission.objectMetadataId,
|
objectMetadataId: objectPermission.objectMetadataId,
|
||||||
canReadObjectRecords: objectPermission.canReadObjectRecords,
|
canReadObjectRecords:
|
||||||
canUpdateObjectRecords:
|
objectPermission.canReadObjectRecords,
|
||||||
objectPermission.canUpdateObjectRecords,
|
canUpdateObjectRecords:
|
||||||
canSoftDeleteObjectRecords:
|
objectPermission.canUpdateObjectRecords,
|
||||||
objectPermission.canSoftDeleteObjectRecords,
|
canSoftDeleteObjectRecords:
|
||||||
canDestroyObjectRecords:
|
objectPermission.canSoftDeleteObjectRecords,
|
||||||
objectPermission.canDestroyObjectRecords,
|
canDestroyObjectRecords:
|
||||||
}),
|
objectPermission.canDestroyObjectRecords,
|
||||||
) ?? [],
|
}),
|
||||||
|
) ?? [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
});
|
||||||
});
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await loadCurrentUser();
|
if (isDefined(dirtyFields.workspaceMembers)) {
|
||||||
|
await addWorkspaceMembersToRole({
|
||||||
|
roleId: data.createOneRole.id,
|
||||||
|
workspaceMemberIds: settingsDraftRole.workspaceMembers.map(
|
||||||
|
(member) => member.id,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateSettings(SettingsPath.RoleDetail, {
|
||||||
|
roleId: data.createOneRole.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (isDefined(dirtyFields.settingPermissions)) {
|
||||||
|
await upsertSettingPermissions({
|
||||||
|
variables: {
|
||||||
|
upsertSettingPermissionsInput: {
|
||||||
|
roleId: roleId,
|
||||||
|
settingPermissionKeys:
|
||||||
|
settingsDraftRole.settingPermissions?.map(
|
||||||
|
(settingPermission) => settingPermission.setting,
|
||||||
|
) ?? [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ROLE_BASIC_KEYS.some((key) => key in dirtyFields)) {
|
||||||
|
await updateRole({
|
||||||
|
variables: {
|
||||||
|
updateRoleInput: {
|
||||||
|
id: roleId,
|
||||||
|
update: {
|
||||||
|
label: settingsDraftRole.label,
|
||||||
|
description: settingsDraftRole.description,
|
||||||
|
icon: settingsDraftRole.icon,
|
||||||
|
canUpdateAllSettings: settingsDraftRole.canUpdateAllSettings,
|
||||||
|
canReadAllObjectRecords:
|
||||||
|
settingsDraftRole.canReadAllObjectRecords,
|
||||||
|
canUpdateAllObjectRecords:
|
||||||
|
settingsDraftRole.canUpdateAllObjectRecords,
|
||||||
|
canSoftDeleteAllObjectRecords:
|
||||||
|
settingsDraftRole.canSoftDeleteAllObjectRecords,
|
||||||
|
canDestroyAllObjectRecords:
|
||||||
|
settingsDraftRole.canDestroyAllObjectRecords,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(dirtyFields.objectPermissions)) {
|
||||||
|
await upsertObjectPermissions({
|
||||||
|
variables: {
|
||||||
|
upsertObjectPermissionsInput: {
|
||||||
|
roleId: roleId,
|
||||||
|
objectPermissions:
|
||||||
|
settingsDraftRole.objectPermissions?.map(
|
||||||
|
(objectPermission) => ({
|
||||||
|
objectMetadataId: objectPermission.objectMetadataId,
|
||||||
|
canReadObjectRecords:
|
||||||
|
objectPermission.canReadObjectRecords,
|
||||||
|
canUpdateObjectRecords:
|
||||||
|
objectPermission.canUpdateObjectRecords,
|
||||||
|
canSoftDeleteObjectRecords:
|
||||||
|
objectPermission.canSoftDeleteObjectRecords,
|
||||||
|
canDestroyObjectRecords:
|
||||||
|
objectPermission.canDestroyObjectRecords,
|
||||||
|
}),
|
||||||
|
) ?? [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_ROLES) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await loadCurrentUser();
|
||||||
|
} finally {
|
||||||
|
setIsSaving(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -292,7 +301,11 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
actionButton={
|
actionButton={
|
||||||
isRoleEditable &&
|
isRoleEditable &&
|
||||||
isDirty && (
|
isDirty && (
|
||||||
<SaveAndCancelButtons onSave={handleSave} onCancel={handleCancel} />
|
<SaveAndCancelButtons
|
||||||
|
onSave={handleSave}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
isLoading={isSaving}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -311,7 +324,6 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
|||||||
<SettingsRolePermissions
|
<SettingsRolePermissions
|
||||||
roleId={roleId}
|
roleId={roleId}
|
||||||
isEditable={isRoleEditable}
|
isEditable={isRoleEditable}
|
||||||
isCreateMode={isCreateMode}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{activeTabId === SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.SETTINGS && (
|
{activeTabId === SETTINGS_ROLE_DETAIL_TABS.TABS_IDS.SETTINGS && (
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { SETTINGS_ROLE_DETAIL_TABS } from '@/settings/roles/role/constants/SettingsRoleDetailTabs';
|
import { SETTINGS_ROLE_DETAIL_TABS } from '@/settings/roles/role/constants/SettingsRoleDetailTabs';
|
||||||
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
|
||||||
|
import { settingsPersistedRoleFamilyState } from '@/settings/roles/states/settingsPersistedRoleFamilyState';
|
||||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
@ -16,6 +17,11 @@ export const SettingsRoleCreateEffect = ({
|
|||||||
const setSettingsDraftRole = useSetRecoilState(
|
const setSettingsDraftRole = useSetRecoilState(
|
||||||
settingsDraftRoleFamilyState(roleId),
|
settingsDraftRoleFamilyState(roleId),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const setSettingsPersistedRole = useSetRecoilState(
|
||||||
|
settingsPersistedRoleFamilyState(roleId),
|
||||||
|
);
|
||||||
|
|
||||||
const setActiveTabId = useSetRecoilComponentStateV2(
|
const setActiveTabId = useSetRecoilComponentStateV2(
|
||||||
activeTabIdComponentState,
|
activeTabIdComponentState,
|
||||||
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
||||||
@ -44,9 +50,16 @@ export const SettingsRoleCreateEffect = ({
|
|||||||
workspaceMembers: [],
|
workspaceMembers: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setSettingsPersistedRole(undefined);
|
||||||
setSettingsDraftRole(newRole);
|
setSettingsDraftRole(newRole);
|
||||||
setIsInitialized(true);
|
setIsInitialized(true);
|
||||||
}, [isInitialized, roleId, setActiveTabId, setSettingsDraftRole]);
|
}, [
|
||||||
|
isInitialized,
|
||||||
|
roleId,
|
||||||
|
setActiveTabId,
|
||||||
|
setSettingsDraftRole,
|
||||||
|
setSettingsPersistedRole,
|
||||||
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,16 @@
|
|||||||
import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect';
|
import { SettingsRolesQueryEffect } from '@/settings/roles/components/SettingsRolesQueryEffect';
|
||||||
import { SettingsRole } from '@/settings/roles/role/components/SettingsRole';
|
import { SettingsRole } from '@/settings/roles/role/components/SettingsRole';
|
||||||
import { SettingsRoleCreateEffect } from '@/settings/roles/role/components/SettingsRoleCreateEffect';
|
import { SettingsRoleCreateEffect } from '@/settings/roles/role/components/SettingsRoleCreateEffect';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
export const PENDING_ROLE_ID = 'pending-role-id';
|
|
||||||
|
|
||||||
export const SettingsRoleCreate = () => {
|
export const SettingsRoleCreate = () => {
|
||||||
|
const newRoleId = v4();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsRolesQueryEffect />
|
<SettingsRolesQueryEffect />
|
||||||
<SettingsRoleCreateEffect roleId={PENDING_ROLE_ID} />
|
<SettingsRoleCreateEffect roleId={newRoleId} />
|
||||||
<SettingsRole roleId={PENDING_ROLE_ID} isCreateMode={true} />
|
<SettingsRole roleId={newRoleId} isCreateMode={true} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,21 +3,29 @@ import { SettingsRole } from '@/settings/roles/role/components/SettingsRole';
|
|||||||
import { SettingsRoleEditEffect } from '@/settings/roles/role/components/SettingsRoleEditEffect';
|
import { SettingsRoleEditEffect } from '@/settings/roles/role/components/SettingsRoleEditEffect';
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { Navigate, useParams } from 'react-router-dom';
|
import { Navigate, useParams } from 'react-router-dom';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { settingsPersistedRoleFamilyState } from '~/modules/settings/roles/states/settingsPersistedRoleFamilyState';
|
||||||
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
|
||||||
|
|
||||||
export const SettingsRoleEdit = () => {
|
export const SettingsRoleEdit = () => {
|
||||||
const { roleId } = useParams();
|
const { roleId } = useParams();
|
||||||
|
|
||||||
|
const persistedRole = useRecoilValue(
|
||||||
|
settingsPersistedRoleFamilyState(roleId ?? ''),
|
||||||
|
);
|
||||||
|
|
||||||
if (!isDefined(roleId)) {
|
if (!isDefined(roleId)) {
|
||||||
return <Navigate to={getSettingsPath(SettingsPath.Roles)} />;
|
return <Navigate to={getSettingsPath(SettingsPath.Roles)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isCreateMode = !isDefined(persistedRole?.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsRolesQueryEffect />
|
<SettingsRolesQueryEffect />
|
||||||
<SettingsRoleEditEffect roleId={roleId} />
|
<SettingsRoleEditEffect roleId={roleId} />
|
||||||
<SettingsRole roleId={roleId} isCreateMode={false} />
|
<SettingsRole roleId={roleId} isCreateMode={isCreateMode} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -67,6 +67,7 @@ export class RoleService {
|
|||||||
await this.validateRoleInputOrThrow({ input, workspaceId });
|
await this.validateRoleInputOrThrow({ input, workspaceId });
|
||||||
|
|
||||||
const role = await this.roleRepository.save({
|
const role = await this.roleRepository.save({
|
||||||
|
id: input.id,
|
||||||
label: input.label,
|
label: input.label,
|
||||||
description: input.description,
|
description: input.description,
|
||||||
icon: input.icon,
|
icon: input.icon,
|
||||||
|
|||||||
Reference in New Issue
Block a user