Migrate to a monorepo structure (#2909)

This commit is contained in:
Charles Bochet
2023-12-10 18:10:54 +01:00
committed by GitHub
parent a70a9281eb
commit 5bdca9de6c
2304 changed files with 37152 additions and 25869 deletions

View File

@ -0,0 +1,28 @@
import styled from '@emotion/styled';
const StyledLayout = styled.div<{ width?: number }>`
background: ${({ theme }) => theme.background.primary};
border: 1px solid ${({ theme }) => theme.border.color.light};
border-radius: 5px;
display: flex;
flex-direction: row;
height: fit-content;
max-width: calc(100% - 40px);
min-width: ${({ width }) => (width ? 'unset' : '300px')};
padding: 20px;
width: ${({ width }) => (width ? width + 'px' : 'fit-content')};
`;
type ComponentStorybookLayoutProps = {
width?: number;
children: JSX.Element;
};
export const ComponentStorybookLayout = ({
width,
children,
}: ComponentStorybookLayoutProps) => (
<StyledLayout width={width}>{children}</StyledLayout>
);

View File

@ -0,0 +1,16 @@
import styled from '@emotion/styled';
const StyledLayout = styled.div`
display: flex;
flex-direction: row;
height: calc(100vh - 32px);
width: calc(100vw - 32px);
`;
type FullHeightStorybookLayoutProps = {
children: JSX.Element;
};
export const FullHeightStorybookLayout = ({
children,
}: FullHeightStorybookLayoutProps) => <StyledLayout>{children}</StyledLayout>;

View File

@ -0,0 +1,18 @@
import { useEffect } from 'react';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
export const InitializeHotkeyStorybookHookEffect = () => {
const setHotkeyScope = useSetHotkeyScope();
useEffect(() => {
setHotkeyScope(AppHotkeyScope.App, {
commandMenu: true,
goto: false,
keyboardShortcutMenu: false,
});
}, [setHotkeyScope]);
return <></>;
};

View File

@ -0,0 +1,160 @@
import { ComponentProps, JSX } from 'react';
import styled from '@emotion/styled';
import { isNumber, isString } from '@sniptt/guards';
import { Decorator } from '@storybook/react';
const StyledColumnTitle = styled.h1`
font-size: ${({ theme }) => theme.font.size.lg};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowsTitle = styled.h2`
color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
width: 100px;
`;
const StyledRowTitle = styled.h3`
color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
width: 100px;
`;
const StyledElementTitle = styled.span`
color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-bottom: ${({ theme }) => theme.spacing(1)};
text-align: center;
text-transform: uppercase;
`;
const StyledContainer = styled.div`
display: flex;
flex-direction: row;
`;
const StyledColumnContainer = styled.div`
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowsContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledRowContainer = styled.div`
display: flex;
flex: 1;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledElementContainer = styled.div<{ width: number }>`
display: flex;
${({ width }) => width && `min-width: ${width}px;`}
`;
const StyledCellContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
const emptyDimension = {
name: '',
values: [undefined],
props: () => ({}),
} as CatalogDimension;
const isStringOrNumber = (term: unknown): term is string | number =>
isString(term) || isNumber(term);
export type CatalogDimension<
ComponentType extends React.ElementType = () => JSX.Element,
> = {
name: string;
values: any[];
props: (value: any) => Partial<ComponentProps<ComponentType>>;
labels?: (value: any) => string;
};
export type CatalogOptions = {
elementContainer?: {
width?: number;
};
};
export const CatalogDecorator: Decorator = (Story, context) => {
const {
catalog: { dimensions, options },
} = context.parameters;
const [
dimension1,
dimension2 = emptyDimension,
dimension3 = emptyDimension,
dimension4 = emptyDimension,
] = dimensions as CatalogDimension[];
return (
<StyledContainer>
{dimension4.values.map((value4: any) => (
<StyledColumnContainer key={value4}>
<StyledColumnTitle>
{dimension4.labels?.(value4) ??
(isStringOrNumber(value4) ? value4 : '')}
</StyledColumnTitle>
{dimension3.values.map((value3: any) => (
<StyledRowsContainer key={value3}>
<StyledRowsTitle>
{dimension3.labels?.(value3) ??
(isStringOrNumber(value3) ? value3 : '')}
</StyledRowsTitle>
{dimension2.values.map((value2: any) => (
<StyledRowContainer key={value2}>
<StyledRowTitle>
{dimension2.labels?.(value2) ??
(isStringOrNumber(value2) ? value2 : '')}
</StyledRowTitle>
{dimension1.values.map((value1: any) => {
return (
<StyledCellContainer key={value1} id={value1}>
<StyledElementTitle>
{dimension1.labels?.(value1) ??
(isStringOrNumber(value1) ? value1 : '')}
</StyledElementTitle>
<StyledElementContainer
width={options?.elementContainer?.width}
>
<Story
args={{
...context.args,
...dimension1.props(value1),
...dimension2.props(value2),
...dimension3.props(value3),
...dimension4.props(value4),
}}
/>
</StyledElementContainer>
</StyledCellContainer>
);
})}
</StyledRowContainer>
))}
</StyledRowsContainer>
))}
</StyledColumnContainer>
))}
</StyledContainer>
);
};

View File

@ -0,0 +1,13 @@
import { Decorator } from '@storybook/react';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentDecorator: Decorator = (Story, context) => {
const { container } = context.parameters;
return (
<ComponentStorybookLayout width={container?.width}>
<Story />
</ComponentStorybookLayout>
);
};

View File

@ -0,0 +1,14 @@
import { Decorator } from '@storybook/react';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
export const ComponentWithRecoilScopeDecorator: Decorator = (
Story,
context,
) => (
<RecoilScope
CustomRecoilScopeContext={context.parameters.customRecoilScopeContext}
>
<Story />
</RecoilScope>
);

View File

@ -0,0 +1,12 @@
import { MemoryRouter } from 'react-router-dom';
import { Decorator } from '@storybook/react';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentWithRouterDecorator: Decorator = (Story) => (
<ComponentStorybookLayout>
<MemoryRouter>
<Story />
</MemoryRouter>
</ComponentStorybookLayout>
);

View File

@ -0,0 +1,9 @@
import { Decorator } from '@storybook/react';
import { ObjectMetadataItemsProvider } from '@/object-metadata/components/ObjectMetadataItemsProvider';
export const ObjectMetadataItemsDecorator: Decorator = (Story) => (
<ObjectMetadataItemsProvider>
<Story />
</ObjectMetadataItemsProvider>
);

View File

@ -0,0 +1,59 @@
import { HelmetProvider } from 'react-helmet-async';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { Decorator } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider';
import { DefaultLayout } from '~/modules/ui/layout/page/DefaultLayout';
import { UserProvider } from '~/modules/users/components/UserProvider';
import { FullHeightStorybookLayout } from '../FullHeightStorybookLayout';
export type PageDecoratorArgs = {
routePath: string;
routeParams: RouteParams;
};
type RouteParams = {
[param: string]: string;
};
const computeLocation = (routePath: string, routeParams: RouteParams) => {
return {
pathname: routePath.replace(
/:(\w+)/g,
(paramName) => routeParams[paramName] ?? '',
),
};
};
export const PageDecorator: Decorator<{
routePath: string;
routeParams: RouteParams;
}> = (Story, { args }) => (
<RecoilRoot>
<UserProvider>
<ClientConfigProvider>
<MemoryRouter
initialEntries={[computeLocation(args.routePath, args.routeParams)]}
>
<FullHeightStorybookLayout>
<HelmetProvider>
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
<RelationPickerScope relationPickerScopeId="relation-picker">
<DefaultLayout>
<Routes>
<Route path={args.routePath} element={<Story />} />
</Routes>
</DefaultLayout>
</RelationPickerScope>
</SnackBarProviderScope>
</HelmetProvider>
</FullHeightStorybookLayout>
</MemoryRouter>
</ClientConfigProvider>
</UserProvider>
</RecoilRoot>
);

View File

@ -0,0 +1,9 @@
import { Decorator } from '@storybook/react';
import { RelationPickerScope } from '@/object-record/relation-picker/scopes/RelationPickerScope';
export const RelationPickerDecorator: Decorator = (Story) => (
<RelationPickerScope relationPickerScopeId="relation-picker">
<Story />
</RelationPickerScope>
);

View File

@ -0,0 +1,19 @@
import { ApolloProvider } from '@apollo/client';
import { Decorator } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { ApolloMetadataClientProvider } from '@/object-metadata/components/ApolloMetadataClientProvider';
import { InitializeHotkeyStorybookHookEffect } from '../InitializeHotkeyStorybookHook';
import { mockedClient } from '../mockedClient';
export const RootDecorator: Decorator = (Story) => (
<RecoilRoot>
<ApolloProvider client={mockedClient}>
<ApolloMetadataClientProvider>
<InitializeHotkeyStorybookHookEffect />
<Story />
</ApolloMetadataClientProvider>
</ApolloProvider>
</RecoilRoot>
);

View File

@ -0,0 +1,9 @@
import { Decorator } from '@storybook/react';
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
export const SnackBarDecorator: Decorator = (Story) => (
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
<Story />
</SnackBarProviderScope>
);

View File

@ -0,0 +1,168 @@
import { getOperationName } from '@apollo/client/utilities';
import { graphql } from 'msw';
import { CREATE_EVENT } from '@/analytics/graphql/queries/createEvent';
import { GET_CLIENT_CONFIG } from '@/client-config/graphql/queries/getClientConfig';
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
import { mockedActivities } from '~/testing/mock-data/activities';
import { mockedCompaniesData } from './mock-data/companies';
import { mockedObjectMetadataItems } from './mock-data/metadata';
import { mockedPeopleData } from './mock-data/people';
import { mockedUsersData } from './mock-data/users';
import { mockedViewFieldsData } from './mock-data/view-fields';
import { mockedViewsData } from './mock-data/views';
const metadataGraphql = graphql.link(
`${process.env.REACT_APP_SERVER_BASE_URL}/metadata`,
);
export const graphqlMocks = {
handlers: [
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', (req, res, ctx) => {
return res(
ctx.data({
currentUser: mockedUsersData[0],
}),
);
}),
graphql.mutation(getOperationName(CREATE_EVENT) ?? '', (req, res, ctx) => {
return res(
ctx.data({
createEvent: { success: 1, __typename: 'Event' },
}),
);
}),
graphql.query(
getOperationName(GET_CLIENT_CONFIG) ?? '',
(req, res, ctx) => {
return res(
ctx.data({
clientConfig: {
signInPrefilled: true,
dataModelSettingsEnabled: true,
developersSettingsEnabled: true,
debugMode: false,
authProviders: { google: true, password: true, magicLink: false },
telemetry: { enabled: false, anonymizationEnabled: true },
support: {
supportDriver: 'front',
supportFrontChatId: null,
},
},
}),
);
},
),
metadataGraphql.query(
getOperationName(FIND_MANY_OBJECT_METADATA_ITEMS) ?? '',
(req, res, ctx) => {
return res(ctx.data({ objects: mockedObjectMetadataItems }));
},
),
graphql.query('FindManyViews', (req, res, ctx) => {
const objectMetadataId = req.variables.filter.objectMetadataId.eq;
const viewType = req.variables.filter.type.eq;
return res(
ctx.data({
views: {
edges: mockedViewsData
.filter(
(view) =>
view.objectMetadataId === objectMetadataId &&
view.type === viewType,
)
.map((view) => ({
node: view,
cursor: null,
})),
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
},
}),
);
}),
graphql.query('FindManyViewFields', (req, res, ctx) => {
const viewId = req.variables.filter.view.eq;
return res(
ctx.data({
viewFields: {
edges: mockedViewFieldsData
.filter((viewField) => viewField.viewId === viewId)
.map((viewField) => ({
node: viewField,
cursor: null,
})),
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
},
}),
);
}),
graphql.query('FindManyCompanies', (req, res, ctx) => {
return res(
ctx.data({
companies: {
edges: mockedCompaniesData.map((company) => ({
node: company,
cursor: null,
})),
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
},
}),
);
}),
graphql.query('FindManyPeople', (req, res, ctx) => {
return res(
ctx.data({
people: {
edges: mockedPeopleData.map((person) => ({
node: person,
cursor: null,
})),
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
},
}),
);
}),
graphql.query('FindManyActivities', (req, res, ctx) => {
return res(
ctx.data({
activities: {
edges: mockedActivities.map((activities) => ({
node: activities,
cursor: null,
})),
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
},
}),
);
}),
],
};

View File

@ -0,0 +1,224 @@
import { Activity } from '@/activities/types/Activity';
import { ActivityTarget } from '@/activities/types/ActivityTarget';
import { Comment } from '@/activities/types/Comment';
import { Company } from '@/companies/types/Company';
import { Person } from '@/people/types/Person';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
type MockedActivity = Pick<
Activity,
| 'id'
| 'createdAt'
| 'updatedAt'
| '__typename'
| 'type'
| 'body'
| 'title'
| 'authorId'
| 'dueAt'
| 'completedAt'
> & {
author: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'>;
assignee: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'>;
comments: Comment[];
activityTargets: Array<
Pick<
ActivityTarget,
| 'id'
| '__typename'
| 'createdAt'
| 'updatedAt'
| 'activityId'
| 'personId'
| 'companyId'
> & {
activity: Pick<Activity, 'id' | 'createdAt' | 'updatedAt'>;
person?: Pick<Person, 'id' | 'name' | 'avatarUrl'> | null;
company?: Pick<Company, 'id' | 'name' | 'domainName'> | null;
}
>;
};
export const mockedTasks: Array<MockedActivity> = [
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first task',
type: 'Task',
body: '',
dueAt: '2023-04-26T10:12:42.33625+00:00',
completedAt: null,
author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
comments: [],
activityTargets: [],
__typename: 'Activity',
},
];
export const mockedActivities: Array<MockedActivity> = [
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
title: 'My very first note',
type: 'Note',
body: '',
dueAt: '2023-04-26T10:12:42.33625+00:00',
completedAt: null,
author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
comments: [],
activityTargets: [
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb300',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
personId: null,
companyId: '89bb825c-171e-4bcc-9cf7-43448d6fb280',
company: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb280',
name: 'Airbnb',
domainName: 'airbnb.com',
},
person: null,
activityId: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
activity: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
},
__typename: 'ActivityTarget',
},
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb301',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
personId: null,
companyId: 'b396e6b9-dc5c-4643-bcff-61b6cf7523ae',
company: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
name: 'Aircall',
domainName: 'aircall.io',
},
person: null,
activityId: 'b396e6b9-dc5c-4643-bcff-61b6cf7523ae',
activity: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb231',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
__typename: 'ActivityTarget',
},
],
__typename: 'Activity',
},
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278a',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
title: 'Another note',
body: '',
type: 'Note',
completedAt: null,
dueAt: '2029-08-26T10:12:42.33625+00:00',
author: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
assignee: {
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: '',
},
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
comments: [],
activityTargets: [
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278t',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
personId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b', // Alexandre
person: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
name: {
firstName: 'Alexandre',
lastName: 'Test',
},
avatarUrl: '',
},
company: null,
companyId: null,
activityId: '89bb825c-171e-4bcc-9cf7-43448d6fb278a',
activity: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278a',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
},
__typename: 'ActivityTarget',
},
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb279t',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
personId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d', // Jean d'Eau
companyId: null,
company: null,
person: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
name: {
firstName: 'Jean',
lastName: "d'Eau",
},
avatarUrl: '',
},
activityId: '89bb825c-171e-4bcc-9cf7-43448d6fb278a',
activity: {
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278a',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
},
__typename: 'ActivityTarget',
},
],
__typename: 'Activity',
},
];

View File

@ -0,0 +1,29 @@
import { ApiKey } from '@/settings/developers/types/ApiKey';
type MockedApiKey = Pick<
ApiKey,
'id' | 'name' | 'createdAt' | 'updatedAt' | 'expiresAt'
>;
export const mockedApiKeys: Array<MockedApiKey> = [
{
id: 'f7c6d736-8fcd-4e9c-ab99-28f6a9031570',
name: 'Zapier Integration',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
expiresAt: '2100-11-06T23:59:59.825Z',
},
{
id: 'f7c6d736-8fcd-4e9c-ab99-28f6a9031571',
name: 'Gmail Integration',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
expiresAt: '2100-11-06T23:59:59.825Z',
},
{
id: 'f7c6d736-8fcd-4e9c-ab99-28f6a9031572',
name: 'Github Integration',
createdAt: '2023-04-26T10:12:42.33625+00:00',
updatedAt: '2023-04-26T10:23:42.33625+00:00',
expiresAt: '2022-11-06T23:59:59.825Z',
},
];

View File

@ -0,0 +1,196 @@
import { Company } from '@/companies/types/Company';
import { Favorite } from '@/favorites/types/Favorite';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { mockedUsersData } from './users';
type MockedCompany = Pick<
Company,
| 'id'
| 'name'
| 'domainName'
| 'createdAt'
| 'address'
| 'employees'
| 'linkedinUrl'
| 'xUrl'
| 'annualRecurringRevenue'
| 'idealCustomerProfile'
| 'accountOwnerId'
> & {
accountOwner: Pick<WorkspaceMember, 'id' | 'avatarUrl' | 'name'> | null;
Favorite: Pick<Favorite, 'id'> | null;
};
export const mockedCompaniesData: Array<MockedCompany> = [
{
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
domainName: 'airbnb.com',
name: 'Airbnb',
createdAt: '2023-04-26T10:08:54.724515+00:00',
address: '17 rue de clignancourt',
employees: 12,
linkedinUrl: {
url: 'https://www.linkedin.com/company/airbnb/',
label: 'https://www.linkedin.com/company/airbnb/',
},
xUrl: {
url: 'https://twitter.com/airbnb',
label: 'https://twitter.com/airbnb',
},
annualRecurringRevenue: { amountMicros: 5000000, currencyCode: 'USD' },
idealCustomerProfile: true,
Favorite: null,
accountOwnerId: mockedUsersData[0].id,
accountOwner: {
name: {
firstName: 'Charles',
lastName: 'Test',
},
avatarUrl: null,
id: mockedUsersData[0].id,
},
},
{
id: 'b396e6b9-dc5c-4643-bcff-61b6cf7523ae',
domainName: 'aircall.io',
name: 'Aircall',
createdAt: '2023-04-26T10:12:42.33625+00:00',
address: '',
employees: 1,
accountOwnerId: null,
linkedinUrl: {
url: 'https://www.linkedin.com/company/aircall/',
label: 'https://www.linkedin.com/company/aircall/',
},
xUrl: {
url: 'https://twitter.com/aircall',
label: 'https://twitter.com/aircall',
},
annualRecurringRevenue: { amountMicros: 500000, currencyCode: 'USD' },
idealCustomerProfile: false,
accountOwner: null,
Favorite: null,
},
{
id: 'a674fa6c-1455-4c57-afaf-dd5dc086361d',
domainName: 'algolia.com',
name: 'Algolia',
createdAt: '2023-04-26T10:10:32.530184+00:00',
address: '',
employees: 1,
linkedinUrl: {
url: 'https://www.linkedin.com/company/algolia/',
label: 'https://www.linkedin.com/company/algolia/',
},
xUrl: {
url: 'https://twitter.com/algolia',
label: 'https://twitter.com/algolia',
},
annualRecurringRevenue: { amountMicros: 5000000, currencyCode: 'USD' },
idealCustomerProfile: true,
accountOwner: null,
Favorite: null,
accountOwnerId: null,
},
{
id: 'b1cfd51b-a831-455f-ba07-4e30671e1dc3',
domainName: 'apple.com',
name: 'Apple',
createdAt: '2023-03-21T06:30:25.39474+00:00',
address: '',
employees: 10,
linkedinUrl: {
url: 'https://www.linkedin.com/company/apple/',
label: 'https://www.linkedin.com/company/apple/',
},
xUrl: {
url: 'https://twitter.com/apple',
label: 'https://twitter.com/apple',
},
annualRecurringRevenue: { amountMicros: 1000000, currencyCode: 'USD' },
idealCustomerProfile: false,
accountOwner: null,
Favorite: null,
accountOwnerId: null,
},
{
id: '5c21e19e-e049-4393-8c09-3e3f8fb09ecb',
domainName: 'qonto.com',
name: 'Qonto',
createdAt: '2023-04-26T10:13:29.712485+00:00',
address: '10 rue de la Paix',
employees: 1,
linkedinUrl: {
url: 'https://www.linkedin.com/company/qonto/',
label: 'https://www.linkedin.com/company/qonto/',
},
xUrl: {
url: 'https://twitter.com/qonto',
label: 'https://twitter.com/qonto',
},
annualRecurringRevenue: { amountMicros: 5000000, currencyCode: 'USD' },
idealCustomerProfile: false,
accountOwner: null,
Favorite: null,
accountOwnerId: null,
},
{
id: '9d162de6-cfbf-4156-a790-e39854dcd4eb',
domainName: 'facebook.com',
name: 'Facebook',
createdAt: '2023-04-26T10:09:25.656555+00:00',
address: '',
employees: 1,
linkedinUrl: {
url: 'https://www.linkedin.com/company/facebook/',
label: 'https://www.linkedin.com/company/facebook/',
},
xUrl: {
url: 'https://twitter.com/facebook',
label: 'https://twitter.com/facebook',
},
annualRecurringRevenue: { amountMicros: 5000000, currencyCode: 'USD' },
idealCustomerProfile: true,
accountOwner: null,
Favorite: null,
accountOwnerId: null,
},
{
id: '9d162de6-cfbf-4156-a790-e39854dcd4ef',
domainName: 'sequoia.com',
name: 'Sequoia',
createdAt: '2023-04-26T10:09:25.656555+00:00',
address: '',
employees: 1,
linkedinUrl: {
url: 'https://www.linkedin.com/company/sequoia/',
label: 'https://www.linkedin.com/company/sequoia/',
},
xUrl: {
url: 'https://twitter.com/sequoia',
label: 'https://twitter.com/sequoia',
},
annualRecurringRevenue: { amountMicros: 5000000, currencyCode: 'USD' },
idealCustomerProfile: true,
accountOwner: null,
Favorite: null,
accountOwnerId: null,
},
];
export const mockedEmptyCompanyData = {
id: '9231e6ee-4cc2-4c7b-8c55-dff16f4d968a',
name: '',
domainName: '',
address: '',
accountOwner: null,
annualRecurringRevenue: null,
createdAt: null,
employees: null,
idealCustomerProfile: null,
linkedinUrl: null,
xUrl: null,
_activityCount: null,
__typename: 'Company',
};

View File

@ -0,0 +1,161 @@
import { isObject, isString } from '@sniptt/guards';
import { GraphQLVariables } from 'msw';
import { isDefined } from '../../utils/isDefined';
type StringFilter = {
equals?: string;
contains?: string;
in?: Array<string>;
notIn?: Array<string>;
};
const filterData = <DataT>(
data: Array<DataT>,
where: Record<string, any>,
): Array<DataT> =>
data.filter((item) => {
// { firstName: {contains: '%string%' }}
// { lastName: {equals: 'string' }}
// { is: { company: { equals: 'string' }}}
let isMatch: boolean = (
Object.keys(where) as Array<keyof typeof where>
).every((key) => {
if (!['OR', 'AND', 'NOT'].includes(key)) {
const filterElement = where[key] as StringFilter & { is?: object };
if (filterElement.is) {
const nestedKey = Object.keys(filterElement.is)[0] as string;
if (
item[key as keyof typeof item] &&
isObject(item[key as keyof typeof item])
) {
const nestedItem = item[key as keyof typeof item];
return (
nestedItem[nestedKey as keyof typeof nestedItem] ===
(
filterElement.is[
nestedKey as keyof typeof filterElement.is
] as StringFilter
).equals
);
}
}
if (filterElement.equals) {
return item[key as keyof typeof item] === filterElement.equals;
}
if (filterElement.contains) {
return (item[key as keyof typeof item] as string)
.toLocaleLowerCase()
.includes(
filterElement.contains.replaceAll('%', '').toLocaleLowerCase(),
);
}
if (filterElement.in) {
const itemValue = item[key as keyof typeof item] as string;
return filterElement.in.includes(itemValue);
}
if (filterElement.notIn) {
const itemValue = item[key as keyof typeof item] as string;
if (filterElement.notIn.length === 0) return true;
return !filterElement.notIn.includes(itemValue);
}
}
return false;
});
// { OR: [{ firstName: filter }, { lastName: filter }]
if (where.OR && Array.isArray(where.OR)) {
isMatch =
isMatch ||
where.OR.some((orFilter) =>
filterData<DataT>(data, orFilter).includes(item),
);
}
if (where.AND && Array.isArray(where.AND)) {
isMatch =
isMatch ||
where.AND.every((andFilter) =>
filterData<DataT>(data, andFilter).includes(item),
);
}
return isMatch;
});
export const filterAndSortData = <DataT>(
data: Array<DataT>,
where?: Record<string, any>,
orderBy?: Array<any>,
limit?: number,
): Array<DataT> => {
let filteredData = data;
if (where) {
filteredData = filterData<DataT>(data, where);
}
if (Array.isArray(orderBy) && orderBy.length > 0 && orderBy[0]) {
const firstOrderBy = orderBy[0];
const key = Object.keys(firstOrderBy)[0];
filteredData.sort((itemA, itemB) => {
const itemAValue = itemA[key as unknown as keyof typeof itemA];
const itemBValue = itemB[key as unknown as keyof typeof itemB];
if (!itemAValue || !itemBValue) {
return 0;
}
const sortDirection =
firstOrderBy[key as unknown as keyof typeof firstOrderBy];
if (isString(itemAValue) && isString(itemBValue)) {
return sortDirection === 'desc'
? itemBValue.localeCompare(itemAValue)
: -itemBValue.localeCompare(itemAValue);
}
return 0;
});
}
if (limit) {
filteredData = filteredData.slice(0, limit);
}
return filteredData;
};
export const fetchOneFromData = <DataT extends { id: string }>(
data: Array<DataT>,
id: string,
): DataT | undefined => {
if (!isDefined(id)) {
throw new Error(
`id is not defined in updateOneFromData, check that you provided where.id if needed.`,
);
}
return data.filter((item) => item.id === id)[0];
};
export const updateOneFromData = <DataT extends { id: string }>(
data: Array<DataT>,
id: string | undefined,
payload: GraphQLVariables,
): DataT | undefined => {
if (!isDefined(id)) {
throw new Error(
`id is not defined in updateOneFromData, check that you provided where.id if needed.`,
);
}
const object = data.filter((item) => item.id === id)[0];
const newObject = Object.assign(object, payload);
return newObject;
};

View File

@ -0,0 +1,2 @@
export const mockedUserJWT =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzNzRmZTNhNS1kZjFlLTQxMTktYWZlMC0yYTYyYTJiYTQ4MWUiLCJ3b3Jrc3BhY2VJZCI6InR3ZW50eS03ZWQ5ZDIxMi0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJpYXQiOjE2ODY5OTMxODIsImV4cCI6MTY4Njk5MzQ4Mn0.F_FD6nJ5fssR_47v2XFhtzqjr-wrEQpqaWVq8iIlLJw';

View File

@ -0,0 +1,970 @@
import {
FieldMetadataType,
RelationMetadataType,
} from '~/generated-metadata/graphql';
export const mockedPeopleMetadata = {
node: {
__typename: 'object',
id: '20202020-c64b-44bc-bd2c-502c99f49dca',
nameSingular: 'person',
namePlural: 'people',
labelSingular: 'Person',
labelPlural: 'People',
description: 'A person',
icon: 'IconUser',
isCustom: false,
isActive: true,
isSystem: false,
createdAt: '2023-11-24T03:29:18.207Z',
updatedAt: '2023-11-24T03:29:18.207Z',
fields: {
edges: [
{
node: {
__typename: 'field',
id: '20202020-2bf4-42b8-8718-a3e852bfa6a6',
type: 'DATE_TIME',
name: 'updatedAt',
label: 'Update date',
description: null,
icon: 'IconCalendar',
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-03cd-4cd0-9afc-92077b69f24f',
type: 'UUID',
name: 'id',
label: 'Id',
description: null,
icon: null,
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-486f-45f9-bbdf-aac18b1831c0',
type: 'TEXT',
name: 'phone',
label: 'Phone',
description: 'Contacts phone number',
icon: 'IconPhone',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-dcf6-445a-b543-37e55de43c25',
type: 'LINK',
name: 'linkedinLink',
label: 'Linkedin',
description: 'Contacts Linkedin account',
icon: 'IconBrandLinkedin',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-64e1-4080-b6ad-db03c3809f8b',
type: 'UUID',
name: 'companyId',
label: 'Company ID (foreign key)',
description: 'Foreign key for company',
icon: null,
isCustom: false,
isActive: true,
isSystem: true,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-bb05-45cb-aa2a-71b58d49dd23',
type: 'TEXT',
name: 'avatarUrl',
label: 'Avatar',
description: 'Contacts avatar',
icon: 'IconFileUpload',
isCustom: false,
isActive: true,
isSystem: true,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-a3a7-4f63-9303-10226f6055be',
type: 'LINK',
name: 'xLink',
label: 'X',
description: 'Contacts X/Twitter account',
icon: 'IconBrandX',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-3b86-413e-ab56-0ebd1a583ff3',
type: 'TEXT',
name: 'jobTitle',
label: 'Job Title',
description: 'Contacts job title',
icon: 'IconBriefcase',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-8a96-4e4b-86fd-ea126530e0c1',
type: 'EMAIL',
name: 'email',
label: 'Email',
description: 'Contacts Email',
icon: 'IconMail',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-9b56-4888-bfe3-f6f59aa999e3',
type: 'FULL_NAME',
name: 'name',
label: 'Name',
description: 'Contacts name',
icon: 'IconUser',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-78f8-4b4c-90ff-86adf77590f5',
type: 'TEXT',
name: 'city',
label: 'City',
description: 'Contacts city',
icon: 'IconMap',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-bec0-4cf0-bf1c-8b2ed21f027a',
type: 'DATE_TIME',
name: 'createdAt',
label: 'Creation date',
description: null,
icon: 'IconCalendar',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: false,
createdAt: '2023-11-24T03:29:18.268Z',
updatedAt: '2023-11-24T03:29:18.268Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '531d5d57-1104-4ba9-b47b-6e526fc46cb6',
type: FieldMetadataType.Relation,
name: 'company',
label: 'Company',
description: '',
placeholder: null,
icon: 'IconBuildingSkyscraper',
isCustom: false,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: {
id: 'b53f8e8d-357c-4e75-8789-ecf95de200c9',
relationType: RelationMetadataType.OneToMany,
toObjectMetadata: {
id: 'a3195559-cc20-4749-9565-572a2f506581',
dataSourceId: '',
nameSingular: 'company',
namePlural: 'companies',
},
toFieldMetadataId: 'a578ffb2-13db-483c-ace7-5c30a13dff2d',
},
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 12,
},
},
};
export const mockedCompaniesMetadata = {
node: {
id: 'a3195559-cc20-4749-9565-572a2f506581',
dataSourceId: '',
nameSingular: 'company',
namePlural: 'companies',
labelSingular: 'Company',
labelPlural: 'Companies',
description: null,
icon: 'IconBuildingSkyscraper',
isCustom: false,
isActive: true,
createdAt: '',
updatedAt: '',
fields: {
edges: [
{
node: {
id: '397eabc0-c5a1-4550-8e68-839c878a8d0e',
type: FieldMetadataType.Text,
name: 'name',
label: 'Name',
description: 'The company name.',
placeholder: null,
icon: 'IconBuildingSkyscraper',
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '7ad234c7-f3b9-4efc-813c-43dc97070b07',
type: FieldMetadataType.Link,
name: 'URL',
label: 'URL',
description:
'The company website URL. We use this url to fetch the company icon.',
placeholder: null,
icon: 'IconLink',
isCustom: false,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: 'a578ffb2-13db-483c-ace7-5c30a13dff2d',
type: FieldMetadataType.Relation,
name: 'people',
label: 'People',
description: 'People linked to the company.',
placeholder: null,
icon: 'IconUsers',
isCustom: false,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: {
id: '91f07688-2243-43a4-91b4-e2984669fe8e',
relationType: RelationMetadataType.OneToMany,
toObjectMetadata: {
id: mockedPeopleMetadata.node.id,
nameSingular: mockedPeopleMetadata.node.nameSingular,
namePlural: mockedPeopleMetadata.node.namePlural,
},
toFieldMetadataId: '531d5d57-1104-4ba9-b47b-6e526fc46cb6',
},
toRelationMetadata: null,
},
},
{
node: {
id: 'b7fd622d-7d8b-4f5a-b148-a7e9fd2c4660',
type: FieldMetadataType.Number,
name: 'employees',
label: 'Employees',
description: 'Number of employees in the company.',
placeholder: null,
icon: 'IconUsers',
isCustom: true,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '60ab27ed-a959-471e-b583-887387f7accd',
type: FieldMetadataType.Link,
name: 'linkedinUrl',
label: 'Linkedin URL',
description: null,
placeholder: null,
icon: 'IconBrandLinkedin',
isCustom: false,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '6daadb98-83ca-4c85-bca5-7792a7d958ad',
type: FieldMetadataType.Boolean,
name: 'idealCustomerProfile',
label: 'ICP',
description: '',
placeholder: null,
icon: 'IconTarget',
isCustom: true,
isActive: false,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: 'd9e366d5-d43d-4f71-ac97-f1d32768f79b',
type: FieldMetadataType.Currency,
name: 'annualRecurringRevenue',
label: 'ARR',
description: '',
placeholder: null,
icon: 'IconMoneybag',
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '39c55b95-f8cf-49a3-9713-fc52bbd117ae',
type: FieldMetadataType.DateTime,
name: 'createdAt',
label: 'Created At',
description: '',
placeholder: null,
icon: 'IconCalendar',
isCustom: false,
isActive: false,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 8,
},
},
};
export const mockedWorkspacesMetadata = {
node: {
id: 'c973efa3-436e-47ea-8dbc-983ed869c04d',
dataSourceId: '',
nameSingular: 'workspace',
namePlural: 'workspaces',
labelSingular: 'Workspace',
labelPlural: 'Workspaces',
description: null,
icon: 'IconApps',
isCustom: true,
isActive: true,
createdAt: '',
updatedAt: '',
fields: {
edges: [
{
node: {
id: 'f955402c-9e8f-4b91-a82c-95f6de392b99',
type: 'TEXT',
name: 'slug',
label: 'Slug',
description: null,
placeholder: null,
icon: 'IconSlash',
isCustom: true,
isActive: true,
isNullable: true,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 1,
},
},
};
export const mockedActivitiesMetadata = {
node: {
__typename: 'object',
id: '20202020-8ee3-4f67-84ab-1b7a6eb5a448',
nameSingular: 'activity',
namePlural: 'activities',
labelSingular: 'Activity',
labelPlural: 'Activities',
description: 'An activity',
icon: 'IconCheckbox',
isCustom: false,
isActive: true,
isSystem: true,
createdAt: '2023-11-24T03:29:18.207Z',
updatedAt: '2023-11-24T03:29:18.207Z',
fields: {
edges: [
{
node: {
__typename: 'field',
id: '20202020-4694-4ec6-9084-8d932ebb3066',
type: 'UUID',
name: 'assigneeId',
label: 'Assignee id (foreign key)',
description: 'Acitivity assignee id foreign key',
icon: null,
isCustom: false,
isActive: true,
isSystem: true,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-88df-4202-bf82-6a06c6963280',
type: 'DATE_TIME',
name: 'updatedAt',
label: 'Update date',
description: null,
icon: 'IconCalendar',
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-aff0-4961-be8a-0e5c2598b9a6',
type: 'TEXT',
name: 'body',
label: 'Body',
description: 'Activity body',
icon: 'IconList',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-cd46-44f4-bf22-b0aa20d009da',
type: 'DATE_TIME',
name: 'reminderAt',
label: 'Reminder Date',
description: 'Activity reminder date',
icon: 'IconCalendarEvent',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-2584-4797-95a8-5cc90d48c040',
type: 'TEXT',
name: 'title',
label: 'Title',
description: 'Activity title',
icon: 'IconNotes',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-f695-419c-b928-c488323d6df3',
type: 'UUID',
name: 'id',
label: 'Id',
description: null,
icon: null,
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-3acb-46bb-b993-0dc49fa2a48d',
type: 'UUID',
name: 'authorId',
label: 'Author id (foreign key)',
description: 'Activity author id foreign key',
icon: null,
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-0924-48f0-a8c2-d2dd4e2098e2',
type: 'DATE_TIME',
name: 'completedAt',
label: 'Completion Date',
description: 'Activity completion date',
icon: 'IconCheck',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-a243-4b94-a4b4-25705af86be2',
type: 'TEXT',
name: 'type',
label: 'Type',
description: 'Activity type',
icon: 'IconCheckbox',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: false,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-65a2-4d9c-b640-bac54007a14d',
type: 'DATE_TIME',
name: 'createdAt',
label: 'Creation date',
description: null,
icon: 'IconCalendar',
isCustom: false,
isActive: true,
isSystem: true,
isNullable: false,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
__typename: 'field',
id: '20202020-20e1-4366-b386-750bdca2dfe3',
type: 'DATE_TIME',
name: 'dueAt',
label: 'Due Date',
description: 'Activity due date',
icon: 'IconCalendarEvent',
isCustom: false,
isActive: true,
isSystem: false,
isNullable: true,
createdAt: '2023-11-24T03:29:18.228Z',
updatedAt: '2023-11-24T03:29:18.228Z',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 11,
},
},
};
export const mockedObjectMetadataItems = {
edges: [
{
node: {
id: 'b25eb5e6-9fdc-4df2-a039-40ccea4c8032',
dataSourceId: '',
nameSingular: 'view',
namePlural: 'views',
labelSingular: 'View',
labelPlural: 'Views',
description: '(System) Views',
icon: 'IconLayoutCollage',
isCustom: false,
isActive: true,
createdAt: '',
updatedAt: '',
fields: {
edges: [
{
node: {
id: '5db475e7-8208-402d-97a1-62c9ce344dd4',
type: 'TEXT',
name: 'objectMetadataId',
label: 'Object Metadata Id',
description: 'View target object',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: 'ddc89a56-9add-4110-aa53-4ecdbba36767',
type: 'TEXT',
name: 'type',
label: 'Type',
description: 'View type',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '35fa806b-5d9d-446d-bd0e-1a6874b871ee',
type: 'TEXT',
name: 'name',
label: 'Name',
description: 'View name',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 3,
},
},
},
{
node: {
id: 'c419540f-ff6e-47bf-9d87-3aa366afd8e4',
dataSourceId: '',
nameSingular: 'viewField',
namePlural: 'viewFields',
labelSingular: 'View Field',
labelPlural: 'View Fields',
description: '(System) View Fields',
icon: 'IconColumns3',
isCustom: false,
isActive: true,
createdAt: '',
updatedAt: '',
fields: {
edges: [
{
node: {
id: '1d718fcf-5a17-4694-91a4-4d3968a51aa4',
type: 'TEXT',
name: 'viewId',
label: 'View Id',
description: 'View Field related view',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '8ead2e86-7b60-4a47-9b4f-ad008e744d52',
type: 'NUMBER',
name: 'position',
label: 'Position',
description: 'View Field position',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '4d77c2dd-2b04-4989-b11e-cb0e386d1b4d',
type: 'TEXT',
name: 'fieldMetadataId',
label: 'Field Metadata Id',
description: 'View Field target field',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '0f5ab566-9fc4-44b7-85c5-1e05db9f6b49',
type: 'BOOLEAN',
name: 'isVisible',
label: 'Visible',
description: 'View Field visibility',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
{
node: {
id: '21268ece-7002-4b04-a442-f25278f8ca13',
type: 'NUMBER',
name: 'size',
label: 'Size',
description: 'View Field size',
icon: null,
placeholder: null,
isCustom: false,
isActive: true,
isNullable: false,
createdAt: '',
updatedAt: '',
fromRelationMetadata: null,
toRelationMetadata: null,
},
},
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 5,
},
},
},
mockedPeopleMetadata,
mockedCompaniesMetadata,
mockedWorkspacesMetadata,
mockedPeopleMetadata,
mockedActivitiesMetadata,
],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
totalCount: 6,
};

View File

@ -0,0 +1,152 @@
import { Company } from '@/companies/types/Company';
import { Person } from '@/people/types/Person';
type RequiredAndNotNull<T> = {
[P in keyof T]-?: Exclude<T[P], null | undefined>;
};
type MockedPerson = RequiredAndNotNull<
Pick<
Person,
| 'id'
| 'name'
| 'linkedinLink'
| 'xLink'
| 'jobTitle'
| 'email'
| 'phone'
| 'city'
| 'avatarUrl'
| 'createdAt'
| 'companyId'
> & {
company: Pick<Company, 'id' | 'name' | 'domainName'>;
}
>;
export const mockedPeopleData: MockedPerson[] = [
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
name: {
firstName: 'Alexandre',
lastName: 'Prot',
},
email: 'alexandre@qonto.com',
linkedinLink: {
url: 'https://www.linkedin.com/in/alexandreprot/',
label: 'https://www.linkedin.com/in/alexandreprot/',
},
xLink: {
url: 'https://twitter.com/alexandreprot',
label: 'https://twitter.com/alexandreprot',
},
avatarUrl:
'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAADygAwAEAAAAAQAAADwAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIADwAPAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAoHCBUSFRgSEhUYGBgYGBgYGBgYGBgYGBgYGBgZGRgaGBgcIS4lHB4rIRgYJjgmKy8xNTU1GiQ7QDszPy40NTH/2wBDAQwMDBAPEBwSEh40ISQkMTQ0NjQxNDQ2NDQ0NDQ0MTQ0NDQ0NDQ0NDQ0NDE0NDQ0NDQ0PzQ0NDQ0NDQ0NDQ0NDT/3QAEAAT/2gAMAwEAAhEDEQA/AOtApcUtLWpkJiub1TxlawHaC0pGM+WAQM9ixIGfal8bas8ESwwjMs5KLjqq4+ZgO55A/wCBe1cDceGLxVyYCysOqfNjnoQOQfzqJTs7GkYNq53uleLba5KoCyO2fldcDI7b/uk/jW8VrxSSJowQ6OPqhwPxxXofw81Mz27IxyYmCjPUKRlee/f8qIyuKUbHT4oxT6SrIP/Q6+ilorUyOJ147tTjzjbFArEk4A3M/wD9au20u4Rl+R1bHXawJFZ89vGbgM4GWj2898HI/rTbXSIo5lkj5fpuyWO3upPccVx1H7zO6nH3EizroBjbIB/KuL+H0eJ7soMIBGPx3Ocfkf1rUbRPPzM0jYYtv3MTjkjCDOF7flS+C7Hyo5XznzZSRxjhAEH16E1VH4ia/wAJ0dFFLXUcZ//R7HFIRWXq/iS1teJZRu6hEG9+/JC9Bx1OK43VPiM7ZW2iCejyHc34Ivyj8zWpmdtqkiq8QfoxYe3bGfryKbNb8HEzIwyUYKCQCOnbP0IPasPwtKb+3JlcvICUck8hgSVYAcLkFSMelSya3LbL5U8Bl28K67efTcD0P0rjm7zZ3UtIocsZEQhDEu5IXrnaTks+Scnqa3LWBY1EaDCqMDkn9TXCSapNBIb+ZR0ZRGSQArY+Vf8Aa4GD9a6XRvE9tdYCuFc/8s3IVvw7MPcVtRStcwrybZuilpopa2Oc/9Ly0J/kUBaVTS1sZl7SNWmtH8yB9pPBBGVYZzhl7j9R611T/ERmHzWqFvXzDt+uNuevb9a4eiolCMtyozlHYu6zrE12QZSAF+6ijCjPfHc+5/Ss3bUlFUkkrITbbuze8P8Aiqe0IDMZIsjcjEsQOh8ticqcduhx26163FKGUMpyGAII6EEZBrwQmvX/AAFIXso93O0ug/3Vdgo/KmI//9k=',
jobTitle: 'CEO',
companyId: '5c21e19e-e049-4393-8c09-3e3f8fb09ecb',
company: {
id: '5c21e19e-e049-4393-8c09-3e3f8fb09ecb',
name: 'Qonto',
domainName: 'qonto.com',
},
phone: '06 12 34 56 78',
createdAt: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
name: { firstName: 'John', lastName: 'Doe' },
linkedinLink: {
url: 'https://www.linkedin.com/in/johndoe/',
label: 'https://www.linkedin.com/in/johndoe/',
},
xLink: {
url: 'https://twitter.com/johndoe',
label: 'https://twitter.com/johndoe',
},
avatarUrl: '',
jobTitle: 'CTO',
email: 'john@linkedin.com',
companyId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6e',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6e',
name: 'LinkedIn',
domainName: 'linkedin.com',
},
phone: '06 12 34 56 78',
createdAt: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6f',
name: {
firstName: 'Jane',
lastName: 'Doe',
},
linkedinLink: {
url: 'https://www.linkedin.com/in/janedoe/',
label: 'https://www.linkedin.com/in/janedoe/',
},
xLink: {
url: 'https://twitter.com/janedoe',
label: 'https://twitter.com/janedoe',
},
avatarUrl: '',
jobTitle: 'Investor',
email: 'jane@sequoiacap.com',
companyId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6g',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6g',
name: 'Sequoia',
domainName: 'sequoiacap.com',
},
phone: '06 12 34 56 78',
createdAt: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6h',
name: {
firstName: 'Janice',
lastName: 'Dane',
},
email: 'janice@facebook.com',
linkedinLink: {
url: 'https://www.linkedin.com/in/janicedane/',
label: 'https://www.linkedin.com/in/janicedane/',
},
xLink: {
url: 'https://twitter.com/janicedane',
label: 'https://twitter.com/janicedane',
},
avatarUrl: '',
jobTitle: 'CEO',
companyId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6i',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6i',
name: 'Facebook',
domainName: 'facebook.com',
},
phone: '06 12 34 56 78',
createdAt: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
];
export const mockedEmptyPersonData = {
id: 'ce7f0a37-88d7-4cd8-8b41-6721c57195b5',
firstName: '',
lastName: '',
phone: null,
email: null,
city: null,
displayName: null,
avatarUrl: null,
createdAt: null,
jobTitle: null,
linkedinUrl: null,
xUrl: null,
_activityCount: null,
company: null,
__typename: 'Person',
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,185 @@
import { mockedViewsData } from './views';
export const mockedViewFieldsData = [
// Companies
{
id: '79035310-e955-4986-a4a4-73f9d9949c6a',
fieldMetadataId: 'name',
viewId: mockedViewsData[0].id,
position: 0,
isVisible: true,
size: 180,
},
{
id: '2a96bbc8-d86d-439a-8e50-4b07ebd27750',
fieldMetadataId: 'domainName',
viewId: mockedViewsData[0].id,
position: 1,
isVisible: true,
size: 100,
},
{
id: '0c1b4c7b-6a3d-4fb0-bf2b-5d7c8fb844ed',
fieldMetadataId: 'accountOwner',
viewId: mockedViewsData[0].id,
position: 2,
isVisible: true,
size: 150,
},
{
id: 'cc7f9560-32b5-4b82-8fd9-b05fe77c8cf7',
fieldMetadataId: 'createdAt',
viewId: mockedViewsData[0].id,
position: 3,
isVisible: true,
size: 150,
},
{
id: '3de4d078-3396-4480-be2d-6f3b1a228b0d',
fieldMetadataId: 'employees',
viewId: mockedViewsData[0].id,
position: 4,
isVisible: true,
size: 150,
},
{
id: '4650c8fb-0f1e-4342-88dc-adedae1445f9',
fieldMetadataId: 'linkedin',
viewId: mockedViewsData[0].id,
position: 5,
isVisible: true,
size: 170,
},
{
id: '727430bf-6ff8-4c85-9828-cbe72ac0fc27',
fieldMetadataId: 'address',
viewId: mockedViewsData[0].id,
position: 6,
isVisible: true,
size: 170,
},
// People
{
id: '28894146-4fde-4a16-a9ca-1a31b5b788b4',
fieldMetadataId: 'displayName',
viewId: mockedViewsData[1].id,
position: 0,
isVisible: true,
size: 210,
},
{
id: 'e1e24864-8601-4cd8-8a63-09c1285f2e39',
fieldMetadataId: 'email',
viewId: mockedViewsData[1].id,
position: 1,
isVisible: true,
size: 150,
},
{
id: '5a1df716-7211-445a-9f16-9783a00998a7',
fieldMetadataId: 'company',
viewId: mockedViewsData[1].id,
position: 2,
isVisible: true,
size: 150,
},
{
id: 'a6e1197a-7e84-4d92-ace2-367c0bc46c49',
fieldMetadataId: 'phone',
viewId: mockedViewsData[1].id,
position: 3,
isVisible: true,
size: 150,
},
{
id: 'c9343097-d14b-4559-a5fa-626c1527d39f',
fieldMetadataId: 'createdAt',
viewId: mockedViewsData[1].id,
position: 4,
isVisible: true,
size: 150,
},
{
id: 'a873e5f0-fed6-47e9-a712-6854eab3ec77',
fieldMetadataId: 'city',
viewId: mockedViewsData[1].id,
position: 5,
isVisible: true,
size: 150,
},
{
id: '66f134b8-5329-422f-b88e-83e6bb707eb5',
fieldMetadataId: 'jobTitle',
viewId: mockedViewsData[1].id,
position: 6,
isVisible: true,
size: 150,
},
{
id: '648faa24-cabb-482a-8578-ba3f09906017',
fieldMetadataId: 'linkedin',
viewId: mockedViewsData[1].id,
position: 7,
isVisible: true,
size: 150,
},
{
id: '3a9e7f0d-a4ce-4ad5-aac7-3a24eb1a412d',
fieldMetadataId: 'x',
viewId: mockedViewsData[1].id,
position: 8,
isVisible: true,
size: 150,
},
// Opportunities
{
id: '35a42e2d-83dd-4b57-ada6-f90616da706d',
fieldMetadataId: 'amount',
viewId: mockedViewsData[2].id,
position: 0,
isVisible: true,
size: 180,
},
{
id: 'e5a731bb-82b9-4abe-ad22-1ddea94722f9',
fieldMetadataId: 'probability',
viewId: mockedViewsData[2].id,
position: 1,
isVisible: true,
size: 150,
},
{
id: '3159acd8-463f-458d-bf9a-af8ac6f57dc0',
fieldMetadataId: 'closeDate',
viewId: mockedViewsData[2].id,
position: 2,
isVisible: true,
size: 100,
},
{
id: 'afc0819d-b694-4e3c-a2e6-25261aa3ed2c',
fieldMetadataId: 'company',
viewId: mockedViewsData[2].id,
position: 3,
isVisible: true,
size: 150,
},
{
id: 'ec0507bb-aedc-4695-ba96-d81bdeb9db83',
fieldMetadataId: 'createdAt',
viewId: mockedViewsData[2].id,
position: 4,
isVisible: true,
size: 150,
},
{
id: '3f1585f6-44f6-45c5-b840-bc05af5d0008',
fieldMetadataId: 'pointOfContact',
viewId: mockedViewsData[2].id,
position: 5,
isVisible: true,
size: 150,
},
];

View File

@ -0,0 +1,26 @@
export const mockedViewsData = [
{
id: '37a8a866-eb17-4e76-9382-03143a2f6a80',
name: 'All companies',
objectMetadataId: 'company',
type: 'table',
},
{
id: '6095799e-b48f-4e00-b071-10818083593a',
name: 'All people',
objectMetadataId: 'person',
type: 'table',
},
{
id: 'e26f66b7-f890-4a5c-b4d2-ec09987b5308',
name: 'All opportunities',
objectMetadataId: 'company',
type: 'kanban',
},
{
id: '5c307222-1dd5-4ff3-ab06-8d990e9b3c74',
name: 'All companies (v2)',
objectMetadataId: 'a3195559-cc20-4749-9565-572a2f506581',
type: 'table',
},
];

View File

@ -0,0 +1,6 @@
import { ApolloClient, InMemoryCache } from '@apollo/client';
export const mockedClient = new ApolloClient({
uri: process.env.REACT_APP_SERVER_BASE_URL + '/graphql',
cache: new InMemoryCache(),
});

View File

@ -0,0 +1,4 @@
export const sleep = async (ms: number) =>
new Promise((resolve) => {
setTimeout(resolve, ms);
});

View File

@ -0,0 +1,24 @@
import { ElementType } from 'react';
import { StoryObj } from '@storybook/react';
import {
CatalogDimension,
CatalogOptions,
} from './decorators/CatalogDecorator';
export type CatalogStory<
StoryType extends StoryObj<ComponentType>,
ComponentType extends ElementType,
> = {
args?: StoryType['args'];
argTypes?: StoryType['argTypes'];
play?: StoryType['play'];
render?: StoryType['render'];
parameters: StoryType['parameters'] & {
catalog: {
dimensions: CatalogDimension<ComponentType>[];
options?: CatalogOptions;
};
};
decorators: StoryType['decorators'];
};