mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-25 20:00:34 +03:00
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:
parent
75b493ba6c
commit
729c990546
@ -6,7 +6,6 @@ module.exports = {
|
||||
'mockServiceWorker.js',
|
||||
'**/generated*/*',
|
||||
'**/generated/standard-metadata-query-result.ts',
|
||||
'**/getObjectMetadataItemsMock.ts',
|
||||
'tsup.config.ts',
|
||||
'build',
|
||||
'coverage',
|
||||
|
@ -2,13 +2,14 @@
|
||||
/* tslint:disable */
|
||||
|
||||
/**
|
||||
* Mock Service Worker (2.0.11).
|
||||
* Mock Service Worker.
|
||||
* @see https://github.com/mswjs/msw
|
||||
* - Please do NOT modify this file.
|
||||
* - 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 activeClientIds = new Set()
|
||||
|
||||
@ -48,7 +49,10 @@ self.addEventListener('message', async function (event) {
|
||||
case 'INTEGRITY_CHECK_REQUEST': {
|
||||
sendToClient(client, {
|
||||
type: 'INTEGRITY_CHECK_RESPONSE',
|
||||
payload: INTEGRITY_CHECKSUM,
|
||||
payload: {
|
||||
packageVersion: PACKAGE_VERSION,
|
||||
checksum: INTEGRITY_CHECKSUM,
|
||||
},
|
||||
})
|
||||
break
|
||||
}
|
||||
@ -202,13 +206,6 @@ async function getResponse(event, client, requestId) {
|
||||
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.
|
||||
const requestBuffer = await request.arrayBuffer()
|
||||
const clientMessage = await sendToClient(
|
||||
@ -240,7 +237,7 @@ async function getResponse(event, client, requestId) {
|
||||
return respondWithMock(clientMessage.data)
|
||||
}
|
||||
|
||||
case 'MOCK_NOT_FOUND': {
|
||||
case '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 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<{
|
||||
appTokenId: Scalars['String'];
|
||||
}>;
|
||||
@ -2886,6 +2900,68 @@ export function useGetCurrentUserLazyQuery(baseOptions?: Apollo.LazyQueryHookOpt
|
||||
export type GetCurrentUserQueryHookResult = ReturnType<typeof useGetCurrentUserQuery>;
|
||||
export type GetCurrentUserLazyQueryHookResult = ReturnType<typeof useGetCurrentUserLazyQuery>;
|
||||
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`
|
||||
mutation DeleteWorkspaceInvitation($appTokenId: String!) {
|
||||
deleteWorkspaceInvitation(appTokenId: $appTokenId)
|
||||
|
@ -7,11 +7,10 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
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 { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { mockWorkspaceMembers } from '~/testing/mock-data/workspace-members';
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const cache = new InMemoryCache();
|
||||
|
||||
@ -141,7 +140,7 @@ describe('useActivityTargetObjectRecords', () => {
|
||||
|
||||
act(() => {
|
||||
result.current.setCurrentWorkspaceMember(mockWorkspaceMembers[0]);
|
||||
result.current.setObjectMetadataItems(mockObjectMetadataItems);
|
||||
result.current.setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
});
|
||||
|
||||
const activityTargetObjectRecords =
|
||||
|
@ -26,13 +26,13 @@ const mocks: MockedResponse[] = [
|
||||
mutation CreateOneTask($input: TaskCreateInput!) {
|
||||
createTask(data: $input) {
|
||||
__typename
|
||||
status
|
||||
assigneeId
|
||||
updatedAt
|
||||
body
|
||||
createdAt
|
||||
dueAt
|
||||
id
|
||||
status
|
||||
body
|
||||
assigneeId
|
||||
title
|
||||
}
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ import { RecoilRoot, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
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 gql from 'graphql-tag';
|
||||
import pick from 'lodash.pick';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { mockedTasks } from '~/testing/mock-data/tasks';
|
||||
|
||||
const mockedDate = '2024-03-15T12:00:00.000Z';
|
||||
@ -69,7 +69,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
const mockObjectMetadataItems = generatedMockObjectMetadataItems;
|
||||
|
||||
describe('useOpenCreateActivityDrawer', () => {
|
||||
it('works as expected', async () => {
|
||||
|
@ -28,20 +28,21 @@ const mocks: MockedResponse[] = [
|
||||
mutation UpdateOneTask($idToUpdate: ID!, $input: TaskUpdateInput!) {
|
||||
updateTask(id: $idToUpdate, data: $input) {
|
||||
__typename
|
||||
status
|
||||
assigneeId
|
||||
updatedAt
|
||||
body
|
||||
createdAt
|
||||
deletedAt
|
||||
dueAt
|
||||
position
|
||||
id
|
||||
title
|
||||
status
|
||||
body
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
assigneeId
|
||||
position
|
||||
title
|
||||
}
|
||||
}
|
||||
`,
|
||||
@ -53,7 +54,7 @@ const mocks: MockedResponse[] = [
|
||||
result: jest.fn(() => ({
|
||||
data: {
|
||||
updateTask: {
|
||||
__typename: 'Activity',
|
||||
__typename: 'Task',
|
||||
createdAt: '2024-03-15T07:33:14.212Z',
|
||||
reminderAt: null,
|
||||
authorId: '123',
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { gql } from '@apollo/client';
|
||||
import { AvatarType } from 'twenty-ui';
|
||||
|
||||
import { PERSON_FRAGMENT } from '@/object-record/hooks/__mocks__/personFragment';
|
||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||
|
||||
export const mockId = '8f3b2121-f194-4ba4-9fbf-2d5a37126806';
|
||||
@ -48,36 +47,38 @@ export const initialFavorites = [
|
||||
},
|
||||
];
|
||||
|
||||
export const sortedFavorites = [
|
||||
{
|
||||
id: '1',
|
||||
recordId: '2',
|
||||
position: 0,
|
||||
avatarType: 'squared',
|
||||
avatarUrl: undefined,
|
||||
labelIdentifier: 'ABC Corp',
|
||||
link: '/object/company/2',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
recordId: '4',
|
||||
position: 1,
|
||||
avatarType: 'squared',
|
||||
avatarUrl: undefined,
|
||||
labelIdentifier: 'Company Test',
|
||||
link: '/object/company/4',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
position: 2,
|
||||
key: '8f3b2121-f194-4ba4-9fbf-2d5a37126806',
|
||||
labelIdentifier: 'favoriteLabel',
|
||||
avatarUrl: 'example.com',
|
||||
avatarType: 'squared',
|
||||
link: 'example.com',
|
||||
recordId: '1',
|
||||
},
|
||||
];
|
||||
export const sortedFavorites = [
|
||||
{
|
||||
"avatarType": "rounded",
|
||||
"avatarUrl": "",
|
||||
"id": "1",
|
||||
"labelIdentifier": " ",
|
||||
"link": "/object/person/1",
|
||||
"position": 0,
|
||||
"recordId": "1",
|
||||
"workspaceMemberId": undefined,
|
||||
},
|
||||
{
|
||||
"avatarType": "rounded",
|
||||
"avatarUrl": "",
|
||||
"id": "2",
|
||||
"labelIdentifier": " ",
|
||||
"link": "/object/person/3",
|
||||
"position": 1,
|
||||
"recordId": "3",
|
||||
"workspaceMemberId": undefined,
|
||||
},
|
||||
{
|
||||
"avatarType": "squared",
|
||||
"avatarUrl": "example.com",
|
||||
"id": "3",
|
||||
"key": "8f3b2121-f194-4ba4-9fbf-2d5a37126806",
|
||||
"labelIdentifier": "favoriteLabel",
|
||||
"link": "example.com",
|
||||
"position": 2,
|
||||
"recordId": "1",
|
||||
},
|
||||
]
|
||||
|
||||
export const mocks = [
|
||||
{
|
||||
@ -86,132 +87,155 @@ export const mocks = [
|
||||
mutation CreateOneFavorite($input: FavoriteCreateInput!) {
|
||||
createFavorite(data: $input) {
|
||||
__typename
|
||||
noteId
|
||||
taskId
|
||||
myCustomObjectId
|
||||
workspaceMemberId
|
||||
workspaceMember {
|
||||
person {
|
||||
__typename
|
||||
userId
|
||||
updatedAt
|
||||
dateFormat
|
||||
id
|
||||
locale
|
||||
avatarUrl
|
||||
timeZone
|
||||
name {
|
||||
firstName
|
||||
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 {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
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 {
|
||||
addressStreet1
|
||||
addressStreet2
|
||||
@ -222,21 +246,76 @@ export const mocks = [
|
||||
addressLat
|
||||
addressLng
|
||||
}
|
||||
position
|
||||
employees
|
||||
deletedAt
|
||||
accountOwnerId
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
name
|
||||
updatedAt
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
myCustomField
|
||||
createdAt
|
||||
accountOwnerId
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
workPolicy
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
tagline
|
||||
idealCustomerProfile
|
||||
}
|
||||
person {
|
||||
${PERSON_FRAGMENT}
|
||||
rocket {
|
||||
__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) {
|
||||
__typename
|
||||
noteId
|
||||
taskId
|
||||
myCustomObjectId
|
||||
workspaceMemberId
|
||||
workspaceMember {
|
||||
person {
|
||||
__typename
|
||||
userId
|
||||
updatedAt
|
||||
dateFormat
|
||||
id
|
||||
locale
|
||||
avatarUrl
|
||||
timeZone
|
||||
name {
|
||||
firstName
|
||||
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 {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
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 {
|
||||
addressStreet1
|
||||
addressStreet2
|
||||
@ -422,21 +524,76 @@ export const mocks = [
|
||||
addressLat
|
||||
addressLng
|
||||
}
|
||||
position
|
||||
employees
|
||||
deletedAt
|
||||
accountOwnerId
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
name
|
||||
updatedAt
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
myCustomField
|
||||
createdAt
|
||||
accountOwnerId
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
workPolicy
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
tagline
|
||||
idealCustomerProfile
|
||||
}
|
||||
person {
|
||||
${PERSON_FRAGMENT}
|
||||
rocket {
|
||||
__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 { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
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 { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import {
|
||||
favoriteId,
|
||||
favoriteTargetObjectRecord,
|
||||
@ -29,8 +29,6 @@ jest.mock('@/object-record/hooks/useFindManyRecords', () => ({
|
||||
useFindManyRecords: () => ({ records: initialFavorites }),
|
||||
}));
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
|
||||
@ -51,7 +49,7 @@ describe('useFavorites', () => {
|
||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFavorites();
|
||||
},
|
||||
@ -72,7 +70,7 @@ describe('useFavorites', () => {
|
||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFavorites();
|
||||
},
|
||||
@ -100,7 +98,7 @@ describe('useFavorites', () => {
|
||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFavorites();
|
||||
},
|
||||
@ -125,7 +123,7 @@ describe('useFavorites', () => {
|
||||
setCurrentWorkspaceMember(mockWorkspaceMember);
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFavorites();
|
||||
},
|
||||
|
@ -4,16 +4,17 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||
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 { AppPath } from '@/types/AppPath';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { mockedUserData } from '~/testing/mock-data/users';
|
||||
|
||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
||||
const setupMockPrefetchedData = (viewId?: string) => {
|
||||
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'company',
|
||||
);
|
||||
|
||||
jest.mocked(usePrefetchedData).mockReturnValue({
|
||||
isDataPrefetched: true,
|
||||
records: viewId
|
||||
@ -21,7 +22,7 @@ const setupMockPrefetchedData = (viewId?: string) => {
|
||||
{
|
||||
id: viewId,
|
||||
__typename: 'object',
|
||||
objectMetadataId: COMPANY_OBJECT_METADATA_ID,
|
||||
objectMetadataId: companyObjectMetadata?.id,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
@ -36,7 +37,7 @@ const renderHooks = (withCurrentUser: boolean) => {
|
||||
objectMetadataItemsState,
|
||||
);
|
||||
|
||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
if (withCurrentUser) {
|
||||
setCurrentUser(mockedUserData);
|
||||
|
@ -6,8 +6,8 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
@ -29,7 +29,7 @@ export const ObjectMetadataItemsLoadEffect = () => {
|
||||
const toSetObjectMetadataItems =
|
||||
isUndefinedOrNull(currentUser) ||
|
||||
currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active
|
||||
? getObjectMetadataItemsMock()
|
||||
? generatedMockObjectMetadataItems
|
||||
: newObjectMetadataItems;
|
||||
if (
|
||||
!loading &&
|
||||
|
@ -3,7 +3,7 @@ import { Nullable } from 'twenty-ui';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('useColumnDefinitionsFromFieldMetadata', () => {
|
||||
it('should return empty definitions if no object is passed', () => {
|
||||
@ -22,22 +22,24 @@ describe('useColumnDefinitionsFromFieldMetadata', () => {
|
||||
});
|
||||
|
||||
it('should return expected definitions', () => {
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
const companyObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'company',
|
||||
);
|
||||
|
||||
const { result } = renderHook(
|
||||
(objectMetadataItem?: Nullable<ObjectMetadataItem>) => {
|
||||
return useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||
},
|
||||
{
|
||||
initialProps: mockObjectMetadataItems[1],
|
||||
initialProps: companyObjectMetadata,
|
||||
},
|
||||
);
|
||||
|
||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
||||
result.current;
|
||||
|
||||
expect(columnDefinitions.length).toBe(5);
|
||||
expect(filterDefinitions.length).toBe(4);
|
||||
expect(sortDefinitions.length).toBe(4);
|
||||
expect(columnDefinitions.length).toBe(21);
|
||||
expect(filterDefinitions.length).toBe(14);
|
||||
expect(sortDefinitions.length).toBe(14);
|
||||
});
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
} from '@/object-metadata/hooks/__mocks__/useFilteredObjectMetadataItems';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
@ -34,14 +34,12 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
describe('useFilteredObjectMetadataItems', () => {
|
||||
it('should findActiveObjectMetadataItemBySlug', async () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFilteredObjectMetadataItems();
|
||||
},
|
||||
@ -61,7 +59,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFilteredObjectMetadataItems();
|
||||
},
|
||||
@ -78,10 +76,14 @@ describe('useFilteredObjectMetadataItems', () => {
|
||||
});
|
||||
|
||||
it('should findObjectMetadataItemById', async () => {
|
||||
const peopleObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.namePlural === 'people',
|
||||
);
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFilteredObjectMetadataItems();
|
||||
},
|
||||
@ -92,7 +94,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
||||
|
||||
act(() => {
|
||||
const res = result.current.findObjectMetadataItemById(
|
||||
'ff2881da-89f6-4f15-8f0a-e3f355ea3b94',
|
||||
peopleObjectMetadata?.id,
|
||||
);
|
||||
expect(res).toBeDefined();
|
||||
expect(res?.namePlural).toBe('people');
|
||||
@ -103,7 +105,7 @@ describe('useFilteredObjectMetadataItems', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFilteredObjectMetadataItems();
|
||||
},
|
||||
|
@ -3,9 +3,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useGetObjectRecordIdentifierByNameSingular } from '@/object-metadata/hooks/useGetObjectRecordIdentifierByNameSingular';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('useGetObjectRecordIdentifierByNameSingular', () => {
|
||||
it('should work as expected', async () => {
|
||||
@ -19,7 +17,7 @@ describe('useGetObjectRecordIdentifierByNameSingular', () => {
|
||||
}) => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useGetObjectRecordIdentifierByNameSingular()(
|
||||
record,
|
||||
|
@ -5,7 +5,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata';
|
||||
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 }) => (
|
||||
<RecoilRoot>
|
||||
@ -15,8 +15,7 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
|
||||
describe('useGetRelationMetadata', () => {
|
||||
it('should return correct properties', async () => {
|
||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
||||
const objectMetadata = objectMetadataItems.find(
|
||||
const objectMetadata = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
const fieldMetadataItem = objectMetadata.fields.find(
|
||||
@ -28,7 +27,7 @@ describe('useGetRelationMetadata', () => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
|
||||
useEffect(() => {
|
||||
setMetadataItems(objectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
}, [setMetadataItems]);
|
||||
|
||||
return useGetRelationMetadata();
|
||||
@ -45,9 +44,10 @@ describe('useGetRelationMetadata', () => {
|
||||
relationType,
|
||||
} = result.current({ fieldMetadataItem }) ?? {};
|
||||
|
||||
const expectedRelationObjectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'opportunity',
|
||||
);
|
||||
const expectedRelationObjectMetadataItem =
|
||||
generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'opportunity',
|
||||
);
|
||||
const expectedRelationFieldMetadataItem =
|
||||
expectedRelationObjectMetadataItem?.fields.find(
|
||||
(field) => field.name === 'pointOfContact',
|
||||
|
@ -4,6 +4,7 @@ import { ReactNode } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
@ -13,6 +14,9 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
|
||||
// Split into tests for each new hook
|
||||
describe('useObjectMetadataItem', () => {
|
||||
const opportunityObjectMetadata = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'opportunity',
|
||||
);
|
||||
it('should return correct properties', async () => {
|
||||
const { result } = renderHook(
|
||||
() => useObjectMetadataItem({ objectNameSingular: 'opportunity' }),
|
||||
@ -23,6 +27,6 @@ describe('useObjectMetadataItem', () => {
|
||||
|
||||
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 { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
||||
|
||||
export const useObjectMetadataItem = ({
|
||||
@ -15,9 +15,6 @@ export const useObjectMetadataItem = ({
|
||||
}: ObjectMetadataItemIdentifier) => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
// Todo: deprecate this logic as mocked objectMetadataItems are load in ObjectMetadataItemsLoadEffect anyway
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
let objectMetadataItem = useRecoilValue(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectName: objectNameSingular,
|
||||
@ -29,11 +26,11 @@ export const useObjectMetadataItem = ({
|
||||
|
||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||
objectMetadataItem =
|
||||
mockObjectMetadataItems.find(
|
||||
generatedMockObjectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.nameSingular === objectNameSingular,
|
||||
) ?? null;
|
||||
objectMetadataItems = mockObjectMetadataItems;
|
||||
objectMetadataItems = generatedMockObjectMetadataItems;
|
||||
}
|
||||
|
||||
if (!isDefined(objectMetadataItem)) {
|
||||
|
@ -2,8 +2,8 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useObjectNamePluralFromSingular = ({
|
||||
@ -12,7 +12,6 @@ export const useObjectNamePluralFromSingular = ({
|
||||
objectNameSingular: string;
|
||||
}) => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
let objectMetadataItem = useRecoilValue(
|
||||
objectMetadataItemFamilySelector({
|
||||
@ -23,7 +22,7 @@ export const useObjectNamePluralFromSingular = ({
|
||||
|
||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||
objectMetadataItem =
|
||||
mockObjectMetadataItems.find(
|
||||
generatedMockObjectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.nameSingular === objectNameSingular,
|
||||
) ?? null;
|
||||
|
@ -2,8 +2,8 @@ import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useObjectNameSingularFromPlural = ({
|
||||
@ -13,8 +13,6 @@ export const useObjectNameSingularFromPlural = ({
|
||||
}) => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
let objectMetadataItem = useRecoilValue(
|
||||
objectMetadataItemFamilySelector({
|
||||
objectName: objectNamePlural,
|
||||
@ -24,7 +22,7 @@ export const useObjectNameSingularFromPlural = ({
|
||||
|
||||
if (currentWorkspace?.activationStatus !== WorkspaceActivationStatus.Active) {
|
||||
objectMetadataItem =
|
||||
mockObjectMetadataItems.find(
|
||||
generatedMockObjectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.namePlural === objectNamePlural,
|
||||
) ?? null;
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { getObjectMetadataItemByNameSingular } from '@/object-metadata/utils/getObjectMetadataItemBySingularName';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('getObjectMetadataItemBySingularName', () => {
|
||||
it('should work as expected', () => {
|
||||
const firstObjectMetadataItem = mockObjectMetadataItems[0];
|
||||
const firstObjectMetadataItem = generatedMockObjectMetadataItems[0];
|
||||
|
||||
const foundObjectMetadataItem = getObjectMetadataItemByNameSingular({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
objectNameSingular: firstObjectMetadataItem.nameSingular,
|
||||
});
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { getOrderByFieldForObjectMetadataItem } from '@/object-metadata/utils/getObjectOrderByField';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('getObjectOrderByField', () => {
|
||||
it('should work as expected', () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
const res = getOrderByFieldForObjectMetadataItem(objectMetadataItem);
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { getObjectSlug } from '@/object-metadata/utils/getObjectSlug';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('getObjectSlug', () => {
|
||||
it('should work as expected', () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { isObjectMetadataAvailableForRelation } from '@/object-metadata/utils/isObjectMetadataAvailableForRelation';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
describe('isObjectMetadataAvailableForRelation', () => {
|
||||
it('should work as expected', () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
const objectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { normalizeGQLField } from '~/utils/normalizeGQLField';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
||||
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
);
|
||||
|
||||
@ -15,7 +13,7 @@ if (!personObjectMetadataItem) {
|
||||
describe('mapFieldMetadataToGraphQLQuery', () => {
|
||||
it('should return fieldName if simpleValue', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'id',
|
||||
)!,
|
||||
@ -24,7 +22,7 @@ describe('mapFieldMetadataToGraphQLQuery', () => {
|
||||
});
|
||||
it('should return fieldName if composite', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'name',
|
||||
)!,
|
||||
@ -40,7 +38,7 @@ describe('mapFieldMetadataToGraphQLQuery', () => {
|
||||
|
||||
it('should return non relation subFields if relation', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!,
|
||||
@ -96,7 +94,7 @@ idealCustomerProfile
|
||||
|
||||
it('should return only return relation subFields that are in recordGqlFields', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
relationrecordFields: {
|
||||
accountOwner: { id: true, name: true },
|
||||
people: true,
|
||||
|
@ -1,10 +1,8 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { normalizeGQLQuery } from '~/utils/normalizeGQLQuery';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
||||
const personObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
);
|
||||
|
||||
@ -15,7 +13,7 @@ if (!personObjectMetadataItem) {
|
||||
describe('mapObjectMetadataToGraphQLQuery', () => {
|
||||
it('should query only specified recordGqlFields', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
recordGqlFields: {
|
||||
company: true,
|
||||
@ -122,7 +120,7 @@ describe('mapObjectMetadataToGraphQLQuery', () => {
|
||||
|
||||
it('should load only specified operation fields nested', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItems: generatedMockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
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 = `
|
||||
__typename
|
||||
updatedAt
|
||||
myCustomObjectId
|
||||
whatsapp {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
email
|
||||
position
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
avatarUrl
|
||||
deletedAt
|
||||
createdAt
|
||||
updatedAt
|
||||
jobTitle
|
||||
intro
|
||||
workPrefereance
|
||||
performanceRating
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
performanceRating
|
||||
createdAt
|
||||
phone {
|
||||
city
|
||||
companyId
|
||||
phones {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
}
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
id
|
||||
city
|
||||
companyId
|
||||
intro
|
||||
workPrefereance
|
||||
position
|
||||
emails {
|
||||
primaryEmail
|
||||
additionalEmails
|
||||
}
|
||||
avatarUrl
|
||||
whatsapp {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
}
|
||||
`
|
||||
|
@ -18,7 +18,6 @@ const basePerson = {
|
||||
},
|
||||
createdAt: '',
|
||||
city: '',
|
||||
email: '',
|
||||
jobTitle: '',
|
||||
name: {
|
||||
firstName: '',
|
||||
|
@ -4,7 +4,6 @@ import { ReactNode, useEffect } from 'react';
|
||||
import { RecoilRoot, useRecoilState } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import {
|
||||
mockPageSize,
|
||||
peopleMockWithIdsOnly,
|
||||
@ -18,6 +17,7 @@ import {
|
||||
} from '@/object-record/hooks/__mocks__/useFetchAllRecordIds';
|
||||
import { useFetchAllRecordIds } from '@/object-record/hooks/useFetchAllRecordIds';
|
||||
import { SnackBarManagerScopeInternalContext } from '@/ui/feedback/snack-bar-manager/scopes/scope-internal-context/SnackBarManagerScopeInternalContext';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
@ -75,7 +75,7 @@ describe('useFetchAllRecordIds', () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
}, [setObjectMetadataItems]);
|
||||
|
||||
return useFetchAllRecordIds({
|
||||
|
@ -5,7 +5,6 @@ import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import {
|
||||
query,
|
||||
responseData,
|
||||
@ -13,6 +12,7 @@ import {
|
||||
} from '@/object-record/hooks/__mocks__/useFindManyRecords';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
@ -65,11 +65,9 @@ describe('useFindManyRecords', () => {
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFindManyRecords({
|
||||
objectNameSingular: 'person',
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { expect } from '@storybook/test';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { useGenerateCombinedFindManyRecordsQuery } from '@/object-record/multiple-objects/hooks/useGenerateCombinedFindManyRecordsQuery';
|
||||
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
@ -18,7 +18,7 @@ describe('useGenerateFindManyRecordsForMultipleMetadataItemsQuery', () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
return useGenerateCombinedFindManyRecordsQuery({
|
||||
operationSignatures: getObjectMetadataItemsMock()
|
||||
operationSignatures: generatedMockObjectMetadataItems
|
||||
.slice(0, 2)
|
||||
.map((item) => ({
|
||||
objectNameSingular: item.nameSingular,
|
||||
|
@ -72,11 +72,11 @@ export const linkFieldDefinition: FieldDefinition<FieldLinkMetadata> = {
|
||||
},
|
||||
};
|
||||
|
||||
const phoneFieldMetadataItem = mockedPersonObjectMetadataItem.fields?.find(
|
||||
({ name }) => name === 'phone',
|
||||
const phonesFieldMetadataItem = mockedPersonObjectMetadataItem.fields?.find(
|
||||
({ name }) => name === 'phones',
|
||||
);
|
||||
export const phoneFieldDefinition = formatFieldMetadataItemAsFieldDefinition({
|
||||
field: phoneFieldMetadataItem!,
|
||||
export const phonesFieldDefinition = formatFieldMetadataItemAsFieldDefinition({
|
||||
field: phonesFieldMetadataItem!,
|
||||
objectMetadataItem: mockedPersonObjectMetadataItem,
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { IconPencil } from 'twenty-ui';
|
||||
|
||||
import {
|
||||
phoneFieldDefinition,
|
||||
phonesFieldDefinition,
|
||||
relationFieldDefinition,
|
||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
@ -29,7 +29,7 @@ const getWrapper =
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
|
||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||
const RelationWrapper = getWrapper(relationFieldDefinition);
|
||||
|
||||
describe('useGetButtonIcon', () => {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { ReactNode } from 'react';
|
||||
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 { useIsFieldEmpty } from '@/object-record/record-field/hooks/useIsFieldEmpty';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
@ -12,7 +12,7 @@ const recordId = 'recordId';
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
fieldDefinition: phoneFieldDefinition,
|
||||
fieldDefinition: phonesFieldDefinition,
|
||||
recordId,
|
||||
hotkeyScope: 'hotkeyScope',
|
||||
isLabelIdentifier: false,
|
||||
|
@ -3,7 +3,7 @@ import { ReactNode } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
import {
|
||||
phoneFieldDefinition,
|
||||
phonesFieldDefinition,
|
||||
ratingFieldDefinition,
|
||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
@ -29,7 +29,7 @@ const getWrapper =
|
||||
);
|
||||
|
||||
const RatingWrapper = getWrapper(ratingFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||
|
||||
describe('useIsFieldInputOnly', () => {
|
||||
it('should return true', () => {
|
||||
|
@ -4,7 +4,7 @@ import { RecoilRoot } from 'recoil';
|
||||
|
||||
import {
|
||||
actorFieldDefinition,
|
||||
phoneFieldDefinition,
|
||||
phonesFieldDefinition,
|
||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { useIsFieldReadOnly } from '@/object-record/record-field/hooks/useIsFieldReadOnly';
|
||||
@ -29,7 +29,7 @@ const getWrapper =
|
||||
);
|
||||
|
||||
const ActorWrapper = getWrapper(actorFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||
|
||||
describe('useIsFieldReadOnly', () => {
|
||||
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 { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import {
|
||||
phoneFieldDefinition,
|
||||
phonesFieldDefinition,
|
||||
relationFieldDefinition,
|
||||
} from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||
import {
|
||||
@ -33,7 +33,16 @@ const mocks: MockedResponse[] = [
|
||||
{
|
||||
request: {
|
||||
query,
|
||||
variables: { idToUpdate: 'recordId', input: { phone: '+1 123 456' } },
|
||||
variables: {
|
||||
idToUpdate: 'recordId',
|
||||
input: {
|
||||
phones: {
|
||||
primaryPhoneNumber: '123 456',
|
||||
primaryPhoneCountryCode: '+1',
|
||||
additionalPhones: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
result: jest.fn(() => ({
|
||||
data: {
|
||||
@ -98,7 +107,7 @@ const getWrapper =
|
||||
);
|
||||
};
|
||||
|
||||
const PhoneWrapper = getWrapper(phoneFieldDefinition);
|
||||
const PhoneWrapper = getWrapper(phonesFieldDefinition);
|
||||
const RelationWrapper = getWrapper(relationFieldDefinition);
|
||||
|
||||
describe('usePersistField', () => {
|
||||
@ -118,7 +127,11 @@ describe('usePersistField', () => {
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.persistField('+1 123 456');
|
||||
result.current.persistField({
|
||||
primaryPhoneNumber: '123 456',
|
||||
primaryPhoneCountryCode: '+1',
|
||||
additionalPhones: [],
|
||||
});
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -26,35 +26,13 @@ const mocks: MockedResponse[] = [
|
||||
) {
|
||||
updateCompany(id: $idToUpdate, data: $input) {
|
||||
__typename
|
||||
id
|
||||
visaSponsorship
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
updatedAt
|
||||
domainName {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
position
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
employees
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
workPolicy
|
||||
visaSponsorship
|
||||
address {
|
||||
addressStreet1
|
||||
addressStreet2
|
||||
@ -65,16 +43,38 @@ const mocks: MockedResponse[] = [
|
||||
addressLat
|
||||
addressLng
|
||||
}
|
||||
position
|
||||
employees
|
||||
deletedAt
|
||||
accountOwnerId
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
name
|
||||
updatedAt
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
myCustomField
|
||||
createdAt
|
||||
accountOwnerId
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
workPolicy
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
tagline
|
||||
idealCustomerProfile
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { MockedProvider, MockedResponse } from '@apollo/client/testing';
|
||||
import gql from 'graphql-tag';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { RecoilRoot, useRecoilValue } from 'recoil';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const defaultResponseData = {
|
||||
pageInfo: {
|
||||
@ -65,7 +66,7 @@ const mockPerson = {
|
||||
city: 'city',
|
||||
companyId: '1',
|
||||
intro: 'intro',
|
||||
workPrefereance: 'workPrefereance',
|
||||
workPreference: 'workPrefereance',
|
||||
};
|
||||
const mocks: MockedResponse[] = [
|
||||
{
|
||||
@ -86,48 +87,51 @@ const mocks: MockedResponse[] = [
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
updatedAt
|
||||
myCustomObjectId
|
||||
whatsapp {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
email
|
||||
position
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
avatarUrl
|
||||
deletedAt
|
||||
createdAt
|
||||
updatedAt
|
||||
jobTitle
|
||||
intro
|
||||
workPrefereance
|
||||
performanceRating
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
performanceRating
|
||||
createdAt
|
||||
phone {
|
||||
city
|
||||
companyId
|
||||
phones {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
}
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
id
|
||||
city
|
||||
companyId
|
||||
intro
|
||||
workPrefereance
|
||||
position
|
||||
emails {
|
||||
primaryEmail
|
||||
additionalEmails
|
||||
}
|
||||
avatarUrl
|
||||
whatsapp {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
additionalPhones
|
||||
}
|
||||
}
|
||||
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 () => {
|
||||
result.current.setKanbanFieldName.setKanbanFieldMetadataName(
|
||||
result.current.kanbanData.hiddenBoardFields[0].metadata.fieldName,
|
||||
updatedAtFieldMetadataItem?.name,
|
||||
);
|
||||
});
|
||||
|
||||
@ -309,7 +321,7 @@ describe('useTableData', () => {
|
||||
{
|
||||
defaultValue: 'now',
|
||||
editButtonIcon: undefined,
|
||||
fieldMetadataId: '102963b7-3e77-4293-a1e6-1ab59a02b663',
|
||||
fieldMetadataId: updatedAtFieldMetadataItem?.id,
|
||||
iconName: 'IconCalendarClock',
|
||||
isFilterable: true,
|
||||
isLabelIdentifier: false,
|
||||
@ -329,7 +341,7 @@ describe('useTableData', () => {
|
||||
relationType: undefined,
|
||||
targetFieldMetadataName: '',
|
||||
},
|
||||
position: 0,
|
||||
position: 7,
|
||||
showLabel: undefined,
|
||||
size: 100,
|
||||
type: 'DATE_TIME',
|
||||
|
@ -5,7 +5,7 @@ import { ComponentDecorator } from 'twenty-ui';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getBasePathToShowPage } from '@/object-metadata/utils/getBasePathToShowPage';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import {
|
||||
RecordFieldValueSelectorContextProvider,
|
||||
@ -21,10 +21,9 @@ import { MemoryRouterDecorator } from '~/testing/decorators/MemoryRouterDecorato
|
||||
import { getProfilingStory } from '~/testing/profiling/utils/getProfilingStory';
|
||||
|
||||
import { RecordTableCellFieldContextWrapper } from '@/object-record/record-table/record-table-cell/components/RecordTableCellFieldContextWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import { mockPerformance } from './mock';
|
||||
|
||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const RelationFieldValueSetterEffect = () => {
|
||||
const setEntity = useSetRecoilState(
|
||||
recordStoreFamilyState(mockPerformance.recordId),
|
||||
@ -48,7 +47,7 @@ const RelationFieldValueSetterEffect = () => {
|
||||
mockPerformance.relationFieldValue,
|
||||
);
|
||||
|
||||
setObjectMetadataItems(objectMetadataItems);
|
||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
}, [setEntity, setRelationEntity, setRecordValue, setObjectMetadataItems]);
|
||||
|
||||
return null;
|
||||
|
@ -5,12 +5,12 @@ import { createState } from 'twenty-ui';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { textfieldDefinition } from '@/object-record/record-field/__mocks__/fieldDefinitions';
|
||||
import { FieldContext } from '@/object-record/record-field/contexts/FieldContext';
|
||||
import { useUpsertRecord } from '@/object-record/record-table/record-table-cell/hooks/useUpsertRecord';
|
||||
import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const draftValue = 'updated Name';
|
||||
|
||||
@ -55,8 +55,6 @@ const updateOneRecordMock = jest.fn();
|
||||
createOneRecord: createOneRecordMock,
|
||||
});
|
||||
|
||||
const objectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const Wrapper = ({
|
||||
children,
|
||||
pendingRecordIdMockedValue,
|
||||
@ -68,7 +66,7 @@ const Wrapper = ({
|
||||
}) => (
|
||||
<RecoilRoot
|
||||
initializeState={(snapshot) => {
|
||||
snapshot.set(objectMetadataItemsState, objectMetadataItems);
|
||||
snapshot.set(objectMetadataItemsState, generatedMockObjectMetadataItems);
|
||||
snapshot.set(pendingRecordIdState, pendingRecordIdMockedValue);
|
||||
snapshot.set(draftValueState, draftValueMockedValue);
|
||||
}}
|
||||
|
@ -2,9 +2,9 @@ import { act, renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray } from '@/object-record/relation-picker/hooks/useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray';
|
||||
import { RelationPickerScopeInternalContext } from '@/object-record/relation-picker/scopes/scope-internal-context/RelationPickerScopeInternalContext';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
const scopeId = 'scopeId';
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
@ -13,8 +13,6 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
</RelationPickerScopeInternalContext.Provider>
|
||||
);
|
||||
|
||||
const objectMetadataItemsMock = getObjectMetadataItemsMock();
|
||||
|
||||
const opportunityId = 'cb702502-4b1d-488e-9461-df3fb096ebf6';
|
||||
const personId = 'ab091fd9-1b81-4dfd-bfdb-564ffee032a2';
|
||||
|
||||
@ -70,7 +68,7 @@ describe('useMultiObjectRecordsQueryResultFormattedAsObjectRecordForSelectArray'
|
||||
},
|
||||
);
|
||||
act(() => {
|
||||
result.current.setObjectMetadata(objectMetadataItemsMock);
|
||||
result.current.setObjectMetadata(generatedMockObjectMetadataItems);
|
||||
});
|
||||
|
||||
expect(
|
||||
|
@ -26,35 +26,13 @@ const companyMocks = [
|
||||
) {
|
||||
createCompanies(data: $data, upsert: $upsert) {
|
||||
__typename
|
||||
id
|
||||
visaSponsorship
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
updatedAt
|
||||
domainName {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
position
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
employees
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
workPolicy
|
||||
visaSponsorship
|
||||
address {
|
||||
addressStreet1
|
||||
addressStreet2
|
||||
@ -65,16 +43,38 @@ const companyMocks = [
|
||||
addressLat
|
||||
addressLng
|
||||
}
|
||||
position
|
||||
employees
|
||||
deletedAt
|
||||
accountOwnerId
|
||||
annualRecurringRevenue {
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
name
|
||||
updatedAt
|
||||
xLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
myCustomField
|
||||
createdAt
|
||||
accountOwnerId
|
||||
createdBy {
|
||||
source
|
||||
workspaceMemberId
|
||||
name
|
||||
}
|
||||
workPolicy
|
||||
introVideo {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
}
|
||||
tagline
|
||||
idealCustomerProfile
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect';
|
||||
import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope';
|
||||
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
import {
|
||||
query,
|
||||
responseData,
|
||||
@ -75,11 +75,9 @@ describe('useFilteredSearchEntityQuery', () => {
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
setMetadataItems(generatedMockObjectMetadataItems);
|
||||
|
||||
return useFilteredSearchEntityQuery({
|
||||
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 { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
|
||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||
@ -45,7 +44,7 @@ export const SIGN_IN_BACKGROUND_MOCK_COLUMN_DEFINITIONS = (
|
||||
},
|
||||
{
|
||||
position: 2,
|
||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
||||
fieldMetadataId: 'REPLACE_ME',
|
||||
label: 'Name',
|
||||
size: 100,
|
||||
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';
|
||||
|
||||
export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [
|
||||
@ -15,7 +14,7 @@ export const SIGN_IN_BACKGROUND_MOCK_FILTER_DEFINITIONS = [
|
||||
type: 'NUMBER',
|
||||
},
|
||||
{
|
||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
||||
fieldMetadataId: 'REPLACE_ME',
|
||||
label: 'Name',
|
||||
iconName: 'IconBuildingSkyscraper',
|
||||
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';
|
||||
|
||||
export const SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS = [
|
||||
@ -13,7 +12,7 @@ export const SIGN_IN_BACKGROUND_MOCK_SORT_DEFINITIONS = [
|
||||
iconName: 'IconUsers',
|
||||
},
|
||||
{
|
||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
||||
fieldMetadataId: 'REPLACE_ME',
|
||||
label: 'Name',
|
||||
iconName: 'IconBuildingSkyscraper',
|
||||
},
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
|
||||
export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
||||
@ -60,7 +59,7 @@ export const SIGN_IN_BACKGROUND_MOCK_VIEW_FIELDS = [
|
||||
{
|
||||
__typename: 'ViewField',
|
||||
id: 'cafacdc8-cbfc-4545-8242-94787f144ace',
|
||||
fieldMetadataId: COMPANY_LABEL_IDENTIFIER_FIELD_METADATA_ID,
|
||||
fieldMetadataId: 'REPLACE_ME',
|
||||
size: 180,
|
||||
createdAt: '2023-11-23T15:38:03.706Z',
|
||||
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 { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||
import { workflowCreateStepFromParentStepIdState } from '@/workflow/states/workflowCreateStepFromParentStepIdState';
|
||||
import { workflowDiagramTriggerNodeSelectionState } from '@/workflow/states/workflowDiagramTriggerNodeSelectionState';
|
||||
import {
|
||||
@ -31,7 +32,11 @@ export const useCreateStep = ({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||
});
|
||||
|
||||
const insertNodeAndSave = ({
|
||||
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
|
||||
const insertNodeAndSave = async ({
|
||||
parentNodeId,
|
||||
nodeToAdd,
|
||||
}: {
|
||||
@ -43,15 +48,28 @@ export const useCreateStep = ({
|
||||
throw new Error("Can't add a node when there is no current version.");
|
||||
}
|
||||
|
||||
return updateOneWorkflowVersion({
|
||||
idToUpdate: currentVersion.id,
|
||||
updateOneRecordInput: {
|
||||
steps: insertStep({
|
||||
steps: currentVersion.steps ?? [],
|
||||
parentStepId: parentNodeId,
|
||||
stepToAdd: nodeToAdd,
|
||||
}),
|
||||
},
|
||||
const updatedSteps = insertStep({
|
||||
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 { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||
import {
|
||||
WorkflowStep,
|
||||
WorkflowVersion,
|
||||
@ -20,20 +21,37 @@ export const useUpdateWorkflowVersionStep = ({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||
});
|
||||
|
||||
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
|
||||
const updateStep = async (updatedStep: WorkflowStep) => {
|
||||
if (!isDefined(workflow.currentVersion)) {
|
||||
throw new Error('Can not update an undefined workflow version.');
|
||||
}
|
||||
|
||||
await updateOneWorkflowVersion({
|
||||
idToUpdate: workflow.currentVersion.id,
|
||||
updateOneRecordInput: {
|
||||
steps: replaceStep({
|
||||
steps: workflow.currentVersion.steps ?? [],
|
||||
stepId,
|
||||
stepToReplace: updatedStep,
|
||||
}),
|
||||
},
|
||||
const updatedSteps = replaceStep({
|
||||
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 { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useCreateNewWorkflowVersion } from '@/workflow/hooks/useCreateNewWorkflowVersion';
|
||||
import {
|
||||
WorkflowTrigger,
|
||||
WorkflowVersion,
|
||||
@ -17,16 +18,31 @@ export const useUpdateWorkflowVersionTrigger = ({
|
||||
objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
|
||||
});
|
||||
|
||||
const { createNewWorkflowVersion } = useCreateNewWorkflowVersion({
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
|
||||
const updateTrigger = async (updatedTrigger: WorkflowTrigger) => {
|
||||
if (!isDefined(workflow.currentVersion)) {
|
||||
throw new Error('Can not update an undefined workflow version.');
|
||||
}
|
||||
|
||||
await updateOneWorkflowVersion({
|
||||
idToUpdate: workflow.currentVersion.id,
|
||||
updateOneRecordInput: {
|
||||
trigger: updatedTrigger,
|
||||
},
|
||||
if (workflow.currentVersion.status === 'DRAFT') {
|
||||
await updateOneWorkflowVersion({
|
||||
idToUpdate: workflow.currentVersion.id,
|
||||
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,
|
||||
name: true,
|
||||
statuses: true,
|
||||
versions: {
|
||||
totalCount: true,
|
||||
},
|
||||
},
|
||||
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 { TimelineActivityContext } from '@/activities/timelineActivities/contexts/TimelineActivityContext';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { RecordShowContainer } from '@/object-record/record-show/components/RecordShowContainer';
|
||||
import { useRecordShowPage } from '@/object-record/record-show/hooks/useRecordShowPage';
|
||||
import { RecordValueSetterEffect } from '@/object-record/record-store/components/RecordValueSetterEffect';
|
||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||
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 { RecordShowPageWorkflowHeader } from '@/workflow/components/RecordShowPageWorkflowHeader';
|
||||
import { RecordShowPageBaseHeader } from '~/pages/object-record/RecordShowPageBaseHeader';
|
||||
import { RecordShowPageHeader } from '~/pages/object-record/RecordShowPageHeader';
|
||||
|
||||
export const RecordShowPage = () => {
|
||||
@ -46,22 +46,21 @@ export const RecordShowPage = () => {
|
||||
headerIcon={headerIcon}
|
||||
>
|
||||
<>
|
||||
<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}
|
||||
/>
|
||||
{objectNameSingular === CoreObjectNameSingular.Workflow ? (
|
||||
<RecordShowPageWorkflowHeader
|
||||
workflowId={parameters.objectRecordId}
|
||||
/>
|
||||
) : (
|
||||
<RecordShowPageBaseHeader
|
||||
{...{
|
||||
isFavorite,
|
||||
handleFavoriteButtonClick,
|
||||
record,
|
||||
objectMetadataItem,
|
||||
objectNameSingular,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</RecordShowPageHeader>
|
||||
<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', () => {
|
||||
return HttpResponse.text(
|
||||
`
|
||||
|
@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems';
|
||||
|
||||
export const JestObjectMetadataItemSetter = ({
|
||||
children,
|
||||
@ -12,7 +12,7 @@ export const JestObjectMetadataItemSetter = ({
|
||||
const setObjectMetadataItems = useSetRecoilState(objectMetadataItemsState);
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
useEffect(() => {
|
||||
setObjectMetadataItems(getObjectMetadataItemsMock());
|
||||
setObjectMetadataItems(generatedMockObjectMetadataItems);
|
||||
setIsLoaded(true);
|
||||
}, [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,
|
||||
ObjectMetadataItemsQuery,
|
||||
} 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
|
||||
const customObjectMetadataItemEdge: ObjectEdge = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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[] =
|
||||
mockedStandardObjectMetadataQueryResult.objects.edges.map((edge) => ({
|
||||
|
@ -28,7 +28,6 @@
|
||||
}
|
||||
},
|
||||
"files": [],
|
||||
"exclude": ["**/object-metadata/utils/getObjectMetadataItemsMock.ts"],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
getDevSeedCompanyCustomFields,
|
||||
getDevSeedPeopleCustomFields,
|
||||
} 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 { seedCalendarChannelEventAssociations } from 'src/database/typeorm-seeds/workspace/calendar-channel-event-association';
|
||||
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],
|
||||
workspaceId,
|
||||
);
|
||||
await this.seedCustomObjects(workspaceId, dataSourceMetadata.id);
|
||||
|
||||
await workspaceDataSource.transaction(
|
||||
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 { IsNull, Not } from 'typeorm';
|
||||
|
||||
import {
|
||||
CreateOneResolverArgs,
|
||||
DeleteOneResolverArgs,
|
||||
@ -11,12 +13,12 @@ import {
|
||||
WorkflowQueryValidationException,
|
||||
WorkflowQueryValidationExceptionCode,
|
||||
} 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 {
|
||||
WorkflowVersionStatus,
|
||||
WorkflowVersionWorkspaceEntity,
|
||||
} 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()
|
||||
export class WorkflowVersionValidationWorkspaceService {
|
||||
@ -48,6 +50,8 @@ export class WorkflowVersionValidationWorkspaceService {
|
||||
where: {
|
||||
workflowId: payload.data.workflowId,
|
||||
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);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
if (workflowVersion.status !== WorkflowVersionStatus.ACTIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.setDeactivatedVersionStatus(
|
||||
workflowVersion,
|
||||
workflowVersionRepository,
|
||||
|
@ -138,6 +138,8 @@ export {
|
||||
IconPhotoUp,
|
||||
IconPilcrow,
|
||||
IconPlayerPlay,
|
||||
IconPlayerStop,
|
||||
IconPower,
|
||||
IconPlaystationSquare,
|
||||
IconPlug,
|
||||
IconPlus,
|
||||
|
Loading…
Reference in New Issue
Block a user