Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2696cbd1f3 |
@@ -1,10 +1,10 @@
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import { type UserWorkspace } from '~/generated-metadata/graphql';
|
||||
|
||||
export type CurrentUserWorkspace = Pick<
|
||||
UserWorkspace,
|
||||
'permissionFlags' | 'twoFactorAuthenticationMethodSummary'
|
||||
'id' | 'permissionFlags' | 'twoFactorAuthenticationMethodSummary'
|
||||
> & {
|
||||
objectsPermissions: Array<ObjectPermissions & { objectMetadataId: string }>;
|
||||
};
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ export const getLabelIdentifierFieldValue = (
|
||||
labelIdentifierFieldMetadataItem: FieldMetadataItem | undefined,
|
||||
): string => {
|
||||
if (!isDefined(labelIdentifierFieldMetadataItem)) {
|
||||
return record.id;
|
||||
return record.id ?? '';
|
||||
}
|
||||
|
||||
const recordIdentifierValue = record[labelIdentifierFieldMetadataItem.name];
|
||||
|
||||
+11
-6
@@ -27,7 +27,6 @@ import { isFieldSelect } from '@/object-record/record-field/ui/types/guards/isFi
|
||||
import { isFieldSelectValue } from '@/object-record/record-field/ui/types/guards/isFieldSelectValue';
|
||||
import { recordStoreFamilySelector } from '@/object-record/record-store/states/selectors/recordStoreFamilySelector';
|
||||
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
@@ -63,10 +62,6 @@ export const usePersistField = ({
|
||||
}: {
|
||||
objectMetadataItemId: string;
|
||||
}) => {
|
||||
const { objectMetadataItem } = useObjectMetadataItemById({
|
||||
objectId: objectMetadataItemId,
|
||||
});
|
||||
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord();
|
||||
@@ -159,6 +154,16 @@ export const usePersistField = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.id === objectMetadataItemId,
|
||||
);
|
||||
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
throw new Error(
|
||||
`Object metadata item not found for id ${objectMetadataItemId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const isValuePersistable =
|
||||
fieldIsMorphRelationManyToOne ||
|
||||
fieldIsRelationManyToOne ||
|
||||
@@ -290,7 +295,7 @@ export const usePersistField = ({
|
||||
}
|
||||
},
|
||||
[
|
||||
objectMetadataItem?.nameSingular,
|
||||
objectMetadataItemId,
|
||||
objectMetadataItems,
|
||||
store,
|
||||
updateOneRecord,
|
||||
|
||||
@@ -387,7 +387,10 @@ export const PageLayoutTabList = ({
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragUpdate={handleDragUpdate}
|
||||
>
|
||||
<StyledContainer className={className}>
|
||||
<StyledContainer
|
||||
data-testid="page-layout-tab-list"
|
||||
className={className}
|
||||
>
|
||||
<PageLayoutTabListVisibleTabs
|
||||
visibleTabs={tabsWithIcons}
|
||||
visibleTabCount={visibleTabCount}
|
||||
@@ -452,7 +455,10 @@ export const PageLayoutTabList = ({
|
||||
</StyledContainer>
|
||||
</DragDropContext>
|
||||
) : (
|
||||
<StyledContainer className={className}>
|
||||
<StyledContainer
|
||||
data-testid="page-layout-tab-list"
|
||||
className={className}
|
||||
>
|
||||
<PageLayoutTabListVisibleTabs
|
||||
visibleTabs={tabsWithIcons}
|
||||
visibleTabCount={visibleTabCount}
|
||||
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { graphql, HttpResponse } from 'msw';
|
||||
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
||||
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
import { RecordShowPage } from '~/pages/object-record/RecordShowPage';
|
||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { RecordStoreDecorator } from '~/testing/decorators/RecordStoreDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedCompanyRecords } from '~/testing/mock-data/generated/data/companies/mock-companies-data';
|
||||
import { mockedUserData } from '~/testing/mock-data/users';
|
||||
import { getOperationName } from '~/utils/getOperationName';
|
||||
|
||||
const companyRecord = mockedCompanyRecords[0];
|
||||
|
||||
const mockedUserDataWithFeatureFlags = {
|
||||
...mockedUserData,
|
||||
currentWorkspace: {
|
||||
...mockedUserData.currentWorkspace,
|
||||
featureFlags: [
|
||||
{
|
||||
__typename: 'FeatureFlag' as const,
|
||||
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED,
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
__typename: 'FeatureFlag' as const,
|
||||
key: FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED,
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const enterEditMode = async (canvasElement: HTMLElement) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
const sidePanelButton = await within(body).findByTestId(
|
||||
'page-header-side-panel-button',
|
||||
);
|
||||
await userEvent.click(sidePanelButton);
|
||||
|
||||
const searchInput = await within(body).findByTestId('side-panel-focus');
|
||||
await userEvent.type(searchInput, 'Edit Layout');
|
||||
|
||||
const editLayoutItem = await within(body).findByText('Edit Layout', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(editLayoutItem);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(within(body).getByText('Layout customization')).toBeVisible();
|
||||
},
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
};
|
||||
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Modules/PageLayout/RecordPageLayoutEditing',
|
||||
component: RecordShowPage,
|
||||
decorators: [PageDecorator, ContextStoreDecorator, RecordStoreDecorator],
|
||||
args: {
|
||||
routePath: '/object/:objectNameSingular/:objectRecordId',
|
||||
routeParams: {
|
||||
':objectNameSingular': 'company',
|
||||
':objectRecordId': companyRecord.id,
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
records: [companyRecord],
|
||||
layout: 'fullscreen',
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedUserDataWithFeatureFlags,
|
||||
},
|
||||
});
|
||||
}),
|
||||
graphql.query('FindOneCompany', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
company: companyRecord,
|
||||
},
|
||||
});
|
||||
}),
|
||||
...graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const DefaultLayout: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await expect(await within(body).findByText('Fields')).toBeVisible();
|
||||
|
||||
await expect(
|
||||
await within(
|
||||
await within(body).findByTestId('page-layout-tab-list'),
|
||||
).findByText('Timeline'),
|
||||
).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const CreateTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const newTabButton = await within(body).findByRole('button', {
|
||||
name: 'New Tab',
|
||||
});
|
||||
await userEvent.click(newTabButton);
|
||||
|
||||
const emptyTabInput = await within(body).findByPlaceholderText('Tab');
|
||||
await expect(emptyTabInput).toHaveValue('Untitled');
|
||||
await userEvent.keyboard('{Escape}');
|
||||
|
||||
const moreButtons = await within(
|
||||
within(body).getByTestId('page-layout-tab-list'),
|
||||
).findAllByRole('button', {
|
||||
name: /\+\d{1} More/,
|
||||
});
|
||||
await expect(moreButtons[1]).toBeVisible();
|
||||
|
||||
await userEvent.click(moreButtons[1]);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(within(body).getAllByRole('listbox')[0]).getByText('Untitled', {
|
||||
exact: true,
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const RenameTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const timelineTab = await within(
|
||||
within(body).getByTestId('page-layout-tab-list'),
|
||||
).findByText('Timeline', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(timelineTab);
|
||||
|
||||
const sidePanel = await waitFor(() => {
|
||||
return canvasElement.querySelector('[data-side-panel]') as HTMLElement;
|
||||
});
|
||||
|
||||
await userEvent.click(await within(sidePanel!).findByText('Timeline'));
|
||||
|
||||
const titleInput =
|
||||
await within(body).findByPlaceholderText('Full tab widget');
|
||||
await userEvent.clear(titleInput);
|
||||
await userEvent.type(titleInput, 'My Custom Timeline{Enter}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(within(body).getByTestId('page-layout-tab-list')).getByText(
|
||||
'My Custom Timeline',
|
||||
{ exact: true },
|
||||
),
|
||||
).toBeVisible();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// TODO
|
||||
export const DeleteTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const defaultMoreTabsCount = 5;
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(
|
||||
within(body).getByText(`+${defaultMoreTabsCount} More`, {
|
||||
exact: true,
|
||||
}),
|
||||
).toBeVisible();
|
||||
},
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
|
||||
const newTabButton = await within(body).findByRole('button', {
|
||||
name: 'New Tab',
|
||||
});
|
||||
await userEvent.click(newTabButton);
|
||||
|
||||
const emptyTabInput = await within(body).findByRole('textbox', {
|
||||
name: 'Tab',
|
||||
});
|
||||
await expect(emptyTabInput).toHaveValue('Untitled');
|
||||
|
||||
await userEvent.keyboard('{Escape}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(body).getByText(`+${defaultMoreTabsCount + 1} More`, {
|
||||
exact: true,
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
const deleteButton = await within(body).findByText('Delete', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(deleteButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(body).getByText(`+${defaultMoreTabsCount} More`, {
|
||||
exact: true,
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// TODO
|
||||
export const DuplicateTab: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const timelineTab = await within(body).findByText('Timeline', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(timelineTab);
|
||||
await userEvent.click(timelineTab);
|
||||
|
||||
const duplicateButton = await within(body).findByText('Duplicate', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(duplicateButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
within(body).getByText('Timeline - Copy', { exact: true }),
|
||||
).toBeVisible();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// TODO
|
||||
export const ReorderTabMoveLeft: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const tasksTab = await within(body).findByText('Tasks', { exact: true });
|
||||
await userEvent.click(tasksTab);
|
||||
await userEvent.click(tasksTab);
|
||||
|
||||
const moveLeftButton = await within(body).findByText('Move left', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(moveLeftButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(within(body).getByText('Tasks', { exact: true })).toBeVisible();
|
||||
expect(within(body).getByText('Timeline', { exact: true })).toBeVisible();
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// TODO
|
||||
export const TabSwitching: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
const emailsTab = await within(body).findByText('Emails', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(emailsTab);
|
||||
|
||||
const tasksTab = await within(body).findByText('Tasks', { exact: true });
|
||||
await userEvent.click(tasksTab);
|
||||
|
||||
const timelineTab = await within(body).findByText('Timeline', {
|
||||
exact: true,
|
||||
});
|
||||
await userEvent.click(timelineTab);
|
||||
},
|
||||
};
|
||||
|
||||
// TODO
|
||||
export const CancelDiscardsChanges: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const body = canvasElement.ownerDocument.body;
|
||||
|
||||
await enterEditMode(canvasElement);
|
||||
|
||||
const newTabButton = await within(body).findByRole('button', {
|
||||
name: 'New Tab',
|
||||
});
|
||||
await userEvent.click(newTabButton);
|
||||
|
||||
const emptyTabInput = await within(body).findByRole('textbox', {
|
||||
name: 'Tab',
|
||||
});
|
||||
await expect(emptyTabInput).toHaveValue('Untitled');
|
||||
|
||||
await userEvent.keyboard('{Escape}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(within(body).getByText('Untitled', { exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
const cancelButton = await within(body).findByRole('button', {
|
||||
name: 'Cancel',
|
||||
});
|
||||
await userEvent.click(cancelButton);
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(
|
||||
within(body).queryByText('Untitled', { exact: true }),
|
||||
).not.toBeInTheDocument();
|
||||
},
|
||||
{ timeout: 5000 },
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -30,7 +30,7 @@ export const RecordShowPageTitle = ({
|
||||
)
|
||||
: '';
|
||||
|
||||
const pageTitle = pageName.trim()
|
||||
const pageTitle = (pageName ?? '').trim()
|
||||
? `${pageName} - ${objectMetadataItem.labelSingular}`
|
||||
: objectMetadataItem.labelSingular;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ApolloProvider } from '@apollo/client/react';
|
||||
import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect';
|
||||
import { ApolloCoreClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloCoreClientMockedProvider';
|
||||
import { loadDevMessages } from '@apollo/client/dev';
|
||||
import { ApolloProvider } from '@apollo/client/react';
|
||||
import { type Decorator } from '@storybook/react-vite';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
@@ -10,19 +12,18 @@ import {
|
||||
Route,
|
||||
RouterProvider,
|
||||
} from 'react-router-dom';
|
||||
import { ClientConfigProviderEffect } from '@/client-config/components/ClientConfigProviderEffect';
|
||||
import { ApolloCoreClientMockedProvider } from '@/object-metadata/hooks/__mocks__/ApolloCoreClientMockedProvider';
|
||||
|
||||
import { DefaultLayout } from '@/ui/layout/page/components/DefaultLayout';
|
||||
import { MinimalMetadataGater } from '@/metadata-store/components/MinimalMetadataGater';
|
||||
import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect';
|
||||
import { IsMinimalMetadataReadyEffect } from '@/metadata-store/effect-components/IsMinimalMetadataReadyEffect';
|
||||
import { MinimalMetadataLoadEffect } from '@/metadata-store/effect-components/MinimalMetadataLoadEffect';
|
||||
import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect';
|
||||
import { DefaultLayout } from '@/ui/layout/page/components/DefaultLayout';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useState } from 'react';
|
||||
import { ClientConfigProvider } from '~/modules/client-config/components/ClientConfigProvider';
|
||||
import { mockedApolloClient } from '~/testing/mockedApolloClient';
|
||||
|
||||
import { CommandRunner } from '@/command-menu-item/engine-command/components/CommandRunner';
|
||||
import { MainContextStoreProvider } from '@/context-store/components/MainContextStoreProvider';
|
||||
import { PreComputedChipGeneratorsProvider } from '@/object-metadata/components/PreComputedChipGeneratorsProvider';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
@@ -104,6 +105,7 @@ const Providers = () => {
|
||||
</FullHeightStorybookLayout>
|
||||
</PreComputedChipGeneratorsProvider>
|
||||
<MainContextStoreProvider />
|
||||
<CommandRunner />
|
||||
</ApolloCoreClientMockedProvider>
|
||||
</MinimalMetadataGater>
|
||||
</ClientConfigProvider>
|
||||
|
||||
@@ -18,21 +18,21 @@ import { GET_PUBLIC_WORKSPACE_DATA_BY_DOMAIN } from '@/auth/graphql/queries/getP
|
||||
import { LIST_PLANS } from '@/settings/billing/graphql/queries/listPlans';
|
||||
import { GET_ROLES } from '@/settings/roles/graphql/queries/getRolesQuery';
|
||||
import { mockBillingPlans } from '~/testing/mock-data/billing-plans';
|
||||
import { mockedBackendCommandMenuItems } from '~/testing/mock-data/command-menu-items';
|
||||
import { mockedCompanyRecords } from '~/testing/mock-data/generated/data/companies/mock-companies-data';
|
||||
import { mockedTaskRecords } from '~/testing/mock-data/generated/data/tasks/mock-tasks-data';
|
||||
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/metadata/objects/mock-objects-metadata';
|
||||
import { mockedRoles } from '~/testing/mock-data/generated/metadata/roles/mock-roles-data';
|
||||
import { mockedBackendCommandMenuItems } from '~/testing/mock-data/command-menu-items';
|
||||
|
||||
import { type Task } from '@/activities/types/Task';
|
||||
import { FIND_MINIMAL_METADATA } from '@/metadata-store/graphql/queries/findMinimalMetadata';
|
||||
import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo';
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import {
|
||||
getConnectionTypename,
|
||||
getEdgeTypename,
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
import { getEmptyPageInfo } from '@/object-record/cache/utils/getEmptyPageInfo';
|
||||
import { getRecordFromRecordNode } from '@/object-record/cache/utils/getRecordFromRecordNode';
|
||||
import { mockedApiKeys } from '~/testing/mock-data/generated/metadata/api-keys/mock-api-keys-data';
|
||||
import { mockedMinimalMetadata } from '~/testing/mock-data/generated/metadata/minimal/mock-minimal-metadata';
|
||||
import { mockedNavigationMenuItems } from '~/testing/mock-data/generated/metadata/navigation-menu-items/mock-navigation-menu-items-data';
|
||||
@@ -648,6 +648,13 @@ export const graphqlMocks = {
|
||||
},
|
||||
});
|
||||
}),
|
||||
metadataGraphql.query('FindManyFrontComponents', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
frontComponents: [],
|
||||
},
|
||||
});
|
||||
}),
|
||||
metadataGraphql.query('GetWebhook', ({ variables }) => {
|
||||
const webhookId = variables.input?.id;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: 'targetObjectReadPermissions.person',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -39,6 +40,7 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
'targetObjectReadPermissions.opportunity',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -56,6 +58,7 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -73,6 +76,7 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: 'targetObjectReadPermissions.task',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -90,6 +94,26 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: 'targetObjectReadPermissions.note',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
id: 'mock-edit-record-page-layout',
|
||||
workflowVersionId: null,
|
||||
frontComponentId: null,
|
||||
frontComponent: null,
|
||||
engineComponentKey: EngineComponentKey.EDIT_RECORD_PAGE_LAYOUT,
|
||||
label: 'Edit Layout',
|
||||
icon: 'IconPencil',
|
||||
shortLabel: 'Edit Layout',
|
||||
position: 18,
|
||||
isPinned: false,
|
||||
hotKeys: null,
|
||||
conditionalAvailabilityExpression:
|
||||
'pageType == "RECORD_PAGE" and featureFlags.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED and noneDefined(selectedRecords, "deletedAt") and objectPermissions.canUpdateObjectRecords and objectMetadataItem.nameSingular != "dashboard"',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -107,6 +131,7 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
{
|
||||
__typename: 'CommandMenuItem',
|
||||
@@ -124,5 +149,6 @@ export const mockedBackendCommandMenuItems: CommandMenuItemFieldsFragment[] = [
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityType: CommandMenuItemAvailabilityType.FALLBACK,
|
||||
availabilityObjectMetadataId: null,
|
||||
payload: null,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { type CurrentUserWorkspace } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { CUSTOM_WORKSPACE_APPLICATION_MOCK } from '@/object-metadata/hooks/__tests__/constants/CustomWorkspaceApplicationMock.test.constant';
|
||||
import { type WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
import {
|
||||
AUTO_SELECT_FAST_MODEL_ID,
|
||||
AUTO_SELECT_SMART_MODEL_ID,
|
||||
} from 'twenty-shared/constants';
|
||||
import { type CurrentUserWorkspace } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { CUSTOM_WORKSPACE_APPLICATION_MOCK } from '@/object-metadata/hooks/__tests__/constants/CustomWorkspaceApplicationMock.test.constant';
|
||||
import { type WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
import {
|
||||
OnboardingStatus,
|
||||
PermissionFlagType,
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
type Workspace,
|
||||
WorkspaceActivationStatus,
|
||||
WorkspaceMemberDateFormatEnum,
|
||||
WorkspaceMemberNumberFormatEnum,
|
||||
WorkspaceMemberTimeFormatEnum,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { mockBillingPlans } from '~/testing/mock-data/billing-plans';
|
||||
@@ -33,6 +34,7 @@ type MockedUser = Pick<
|
||||
| 'userVars'
|
||||
| 'availableWorkspaces'
|
||||
| 'hasPassword'
|
||||
| 'deletedWorkspaceMembers'
|
||||
> & {
|
||||
workspaceMember: WorkspaceMember | null;
|
||||
locale: string;
|
||||
@@ -161,6 +163,26 @@ export const mockCurrentWorkspace = {
|
||||
databaseSchema: null,
|
||||
isTwoFactorAuthenticationEnforced: false,
|
||||
eventLogRetentionDays: 90,
|
||||
customDomain: null,
|
||||
defaultRole: {
|
||||
__typename: 'Role',
|
||||
id: '5722c41f-6ed1-42e7-a61c-525a377d4a83',
|
||||
label: 'Admin',
|
||||
description: 'Admin role',
|
||||
icon: 'IconUserCog',
|
||||
canUpdateAllSettings: true,
|
||||
canAccessAllTools: true,
|
||||
isEditable: false,
|
||||
canReadAllObjectRecords: true,
|
||||
canUpdateAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: true,
|
||||
canDestroyAllObjectRecords: true,
|
||||
canBeAssignedToUsers: true,
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToApiKeys: true,
|
||||
},
|
||||
aiAdditionalInstructions: null,
|
||||
editableProfileFields: [],
|
||||
__typename: 'Workspace',
|
||||
} as const satisfies Workspace;
|
||||
|
||||
@@ -181,6 +203,9 @@ export const mockedWorkspaceMemberData: WorkspaceMember = {
|
||||
dateFormat: WorkspaceMemberDateFormatEnum.DAY_FIRST,
|
||||
timeFormat: WorkspaceMemberTimeFormatEnum.HOUR_24,
|
||||
timeZone: 'America/New_York',
|
||||
userWorkspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6e',
|
||||
calendarStartDay: 0,
|
||||
numberFormat: WorkspaceMemberNumberFormatEnum.SYSTEM,
|
||||
};
|
||||
|
||||
export const mockedUserData: MockedUser = {
|
||||
@@ -196,7 +221,9 @@ export const mockedUserData: MockedUser = {
|
||||
'a95afad9ff6f0b364e2a3fd3e246a1a852c22b6e55a3ca33745a86c201f9c10d',
|
||||
workspaceMember: mockedWorkspaceMemberData,
|
||||
currentWorkspace: mockCurrentWorkspace,
|
||||
deletedWorkspaceMembers: [],
|
||||
currentUserWorkspace: {
|
||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6e',
|
||||
permissionFlags: [
|
||||
PermissionFlagType.WORKSPACE_MEMBERS,
|
||||
PermissionFlagType.CONNECTED_ACCOUNTS,
|
||||
|
||||
Reference in New Issue
Block a user