Activate/Deactivate workflow and Discard Draft (#7022)
## Setup This PR can be tested only if some feature flags have specific values: - `IsWorkflowEnabled` equals `true` - `IsQueryRunnerTwentyORMEnabled` equals `false` These feature flags weren't committed to don't break other branches. ## What this PR brings - Display buttons to activate and deactivate a workflow version and a button to discard the current draft version. I also scaffolded a "Test" button, which doesn't do anything for now. - Wired the activate, deactivate and discard draft buttons to the backend. - Made it possible to "edit" active and deactivated versions by automatically creating a new draft version when the user tries to edit the version. - Hide the "Discard Draft", button if the current version is not a draft or is the first version ever created. - On the backend, don't consider discarded drafts when checking if a new draft version can be created. - On the backend, disallow deleting the first created workflow version. Otherwise, we will end up with a blank canvas in the front end, and it will be impossible to recover from it. - On the backend, disallow running deactivation steps if the workflow version is not currently active. Previously, we were throwing, which is unnecessary as it's a valid case. ## Spotted bugs that we must dive into ### Duplicate workflow versions in Apollo cache https://github.com/user-attachments/assets/7cfffd06-11e0-417a-8da0-f9a5f43b84e2 --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
75b493ba6c
commit
729c990546
@ -6,7 +6,6 @@ module.exports = {
|
|||||||
'mockServiceWorker.js',
|
'mockServiceWorker.js',
|
||||||
'**/generated*/*',
|
'**/generated*/*',
|
||||||
'**/generated/standard-metadata-query-result.ts',
|
'**/generated/standard-metadata-query-result.ts',
|
||||||
'**/getObjectMetadataItemsMock.ts',
|
|
||||||
'tsup.config.ts',
|
'tsup.config.ts',
|
||||||
'build',
|
'build',
|
||||||
'coverage',
|
'coverage',
|
||||||
|
|||||||
@ -2,13 +2,14 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock Service Worker (2.0.11).
|
* Mock Service Worker.
|
||||||
* @see https://github.com/mswjs/msw
|
* @see https://github.com/mswjs/msw
|
||||||
* - Please do NOT modify this file.
|
* - Please do NOT modify this file.
|
||||||
* - Please do NOT serve this file on production.
|
* - Please do NOT serve this file on production.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const INTEGRITY_CHECKSUM = 'c5f7f8e188b673ea4e677df7ea3c5a39'
|
const PACKAGE_VERSION = '2.3.5'
|
||||||
|
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
|
||||||
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
||||||
const activeClientIds = new Set()
|
const activeClientIds = new Set()
|
||||||
|
|
||||||
@ -48,7 +49,10 @@ self.addEventListener('message', async function (event) {
|
|||||||
case 'INTEGRITY_CHECK_REQUEST': {
|
case 'INTEGRITY_CHECK_REQUEST': {
|
||||||
sendToClient(client, {
|
sendToClient(client, {
|
||||||
type: 'INTEGRITY_CHECK_RESPONSE',
|
type: 'INTEGRITY_CHECK_RESPONSE',
|
||||||
payload: INTEGRITY_CHECKSUM,
|
payload: {
|
||||||
|
packageVersion: PACKAGE_VERSION,
|
||||||
|
checksum: INTEGRITY_CHECKSUM,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -202,13 +206,6 @@ async function getResponse(event, client, requestId) {
|
|||||||
return passthrough()
|
return passthrough()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass requests with the explicit bypass header.
|
|
||||||
// Such requests can be issued by "ctx.fetch()".
|
|
||||||
const mswIntention = request.headers.get('x-msw-intention')
|
|
||||||
if (['bypass', 'passthrough'].includes(mswIntention)) {
|
|
||||||
return passthrough()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify the client that a request has been intercepted.
|
// Notify the client that a request has been intercepted.
|
||||||
const requestBuffer = await request.arrayBuffer()
|
const requestBuffer = await request.arrayBuffer()
|
||||||
const clientMessage = await sendToClient(
|
const clientMessage = await sendToClient(
|
||||||
@ -240,7 +237,7 @@ async function getResponse(event, client, requestId) {
|
|||||||
return respondWithMock(clientMessage.data)
|
return respondWithMock(clientMessage.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'MOCK_NOT_FOUND': {
|
case 'PASSTHROUGH': {
|
||||||
return passthrough()
|
return passthrough()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1544,6 +1544,20 @@ export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
|||||||
|
|
||||||
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars: any, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, metadataVersion: number, workspaceMembersCount?: number | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: SubscriptionStatus, interval?: SubscriptionInterval | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } };
|
||||||
|
|
||||||
|
export type ActivateWorkflowVersionMutationVariables = Exact<{
|
||||||
|
workflowVersionId: Scalars['String'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ActivateWorkflowVersionMutation = { __typename?: 'Mutation', activateWorkflowVersion: boolean };
|
||||||
|
|
||||||
|
export type DeactivateWorkflowVersionMutationVariables = Exact<{
|
||||||
|
workflowVersionId: Scalars['String'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type DeactivateWorkflowVersionMutation = { __typename?: 'Mutation', deactivateWorkflowVersion: boolean };
|
||||||
|
|
||||||
export type DeleteWorkspaceInvitationMutationVariables = Exact<{
|
export type DeleteWorkspaceInvitationMutationVariables = Exact<{
|
||||||
appTokenId: Scalars['String'];
|
appTokenId: Scalars['String'];
|
||||||
}>;
|
}>;
|
||||||
@ -2886,6 +2900,68 @@ export function useGetCurrentUserLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt
|
|||||||
export type GetCurrentUserQueryHookResult = ReturnType<typeof useGetCurrentUserQuery>;
|
export type GetCurrentUserQueryHookResult = ReturnType<typeof useGetCurrentUserQuery>;
|
||||||
export type GetCurrentUserLazyQueryHookResult = ReturnType<typeof useGetCurrentUserLazyQuery>;
|
export type GetCurrentUserLazyQueryHookResult = ReturnType<typeof useGetCurrentUserLazyQuery>;
|
||||||
export type GetCurrentUserQueryResult = Apollo.QueryResult<GetCurrentUserQuery, GetCurrentUserQueryVariables>;
|
export type GetCurrentUserQueryResult = Apollo.QueryResult<GetCurrentUserQuery, GetCurrentUserQueryVariables>;
|
||||||
|
export const ActivateWorkflowVersionDocument = gql`
|
||||||
|
mutation ActivateWorkflowVersion($workflowVersionId: String!) {
|
||||||
|
activateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type ActivateWorkflowVersionMutationFn = Apollo.MutationFunction<ActivateWorkflowVersionMutation, ActivateWorkflowVersionMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useActivateWorkflowVersionMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useActivateWorkflowVersionMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useActivateWorkflowVersionMutation` returns a tuple that includes:
|
||||||
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const [activateWorkflowVersionMutation, { data, loading, error }] = useActivateWorkflowVersionMutation({
|
||||||
|
* variables: {
|
||||||
|
* workflowVersionId: // value for 'workflowVersionId'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useActivateWorkflowVersionMutation(baseOptions?: Apollo.MutationHookOptions<ActivateWorkflowVersionMutation, ActivateWorkflowVersionMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<ActivateWorkflowVersionMutation, ActivateWorkflowVersionMutationVariables>(ActivateWorkflowVersionDocument, options);
|
||||||
|
}
|
||||||
|
export type ActivateWorkflowVersionMutationHookResult = ReturnType<typeof useActivateWorkflowVersionMutation>;
|
||||||
|
export type ActivateWorkflowVersionMutationResult = Apollo.MutationResult<ActivateWorkflowVersionMutation>;
|
||||||
|
export type ActivateWorkflowVersionMutationOptions = Apollo.BaseMutationOptions<ActivateWorkflowVersionMutation, ActivateWorkflowVersionMutationVariables>;
|
||||||
|
export const DeactivateWorkflowVersionDocument = gql`
|
||||||
|
mutation DeactivateWorkflowVersion($workflowVersionId: String!) {
|
||||||
|
deactivateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type DeactivateWorkflowVersionMutationFn = Apollo.MutationFunction<DeactivateWorkflowVersionMutation, DeactivateWorkflowVersionMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useDeactivateWorkflowVersionMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useDeactivateWorkflowVersionMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useDeactivateWorkflowVersionMutation` returns a tuple that includes:
|
||||||
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const [deactivateWorkflowVersionMutation, { data, loading, error }] = useDeactivateWorkflowVersionMutation({
|
||||||
|
* variables: {
|
||||||
|
* workflowVersionId: // value for 'workflowVersionId'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useDeactivateWorkflowVersionMutation(baseOptions?: Apollo.MutationHookOptions<DeactivateWorkflowVersionMutation, DeactivateWorkflowVersionMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<DeactivateWorkflowVersionMutation, DeactivateWorkflowVersionMutationVariables>(DeactivateWorkflowVersionDocument, options);
|
||||||
|
}
|
||||||
|
export type DeactivateWorkflowVersionMutationHookResult = ReturnType<typeof useDeactivateWorkflowVersionMutation>;
|
||||||
|
export type DeactivateWorkflowVersionMutationResult = Apollo.MutationResult<DeactivateWorkflowVersionMutation>;
|
||||||
|
export type DeactivateWorkflowVersionMutationOptions = Apollo.BaseMutationOptions<DeactivateWorkflowVersionMutation, DeactivateWorkflowVersionMutationVariables>;
|
||||||
export const DeleteWorkspaceInvitationDocument = gql`
|
export const DeleteWorkspaceInvitationDocument = gql`
|
||||||
mutation DeleteWorkspaceInvitation($appTokenId: String!) {
|
mutation DeleteWorkspaceInvitation($appTokenId: String!) {
|
||||||
deleteWorkspaceInvitation(appTokenId: $appTokenId)
|
deleteWorkspaceInvitation(appTokenId: $appTokenId)
|
||||||
|
|||||||
@ -7,11 +7,10 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords';
|
import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords';
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||||
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const cache = new InMemoryCache();
|
const cache = new InMemoryCache();
|
||||||
|
|
||||||
@ -141,7 +140,7 @@ describe('useActivityTargetObjectRecords', () => {
|
|||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
|
result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
|
||||||
result.current.setObjectMetadataItems(mockObjectMetadataItems);
|
result.current.setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
});
|
});
|
||||||
|
|
||||||
const activityTargetObjectRecords =
|
const activityTargetObjectRecords =
|
||||||
|
|||||||
@ -26,13 +26,13 @@ const mocks: MockedResponse[] = [
|
|||||||
mutation CreateOneTask($input: TaskCreateInput!) {
|
mutation CreateOneTask($input: TaskCreateInput!) {
|
||||||
createTask(data: $input) {
|
createTask(data: $input) {
|
||||||
__typename
|
__typename
|
||||||
status
|
|
||||||
assigneeId
|
|
||||||
updatedAt
|
updatedAt
|
||||||
body
|
|
||||||
createdAt
|
createdAt
|
||||||
dueAt
|
dueAt
|
||||||
id
|
id
|
||||||
|
status
|
||||||
|
body
|
||||||
|
assigneeId
|
||||||
title
|
title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,10 @@ import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil';
|
|||||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import pick from 'lodash.pick';
|
import pick from 'lodash.pick';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { mockedTasks } from '~/testing/mock-data/tasks';
|
import { mockedTasks } from '~/testing/mock-data/tasks';
|
||||||
|
|
||||||
const mockedDate = '2024-03-15T12:00:00.000Z';
|
const mockedDate = '2024-03-15T12:00:00.000Z';
|
||||||
@ -69,7 +69,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const mockObjectMetadataItems = generatedMockObjectMetadataItems;
|
||||||
|
|
||||||
describe('useOpenCreateActivityDrawer', () => {
|
describe('useOpenCreateActivityDrawer', () => {
|
||||||
it('works as expected', async () => {
|
it('works as expected', async () => {
|
||||||
|
|||||||
@ -28,20 +28,21 @@ const mocks: MockedResponse[] = [
|
|||||||
mutation UpdateOneTask($idToUpdate: ID!, $input: TaskUpdateInput!) {
|
mutation UpdateOneTask($idToUpdate: ID!, $input: TaskUpdateInput!) {
|
||||||
updateTask(id: $idToUpdate, data: $input) {
|
updateTask(id: $idToUpdate, data: $input) {
|
||||||
__typename
|
__typename
|
||||||
status
|
|
||||||
assigneeId
|
|
||||||
updatedAt
|
updatedAt
|
||||||
body
|
|
||||||
createdAt
|
createdAt
|
||||||
|
deletedAt
|
||||||
dueAt
|
dueAt
|
||||||
position
|
|
||||||
id
|
id
|
||||||
title
|
status
|
||||||
|
body
|
||||||
createdBy {
|
createdBy {
|
||||||
source
|
source
|
||||||
workspaceMemberId
|
workspaceMemberId
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
assigneeId
|
||||||
|
position
|
||||||
|
title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
@ -53,7 +54,7 @@ const mocks: MockedResponse[] = [
|
|||||||
result: jest.fn(() => ({
|
result: jest.fn(() => ({
|
||||||
data: {
|
data: {
|
||||||
updateTask: {
|
updateTask: {
|
||||||
__typename: 'Activity',
|
__typename: 'Task',
|
||||||
createdAt: '2024-03-15T07:33:14.212Z',
|
createdAt: '2024-03-15T07:33:14.212Z',
|
||||||
reminderAt: null,
|
reminderAt: null,
|
||||||
authorId: '123',
|
authorId: '123',
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import { AvatarType } from 'twenty-ui';
|
import { AvatarType } from 'twenty-ui';
|
||||||
|
|
||||||
import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
|
|
||||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||||
|
|
||||||
export const mockId = '8f3b2121-f194-4ba4-9fbf-2d5a37126806';
|
export const mockId = '8f3b2121-f194-4ba4-9fbf-2d5a37126806';
|
||||||
@ -48,36 +47,38 @@ export const initialFavorites = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const sortedFavorites = [
|
export const sortedFavorites = [
|
||||||
{
|
{
|
||||||
id: '1',
|
"avatarType": "rounded",
|
||||||
recordId: '2',
|
"avatarUrl": "",
|
||||||
position: 0,
|
"id": "1",
|
||||||
avatarType: 'squared',
|
"labelIdentifier": " ",
|
||||||
avatarUrl: undefined,
|
"link": "/object/person/1",
|
||||||
labelIdentifier: 'ABC Corp',
|
"position": 0,
|
||||||
link: '/object/company/2',
|
"recordId": "1",
|
||||||
},
|
"workspaceMemberId": undefined,
|
||||||
{
|
},
|
||||||
id: '2',
|
{
|
||||||
recordId: '4',
|
"avatarType": "rounded",
|
||||||
position: 1,
|
"avatarUrl": "",
|
||||||
avatarType: 'squared',
|
"id": "2",
|
||||||
avatarUrl: undefined,
|
"labelIdentifier": " ",
|
||||||
labelIdentifier: 'Company Test',
|
"link": "/object/person/3",
|
||||||
link: '/object/company/4',
|
"position": 1,
|
||||||
},
|
"recordId": "3",
|
||||||
{
|
"workspaceMemberId": undefined,
|
||||||
id: '3',
|
},
|
||||||
position: 2,
|
{
|
||||||
key: '8f3b2121-f194-4ba4-9fbf-2d5a37126806',
|
"avatarType": "squared",
|
||||||
labelIdentifier: 'favoriteLabel',
|
"avatarUrl": "example.com",
|
||||||
avatarUrl: 'example.com',
|
"id": "3",
|
||||||
avatarType: 'squared',
|
"key": "8f3b2121-f194-4ba4-9fbf-2d5a37126806",
|
||||||
link: 'example.com',
|
"labelIdentifier": "favoriteLabel",
|
||||||
recordId: '1',
|
"link": "example.com",
|
||||||
},
|
"position": 2,
|
||||||
];
|
"recordId": "1",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export const mocks = [
|
export const mocks = [
|
||||||
{
|
{
|
||||||
@ -86,132 +87,155 @@ export const mocks = [
|
|||||||
mutation CreateOneFavorite($input: FavoriteCreateInput!) {
|
mutation CreateOneFavorite($input: FavoriteCreateInput!) {
|
||||||
createFavorite(data: $input) {
|
createFavorite(data: $input) {
|
||||||
__typename
|
__typename
|
||||||
|
noteId
|
||||||
taskId
|
taskId
|
||||||
myCustomObjectId
|
person {
|
||||||
workspaceMemberId
|
|
||||||
workspaceMember {
|
|
||||||
__typename
|
__typename
|
||||||
userId
|
|
||||||
updatedAt
|
|
||||||
dateFormat
|
|
||||||
id
|
|
||||||
locale
|
|
||||||
avatarUrl
|
|
||||||
timeZone
|
|
||||||
name {
|
name {
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
userEmail
|
|
||||||
createdAt
|
|
||||||
timeFormat
|
|
||||||
colorScheme
|
|
||||||
}
|
|
||||||
companyId
|
|
||||||
myCustomObject {
|
|
||||||
__typename
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
position
|
|
||||||
updatedAt
|
|
||||||
name
|
|
||||||
myCustomField
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
}
|
|
||||||
updatedAt
|
|
||||||
id
|
|
||||||
opportunity {
|
|
||||||
__typename
|
|
||||||
companyId
|
|
||||||
closeDate
|
|
||||||
stage
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
id
|
|
||||||
updatedAt
|
|
||||||
name
|
|
||||||
createdAt
|
|
||||||
pointOfContactId
|
|
||||||
amount {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
position
|
|
||||||
}
|
|
||||||
noteId
|
|
||||||
note {
|
|
||||||
__typename
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
position
|
|
||||||
body
|
|
||||||
updatedAt
|
|
||||||
createdAt
|
|
||||||
title
|
|
||||||
id
|
|
||||||
}
|
|
||||||
personId
|
|
||||||
task {
|
|
||||||
__typename
|
|
||||||
status
|
|
||||||
assigneeId
|
|
||||||
updatedAt
|
|
||||||
body
|
|
||||||
createdAt
|
|
||||||
dueAt
|
|
||||||
position
|
|
||||||
id
|
|
||||||
title
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opportunityId
|
|
||||||
position
|
|
||||||
createdAt
|
|
||||||
company {
|
|
||||||
__typename
|
|
||||||
id
|
|
||||||
visaSponsorship
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
domainName {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
introVideo {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
position
|
|
||||||
annualRecurringRevenue {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
employees
|
|
||||||
linkedinLink {
|
linkedinLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
workPolicy
|
deletedAt
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
jobTitle
|
||||||
|
intro
|
||||||
|
workPrefereance
|
||||||
|
performanceRating
|
||||||
|
xLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
city
|
||||||
|
companyId
|
||||||
|
phones {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
id
|
||||||
|
position
|
||||||
|
emails {
|
||||||
|
primaryEmail
|
||||||
|
additionalEmails
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
whatsapp {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task {
|
||||||
|
__typename
|
||||||
|
updatedAt
|
||||||
|
createdAt
|
||||||
|
deletedAt
|
||||||
|
dueAt
|
||||||
|
id
|
||||||
|
status
|
||||||
|
body
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
assigneeId
|
||||||
|
position
|
||||||
|
title
|
||||||
|
}
|
||||||
|
rocketId
|
||||||
|
viewId
|
||||||
|
updatedAt
|
||||||
|
workflowId
|
||||||
|
personId
|
||||||
|
workspaceMemberId
|
||||||
|
note {
|
||||||
|
__typename
|
||||||
|
deletedAt
|
||||||
|
id
|
||||||
|
position
|
||||||
|
updatedAt
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
body
|
||||||
|
title
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
view {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
type
|
||||||
|
icon
|
||||||
|
key
|
||||||
|
isCompact
|
||||||
|
kanbanFieldMetadataId
|
||||||
|
objectMetadataId
|
||||||
|
position
|
||||||
|
createdAt
|
||||||
|
deletedAt
|
||||||
|
updatedAt
|
||||||
|
name
|
||||||
|
}
|
||||||
|
opportunityId
|
||||||
|
position
|
||||||
|
deletedAt
|
||||||
|
id
|
||||||
|
companyId
|
||||||
|
workflow {
|
||||||
|
__typename
|
||||||
|
deletedAt
|
||||||
|
lastPublishedVersionId
|
||||||
|
createdAt
|
||||||
|
id
|
||||||
|
statuses
|
||||||
|
name
|
||||||
|
position
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
workspaceMember {
|
||||||
|
__typename
|
||||||
|
name {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
userId
|
||||||
|
createdAt
|
||||||
|
timeZone
|
||||||
|
id
|
||||||
|
timeFormat
|
||||||
|
updatedAt
|
||||||
|
locale
|
||||||
|
userEmail
|
||||||
|
deletedAt
|
||||||
|
colorScheme
|
||||||
|
dateFormat
|
||||||
|
}
|
||||||
|
company {
|
||||||
|
__typename
|
||||||
|
updatedAt
|
||||||
|
domainName {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
visaSponsorship
|
||||||
address {
|
address {
|
||||||
addressStreet1
|
addressStreet1
|
||||||
addressStreet2
|
addressStreet2
|
||||||
@ -222,21 +246,76 @@ export const mocks = [
|
|||||||
addressLat
|
addressLat
|
||||||
addressLng
|
addressLng
|
||||||
}
|
}
|
||||||
|
position
|
||||||
|
employees
|
||||||
|
deletedAt
|
||||||
|
accountOwnerId
|
||||||
|
annualRecurringRevenue {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
id
|
||||||
name
|
name
|
||||||
updatedAt
|
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
myCustomField
|
|
||||||
createdAt
|
createdAt
|
||||||
accountOwnerId
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
workPolicy
|
||||||
|
introVideo {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
linkedinLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
tagline
|
tagline
|
||||||
idealCustomerProfile
|
idealCustomerProfile
|
||||||
}
|
}
|
||||||
person {
|
rocket {
|
||||||
${PERSON_FRAGMENT}
|
__typename
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
updatedAt
|
||||||
|
name
|
||||||
|
position
|
||||||
|
createdAt
|
||||||
|
id
|
||||||
|
deletedAt
|
||||||
|
}
|
||||||
|
opportunity {
|
||||||
|
__typename
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
amount {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
stage
|
||||||
|
position
|
||||||
|
closeDate
|
||||||
|
id
|
||||||
|
name
|
||||||
|
pointOfContactId
|
||||||
|
companyId
|
||||||
|
updatedAt
|
||||||
|
deletedAt
|
||||||
|
createdAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,132 +365,155 @@ export const mocks = [
|
|||||||
) {
|
) {
|
||||||
updateFavorite(id: $idToUpdate, data: $input) {
|
updateFavorite(id: $idToUpdate, data: $input) {
|
||||||
__typename
|
__typename
|
||||||
|
noteId
|
||||||
taskId
|
taskId
|
||||||
myCustomObjectId
|
person {
|
||||||
workspaceMemberId
|
|
||||||
workspaceMember {
|
|
||||||
__typename
|
__typename
|
||||||
userId
|
|
||||||
updatedAt
|
|
||||||
dateFormat
|
|
||||||
id
|
|
||||||
locale
|
|
||||||
avatarUrl
|
|
||||||
timeZone
|
|
||||||
name {
|
name {
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
}
|
}
|
||||||
userEmail
|
|
||||||
createdAt
|
|
||||||
timeFormat
|
|
||||||
colorScheme
|
|
||||||
}
|
|
||||||
companyId
|
|
||||||
myCustomObject {
|
|
||||||
__typename
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
position
|
|
||||||
updatedAt
|
|
||||||
name
|
|
||||||
myCustomField
|
|
||||||
id
|
|
||||||
createdAt
|
|
||||||
}
|
|
||||||
updatedAt
|
|
||||||
id
|
|
||||||
opportunity {
|
|
||||||
__typename
|
|
||||||
companyId
|
|
||||||
closeDate
|
|
||||||
stage
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
id
|
|
||||||
updatedAt
|
|
||||||
name
|
|
||||||
createdAt
|
|
||||||
pointOfContactId
|
|
||||||
amount {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
position
|
|
||||||
}
|
|
||||||
noteId
|
|
||||||
note {
|
|
||||||
__typename
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
position
|
|
||||||
body
|
|
||||||
updatedAt
|
|
||||||
createdAt
|
|
||||||
title
|
|
||||||
id
|
|
||||||
}
|
|
||||||
personId
|
|
||||||
task {
|
|
||||||
__typename
|
|
||||||
status
|
|
||||||
assigneeId
|
|
||||||
updatedAt
|
|
||||||
body
|
|
||||||
createdAt
|
|
||||||
dueAt
|
|
||||||
position
|
|
||||||
id
|
|
||||||
title
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opportunityId
|
|
||||||
position
|
|
||||||
createdAt
|
|
||||||
company {
|
|
||||||
__typename
|
|
||||||
id
|
|
||||||
visaSponsorship
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
domainName {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
introVideo {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
position
|
|
||||||
annualRecurringRevenue {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
employees
|
|
||||||
linkedinLink {
|
linkedinLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
workPolicy
|
deletedAt
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
jobTitle
|
||||||
|
intro
|
||||||
|
workPrefereance
|
||||||
|
performanceRating
|
||||||
|
xLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
city
|
||||||
|
companyId
|
||||||
|
phones {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
id
|
||||||
|
position
|
||||||
|
emails {
|
||||||
|
primaryEmail
|
||||||
|
additionalEmails
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
whatsapp {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task {
|
||||||
|
__typename
|
||||||
|
updatedAt
|
||||||
|
createdAt
|
||||||
|
deletedAt
|
||||||
|
dueAt
|
||||||
|
id
|
||||||
|
status
|
||||||
|
body
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
assigneeId
|
||||||
|
position
|
||||||
|
title
|
||||||
|
}
|
||||||
|
rocketId
|
||||||
|
viewId
|
||||||
|
updatedAt
|
||||||
|
workflowId
|
||||||
|
personId
|
||||||
|
workspaceMemberId
|
||||||
|
note {
|
||||||
|
__typename
|
||||||
|
deletedAt
|
||||||
|
id
|
||||||
|
position
|
||||||
|
updatedAt
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
body
|
||||||
|
title
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
createdAt
|
||||||
|
view {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
type
|
||||||
|
icon
|
||||||
|
key
|
||||||
|
isCompact
|
||||||
|
kanbanFieldMetadataId
|
||||||
|
objectMetadataId
|
||||||
|
position
|
||||||
|
createdAt
|
||||||
|
deletedAt
|
||||||
|
updatedAt
|
||||||
|
name
|
||||||
|
}
|
||||||
|
opportunityId
|
||||||
|
position
|
||||||
|
deletedAt
|
||||||
|
id
|
||||||
|
companyId
|
||||||
|
workflow {
|
||||||
|
__typename
|
||||||
|
deletedAt
|
||||||
|
lastPublishedVersionId
|
||||||
|
createdAt
|
||||||
|
id
|
||||||
|
statuses
|
||||||
|
name
|
||||||
|
position
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
workspaceMember {
|
||||||
|
__typename
|
||||||
|
name {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
userId
|
||||||
|
createdAt
|
||||||
|
timeZone
|
||||||
|
id
|
||||||
|
timeFormat
|
||||||
|
updatedAt
|
||||||
|
locale
|
||||||
|
userEmail
|
||||||
|
deletedAt
|
||||||
|
colorScheme
|
||||||
|
dateFormat
|
||||||
|
}
|
||||||
|
company {
|
||||||
|
__typename
|
||||||
|
updatedAt
|
||||||
|
domainName {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
visaSponsorship
|
||||||
address {
|
address {
|
||||||
addressStreet1
|
addressStreet1
|
||||||
addressStreet2
|
addressStreet2
|
||||||
@ -422,21 +524,76 @@ export const mocks = [
|
|||||||
addressLat
|
addressLat
|
||||||
addressLng
|
addressLng
|
||||||
}
|
}
|
||||||
|
position
|
||||||
|
employees
|
||||||
|
deletedAt
|
||||||
|
accountOwnerId
|
||||||
|
annualRecurringRevenue {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
id
|
||||||
name
|
name
|
||||||
updatedAt
|
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
myCustomField
|
|
||||||
createdAt
|
createdAt
|
||||||
accountOwnerId
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
workPolicy
|
||||||
|
introVideo {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
linkedinLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
tagline
|
tagline
|
||||||
idealCustomerProfile
|
idealCustomerProfile
|
||||||
}
|
}
|
||||||
person {
|
rocket {
|
||||||
${PERSON_FRAGMENT}
|
__typename
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
updatedAt
|
||||||
|
name
|
||||||
|
position
|
||||||
|
createdAt
|
||||||
|
id
|
||||||
|
deletedAt
|
||||||
|
}
|
||||||
|
opportunity {
|
||||||
|
__typename
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
amount {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
stage
|
||||||
|
position
|
||||||
|
closeDate
|
||||||
|
id
|
||||||
|
name
|
||||||
|
pointOfContactId
|
||||||
|
companyId
|
||||||
|
updatedAt
|
||||||
|
deletedAt
|
||||||
|
createdAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
|
|||||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||||
|
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import {
|
import {
|
||||||
favoriteId,
|
favoriteId,
|
||||||
favoriteTargetObjectRecord,
|
favoriteTargetObjectRecord,
|
||||||
@ -29,8 +29,6 @@ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
|
|||||||
useFindManyRecords: () => ({ records: initialFavorites }),
|
useFindManyRecords: () => ({ records: initialFavorites }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||||
@ -51,7 +49,7 @@ describe('useFavorites', () => {
|
|||||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFavorites();
|
return useFavorites();
|
||||||
},
|
},
|
||||||
@ -72,7 +70,7 @@ describe('useFavorites', () => {
|
|||||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFavorites();
|
return useFavorites();
|
||||||
},
|
},
|
||||||
@ -100,7 +98,7 @@ describe('useFavorites', () => {
|
|||||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFavorites();
|
return useFavorites();
|
||||||
},
|
},
|
||||||
@ -125,7 +123,7 @@ describe('useFavorites', () => {
|
|||||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFavorites();
|
return useFavorites();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,16 +4,17 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import {
|
|
||||||
COMPANY_OBJECT_METADATA_ID,
|
|
||||||
getObjectMetadataItemsMock,
|
|
||||||
} from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { mockedUserData } from '~/testing/mock-data/users';
|
import { mockedUserData } from '~/testing/mock-data/users';
|
||||||
|
|
||||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
||||||
const setupMockPrefetchedData = (viewId?: string) => {
|
const setupMockPrefetchedData = (viewId?: string) => {
|
||||||
|
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'company',
|
||||||
|
);
|
||||||
|
|
||||||
jest.mocked(usePrefetchedData).mockReturnValue({
|
jest.mocked(usePrefetchedData).mockReturnValue({
|
||||||
isDataPrefetched: true,
|
isDataPrefetched: true,
|
||||||
records: viewId
|
records: viewId
|
||||||
@ -21,7 +22,7 @@ const setupMockPrefetchedData = (viewId?: string) => {
|
|||||||
{
|
{
|
||||||
id: viewId,
|
id: viewId,
|
||||||
__typename: 'object',
|
__typename: 'object',
|
||||||
objectMetadataId: COMPANY_OBJECT_METADATA_ID,
|
objectMetadataId: companyObjectMetadata?.id,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [],
|
: [],
|
||||||
@ -36,7 +37,7 @@ const renderHooks = (withCurrentUser: boolean) => {
|
|||||||
objectMetadataItemsState,
|
objectMetadataItemsState,
|
||||||
);
|
);
|
||||||
|
|
||||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
if (withCurrentUser) {
|
if (withCurrentUser) {
|
||||||
setCurrentUser(mockedUserData);
|
setCurrentUser(mockedUserData);
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
|||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
|
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ export const ObjectMetadataItemsLoadEffect = () => {
|
|||||||
const toSetObjectMetadataItems =
|
const toSetObjectMetadataItems =
|
||||||
isUndefinedOrNull(currentUser) ||
|
isUndefinedOrNull(currentUser) ||
|
||||||
currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active
|
currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active
|
||||||
? getObjectMetadataItemsMock()
|
? generatedMockObjectMetadataItems
|
||||||
: newObjectMetadataItems;
|
: newObjectMetadataItems;
|
||||||
if (
|
if (
|
||||||
!loading &&
|
!loading &&
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Nullable } from 'twenty-ui';
|
|||||||
|
|
||||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
describe('useColumnDefinitionsFromFieldMetadata', () => {
|
describe('useColumnDefinitionsFromFieldMetadata', () => {
|
||||||
it('should return empty definitions if no object is passed', () => {
|
it('should return empty definitions if no object is passed', () => {
|
||||||
@ -22,22 +22,24 @@ describe('useColumnDefinitionsFromFieldMetadata', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should return expected definitions', () => {
|
it('should return expected definitions', () => {
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'company',
|
||||||
|
);
|
||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
(objectMetadataItem?: Nullable<ObjectMetadataItem>) => {
|
(objectMetadataItem?: Nullable<ObjectMetadataItem>) => {
|
||||||
return useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
return useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
initialProps: mockObjectMetadataItems[1],
|
initialProps: companyObjectMetadata,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
||||||
result.current;
|
result.current;
|
||||||
|
|
||||||
expect(columnDefinitions.length).toBe(5);
|
expect(columnDefinitions.length).toBe(21);
|
||||||
expect(filterDefinitions.length).toBe(4);
|
expect(filterDefinitions.length).toBe(14);
|
||||||
expect(sortDefinitions.length).toBe(4);
|
expect(sortDefinitions.length).toBe(14);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import {
|
|||||||
} from '@/object-metadata/hooks/__mocks__/useFilteredObjectMetadataItems';
|
} from '@/object-metadata/hooks/__mocks__/useFilteredObjectMetadataItems';
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
{
|
{
|
||||||
@ -34,14 +34,12 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
</RecoilRoot>
|
</RecoilRoot>
|
||||||
);
|
);
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('useFilteredObjectMetadataItems', () => {
|
describe('useFilteredObjectMetadataItems', () => {
|
||||||
it('should findActiveObjectMetadataItemBySlug', async () => {
|
it('should findActiveObjectMetadataItemBySlug', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFilteredObjectMetadataItems();
|
return useFilteredObjectMetadataItems();
|
||||||
},
|
},
|
||||||
@ -61,7 +59,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFilteredObjectMetadataItems();
|
return useFilteredObjectMetadataItems();
|
||||||
},
|
},
|
||||||
@ -78,10 +76,14 @@ describe('useFilteredObjectMetadataItems', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should findObjectMetadataItemById', async () => {
|
it('should findObjectMetadataItemById', async () => {
|
||||||
|
const peopleObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.namePlural === 'people',
|
||||||
|
);
|
||||||
|
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFilteredObjectMetadataItems();
|
return useFilteredObjectMetadataItems();
|
||||||
},
|
},
|
||||||
@ -92,7 +94,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
|||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
const res = result.current.findObjectMetadataItemById(
|
const res = result.current.findObjectMetadataItemById(
|
||||||
'ff2881da-89f6-4f15-8f0a-e3f355ea3b94',
|
peopleObjectMetadata?.id,
|
||||||
);
|
);
|
||||||
expect(res).toBeDefined();
|
expect(res).toBeDefined();
|
||||||
expect(res?.namePlural).toBe('people');
|
expect(res?.namePlural).toBe('people');
|
||||||
@ -103,7 +105,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFilteredObjectMetadataItems();
|
return useFilteredObjectMetadataItems();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -3,9 +3,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('useGetObjectRecordIdentifierByNameSingular', () => {
|
describe('useGetObjectRecordIdentifierByNameSingular', () => {
|
||||||
it('should work as expected', async () => {
|
it('should work as expected', async () => {
|
||||||
@ -19,7 +17,7 @@ describe('useGetObjectRecordIdentifierByNameSingular', () => {
|
|||||||
}) => {
|
}) => {
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
|
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useGetObjectRecordIdentifierByNameSingular()(
|
return useGetObjectRecordIdentifierByNameSingular()(
|
||||||
record,
|
record,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
|
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
@ -15,8 +15,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
|
|
||||||
describe('useGetRelationMetadata', () => {
|
describe('useGetRelationMetadata', () => {
|
||||||
it('should return correct properties', async () => {
|
it('should return correct properties', async () => {
|
||||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
const objectMetadata = generatedMockObjectMetadataItems.find(
|
||||||
const objectMetadata = objectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
const fieldMetadataItem = objectMetadata.fields.find(
|
const fieldMetadataItem = objectMetadata.fields.find(
|
||||||
@ -28,7 +27,7 @@ describe('useGetRelationMetadata', () => {
|
|||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMetadataItems(objectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
}, [setMetadataItems]);
|
}, [setMetadataItems]);
|
||||||
|
|
||||||
return useGetRelationMetadata();
|
return useGetRelationMetadata();
|
||||||
@ -45,9 +44,10 @@ describe('useGetRelationMetadata', () => {
|
|||||||
relationType,
|
relationType,
|
||||||
} = result.current({ fieldMetadataItem }) ?? {};
|
} = result.current({ fieldMetadataItem }) ?? {};
|
||||||
|
|
||||||
const expectedRelationObjectMetadataItem = objectMetadataItems.find(
|
const expectedRelationObjectMetadataItem =
|
||||||
(item) => item.nameSingular === 'opportunity',
|
generatedMockObjectMetadataItems.find(
|
||||||
);
|
(item) => item.nameSingular === 'opportunity',
|
||||||
|
);
|
||||||
const expectedRelationFieldMetadataItem =
|
const expectedRelationFieldMetadataItem =
|
||||||
expectedRelationObjectMetadataItem?.fields.find(
|
expectedRelationObjectMetadataItem?.fields.find(
|
||||||
(field) => field.name === 'pointOfContact',
|
(field) => field.name === 'pointOfContact',
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { ReactNode } from 'react';
|
|||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
@ -13,6 +14,9 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
|||||||
|
|
||||||
// Split into tests for each new hook
|
// Split into tests for each new hook
|
||||||
describe('useObjectMetadataItem', () => {
|
describe('useObjectMetadataItem', () => {
|
||||||
|
const opportunityObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'opportunity',
|
||||||
|
);
|
||||||
it('should return correct properties', async () => {
|
it('should return correct properties', async () => {
|
||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => useObjectMetadataItem({ objectNameSingular: 'opportunity' }),
|
() => useObjectMetadataItem({ objectNameSingular: 'opportunity' }),
|
||||||
@ -23,6 +27,6 @@ describe('useObjectMetadataItem', () => {
|
|||||||
|
|
||||||
const { objectMetadataItem } = result.current;
|
const { objectMetadataItem } = result.current;
|
||||||
|
|
||||||
expect(objectMetadataItem.id).toBe('b95b3f38-9fc2-4d7e-a823-7791cf13d089');
|
expect(objectMetadataItem.id).toBe(opportunityObjectMetadata?.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,10 +4,10 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
import { ObjectMetadataItemNotFoundError } from '@/object-metadata/errors/ObjectMetadataNotFoundError';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
||||||
|
|
||||||
export const useObjectMetadataItem = ({
|
export const useObjectMetadataItem = ({
|
||||||
@ -15,9 +15,6 @@ export const useObjectMetadataItem = ({
|
|||||||
}: ObjectMetadataItemIdentifier) => {
|
}: ObjectMetadataItemIdentifier) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|
||||||
// Todo: deprecate this logic as mocked objectMetadataItems are load in ObjectMetadataItemsLoadEffect anyway
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
objectMetadataItemFamilySelector({
|
objectMetadataItemFamilySelector({
|
||||||
objectName: objectNameSingular,
|
objectName: objectNameSingular,
|
||||||
@ -29,11 +26,11 @@ export const useObjectMetadataItem = ({
|
|||||||
|
|
||||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
generatedMockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
objectMetadataItem.nameSingular === objectNameSingular,
|
objectMetadataItem.nameSingular === objectNameSingular,
|
||||||
) ?? null;
|
) ?? null;
|
||||||
objectMetadataItems = mockObjectMetadataItems;
|
objectMetadataItems = generatedMockObjectMetadataItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDefined(objectMetadataItem)) {
|
if (!isDefined(objectMetadataItem)) {
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import { useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useObjectNamePluralFromSingular = ({
|
export const useObjectNamePluralFromSingular = ({
|
||||||
@ -12,7 +12,6 @@ export const useObjectNamePluralFromSingular = ({
|
|||||||
objectNameSingular: string;
|
objectNameSingular: string;
|
||||||
}) => {
|
}) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
objectMetadataItemFamilySelector({
|
objectMetadataItemFamilySelector({
|
||||||
@ -23,7 +22,7 @@ export const useObjectNamePluralFromSingular = ({
|
|||||||
|
|
||||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
generatedMockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
objectMetadataItem.nameSingular === objectNameSingular,
|
objectMetadataItem.nameSingular === objectNameSingular,
|
||||||
) ?? null;
|
) ?? null;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ import { useRecoilValue } from 'recoil';
|
|||||||
|
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { isDefined } from '~/utils/isDefined';
|
import { isDefined } from '~/utils/isDefined';
|
||||||
|
|
||||||
export const useObjectNameSingularFromPlural = ({
|
export const useObjectNameSingularFromPlural = ({
|
||||||
@ -13,8 +13,6 @@ export const useObjectNameSingularFromPlural = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
let objectMetadataItem = useRecoilValue(
|
let objectMetadataItem = useRecoilValue(
|
||||||
objectMetadataItemFamilySelector({
|
objectMetadataItemFamilySelector({
|
||||||
objectName: objectNamePlural,
|
objectName: objectNamePlural,
|
||||||
@ -24,7 +22,7 @@ export const useObjectNameSingularFromPlural = ({
|
|||||||
|
|
||||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||||
objectMetadataItem =
|
objectMetadataItem =
|
||||||
mockObjectMetadataItems.find(
|
generatedMockObjectMetadataItems.find(
|
||||||
(objectMetadataItem) =>
|
(objectMetadataItem) =>
|
||||||
objectMetadataItem.namePlural === objectNamePlural,
|
objectMetadataItem.namePlural === objectNamePlural,
|
||||||
) ?? null;
|
) ?? null;
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName';
|
import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('getObjectMetadataItemBySingularName', () => {
|
describe('getObjectMetadataItemBySingularName', () => {
|
||||||
it('should work as expected', () => {
|
it('should work as expected', () => {
|
||||||
const firstObjectMetadataItem = mockObjectMetadataItems[0];
|
const firstObjectMetadataItem = generatedMockObjectMetadataItems[0];
|
||||||
|
|
||||||
const foundObjectMetadataItem = getObjectMetadataItemByNameSingular({
|
const foundObjectMetadataItem = getObjectMetadataItemByNameSingular({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
objectNameSingular: firstObjectMetadataItem.nameSingular,
|
objectNameSingular: firstObjectMetadataItem.nameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField';
|
import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('getObjectOrderByField', () => {
|
describe('getObjectOrderByField', () => {
|
||||||
it('should work as expected', () => {
|
it('should work as expected', () => {
|
||||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
const res = getOrderByFieldForObjectMetadataItem(objectMetadataItem);
|
const res = getOrderByFieldForObjectMetadataItem(objectMetadataItem);
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('getObjectSlug', () => {
|
describe('getObjectSlug', () => {
|
||||||
it('should work as expected', () => {
|
it('should work as expected', () => {
|
||||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
|
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
describe('isObjectMetadataAvailableForRelation', () => {
|
describe('isObjectMetadataAvailableForRelation', () => {
|
||||||
it('should work as expected', () => {
|
it('should work as expected', () => {
|
||||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
|
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { normalizeGQLField } from '~/utils/normalizeGQLField';
|
import { normalizeGQLField } from '~/utils/normalizeGQLField';
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
|
||||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ if (!personObjectMetadataItem) {
|
|||||||
describe('mapFieldMetadataToGraphQLQuery', () => {
|
describe('mapFieldMetadataToGraphQLQuery', () => {
|
||||||
it('should return fieldName if simpleValue', async () => {
|
it('should return fieldName if simpleValue', async () => {
|
||||||
const res = mapFieldMetadataToGraphQLQuery({
|
const res = mapFieldMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
field: personObjectMetadataItem.fields.find(
|
field: personObjectMetadataItem.fields.find(
|
||||||
(field) => field.name === 'id',
|
(field) => field.name === 'id',
|
||||||
)!,
|
)!,
|
||||||
@ -24,7 +22,7 @@ describe('mapFieldMetadataToGraphQLQuery', () => {
|
|||||||
});
|
});
|
||||||
it('should return fieldName if composite', async () => {
|
it('should return fieldName if composite', async () => {
|
||||||
const res = mapFieldMetadataToGraphQLQuery({
|
const res = mapFieldMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
field: personObjectMetadataItem.fields.find(
|
field: personObjectMetadataItem.fields.find(
|
||||||
(field) => field.name === 'name',
|
(field) => field.name === 'name',
|
||||||
)!,
|
)!,
|
||||||
@ -40,7 +38,7 @@ describe('mapFieldMetadataToGraphQLQuery', () => {
|
|||||||
|
|
||||||
it('should return non relation subFields if relation', async () => {
|
it('should return non relation subFields if relation', async () => {
|
||||||
const res = mapFieldMetadataToGraphQLQuery({
|
const res = mapFieldMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
field: personObjectMetadataItem.fields.find(
|
field: personObjectMetadataItem.fields.find(
|
||||||
(field) => field.name === 'company',
|
(field) => field.name === 'company',
|
||||||
)!,
|
)!,
|
||||||
@ -96,7 +94,7 @@ idealCustomerProfile
|
|||||||
|
|
||||||
it('should return only return relation subFields that are in recordGqlFields', async () => {
|
it('should return only return relation subFields that are in recordGqlFields', async () => {
|
||||||
const res = mapFieldMetadataToGraphQLQuery({
|
const res = mapFieldMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
relationrecordFields: {
|
relationrecordFields: {
|
||||||
accountOwner: { id: true, name: true },
|
accountOwner: { id: true, name: true },
|
||||||
people: true,
|
people: true,
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { normalizeGQLQuery } from '~/utils/normalizeGQLQuery';
|
import { normalizeGQLQuery } from '~/utils/normalizeGQLQuery';
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
|
||||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
|
||||||
(item) => item.nameSingular === 'person',
|
(item) => item.nameSingular === 'person',
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ if (!personObjectMetadataItem) {
|
|||||||
describe('mapObjectMetadataToGraphQLQuery', () => {
|
describe('mapObjectMetadataToGraphQLQuery', () => {
|
||||||
it('should query only specified recordGqlFields', async () => {
|
it('should query only specified recordGqlFields', async () => {
|
||||||
const res = mapObjectMetadataToGraphQLQuery({
|
const res = mapObjectMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
objectMetadataItem: personObjectMetadataItem,
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
recordGqlFields: {
|
recordGqlFields: {
|
||||||
company: true,
|
company: true,
|
||||||
@ -122,7 +120,7 @@ describe('mapObjectMetadataToGraphQLQuery', () => {
|
|||||||
|
|
||||||
it('should load only specified operation fields nested', async () => {
|
it('should load only specified operation fields nested', async () => {
|
||||||
const res = mapObjectMetadataToGraphQLQuery({
|
const res = mapObjectMetadataToGraphQLQuery({
|
||||||
objectMetadataItems: mockObjectMetadataItems,
|
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||||
objectMetadataItem: personObjectMetadataItem,
|
objectMetadataItem: personObjectMetadataItem,
|
||||||
recordGqlFields: { company: { id: true }, id: true, name: true },
|
recordGqlFields: { company: { id: true }, id: true, name: true },
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,45 +1,48 @@
|
|||||||
export const PERSON_FRAGMENT = `
|
export const PERSON_FRAGMENT = `
|
||||||
__typename
|
__typename
|
||||||
updatedAt
|
name {
|
||||||
myCustomObjectId
|
firstName
|
||||||
whatsapp {
|
lastName
|
||||||
primaryPhoneNumber
|
|
||||||
primaryPhoneCountryCode
|
|
||||||
additionalPhones
|
|
||||||
}
|
}
|
||||||
linkedinLink {
|
linkedinLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
name {
|
deletedAt
|
||||||
firstName
|
createdAt
|
||||||
lastName
|
updatedAt
|
||||||
}
|
|
||||||
email
|
|
||||||
position
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
avatarUrl
|
|
||||||
jobTitle
|
jobTitle
|
||||||
|
intro
|
||||||
|
workPrefereance
|
||||||
|
performanceRating
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
performanceRating
|
city
|
||||||
createdAt
|
companyId
|
||||||
phone {
|
phones {
|
||||||
primaryPhoneNumber
|
primaryPhoneNumber
|
||||||
primaryPhoneCountryCode
|
primaryPhoneCountryCode
|
||||||
additionalPhones
|
additionalPhones
|
||||||
}
|
}
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
id
|
id
|
||||||
city
|
position
|
||||||
companyId
|
emails {
|
||||||
intro
|
primaryEmail
|
||||||
workPrefereance
|
additionalEmails
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
whatsapp {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
@ -18,7 +18,6 @@ const basePerson = {
|
|||||||
},
|
},
|
||||||
createdAt: '',
|
createdAt: '',
|
||||||
city: '',
|
city: '',
|
||||||
email: '',
|
|
||||||
jobTitle: '',
|
jobTitle: '',
|
||||||
name: {
|
name: {
|
||||||
firstName: '',
|
firstName: '',
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import { ReactNode, useEffect } from 'react';
|
|||||||
import { RecoilRoot, useRecoilState } from 'recoil';
|
import { RecoilRoot, useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import {
|
import {
|
||||||
mockPageSize,
|
mockPageSize,
|
||||||
peopleMockWithIdsOnly,
|
peopleMockWithIdsOnly,
|
||||||
@ -18,6 +17,7 @@ import {
|
|||||||
} from '@/object-record/hooks/__mocks__/useFetchAllRecordIds';
|
} from '@/object-record/hooks/__mocks__/useFetchAllRecordIds';
|
||||||
import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds';
|
import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds';
|
||||||
import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext';
|
import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ describe('useFetchAllRecordIds', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
}, [setObjectMetadataItems]);
|
}, [setObjectMetadataItems]);
|
||||||
|
|
||||||
return useFetchAllRecordIds({
|
return useFetchAllRecordIds({
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import {
|
import {
|
||||||
query,
|
query,
|
||||||
responseData,
|
responseData,
|
||||||
@ -13,6 +12,7 @@ import {
|
|||||||
} from '@/object-record/hooks/__mocks__/useFindManyRecords';
|
} from '@/object-record/hooks/__mocks__/useFindManyRecords';
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const mocks = [
|
const mocks = [
|
||||||
{
|
{
|
||||||
@ -65,11 +65,9 @@ describe('useFindManyRecords', () => {
|
|||||||
locale: 'en',
|
locale: 'en',
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
|
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFindManyRecords({
|
return useFindManyRecords({
|
||||||
objectNameSingular: 'person',
|
objectNameSingular: 'person',
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import { expect } from '@storybook/test';
|
import { expect } from '@storybook/test';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||||
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
<RecoilRoot>
|
<RecoilRoot>
|
||||||
@ -18,7 +18,7 @@ describe('useGenerateFindManyRecordsForMultipleMetadataItemsQuery', () => {
|
|||||||
const { result } = renderHook(
|
const { result } = renderHook(
|
||||||
() => {
|
() => {
|
||||||
return useGenerateCombinedFindManyRecordsQuery({
|
return useGenerateCombinedFindManyRecordsQuery({
|
||||||
operationSignatures: getObjectMetadataItemsMock()
|
operationSignatures: generatedMockObjectMetadataItems
|
||||||
.slice(0, 2)
|
.slice(0, 2)
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
objectNameSingular: item.nameSingular,
|
objectNameSingular: item.nameSingular,
|
||||||
|
|||||||
@ -72,11 +72,11 @@ export const linkFieldDefinition: FieldDefinition<FieldLinkMetadata> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const phoneFieldMetadataItem = mockedPersonObjectMetadataItem.fields?.find(
|
const phonesFieldMetadataItem = mockedPersonObjectMetadataItem.fields?.find(
|
||||||
({ name }) => name === 'phone',
|
({ name }) => name === 'phones',
|
||||||
);
|
);
|
||||||
export const phoneFieldDefinition = formatFieldMetadataItemAsFieldDefinition({
|
export const phonesFieldDefinition = formatFieldMetadataItemAsFieldDefinition({
|
||||||
field: phoneFieldMetadataItem!,
|
field: phonesFieldMetadataItem!,
|
||||||
objectMetadataItem: mockedPersonObjectMetadataItem,
|
objectMetadataItem: mockedPersonObjectMetadataItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
import { IconPencil } from 'twenty-ui';
|
import { IconPencil } from 'twenty-ui';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
phoneFieldDefinition,
|
phonesFieldDefinition,
|
||||||
relationFieldDefinition,
|
relationFieldDefinition,
|
||||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
@ -29,7 +29,7 @@ const getWrapper =
|
|||||||
</FieldContext.Provider>
|
</FieldContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||||
const RelationWrapper = getWrapper(relationFieldDefinition);
|
const RelationWrapper = getWrapper(relationFieldDefinition);
|
||||||
|
|
||||||
describe('useGetButtonIcon', () => {
|
describe('useGetButtonIcon', () => {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import { act, renderHook } from '@testing-library/react';
|
import { act, renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { phoneFieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
import { phonesFieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
import { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
@ -12,7 +12,7 @@ const recordId = 'recordId';
|
|||||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||||
<FieldContext.Provider
|
<FieldContext.Provider
|
||||||
value={{
|
value={{
|
||||||
fieldDefinition: phoneFieldDefinition,
|
fieldDefinition: phonesFieldDefinition,
|
||||||
recordId,
|
recordId,
|
||||||
hotkeyScope: 'hotkeyScope',
|
hotkeyScope: 'hotkeyScope',
|
||||||
isLabelIdentifier: false,
|
isLabelIdentifier: false,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
|||||||
import { RecoilRoot } from 'recoil';
|
import { RecoilRoot } from 'recoil';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
phoneFieldDefinition,
|
phonesFieldDefinition,
|
||||||
ratingFieldDefinition,
|
ratingFieldDefinition,
|
||||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
@ -29,7 +29,7 @@ const getWrapper =
|
|||||||
);
|
);
|
||||||
|
|
||||||
const RatingWrapper = getWrapper(ratingFieldDefinition);
|
const RatingWrapper = getWrapper(ratingFieldDefinition);
|
||||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||||
|
|
||||||
describe('useIsFieldInputOnly', () => {
|
describe('useIsFieldInputOnly', () => {
|
||||||
it('should return true', () => {
|
it('should return true', () => {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { RecoilRoot } from 'recoil';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
actorFieldDefinition,
|
actorFieldDefinition,
|
||||||
phoneFieldDefinition,
|
phonesFieldDefinition,
|
||||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useIsFieldReadOnly } from '@/object-record/record-field/hooks/useIsFieldReadOnly';
|
import { useIsFieldReadOnly } from '@/object-record/record-field/hooks/useIsFieldReadOnly';
|
||||||
@ -29,7 +29,7 @@ const getWrapper =
|
|||||||
);
|
);
|
||||||
|
|
||||||
const ActorWrapper = getWrapper(actorFieldDefinition);
|
const ActorWrapper = getWrapper(actorFieldDefinition);
|
||||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||||
|
|
||||||
describe('useIsFieldReadOnly', () => {
|
describe('useIsFieldReadOnly', () => {
|
||||||
it('should return true', () => {
|
it('should return true', () => {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi
|
|||||||
import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
|
import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import {
|
import {
|
||||||
phoneFieldDefinition,
|
phonesFieldDefinition,
|
||||||
relationFieldDefinition,
|
relationFieldDefinition,
|
||||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import {
|
import {
|
||||||
@ -33,7 +33,16 @@ const mocks: MockedResponse[] = [
|
|||||||
{
|
{
|
||||||
request: {
|
request: {
|
||||||
query,
|
query,
|
||||||
variables: { idToUpdate: 'recordId', input: { phone: '+1 123 456' } },
|
variables: {
|
||||||
|
idToUpdate: 'recordId',
|
||||||
|
input: {
|
||||||
|
phones: {
|
||||||
|
primaryPhoneNumber: '123 456',
|
||||||
|
primaryPhoneCountryCode: '+1',
|
||||||
|
additionalPhones: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
result: jest.fn(() => ({
|
result: jest.fn(() => ({
|
||||||
data: {
|
data: {
|
||||||
@ -98,7 +107,7 @@ const getWrapper =
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||||
const RelationWrapper = getWrapper(relationFieldDefinition);
|
const RelationWrapper = getWrapper(relationFieldDefinition);
|
||||||
|
|
||||||
describe('usePersistField', () => {
|
describe('usePersistField', () => {
|
||||||
@ -118,7 +127,11 @@ describe('usePersistField', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.persistField('+1 123 456');
|
result.current.persistField({
|
||||||
|
primaryPhoneNumber: '123 456',
|
||||||
|
primaryPhoneCountryCode: '+1',
|
||||||
|
additionalPhones: [],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
|
|||||||
@ -26,35 +26,13 @@ const mocks: MockedResponse[] = [
|
|||||||
) {
|
) {
|
||||||
updateCompany(id: $idToUpdate, data: $input) {
|
updateCompany(id: $idToUpdate, data: $input) {
|
||||||
__typename
|
__typename
|
||||||
id
|
updatedAt
|
||||||
visaSponsorship
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
domainName {
|
domainName {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
introVideo {
|
visaSponsorship
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
position
|
|
||||||
annualRecurringRevenue {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
employees
|
|
||||||
linkedinLink {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
workPolicy
|
|
||||||
address {
|
address {
|
||||||
addressStreet1
|
addressStreet1
|
||||||
addressStreet2
|
addressStreet2
|
||||||
@ -65,16 +43,38 @@ const mocks: MockedResponse[] = [
|
|||||||
addressLat
|
addressLat
|
||||||
addressLng
|
addressLng
|
||||||
}
|
}
|
||||||
|
position
|
||||||
|
employees
|
||||||
|
deletedAt
|
||||||
|
accountOwnerId
|
||||||
|
annualRecurringRevenue {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
id
|
||||||
name
|
name
|
||||||
updatedAt
|
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
myCustomField
|
|
||||||
createdAt
|
createdAt
|
||||||
accountOwnerId
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
workPolicy
|
||||||
|
introVideo {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
linkedinLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
tagline
|
tagline
|
||||||
idealCustomerProfile
|
idealCustomerProfile
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { MockedProvider, MockedResponse } from '@apollo/client/testing';
|
|||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import { RecoilRoot, useRecoilValue } from 'recoil';
|
import { RecoilRoot, useRecoilValue } from 'recoil';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const defaultResponseData = {
|
const defaultResponseData = {
|
||||||
pageInfo: {
|
pageInfo: {
|
||||||
@ -65,7 +66,7 @@ const mockPerson = {
|
|||||||
city: 'city',
|
city: 'city',
|
||||||
companyId: '1',
|
companyId: '1',
|
||||||
intro: 'intro',
|
intro: 'intro',
|
||||||
workPrefereance: 'workPrefereance',
|
workPreference: 'workPrefereance',
|
||||||
};
|
};
|
||||||
const mocks: MockedResponse[] = [
|
const mocks: MockedResponse[] = [
|
||||||
{
|
{
|
||||||
@ -86,48 +87,51 @@ const mocks: MockedResponse[] = [
|
|||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
__typename
|
__typename
|
||||||
updatedAt
|
name {
|
||||||
myCustomObjectId
|
firstName
|
||||||
whatsapp {
|
lastName
|
||||||
primaryPhoneNumber
|
|
||||||
primaryPhoneCountryCode
|
|
||||||
additionalPhones
|
|
||||||
}
|
}
|
||||||
linkedinLink {
|
linkedinLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
name {
|
deletedAt
|
||||||
firstName
|
createdAt
|
||||||
lastName
|
updatedAt
|
||||||
}
|
|
||||||
email
|
|
||||||
position
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
avatarUrl
|
|
||||||
jobTitle
|
jobTitle
|
||||||
|
intro
|
||||||
|
workPrefereance
|
||||||
|
performanceRating
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
performanceRating
|
city
|
||||||
createdAt
|
companyId
|
||||||
phone {
|
phones {
|
||||||
primaryPhoneNumber
|
primaryPhoneNumber
|
||||||
primaryPhoneCountryCode
|
primaryPhoneCountryCode
|
||||||
additionalPhones
|
additionalPhones
|
||||||
}
|
}
|
||||||
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
id
|
id
|
||||||
city
|
position
|
||||||
companyId
|
emails {
|
||||||
intro
|
primaryEmail
|
||||||
workPrefereance
|
additionalEmails
|
||||||
|
}
|
||||||
|
avatarUrl
|
||||||
|
whatsapp {
|
||||||
|
primaryPhoneNumber
|
||||||
|
primaryPhoneCountryCode
|
||||||
|
additionalPhones
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cursor
|
cursor
|
||||||
}
|
}
|
||||||
@ -292,9 +296,17 @@ describe('useTableData', () => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
|
(item) => item.nameSingular === 'person',
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedAtFieldMetadataItem = personObjectMetadataItem?.fields.find(
|
||||||
|
(field) => field.name === 'updatedAt',
|
||||||
|
);
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
result.current.setKanbanFieldName.setKanbanFieldMetadataName(
|
result.current.setKanbanFieldName.setKanbanFieldMetadataName(
|
||||||
result.current.kanbanData.hiddenBoardFields[0].metadata.fieldName,
|
updatedAtFieldMetadataItem?.name,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -309,7 +321,7 @@ describe('useTableData', () => {
|
|||||||
{
|
{
|
||||||
defaultValue: 'now',
|
defaultValue: 'now',
|
||||||
editButtonIcon: undefined,
|
editButtonIcon: undefined,
|
||||||
fieldMetadataId: '102963b7-3e77-4293-a1e6-1ab59a02b663',
|
fieldMetadataId: updatedAtFieldMetadataItem?.id,
|
||||||
iconName: 'IconCalendarClock',
|
iconName: 'IconCalendarClock',
|
||||||
isFilterable: true,
|
isFilterable: true,
|
||||||
isLabelIdentifier: false,
|
isLabelIdentifier: false,
|
||||||
@ -329,7 +341,7 @@ describe('useTableData', () => {
|
|||||||
relationType: undefined,
|
relationType: undefined,
|
||||||
targetFieldMetadataName: '',
|
targetFieldMetadataName: '',
|
||||||
},
|
},
|
||||||
position: 0,
|
position: 7,
|
||||||
showLabel: undefined,
|
showLabel: undefined,
|
||||||
size: 100,
|
size: 100,
|
||||||
type: 'DATE_TIME',
|
type: 'DATE_TIME',
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ComponentDecorator } from 'twenty-ui';
|
|||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import {
|
import {
|
||||||
RecordFieldValueSelectorContextProvider,
|
RecordFieldValueSelectorContextProvider,
|
||||||
@ -21,10 +21,9 @@ import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorato
|
|||||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||||
|
|
||||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import { mockPerformance } from './mock';
|
import { mockPerformance } from './mock';
|
||||||
|
|
||||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const RelationFieldValueSetterEffect = () => {
|
const RelationFieldValueSetterEffect = () => {
|
||||||
const setEntity = useSetRecoilState(
|
const setEntity = useSetRecoilState(
|
||||||
recordStoreFamilyState(mockPerformance.recordId),
|
recordStoreFamilyState(mockPerformance.recordId),
|
||||||
@ -48,7 +47,7 @@ const RelationFieldValueSetterEffect = () => {
|
|||||||
mockPerformance.relationFieldValue,
|
mockPerformance.relationFieldValue,
|
||||||
);
|
);
|
||||||
|
|
||||||
setObjectMetadataItems(objectMetadataItems);
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
|
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -5,12 +5,12 @@ import { createState } from 'twenty-ui';
|
|||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
||||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const draftValue = 'updated Name';
|
const draftValue = 'updated Name';
|
||||||
|
|
||||||
@ -55,8 +55,6 @@ const updateOneRecordMock = jest.fn();
|
|||||||
createOneRecord: createOneRecordMock,
|
createOneRecord: createOneRecordMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const Wrapper = ({
|
const Wrapper = ({
|
||||||
children,
|
children,
|
||||||
pendingRecordIdMockedValue,
|
pendingRecordIdMockedValue,
|
||||||
@ -68,7 +66,7 @@ const Wrapper = ({
|
|||||||
}) => (
|
}) => (
|
||||||
<RecoilRoot
|
<RecoilRoot
|
||||||
initializeState={(snapshot) => {
|
initializeState={(snapshot) => {
|
||||||
snapshot.set(objectMetadataItemsState, objectMetadataItems);
|
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||||
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
|
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
|
||||||
snapshot.set(draftValueState, draftValueMockedValue);
|
snapshot.set(draftValueState, draftValueMockedValue);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { act, renderHook } from '@testing-library/react';
|
|||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
|
import { useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
|
||||||
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
|
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
const scopeId = 'scopeId';
|
const scopeId = 'scopeId';
|
||||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||||
@ -13,8 +13,6 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|||||||
</RelationPickerScopeInternalContext.Provider>
|
</RelationPickerScopeInternalContext.Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const objectMetadataItemsMock = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const opportunityId = 'cb702502-4b1d-488e-9461-df3fb096ebf6';
|
const opportunityId = 'cb702502-4b1d-488e-9461-df3fb096ebf6';
|
||||||
const personId = 'ab091fd9-1b81-4dfd-bfdb-564ffee032a2';
|
const personId = 'ab091fd9-1b81-4dfd-bfdb-564ffee032a2';
|
||||||
|
|
||||||
@ -70,7 +68,7 @@ describe('useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray'
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.setObjectMetadata(objectMetadataItemsMock);
|
result.current.setObjectMetadata(generatedMockObjectMetadataItems);
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@ -26,35 +26,13 @@ const companyMocks = [
|
|||||||
) {
|
) {
|
||||||
createCompanies(data: $data, upsert: $upsert) {
|
createCompanies(data: $data, upsert: $upsert) {
|
||||||
__typename
|
__typename
|
||||||
id
|
updatedAt
|
||||||
visaSponsorship
|
|
||||||
createdBy {
|
|
||||||
source
|
|
||||||
workspaceMemberId
|
|
||||||
name
|
|
||||||
}
|
|
||||||
domainName {
|
domainName {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
introVideo {
|
visaSponsorship
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
position
|
|
||||||
annualRecurringRevenue {
|
|
||||||
amountMicros
|
|
||||||
currencyCode
|
|
||||||
}
|
|
||||||
employees
|
|
||||||
linkedinLink {
|
|
||||||
primaryLinkUrl
|
|
||||||
primaryLinkLabel
|
|
||||||
secondaryLinks
|
|
||||||
}
|
|
||||||
workPolicy
|
|
||||||
address {
|
address {
|
||||||
addressStreet1
|
addressStreet1
|
||||||
addressStreet2
|
addressStreet2
|
||||||
@ -65,16 +43,38 @@ const companyMocks = [
|
|||||||
addressLat
|
addressLat
|
||||||
addressLng
|
addressLng
|
||||||
}
|
}
|
||||||
|
position
|
||||||
|
employees
|
||||||
|
deletedAt
|
||||||
|
accountOwnerId
|
||||||
|
annualRecurringRevenue {
|
||||||
|
amountMicros
|
||||||
|
currencyCode
|
||||||
|
}
|
||||||
|
id
|
||||||
name
|
name
|
||||||
updatedAt
|
|
||||||
xLink {
|
xLink {
|
||||||
primaryLinkUrl
|
primaryLinkUrl
|
||||||
primaryLinkLabel
|
primaryLinkLabel
|
||||||
secondaryLinks
|
secondaryLinks
|
||||||
}
|
}
|
||||||
myCustomField
|
|
||||||
createdAt
|
createdAt
|
||||||
accountOwnerId
|
createdBy {
|
||||||
|
source
|
||||||
|
workspaceMemberId
|
||||||
|
name
|
||||||
|
}
|
||||||
|
workPolicy
|
||||||
|
introVideo {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
|
linkedinLink {
|
||||||
|
primaryLinkUrl
|
||||||
|
primaryLinkLabel
|
||||||
|
secondaryLinks
|
||||||
|
}
|
||||||
tagline
|
tagline
|
||||||
idealCustomerProfile
|
idealCustomerProfile
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { ReactNode } from 'react';
|
|
||||||
import { MockedProvider } from '@apollo/client/testing';
|
import { MockedProvider } from '@apollo/client/testing';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
|
import { ReactNode } from 'react';
|
||||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
|
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
|
||||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||||
|
|
||||||
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
import {
|
import {
|
||||||
query,
|
query,
|
||||||
responseData,
|
responseData,
|
||||||
@ -75,11 +75,9 @@ describe('useFilteredSearchEntityQuery', () => {
|
|||||||
locale: 'en',
|
locale: 'en',
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
|
||||||
|
|
||||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
|
|
||||||
setMetadataItems(mockObjectMetadataItems);
|
setMetadataItems(generatedMockObjectMetadataItems);
|
||||||
|
|
||||||
return useFilteredSearchEntityQuery({
|
return useFilteredSearchEntityQuery({
|
||||||
orderByField: 'name',
|
orderByField: 'name',
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
|
||||||
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||||
@ -45,7 +44,7 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = (
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
position: 2,
|
position: 2,
|
||||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
fieldMetadataId: 'REPLACE_ME',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
size: 100,
|
size: 100,
|
||||||
type: FieldMetadataType.Text,
|
type: FieldMetadataType.Text,
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||||
|
|
||||||
export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [
|
export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [
|
||||||
@ -15,7 +14,7 @@ export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [
|
|||||||
type: 'NUMBER',
|
type: 'NUMBER',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
fieldMetadataId: 'REPLACE_ME',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
iconName: 'IconBuildingSkyscraper',
|
iconName: 'IconBuildingSkyscraper',
|
||||||
type: 'TEXT',
|
type: 'TEXT',
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
import { SortDefinition } from '@/object-record/object-sort-dropdown/types/SortDefinition';
|
||||||
|
|
||||||
export const SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS = [
|
export const SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS = [
|
||||||
@ -13,7 +12,7 @@ export const SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS = [
|
|||||||
iconName: 'IconUsers',
|
iconName: 'IconUsers',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
fieldMetadataId: 'REPLACE_ME',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
iconName: 'IconBuildingSkyscraper',
|
iconName: 'IconBuildingSkyscraper',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
|
||||||
import { ViewField } from '@/views/types/ViewField';
|
import { ViewField } from '@/views/types/ViewField';
|
||||||
|
|
||||||
export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
||||||
@ -60,7 +59,7 @@ export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
|||||||
{
|
{
|
||||||
__typename: 'ViewField',
|
__typename: 'ViewField',
|
||||||
id: 'cafacdc8-cbfc-4545-8242-94787f144ace',
|
id: 'cafacdc8-cbfc-4545-8242-94787f144ace',
|
||||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
fieldMetadataId: 'REPLACE_ME',
|
||||||
size: 180,
|
size: 180,
|
||||||
createdAt: '2023-11-23T15:38:03.706Z',
|
createdAt: '2023-11-23T15:38:03.706Z',
|
||||||
viewId: '20202020-2441-4424-8163-4002c523d415',
|
viewId: '20202020-2441-4424-8163-4002c523d415',
|
||||||
|
|||||||
@ -0,0 +1,112 @@
|
|||||||
|
// Generate test for getCombinedViewFilters
|
||||||
|
|
||||||
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import { getCombinedViewFilters } from '../getCombinedViewFilters';
|
||||||
|
|
||||||
|
describe('getCombinedViewFilters', () => {
|
||||||
|
it('should return expected combined view filters when additional filters are present', () => {
|
||||||
|
const viewFilters: ViewFilter[] = [
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toUpsertViewFilters: ViewFilter[] = [
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toDeleteViewFilterIds: string[] = [];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getCombinedViewFilters(
|
||||||
|
viewFilters,
|
||||||
|
toUpsertViewFilters,
|
||||||
|
toDeleteViewFilterIds,
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return expected combined view filters when additional filters are not present', () => {
|
||||||
|
const viewFilters: ViewFilter[] = [
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toUpsertViewFilters: ViewFilter[] = [];
|
||||||
|
const toDeleteViewFilterIds: string[] = [];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getCombinedViewFilters(
|
||||||
|
viewFilters,
|
||||||
|
toUpsertViewFilters,
|
||||||
|
toDeleteViewFilterIds,
|
||||||
|
),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return expected combined view filters when additional filters are present and some filters are to be deleted', () => {
|
||||||
|
const viewFilters: ViewFilter[] = [
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toUpsertViewFilters: ViewFilter[] = [
|
||||||
|
{
|
||||||
|
__typename: 'ViewFilter',
|
||||||
|
id: 'id',
|
||||||
|
fieldMetadataId: '05731f68-6e7a-4903-8374-c0b6a9063482',
|
||||||
|
value: 'testValue',
|
||||||
|
displayValue: 'Test Display Value',
|
||||||
|
operand: ViewFilterOperand.Is,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const toDeleteViewFilterIds: string[] = ['id'];
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getCombinedViewFilters(
|
||||||
|
viewFilters,
|
||||||
|
toUpsertViewFilters,
|
||||||
|
toDeleteViewFilterIds,
|
||||||
|
),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
import { Button } from '@/ui/input/button/components/Button';
|
||||||
|
import { useActivateWorkflowVersion } from '@/workflow/hooks/useActivateWorkflowVersion';
|
||||||
|
import { useDeactivateWorkflowVersion } from '@/workflow/hooks/useDeactivateWorkflowVersion';
|
||||||
|
import { useDeleteOneWorkflowVersion } from '@/workflow/hooks/useDeleteOneWorkflowVersion';
|
||||||
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
|
import {
|
||||||
|
IconPlayerPlay,
|
||||||
|
IconPlayerStop,
|
||||||
|
IconPower,
|
||||||
|
IconTrash,
|
||||||
|
isDefined,
|
||||||
|
} from 'twenty-ui';
|
||||||
|
import { assertWorkflowWithCurrentVersionIsDefined } from '../utils/assertWorkflowWithCurrentVersionIsDefined';
|
||||||
|
|
||||||
|
export const RecordShowPageWorkflowHeader = ({
|
||||||
|
workflowId,
|
||||||
|
}: {
|
||||||
|
workflowId: string | undefined;
|
||||||
|
}) => {
|
||||||
|
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(workflowId);
|
||||||
|
|
||||||
|
const isWaitingForWorkflowWithCurrentVersion =
|
||||||
|
!isDefined(workflowWithCurrentVersion) ||
|
||||||
|
!isDefined(workflowWithCurrentVersion.currentVersion);
|
||||||
|
|
||||||
|
const { activateWorkflowVersion } = useActivateWorkflowVersion();
|
||||||
|
const { deactivateWorkflowVersion } = useDeactivateWorkflowVersion();
|
||||||
|
const { deleteOneWorkflowVersion } = useDeleteOneWorkflowVersion();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
title="Test"
|
||||||
|
variant="secondary"
|
||||||
|
Icon={IconPlayerPlay}
|
||||||
|
disabled={isWaitingForWorkflowWithCurrentVersion}
|
||||||
|
onClick={() => {}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{workflowWithCurrentVersion?.currentVersion?.status === 'DRAFT' &&
|
||||||
|
workflowWithCurrentVersion.versions?.length > 1 ? (
|
||||||
|
<Button
|
||||||
|
title="Discard Draft"
|
||||||
|
variant="secondary"
|
||||||
|
Icon={IconTrash}
|
||||||
|
disabled={isWaitingForWorkflowWithCurrentVersion}
|
||||||
|
onClick={() => {
|
||||||
|
assertWorkflowWithCurrentVersionIsDefined(
|
||||||
|
workflowWithCurrentVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
return deleteOneWorkflowVersion({
|
||||||
|
workflowId: workflowWithCurrentVersion.id,
|
||||||
|
workflowVersionId: workflowWithCurrentVersion.currentVersion.id,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{workflowWithCurrentVersion?.currentVersion?.status === 'DRAFT' ||
|
||||||
|
workflowWithCurrentVersion?.currentVersion?.status === 'DEACTIVATED' ? (
|
||||||
|
<Button
|
||||||
|
title="Activate"
|
||||||
|
variant="secondary"
|
||||||
|
Icon={IconPower}
|
||||||
|
disabled={isWaitingForWorkflowWithCurrentVersion}
|
||||||
|
onClick={() => {
|
||||||
|
assertWorkflowWithCurrentVersionIsDefined(
|
||||||
|
workflowWithCurrentVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
return activateWorkflowVersion(
|
||||||
|
workflowWithCurrentVersion.currentVersion.id,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : workflowWithCurrentVersion?.currentVersion?.status === 'ACTIVE' ? (
|
||||||
|
<Button
|
||||||
|
title="Deactivate"
|
||||||
|
variant="secondary"
|
||||||
|
Icon={IconPlayerStop}
|
||||||
|
disabled={isWaitingForWorkflowWithCurrentVersion}
|
||||||
|
onClick={() => {
|
||||||
|
assertWorkflowWithCurrentVersionIsDefined(
|
||||||
|
workflowWithCurrentVersion,
|
||||||
|
);
|
||||||
|
|
||||||
|
return deactivateWorkflowVersion(
|
||||||
|
workflowWithCurrentVersion.currentVersion.id,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,666 @@
|
|||||||
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { graphql, HttpResponse } from 'msw';
|
||||||
|
import { ComponentDecorator } from 'twenty-ui';
|
||||||
|
|
||||||
|
import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
||||||
|
import { expect, within } from '@storybook/test';
|
||||||
|
import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadataItemsDecorator';
|
||||||
|
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||||
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
|
||||||
|
const meta: Meta<typeof RecordShowPageWorkflowHeader> = {
|
||||||
|
title: 'Modules/Workflow/RecordShowPageWorkflowHeader',
|
||||||
|
component: RecordShowPageWorkflowHeader,
|
||||||
|
decorators: [
|
||||||
|
ComponentDecorator,
|
||||||
|
ObjectMetadataItemsDecorator,
|
||||||
|
SnackBarDecorator,
|
||||||
|
],
|
||||||
|
parameters: {
|
||||||
|
container: { width: 728 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof RecordShowPageWorkflowHeader>;
|
||||||
|
|
||||||
|
const blankInitialVersionWorkflowId = '78fd5184-08f4-47b7-bb60-adb541608f65';
|
||||||
|
|
||||||
|
export const BlankInitialVersion: Story = {
|
||||||
|
args: {
|
||||||
|
workflowId: blankInitialVersionWorkflowId,
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
msw: {
|
||||||
|
handlers: [
|
||||||
|
graphql.query('FindManyWorkflows', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflows: {
|
||||||
|
__typename: 'WorkflowConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: blankInitialVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindOneWorkflow', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflow: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: blankInitialVersionWorkflowId,
|
||||||
|
name: '1231 qqerrt',
|
||||||
|
statuses: null,
|
||||||
|
lastPublishedVersionId: '',
|
||||||
|
deletedAt: null,
|
||||||
|
updatedAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
position: 0,
|
||||||
|
createdAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
favorites: {
|
||||||
|
__typename: 'FavoriteConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
eventListeners: {
|
||||||
|
__typename: 'WorkflowEventListenerConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
runs: {
|
||||||
|
__typename: 'WorkflowRunConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
versions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:04.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v1',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f0',
|
||||||
|
trigger: null,
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId: blankInitialVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindManyWorkflowVersions', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflowVersions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:04.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v1',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f0',
|
||||||
|
trigger: null,
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId: blankInitialVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
...graphqlMocks.handlers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
play: async () => {
|
||||||
|
const canvas = within(document.body);
|
||||||
|
|
||||||
|
expect(await canvas.findByText('Test')).toBeVisible();
|
||||||
|
expect(await canvas.findByText('Activate')).toBeVisible();
|
||||||
|
expect(canvas.queryByText('Discard Draft')).not.toBeInTheDocument();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const activeVersionWorkflowId = 'ca177fb1-7780-4911-8b1f-ef0a245fbd61';
|
||||||
|
|
||||||
|
export const ActiveVersion: Story = {
|
||||||
|
args: {
|
||||||
|
workflowId: activeVersionWorkflowId,
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
msw: {
|
||||||
|
handlers: [
|
||||||
|
graphql.query('FindManyWorkflows', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflows: {
|
||||||
|
__typename: 'WorkflowConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJwb3NpdGlvbiI6LTEsImlkIjoiN2JlM2E4MmMtNDRiNy00MTUwLWEyZTgtNDA4ODcxNDZmNGQ0In0=',
|
||||||
|
endCursor:
|
||||||
|
'eyJwb3NpdGlvbiI6LTEsImlkIjoiN2JlM2E4MmMtNDRiNy00MTUwLWEyZTgtNDA4ODcxNDZmNGQ0In0=',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJwb3NpdGlvbiI6LTEsImlkIjoiN2JlM2E4MmMtNDRiNy00MTUwLWEyZTgtNDA4ODcxNDZmNGQ0In0=',
|
||||||
|
node: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: activeVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindOneWorkflow', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflow: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
name: 'test qqqq',
|
||||||
|
lastPublishedVersionId: 'b57e577a-ae55-4de2-ba08-fe361dcc1a57',
|
||||||
|
id: activeVersionWorkflowId,
|
||||||
|
deletedAt: null,
|
||||||
|
statuses: null,
|
||||||
|
createdAt: '2024-09-20T10:18:59.977Z',
|
||||||
|
updatedAt: '2024-09-20T16:59:37.212Z',
|
||||||
|
position: -1,
|
||||||
|
runs: {
|
||||||
|
__typename: 'WorkflowRunConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
favorites: {
|
||||||
|
__typename: 'FavoriteConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
eventListeners: {
|
||||||
|
__typename: 'WorkflowEventListenerConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
versions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-20T16:59:37.212Z',
|
||||||
|
status: 'ARCHIVED',
|
||||||
|
deletedAt: null,
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: '93c41c1d-eff3-4c91-ac61-f56cc1a0df8a',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workflowId: activeVersionWorkflowId,
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'v1',
|
||||||
|
id: '394cd0b5-bd48-41d7-a110-a92cafaf171d',
|
||||||
|
createdAt: '2024-09-20T10:19:00.141Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-20T17:01:15.637Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
deletedAt: null,
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: '93c41c1d-eff3-4c91-ac61-f56cc1a0df8a',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4177d57d-35dc-4eb1-a467-07e25cb31da0',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '0cc392d9-5f28-4d92-90a0-08180f264e68',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workflowId: activeVersionWorkflowId,
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'v3',
|
||||||
|
id: '5eae34ef-9d62-4a9e-b827-3eb927481728',
|
||||||
|
createdAt: '2024-09-20T17:01:15.637Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-20T17:00:16.097Z',
|
||||||
|
status: 'ACTIVE',
|
||||||
|
deletedAt: null,
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: '93c41c1d-eff3-4c91-ac61-f56cc1a0df8a',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4177d57d-35dc-4eb1-a467-07e25cb31da0',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workflowId: activeVersionWorkflowId,
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'v2',
|
||||||
|
id: 'b57e577a-ae55-4de2-ba08-fe361dcc1a57',
|
||||||
|
createdAt: '2024-09-20T16:59:35.755Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindManyWorkflowVersions', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflowVersions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
totalCount: 3,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: true,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTIwVDE3OjAxOjE1LjYzN1oiLCJpZCI6IjVlYWUzNGVmLTlkNjItNGE5ZS1iODI3LTNlYjkyNzQ4MTcyOCJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTIwVDE3OjAxOjE1LjYzN1oiLCJpZCI6IjVlYWUzNGVmLTlkNjItNGE5ZS1iODI3LTNlYjkyNzQ4MTcyOCJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTIwVDE3OjAxOjE1LjYzN1oiLCJpZCI6IjVlYWUzNGVmLTlkNjItNGE5ZS1iODI3LTNlYjkyNzQ4MTcyOCJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-20T17:01:15.637Z',
|
||||||
|
status: 'ACTIVE',
|
||||||
|
deletedAt: null,
|
||||||
|
steps: [
|
||||||
|
{
|
||||||
|
id: '93c41c1d-eff3-4c91-ac61-f56cc1a0df8a',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4177d57d-35dc-4eb1-a467-07e25cb31da0',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '0cc392d9-5f28-4d92-90a0-08180f264e68',
|
||||||
|
name: 'Code',
|
||||||
|
type: 'CODE',
|
||||||
|
valid: false,
|
||||||
|
settings: {
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
continueOnFailure: {
|
||||||
|
value: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
serverlessFunctionId: '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
workflowId: activeVersionWorkflowId,
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
name: 'v3',
|
||||||
|
id: '5eae34ef-9d62-4a9e-b827-3eb927481728',
|
||||||
|
createdAt: '2024-09-20T17:01:15.637Z',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
...graphqlMocks.handlers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
play: async () => {
|
||||||
|
const canvas = within(document.body);
|
||||||
|
|
||||||
|
expect(await canvas.findByText('Test')).toBeVisible();
|
||||||
|
expect(await canvas.findByText('Deactivate')).toBeVisible();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const draftVersionWithPreviousActiveVersionWorkflowId =
|
||||||
|
'89c00f14-4ebd-4675-a098-cdf59eee372b';
|
||||||
|
|
||||||
|
export const DraftVersionWithPreviousActiveVersion: Story = {
|
||||||
|
args: {
|
||||||
|
workflowId: draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
msw: {
|
||||||
|
handlers: [
|
||||||
|
graphql.query('FindManyWorkflows', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflows: {
|
||||||
|
__typename: 'WorkflowConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindOneWorkflow', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflow: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
name: '1231 qqerrt',
|
||||||
|
statuses: null,
|
||||||
|
lastPublishedVersionId: '',
|
||||||
|
deletedAt: null,
|
||||||
|
updatedAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
position: 0,
|
||||||
|
createdAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
favorites: {
|
||||||
|
__typename: 'FavoriteConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
eventListeners: {
|
||||||
|
__typename: 'WorkflowEventListenerConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
runs: {
|
||||||
|
__typename: 'WorkflowRunConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
versions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:04.725Z',
|
||||||
|
status: 'ACTIVE',
|
||||||
|
name: 'v1',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f0',
|
||||||
|
trigger: null,
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId:
|
||||||
|
draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:05.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v2',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f1',
|
||||||
|
trigger: null,
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId:
|
||||||
|
draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindManyWorkflowVersions', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflowVersions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:05.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v2',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f1',
|
||||||
|
trigger: null,
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId:
|
||||||
|
draftVersionWithPreviousActiveVersionWorkflowId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
...graphqlMocks.handlers,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
play: async () => {
|
||||||
|
const canvas = within(document.body);
|
||||||
|
|
||||||
|
expect(await canvas.findByText('Test')).toBeVisible();
|
||||||
|
expect(await canvas.findByText('Discard Draft')).toBeVisible();
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const ACTIVATE_WORKFLOW_VERSION = gql`
|
||||||
|
mutation ActivateWorkflowVersion($workflowVersionId: String!) {
|
||||||
|
activateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const DEACTIVATE_WORKFLOW_VERSION = gql`
|
||||||
|
mutation DeactivateWorkflowVersion($workflowVersionId: String!) {
|
||||||
|
deactivateWorkflowVersion(workflowVersionId: $workflowVersionId)
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||||
|
import { ApolloClient, useApolloClient, useMutation } from '@apollo/client';
|
||||||
|
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||||
|
import { ACTIVATE_WORKFLOW_VERSION } from '@/workflow/graphql/activateWorkflowVersion';
|
||||||
|
import {
|
||||||
|
ActivateWorkflowVersionMutation,
|
||||||
|
ActivateWorkflowVersionMutationVariables,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useActivateWorkflowVersion = () => {
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const apolloMetadataClient = useApolloMetadataClient();
|
||||||
|
const [mutate] = useMutation<
|
||||||
|
ActivateWorkflowVersionMutation,
|
||||||
|
ActivateWorkflowVersionMutationVariables
|
||||||
|
>(ACTIVATE_WORKFLOW_VERSION, {
|
||||||
|
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { findOneRecordQuery: findOneWorkflowVersionQuery } =
|
||||||
|
useFindOneRecordQuery({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
const activateWorkflowVersion = async (workflowVersionId: string) => {
|
||||||
|
await mutate({
|
||||||
|
variables: {
|
||||||
|
workflowVersionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await apolloClient.query({
|
||||||
|
query: findOneWorkflowVersionQuery,
|
||||||
|
variables: {
|
||||||
|
objectRecordId: workflowVersionId,
|
||||||
|
},
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return { activateWorkflowVersion };
|
||||||
|
};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||||
|
import { WorkflowVersion } from '@/workflow/types/Workflow';
|
||||||
|
|
||||||
|
export const useCreateNewWorkflowVersion = ({
|
||||||
|
workflowId,
|
||||||
|
}: {
|
||||||
|
workflowId: string;
|
||||||
|
}) => {
|
||||||
|
const { createOneRecord: createOneWorkflowVersion } =
|
||||||
|
useCreateOneRecord<WorkflowVersion>({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
const createNewWorkflowVersion = (
|
||||||
|
workflowVersionData: Pick<
|
||||||
|
WorkflowVersion,
|
||||||
|
'name' | 'status' | 'trigger' | 'steps'
|
||||||
|
>,
|
||||||
|
) => {
|
||||||
|
return createOneWorkflowVersion({
|
||||||
|
workflowId,
|
||||||
|
...workflowVersionData,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createNewWorkflowVersion,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
|
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/states/workflowCreateStepFromParentStepIdState';
|
import { workflowCreateStepFromParentStepIdState } from '@/workflow/states/workflowCreateStepFromParentStepIdState';
|
||||||
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/states/workflowDiagramTriggerNodeSelectionState';
|
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/states/workflowDiagramTriggerNodeSelectionState';
|
||||||
import {
|
import {
|
||||||
@ -31,7 +32,11 @@ export const useCreateStep = ({
|
|||||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
const insertNodeAndSave = ({
|
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||||
|
workflowId: workflow.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const insertNodeAndSave = async ({
|
||||||
parentNodeId,
|
parentNodeId,
|
||||||
nodeToAdd,
|
nodeToAdd,
|
||||||
}: {
|
}: {
|
||||||
@ -43,15 +48,28 @@ export const useCreateStep = ({
|
|||||||
throw new Error("Can't add a node when there is no current version.");
|
throw new Error("Can't add a node when there is no current version.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateOneWorkflowVersion({
|
const updatedSteps = insertStep({
|
||||||
idToUpdate: currentVersion.id,
|
steps: currentVersion.steps ?? [],
|
||||||
updateOneRecordInput: {
|
parentStepId: parentNodeId,
|
||||||
steps: insertStep({
|
stepToAdd: nodeToAdd,
|
||||||
steps: currentVersion.steps ?? [],
|
});
|
||||||
parentStepId: parentNodeId,
|
|
||||||
stepToAdd: nodeToAdd,
|
if (workflow.currentVersion.status === 'DRAFT') {
|
||||||
}),
|
await updateOneWorkflowVersion({
|
||||||
},
|
idToUpdate: currentVersion.id,
|
||||||
|
updateOneRecordInput: {
|
||||||
|
steps: updatedSteps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await createNewWorkflowVersion({
|
||||||
|
name: `v${workflow.versions.length + 1}`,
|
||||||
|
status: 'DRAFT',
|
||||||
|
trigger: workflow.currentVersion.trigger,
|
||||||
|
steps: updatedSteps,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||||
|
import { ApolloClient, useApolloClient, useMutation } from '@apollo/client';
|
||||||
|
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||||
|
import { DEACTIVATE_WORKFLOW_VERSION } from '@/workflow/graphql/deactivateWorkflowVersion';
|
||||||
|
import {
|
||||||
|
ActivateWorkflowVersionMutation,
|
||||||
|
ActivateWorkflowVersionMutationVariables,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useDeactivateWorkflowVersion = () => {
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const apolloMetadataClient = useApolloMetadataClient();
|
||||||
|
const [mutate] = useMutation<
|
||||||
|
ActivateWorkflowVersionMutation,
|
||||||
|
ActivateWorkflowVersionMutationVariables
|
||||||
|
>(DEACTIVATE_WORKFLOW_VERSION, {
|
||||||
|
client: apolloMetadataClient ?? ({} as ApolloClient<any>),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { findOneRecordQuery: findOneWorkflowVersionQuery } =
|
||||||
|
useFindOneRecordQuery({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deactivateWorkflowVersion = async (workflowVersionId: string) => {
|
||||||
|
await mutate({
|
||||||
|
variables: {
|
||||||
|
workflowVersionId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await apolloClient.query({
|
||||||
|
query: findOneWorkflowVersionQuery,
|
||||||
|
variables: {
|
||||||
|
objectRecordId: workflowVersionId,
|
||||||
|
},
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return { deactivateWorkflowVersion };
|
||||||
|
};
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||||
|
import { useFindOneRecordQuery } from '@/object-record/hooks/useFindOneRecordQuery';
|
||||||
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
|
||||||
|
export const useDeleteOneWorkflowVersion = () => {
|
||||||
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
|
const { findOneRecordQuery: findOneWorkflowRecordQuery } =
|
||||||
|
useFindOneRecordQuery({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.Workflow,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { deleteOneRecord } = useDeleteOneRecord({
|
||||||
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
const deleteOneWorkflowVersion = async ({
|
||||||
|
workflowId,
|
||||||
|
workflowVersionId,
|
||||||
|
}: {
|
||||||
|
workflowId: string;
|
||||||
|
workflowVersionId: string;
|
||||||
|
}) => {
|
||||||
|
await deleteOneRecord(workflowVersionId);
|
||||||
|
|
||||||
|
await apolloClient.query({
|
||||||
|
query: findOneWorkflowRecordQuery,
|
||||||
|
variables: {
|
||||||
|
objectRecordId: workflowId,
|
||||||
|
},
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return { deleteOneWorkflowVersion };
|
||||||
|
};
|
||||||
@ -1,5 +1,6 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
|
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||||
import {
|
import {
|
||||||
WorkflowStep,
|
WorkflowStep,
|
||||||
WorkflowVersion,
|
WorkflowVersion,
|
||||||
@ -20,20 +21,37 @@ export const useUpdateWorkflowVersionStep = ({
|
|||||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||||
|
workflowId: workflow.id,
|
||||||
|
});
|
||||||
|
|
||||||
const updateStep = async (updatedStep: WorkflowStep) => {
|
const updateStep = async (updatedStep: WorkflowStep) => {
|
||||||
if (!isDefined(workflow.currentVersion)) {
|
if (!isDefined(workflow.currentVersion)) {
|
||||||
throw new Error('Can not update an undefined workflow version.');
|
throw new Error('Can not update an undefined workflow version.');
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateOneWorkflowVersion({
|
const updatedSteps = replaceStep({
|
||||||
idToUpdate: workflow.currentVersion.id,
|
steps: workflow.currentVersion.steps ?? [],
|
||||||
updateOneRecordInput: {
|
stepId,
|
||||||
steps: replaceStep({
|
stepToReplace: updatedStep,
|
||||||
steps: workflow.currentVersion.steps ?? [],
|
});
|
||||||
stepId,
|
|
||||||
stepToReplace: updatedStep,
|
if (workflow.currentVersion.status === 'DRAFT') {
|
||||||
}),
|
await updateOneWorkflowVersion({
|
||||||
},
|
idToUpdate: workflow.currentVersion.id,
|
||||||
|
updateOneRecordInput: {
|
||||||
|
steps: updatedSteps,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await createNewWorkflowVersion({
|
||||||
|
name: `v${workflow.versions.length + 1}`,
|
||||||
|
status: 'DRAFT',
|
||||||
|
trigger: workflow.currentVersion.trigger,
|
||||||
|
steps: updatedSteps,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
|
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||||
import {
|
import {
|
||||||
WorkflowTrigger,
|
WorkflowTrigger,
|
||||||
WorkflowVersion,
|
WorkflowVersion,
|
||||||
@ -17,16 +18,31 @@ export const useUpdateWorkflowVersionTrigger = ({
|
|||||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||||
|
workflowId: workflow.id,
|
||||||
|
});
|
||||||
|
|
||||||
const updateTrigger = async (updatedTrigger: WorkflowTrigger) => {
|
const updateTrigger = async (updatedTrigger: WorkflowTrigger) => {
|
||||||
if (!isDefined(workflow.currentVersion)) {
|
if (!isDefined(workflow.currentVersion)) {
|
||||||
throw new Error('Can not update an undefined workflow version.');
|
throw new Error('Can not update an undefined workflow version.');
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateOneWorkflowVersion({
|
if (workflow.currentVersion.status === 'DRAFT') {
|
||||||
idToUpdate: workflow.currentVersion.id,
|
await updateOneWorkflowVersion({
|
||||||
updateOneRecordInput: {
|
idToUpdate: workflow.currentVersion.id,
|
||||||
trigger: updatedTrigger,
|
updateOneRecordInput: {
|
||||||
},
|
trigger: updatedTrigger,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await createNewWorkflowVersion({
|
||||||
|
name: `v${workflow.versions.length + 1}`,
|
||||||
|
status: 'DRAFT',
|
||||||
|
trigger: updatedTrigger,
|
||||||
|
steps: workflow.currentVersion.steps,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,9 @@ export const useWorkflowWithCurrentVersion = (
|
|||||||
id: true,
|
id: true,
|
||||||
name: true,
|
name: true,
|
||||||
statuses: true,
|
statuses: true,
|
||||||
|
versions: {
|
||||||
|
totalCount: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
skip: !isDefined(workflowId),
|
skip: !isDefined(workflowId),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
import {
|
||||||
|
Workflow,
|
||||||
|
WorkflowVersion,
|
||||||
|
WorkflowWithCurrentVersion,
|
||||||
|
} from '@/workflow/types/Workflow';
|
||||||
|
import { isDefined } from 'twenty-ui';
|
||||||
|
|
||||||
|
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||||
|
export function assertWorkflowWithCurrentVersionIsDefined(
|
||||||
|
workflow: WorkflowWithCurrentVersion | undefined,
|
||||||
|
): asserts workflow is Workflow & { currentVersion: WorkflowVersion } {
|
||||||
|
if (!isDefined(workflow) || !isDefined(workflow.currentVersion)) {
|
||||||
|
throw new Error('Expected workflow and its current version to be defined');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,16 @@
|
|||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
|
|
||||||
import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext';
|
import { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||||
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
|
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||||
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
|
|
||||||
import { ShowPageAddButton } from '@/ui/layout/show-page/components/ShowPageAddButton';
|
|
||||||
import { ShowPageMoreButton } from '@/ui/layout/show-page/components/ShowPageMoreButton';
|
|
||||||
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
||||||
|
import { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
||||||
|
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
||||||
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
||||||
|
|
||||||
export const RecordShowPage = () => {
|
export const RecordShowPage = () => {
|
||||||
@ -46,22 +46,21 @@ export const RecordShowPage = () => {
|
|||||||
headerIcon={headerIcon}
|
headerIcon={headerIcon}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<PageFavoriteButton
|
{objectNameSingular === CoreObjectNameSingular.Workflow ? (
|
||||||
isFavorite={isFavorite}
|
<RecordShowPageWorkflowHeader
|
||||||
onClick={handleFavoriteButtonClick}
|
workflowId={parameters.objectRecordId}
|
||||||
/>
|
/>
|
||||||
<ShowPageAddButton
|
) : (
|
||||||
key="add"
|
<RecordShowPageBaseHeader
|
||||||
activityTargetObject={{
|
{...{
|
||||||
id: record?.id ?? '0',
|
isFavorite,
|
||||||
targetObjectNameSingular: objectMetadataItem?.nameSingular,
|
handleFavoriteButtonClick,
|
||||||
}}
|
record,
|
||||||
/>
|
objectMetadataItem,
|
||||||
<ShowPageMoreButton
|
objectNameSingular,
|
||||||
key="more"
|
}}
|
||||||
recordId={record?.id ?? '0'}
|
/>
|
||||||
objectNameSingular={objectNameSingular}
|
)}
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
</RecordShowPageHeader>
|
</RecordShowPageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
|
|||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
|
||||||
|
import { ShowPageAddButton } from '@/ui/layout/show-page/components/ShowPageAddButton';
|
||||||
|
import { ShowPageMoreButton } from '@/ui/layout/show-page/components/ShowPageMoreButton';
|
||||||
|
|
||||||
|
export const RecordShowPageBaseHeader = ({
|
||||||
|
isFavorite,
|
||||||
|
handleFavoriteButtonClick,
|
||||||
|
record,
|
||||||
|
objectMetadataItem,
|
||||||
|
objectNameSingular,
|
||||||
|
}: {
|
||||||
|
isFavorite: boolean;
|
||||||
|
handleFavoriteButtonClick: () => void;
|
||||||
|
record: ObjectRecord | undefined;
|
||||||
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
|
objectNameSingular: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PageFavoriteButton
|
||||||
|
isFavorite={isFavorite}
|
||||||
|
onClick={handleFavoriteButtonClick}
|
||||||
|
/>
|
||||||
|
<ShowPageAddButton
|
||||||
|
key="add"
|
||||||
|
activityTargetObject={{
|
||||||
|
id: record?.id ?? '0',
|
||||||
|
targetObjectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<ShowPageMoreButton
|
||||||
|
key="more"
|
||||||
|
recordId={record?.id ?? '0'}
|
||||||
|
objectNameSingular={objectNameSingular}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -416,6 +416,133 @@ export const graphqlMocks = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
graphql.query('FindManyWorkflows', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflows: {
|
||||||
|
__typename: 'WorkflowConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJpZCI6IjIwMGMxNTA4LWYxMDItNGJiOS1hZjMyLWVkYTU1MjM5YWU2MSJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: '200c1508-f102-4bb9-af32-eda55239ae61',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindOneWorkflow', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflow: {
|
||||||
|
__typename: 'Workflow',
|
||||||
|
id: '200c1508-f102-4bb9-af32-eda55239ae61',
|
||||||
|
name: '1231 qqerrt',
|
||||||
|
statuses: null,
|
||||||
|
lastPublishedVersionId: '',
|
||||||
|
deletedAt: null,
|
||||||
|
updatedAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
position: 0,
|
||||||
|
createdAt: '2024-09-19T10:10:04.505Z',
|
||||||
|
favorites: {
|
||||||
|
__typename: 'FavoriteConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
eventListeners: {
|
||||||
|
__typename: 'WorkflowEventListenerConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
runs: {
|
||||||
|
__typename: 'WorkflowRunConnection',
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
versions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:04.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v1',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f0',
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId: '200c1508-f102-4bb9-af32-eda55239ae61',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
graphql.query('FindManyWorkflowVersions', () => {
|
||||||
|
return HttpResponse.json({
|
||||||
|
data: {
|
||||||
|
workflowVersions: {
|
||||||
|
__typename: 'WorkflowVersionConnection',
|
||||||
|
totalCount: 1,
|
||||||
|
pageInfo: {
|
||||||
|
__typename: 'PageInfo',
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
endCursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
},
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
__typename: 'WorkflowVersionEdge',
|
||||||
|
cursor:
|
||||||
|
'eyJjcmVhdGVkQXQiOiIyMDI0LTA5LTE5VDEwOjEwOjA0LjcyNVoiLCJpZCI6ImY2MTg4NDNhLTI2YmUtNGE1NC1hNjBmLWY0Y2U4OGE1OTRmMCJ9',
|
||||||
|
node: {
|
||||||
|
__typename: 'WorkflowVersion',
|
||||||
|
updatedAt: '2024-09-19T10:13:12.075Z',
|
||||||
|
steps: null,
|
||||||
|
createdAt: '2024-09-19T10:10:04.725Z',
|
||||||
|
status: 'DRAFT',
|
||||||
|
name: 'v1',
|
||||||
|
id: 'f618843a-26be-4a54-a60f-f4ce88a594f0',
|
||||||
|
trigger: {
|
||||||
|
type: 'DATABASE_EVENT',
|
||||||
|
settings: {
|
||||||
|
eventName: 'note.created',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
workflowId: '200c1508-f102-4bb9-af32-eda55239ae61',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
http.get('https://chat-assets.frontapp.com/v1/chat.bundle.js', () => {
|
http.get('https://chat-assets.frontapp.com/v1/chat.bundle.js', () => {
|
||||||
return HttpResponse.text(
|
return HttpResponse.text(
|
||||||
`
|
`
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from 'react';
|
|||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||||
|
|
||||||
export const JestObjectMetadataItemSetter = ({
|
export const JestObjectMetadataItemSetter = ({
|
||||||
children,
|
children,
|
||||||
@ -12,7 +12,7 @@ export const JestObjectMetadataItemSetter = ({
|
|||||||
const setObjectMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
const setObjectMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
}, [setObjectMetadataItems]);
|
}, [setObjectMetadataItems]);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ import {
|
|||||||
ObjectEdge,
|
ObjectEdge,
|
||||||
ObjectMetadataItemsQuery,
|
ObjectMetadataItemsQuery,
|
||||||
} from '~/generated-metadata/graphql';
|
} from '~/generated-metadata/graphql';
|
||||||
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/standard-metadata-query-result';
|
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
|
||||||
|
|
||||||
// TODO: replace with new mock
|
// TODO: replace with new mock
|
||||||
const customObjectMetadataItemEdge: ObjectEdge = {
|
const customObjectMetadataItemEdge: ObjectEdge = {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/standard-metadata-query-result';
|
import { mockedStandardObjectMetadataQueryResult } from '~/testing/mock-data/generated/mock-metadata-query-result';
|
||||||
|
|
||||||
export const generatedMockObjectMetadataItems: ObjectMetadataItem[] =
|
export const generatedMockObjectMetadataItems: ObjectMetadataItem[] =
|
||||||
mockedStandardObjectMetadataQueryResult.objects.edges.map((edge) => ({
|
mockedStandardObjectMetadataQueryResult.objects.edges.map((edge) => ({
|
||||||
|
|||||||
@ -28,7 +28,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [],
|
"files": [],
|
||||||
"exclude": ["**/object-metadata/utils/getObjectMetadataItemsMock.ts"],
|
|
||||||
"include": [],
|
"include": [],
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import {
|
|||||||
getDevSeedCompanyCustomFields,
|
getDevSeedCompanyCustomFields,
|
||||||
getDevSeedPeopleCustomFields,
|
getDevSeedPeopleCustomFields,
|
||||||
} from 'src/database/typeorm-seeds/metadata/fieldsMetadata';
|
} from 'src/database/typeorm-seeds/metadata/fieldsMetadata';
|
||||||
|
import { getDevSeedCustomObjects } from 'src/database/typeorm-seeds/metadata/objectsMetadata';
|
||||||
import { seedCalendarChannels } from 'src/database/typeorm-seeds/workspace/calendar-channel';
|
import { seedCalendarChannels } from 'src/database/typeorm-seeds/workspace/calendar-channel';
|
||||||
import { seedCalendarChannelEventAssociations } from 'src/database/typeorm-seeds/workspace/calendar-channel-event-association';
|
import { seedCalendarChannelEventAssociations } from 'src/database/typeorm-seeds/workspace/calendar-channel-event-association';
|
||||||
import { seedCalendarEventParticipants } from 'src/database/typeorm-seeds/workspace/calendar-event-participants';
|
import { seedCalendarEventParticipants } from 'src/database/typeorm-seeds/workspace/calendar-event-participants';
|
||||||
@ -150,6 +151,7 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
|
|||||||
objectMetadataMap[STANDARD_OBJECT_IDS.person],
|
objectMetadataMap[STANDARD_OBJECT_IDS.person],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
await this.seedCustomObjects(workspaceId, dataSourceMetadata.id);
|
||||||
|
|
||||||
await workspaceDataSource.transaction(
|
await workspaceDataSource.transaction(
|
||||||
async (entityManager: EntityManager) => {
|
async (entityManager: EntityManager) => {
|
||||||
@ -282,4 +284,15 @@ export class DataSeedWorkspaceCommand extends CommandRunner {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async seedCustomObjects(workspaceId: string, dataSourceId: string) {
|
||||||
|
const devSeedCustomObjects = getDevSeedCustomObjects(
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const customObject of devSeedCustomObjects) {
|
||||||
|
await this.objectMetadataService.createOne(customObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
|
||||||
|
|
||||||
|
export const getDevSeedCustomObjects = (
|
||||||
|
workspaceId: string,
|
||||||
|
dataSourceId: string,
|
||||||
|
): CreateObjectInput[] => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
workspaceId,
|
||||||
|
dataSourceId,
|
||||||
|
labelPlural: 'Rockets',
|
||||||
|
labelSingular: 'Rocket',
|
||||||
|
namePlural: 'rockets',
|
||||||
|
nameSingular: 'rocket',
|
||||||
|
description: 'A rocket',
|
||||||
|
icon: 'IconRocket',
|
||||||
|
isRemote: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { IsNull, Not } from 'typeorm';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CreateOneResolverArgs,
|
CreateOneResolverArgs,
|
||||||
DeleteOneResolverArgs,
|
DeleteOneResolverArgs,
|
||||||
@ -11,12 +13,12 @@ import {
|
|||||||
WorkflowQueryValidationException,
|
WorkflowQueryValidationException,
|
||||||
WorkflowQueryValidationExceptionCode,
|
WorkflowQueryValidationExceptionCode,
|
||||||
} from 'src/modules/workflow/common/exceptions/workflow-query-validation.exception';
|
} from 'src/modules/workflow/common/exceptions/workflow-query-validation.exception';
|
||||||
import { assertWorkflowVersionIsDraft } from 'src/modules/workflow/common/utils/assert-workflow-version-is-draft.util';
|
|
||||||
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
|
||||||
import {
|
import {
|
||||||
WorkflowVersionStatus,
|
WorkflowVersionStatus,
|
||||||
WorkflowVersionWorkspaceEntity,
|
WorkflowVersionWorkspaceEntity,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
|
||||||
|
import { assertWorkflowVersionIsDraft } from 'src/modules/workflow/common/utils/assert-workflow-version-is-draft.util';
|
||||||
|
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowVersionValidationWorkspaceService {
|
export class WorkflowVersionValidationWorkspaceService {
|
||||||
@ -48,6 +50,8 @@ export class WorkflowVersionValidationWorkspaceService {
|
|||||||
where: {
|
where: {
|
||||||
workflowId: payload.data.workflowId,
|
workflowId: payload.data.workflowId,
|
||||||
status: WorkflowVersionStatus.DRAFT,
|
status: WorkflowVersionStatus.DRAFT,
|
||||||
|
// FIXME: soft-deleted rows selection will have to be improved globally
|
||||||
|
deletedAt: IsNull(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,5 +88,25 @@ export class WorkflowVersionValidationWorkspaceService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assertWorkflowVersionIsDraft(workflowVersion);
|
assertWorkflowVersionIsDraft(workflowVersion);
|
||||||
|
|
||||||
|
const workflowVersionRepository =
|
||||||
|
await this.twentyORMManager.getRepository<WorkflowVersionWorkspaceEntity>(
|
||||||
|
'workflowVersion',
|
||||||
|
);
|
||||||
|
|
||||||
|
const otherWorkflowVersionsExist = await workflowVersionRepository.exists({
|
||||||
|
where: {
|
||||||
|
workflowId: workflowVersion.workflowId,
|
||||||
|
deletedAt: IsNull(),
|
||||||
|
id: Not(workflowVersion.id),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!otherWorkflowVersionsExist) {
|
||||||
|
throw new WorkflowQueryValidationException(
|
||||||
|
'The initial version of a workflow can not be deleted',
|
||||||
|
WorkflowQueryValidationExceptionCode.FORBIDDEN,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -203,6 +203,10 @@ export class WorkflowTriggerWorkspaceService {
|
|||||||
workflowVersionNullable,
|
workflowVersionNullable,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (workflowVersion.status !== WorkflowVersionStatus.ACTIVE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.setDeactivatedVersionStatus(
|
await this.setDeactivatedVersionStatus(
|
||||||
workflowVersion,
|
workflowVersion,
|
||||||
workflowVersionRepository,
|
workflowVersionRepository,
|
||||||
|
|||||||
@ -138,6 +138,8 @@ export {
|
|||||||
IconPhotoUp,
|
IconPhotoUp,
|
||||||
IconPilcrow,
|
IconPilcrow,
|
||||||
IconPlayerPlay,
|
IconPlayerPlay,
|
||||||
|
IconPlayerStop,
|
||||||
|
IconPower,
|
||||||
IconPlaystationSquare,
|
IconPlaystationSquare,
|
||||||
IconPlug,
|
IconPlug,
|
||||||
IconPlus,
|
IconPlus,
|
||||||
|
|||||||
Reference in New Issue
Block a user