add role update (#11217)

## Context
This PR introduces the new Create and Edit role components, behind the
PERMISSIONS_ENABLED_V2 feature flag.
This commit is contained in:
Weiko
2025-03-31 17:57:14 +02:00
committed by GitHub
parent 3c9bf2294f
commit 06ff16e086
58 changed files with 1527 additions and 624 deletions
@@ -1,47 +0,0 @@
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { Section } from 'twenty-ui';
import { Role } from '~/generated-metadata/graphql';
const StyledInputsContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
width: 100%;
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
const StyledInputContainer = styled.div`
display: flex;
flex-direction: column;
`;
type RoleSettingsProps = {
role: Pick<Role, 'id' | 'label' | 'description' | 'icon'>;
};
export const RoleSettings = ({ role }: RoleSettingsProps) => {
return (
<Section>
<StyledInputsContainer>
<StyledInputContainer>
<IconPicker
disabled={true}
selectedIconKey={role.icon ?? 'IconUser'}
onChange={() => {}}
/>
</StyledInputContainer>
<TextInput value={role.label} disabled fullWidth />
</StyledInputsContainer>
<TextArea
minRows={4}
placeholder={t`Write a description`}
value={role.description || ''}
disabled
/>
</Section>
);
};
@@ -0,0 +1,79 @@
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { TextArea } from '@/ui/input/components/TextArea';
import { TextInput } from '@/ui/input/components/TextInput';
import { useRecoilState } from 'recoil';
import { Section } from 'twenty-ui';
const StyledInputsContainer = styled.div`
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
width: 100%;
margin-bottom: ${({ theme }) => theme.spacing(2)};
`;
const StyledInputContainer = styled.div`
display: flex;
flex-direction: column;
`;
type SettingsRoleSettingsProps = {
roleId: string;
isEditable: boolean;
};
export const SettingsRoleSettings = ({
roleId,
isEditable,
}: SettingsRoleSettingsProps) => {
const [settingsDraftRole, setSettingsDraftRole] = useRecoilState(
settingsDraftRoleFamilyState(roleId),
);
return (
<Section>
<StyledInputsContainer>
<StyledInputContainer>
<IconPicker
selectedIconKey={settingsDraftRole.icon ?? 'IconUser'}
dropdownId="role-settings-icon-picker"
onChange={({ iconKey }: { iconKey: string }) => {
setSettingsDraftRole({
...settingsDraftRole,
icon: iconKey,
});
}}
disabled={!isEditable}
/>
</StyledInputContainer>
<TextInput
value={settingsDraftRole.label}
fullWidth
onChange={(value: string) => {
setSettingsDraftRole({
...settingsDraftRole,
label: value,
});
}}
placeholder={t`Role name`}
disabled={!isEditable}
/>
</StyledInputsContainer>
<TextArea
minRows={4}
placeholder={t`Write a description`}
value={settingsDraftRole.description || ''}
onChange={(value: string) => {
setSettingsDraftRole({
...settingsDraftRole,
description: value,
});
}}
disabled={!isEditable}
/>
</Section>
);
};
@@ -0,0 +1,56 @@
import { SettingsRoleSettings } from '@/settings/roles/role-settings/components/SettingsRoleSettings';
import { settingsDraftRoleFamilyState } from '@/settings/roles/states/settingsDraftRoleFamilyState';
import { Meta, StoryObj } from '@storybook/react';
import { useSetRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
import { PENDING_ROLE_ID } from '~/pages/settings/roles/SettingsRoleCreate';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { getRolesMock } from '~/testing/mock-data/roles';
const SettingsRoleSettingsWrapper = (
args: React.ComponentProps<typeof SettingsRoleSettings>,
) => {
const setDraftRole = useSetRecoilState(
settingsDraftRoleFamilyState(args.roleId),
);
const role = getRolesMock().find((role) => role.id === args.roleId);
if (isDefined(role)) {
setDraftRole(role);
}
return (
<SettingsRoleSettings roleId={args.roleId} isEditable={args.isEditable} />
);
};
const meta: Meta<typeof SettingsRoleSettingsWrapper> = {
title: 'Modules/Settings/Roles/RoleSettings/SettingsRoleSettings',
component: SettingsRoleSettingsWrapper,
decorators: [RouterDecorator, ComponentDecorator, I18nFrontDecorator],
};
export default meta;
type Story = StoryObj<typeof SettingsRoleSettingsWrapper>;
export const Default: Story = {
args: {
roleId: '1',
isEditable: true,
},
};
export const ReadOnly: Story = {
args: {
roleId: '1',
isEditable: false,
},
};
export const PendingRole: Story = {
args: {
roleId: PENDING_ROLE_ID,
},
};