add stories to roles components (#10503)

## Context
Adding stories for roles components. Also moving modules components to
the proper "modules" folder, "pages" folder being only for entry points.

## Test
Run storybook

<img width="1145" alt="Screenshot 2025-02-26 at 13 40 40"
src="https://github.com/user-attachments/assets/bc184ab0-c590-4362-8c5a-1bf5ef176e6c"
/>
<img width="1149" alt="Screenshot 2025-02-26 at 13 40 32"
src="https://github.com/user-attachments/assets/699cd205-31db-45e9-b9c1-caff1832bd47"
/>
<img width="1153" alt="Screenshot 2025-02-26 at 13 40 11"
src="https://github.com/user-attachments/assets/72e45a67-ea89-4999-8b16-6f7d027d07f6"
/>
<img width="471" alt="Screenshot 2025-02-26 at 13 38 16"
src="https://github.com/user-attachments/assets/62676943-9935-42b5-b769-5544f7eed85f"
/>
<img width="472" alt="Screenshot 2025-02-26 at 13 38 12"
src="https://github.com/user-attachments/assets/946baab9-1be4-439e-bf99-0ebeab0995f7"
/>
This commit is contained in:
Weiko
2025-02-26 18:16:05 +01:00
committed by GitHub
parent d40a5ed74f
commit 431da37cdf
34 changed files with 195 additions and 23 deletions

View File

@ -47,6 +47,7 @@ describe('getDisplayNameFromParticipant', () => {
updatedAt: '',
userEmail: '',
userId: '',
colorScheme: 'Light',
},
};

View File

@ -28,6 +28,7 @@ const mockWorkspaceMember = {
firstName: 'John',
lastName: 'Doe',
},
colorScheme: 'Light' as const,
};
const createMockOptions = (): Options<any> => ({
@ -168,6 +169,7 @@ describe('ApolloFactory', () => {
firstName: 'John',
lastName: 'Doe',
},
colorScheme: 'Light' as const,
};
apolloFactory.updateWorkspaceMember(newWorkspaceMember);

View File

@ -42,6 +42,7 @@ describe('useFindManyRecords', () => {
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
name: { firstName: 'John', lastName: 'Connor' },
locale: 'en',
colorScheme: 'Light',
});
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);

View File

@ -73,6 +73,7 @@ describe('useFilteredSearchRecordQuery', () => {
id: '32219445-f587-4c40-b2b1-6d3205ed96da',
name: { firstName: 'John', lastName: 'Connor' },
locale: 'en',
colorScheme: 'Light',
});
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);

View File

@ -2,10 +2,10 @@ import { Table } from '@/ui/layout/table/components/Table';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { RolesTableHeader } from '@/settings/roles/components/RolesTableHeader';
import { RolesTableRow } from '@/settings/roles/components/RolesTableRow';
import { Button, H2Title, IconPlus, Section } from 'twenty-ui';
import { Role } from '~/generated-metadata/graphql';
import { RolesTableHeader } from '~/pages/settings/roles/components/RolesTableHeader';
import { RolesTableRow } from '~/pages/settings/roles/components/RolesTableRow';
const StyledTable = styled(Table)`
margin-top: ${({ theme }) => theme.spacing(0.5)};

View File

@ -44,7 +44,7 @@ export const RolesDefaultRole = ({ roles }: { roles: Role[] }) => {
});
};
if (!currentWorkspace) {
if (!currentWorkspace || !defaultRole) {
return null;
}

View File

@ -0,0 +1,24 @@
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator, RouterDecorator } from 'twenty-ui';
import { Roles } from '@/settings/roles/components/Roles';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { getRolesMock } from '~/testing/mock-data/roles';
const meta: Meta<typeof Roles> = {
title: 'Modules/Settings/Roles/Roles',
component: Roles,
decorators: [ComponentDecorator, I18nFrontDecorator, RouterDecorator],
parameters: {
maxWidth: 800,
},
};
export default meta;
type Story = StoryObj<typeof Roles>;
export const Default: Story = {
args: {
roles: getRolesMock(),
},
};

View File

@ -0,0 +1,43 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { RolesDefaultRole } from '@/settings/roles/components/RolesDefaultRole';
import { Meta, StoryObj } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { ComponentDecorator } from 'twenty-ui';
import { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
import { getRolesMock } from '~/testing/mock-data/roles';
import { mockCurrentWorkspace } from '~/testing/mock-data/users';
const rolesMock = getRolesMock();
const RolesDefaultRoleWrapper = () => {
return (
<RecoilRoot
initializeState={(snapshot) => {
snapshot.set(currentWorkspaceState, {
...mockCurrentWorkspace,
defaultRole: rolesMock[1],
});
}}
>
<RolesDefaultRole roles={rolesMock} />
</RecoilRoot>
);
};
const meta: Meta<typeof RolesDefaultRoleWrapper> = {
title: 'Modules/Settings/Roles/RolesDefaultRole',
component: RolesDefaultRoleWrapper,
decorators: [ComponentDecorator, I18nFrontDecorator],
parameters: {
maxWidth: 800,
},
};
export default meta;
type Story = StoryObj<typeof RolesDefaultRoleWrapper>;
export const Default: Story = {
args: {
roles: rolesMock,
},
};

View File

@ -1,5 +1,8 @@
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
import { RoleAssignmentTableHeader } from '@/settings/roles/role-assignment/components/RoleAssignmentTableHeader';
import { RoleAssignmentWorkspaceMemberPickerDropdown } from '@/settings/roles/role-assignment/components/RoleAssignmentWorkspaceMemberPickerDropdown';
import { RoleAssignmentConfirmationModalSelectedWorkspaceMember } from '@/settings/roles/role-assignment/types/RoleAssignmentConfirmationModalSelectedWorkspaceMember';
import { SettingsPath } from '@/types/SettingsPath';
import { TextInput } from '@/ui/input/components/TextInput';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
@ -25,9 +28,6 @@ import {
useUpdateWorkspaceMemberRoleMutation,
} from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
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 { RoleAssignmentTableRow } from './RoleAssignmentTableRow';

View File

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

View File

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

View File

@ -1,12 +1,12 @@
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useSearchRecords } from '@/object-record/hooks/useSearchRecords';
import { RoleAssignmentWorkspaceMemberPickerDropdownContent } from '@/settings/roles/role-assignment/components/RoleAssignmentWorkspaceMemberPickerDropdownContent';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { ChangeEvent, useState } from 'react';
import { WorkspaceMember } from '~/generated-metadata/graphql';
import { RoleAssignmentWorkspaceMemberPickerDropdownContent } from '~/pages/settings/roles/role-assignment/components/RoleAssignmentWorkspaceMemberPickerDropdownContent';
type RoleAssignmentWorkspaceMemberPickerDropdownProps = {
excludedWorkspaceMemberIds: string[];

View File

@ -1,3 +1,7 @@
import { RolePermissionsObjectsTableHeader } from '@/settings/roles/role-permissions/components/RolePermissionsObjectsTableHeader';
import { RolePermissionsSettingsTableHeader } from '@/settings/roles/role-permissions/components/RolePermissionsSettingsTableHeader';
import { RolePermissionsSettingsTableRow } from '@/settings/roles/role-permissions/components/RolePermissionsSettingsTableRow';
import { RolePermissionsObjectPermission } from '@/settings/roles/types/RolePermissionsObjectPermission';
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import {
@ -10,10 +14,6 @@ import {
} from 'twenty-ui';
import { Role } from '~/generated-metadata/graphql';
import { SettingsPermissions } from '~/generated/graphql';
import { RolePermissionsObjectsTableHeader } from '~/pages/settings/roles/role-permissions/components/RolePermissionsObjectsTableHeader';
import { RolePermissionsSettingsTableHeader } from '~/pages/settings/roles/role-permissions/components/RolePermissionsSettingsTableHeader';
import { RolePermissionsSettingsTableRow } from '~/pages/settings/roles/role-permissions/components/RolePermissionsSettingsTableRow';
import { RolePermissionsObjectPermission } from '~/pages/settings/roles/types/RolePermissionsObjectPermission';
import { RolePermissionsObjectsTableRow } from './RolePermissionsObjectsTableRow';
const StyledRolePermissionsContainer = styled.div`

View File

@ -1,8 +1,8 @@
import { RolePermissionsObjectPermission } from '@/settings/roles/types/RolePermissionsObjectPermission';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { Checkbox } from 'twenty-ui';
import { RolePermissionsObjectPermission } from '~/pages/settings/roles/types/RolePermissionsObjectPermission';
const StyledIconWrapper = styled.div`
align-items: center;

View File

@ -1,8 +1,8 @@
import { RolePermissionsSettingPermission } from '@/settings/roles/types/RolePermissionsSettingPermission';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import styled from '@emotion/styled';
import { Checkbox } from 'twenty-ui';
import { RolePermissionsSettingPermission } from '~/pages/settings/roles/types/RolePermissionsSettingPermission';
const StyledLabel = styled.span`
color: ${({ theme }) => theme.font.color.primary};

View File

@ -24,6 +24,7 @@ const workspaceMember: Omit<
lastName: 'lastName',
},
locale: 'en',
colorScheme: 'System',
};
describe('useColorScheme', () => {

View File

@ -15,7 +15,7 @@ export type WorkspaceMember = {
};
avatarUrl?: string | null;
locale: string | null;
colorScheme?: ColorScheme;
colorScheme: ColorScheme;
createdAt: string;
updatedAt: string;
userEmail: string;

View File

@ -11,16 +11,17 @@ import {
} from 'twenty-ui';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { RoleAssignment } from '@/settings/roles/role-assignment/components/RoleAssignment';
import { RolePermissions } from '@/settings/roles/role-permissions/components/RolePermissions';
import { RoleSettings } from '@/settings/roles/role-settings/components/RoleSettings';
import { SettingsPath } from '@/types/SettingsPath';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { TabList } from '@/ui/layout/tab/components/TabList';
import { useTabList } from '@/ui/layout/tab/hooks/useTabList';
import { useTheme } from '@emotion/react';
import { useGetRolesQuery } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { RolePermissions } from '~/pages/settings/roles/role-permissions/components/RolePermissions';
import { RoleSettings } from '~/pages/settings/roles/role-settings/components/RoleSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { RoleAssignment } from './role-assignment/components/RoleAssignment';
const StyledContentContainer = styled.div`
flex: 1;
@ -49,6 +50,7 @@ export const SETTINGS_ROLE_DETAIL_TABS = {
export const SettingsRoleEdit = () => {
const { roleId = '' } = useParams();
const theme = useTheme();
const navigateSettings = useNavigateSettings();
const { data: rolesData, loading: rolesLoading } = useGetRolesQuery({
fetchPolicy: 'network-only',
@ -106,7 +108,7 @@ export const SettingsRoleEdit = () => {
<SubMenuTopBarContainer
title={
<StyledTitleContainer>
<StyledIconUser size={16} />
<StyledIconUser size={theme.icon.size.md} />
<H3Title title={role.label} />
</StyledTitleContainer>
}

View File

@ -1,11 +1,11 @@
import { Trans, useLingui } from '@lingui/react/macro';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { Roles } from '@/settings/roles/components/Roles';
import { RolesDefaultRole } from '@/settings/roles/components/RolesDefaultRole';
import { SettingsPath } from '@/types/SettingsPath';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { useGetRolesQuery } from '~/generated/graphql';
import { Roles } from '~/pages/settings/roles/components/Roles';
import { RolesDefaultRole } from '~/pages/settings/roles/components/RolesDefaultRole';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
export const SettingsRoles = () => {

View File

@ -0,0 +1,30 @@
import { Meta, StoryObj } from '@storybook/react';
import {
PageDecorator,
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsRoleEdit } from '../SettingsRoleEdit';
const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Roles/SettingsRoleEdit',
component: SettingsRoleEdit,
decorators: [PageDecorator],
args: {
routePath: '/settings/roles/:roleId',
routeParams: {
':roleId': '1',
},
},
parameters: {
msw: graphqlMocks,
},
};
export default meta;
export type Story = StoryObj<typeof SettingsRoleEdit>;
export const Default: Story = {};

View File

@ -0,0 +1,25 @@
import { Meta, StoryObj } from '@storybook/react';
import {
PageDecorator,
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { SettingsRoles } from '../SettingsRoles';
const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Roles/SettingsRoles',
component: SettingsRoles,
decorators: [PageDecorator],
args: { routePath: '/settings/roles' },
parameters: {
msw: graphqlMocks,
},
};
export default meta;
export type Story = StoryObj<typeof SettingsRoles>;
export const Default: Story = {};

View File

@ -21,7 +21,9 @@ import { mockedViewsData } from '~/testing/mock-data/views';
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
import { GET_PUBLIC_WORKSPACE_DATA_BY_DOMAIN } from '@/auth/graphql/queries/getPublicWorkspaceDataByDomain';
import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery';
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
import { getRolesMock } from '~/testing/mock-data/roles';
import { mockedTasks } from '~/testing/mock-data/tasks';
import {
getWorkflowMock,
@ -719,6 +721,13 @@ export const graphqlMocks = {
},
});
}),
graphql.query(getOperationName(GET_ROLES) ?? '', () => {
return HttpResponse.json({
data: {
getRoles: getRolesMock(),
},
});
}),
http.get('https://chat-assets.frontapp.com/v1/chat.bundle.js', () => {
return HttpResponse.text(
`

View File

@ -0,0 +1,33 @@
import { Role } from '~/generated/graphql';
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
const rolesMock: Role[] = [
{
__typename: 'Role',
id: '1',
label: 'Admin',
canDestroyAllObjectRecords: true,
canReadAllObjectRecords: true,
canSoftDeleteAllObjectRecords: true,
canUpdateAllObjectRecords: true,
canUpdateAllSettings: true,
isEditable: false,
workspaceMembers: [mockWorkspaceMembers[0]],
},
{
__typename: 'Role',
id: '2',
label: 'Guest',
canDestroyAllObjectRecords: false,
canReadAllObjectRecords: false,
canSoftDeleteAllObjectRecords: false,
canUpdateAllObjectRecords: false,
canUpdateAllSettings: false,
isEditable: true,
workspaceMembers: [mockWorkspaceMembers[1]],
},
];
export const getRolesMock = () => {
return rolesMock;
};