Enable workflow in lab (#9997)
Refresh of `objectmetadataitems` was not happening fast enough. Page was breaking when enabling the feature flag. Instead of not storing worklow objects in state, we will use the feature flag to block on read. This way we avoid race conditions <img width="1511" alt="Capture d’écran 2025-02-04 à 14 11 56" src="https://github.com/user-attachments/assets/912cc59a-f422-48ab-84b7-7fdd7bbc35c1" />
This commit is contained in:
@ -1,15 +1,25 @@
|
|||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
import { mockCurrentWorkspace } from '~/testing/mock-data/users';
|
||||||
import { useActivateWorkflowSingleRecordAction } from '../useActivateWorkflowSingleRecordAction';
|
import { useActivateWorkflowSingleRecordAction } from '../useActivateWorkflowSingleRecordAction';
|
||||||
|
|
||||||
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'workflow',
|
(item) => item.nameSingular === 'workflow',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
const mockedWorkflowEnabledFeatureFlag = {
|
||||||
|
id: '1',
|
||||||
|
key: FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
value: true,
|
||||||
|
workspaceId: '1',
|
||||||
|
};
|
||||||
|
|
||||||
const baseWorkflowMock = {
|
const baseWorkflowMock = {
|
||||||
__typename: 'Workflow',
|
__typename: 'Workflow',
|
||||||
id: 'workflowId',
|
id: 'workflowId',
|
||||||
@ -116,6 +126,10 @@ const createWrapper = (workflow: {
|
|||||||
},
|
},
|
||||||
onInitializeRecoilSnapshot: (snapshot) => {
|
onInitializeRecoilSnapshot: (snapshot) => {
|
||||||
snapshot.set(recordStoreFamilyState(workflow.id), workflow);
|
snapshot.set(recordStoreFamilyState(workflow.id), workflow);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,24 @@
|
|||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
import { mockCurrentWorkspace } from '~/testing/mock-data/users';
|
||||||
import { useDeactivateWorkflowSingleRecordAction } from '../useDeactivateWorkflowSingleRecordAction';
|
import { useDeactivateWorkflowSingleRecordAction } from '../useDeactivateWorkflowSingleRecordAction';
|
||||||
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'workflow',
|
(item) => item.nameSingular === 'workflow',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
const mockedWorkflowEnabledFeatureFlag = {
|
||||||
|
id: '1',
|
||||||
|
key: FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
value: true,
|
||||||
|
workspaceId: '1',
|
||||||
|
};
|
||||||
|
|
||||||
const activeWorkflowMock = {
|
const activeWorkflowMock = {
|
||||||
__typename: 'Workflow',
|
__typename: 'Workflow',
|
||||||
id: 'workflowId',
|
id: 'workflowId',
|
||||||
@ -72,6 +82,10 @@ const activeWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper(
|
|||||||
recordStoreFamilyState(activeWorkflowMock.id),
|
recordStoreFamilyState(activeWorkflowMock.id),
|
||||||
activeWorkflowMock,
|
activeWorkflowMock,
|
||||||
);
|
);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -91,6 +105,10 @@ const deactivatedWorkflowWrapper =
|
|||||||
recordStoreFamilyState(deactivatedWorkflowMock.id),
|
recordStoreFamilyState(deactivatedWorkflowMock.id),
|
||||||
deactivatedWorkflowMock,
|
deactivatedWorkflowMock,
|
||||||
);
|
);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||||
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
|
||||||
import { renderHook } from '@testing-library/react';
|
import { renderHook } from '@testing-library/react';
|
||||||
import { act } from 'react';
|
import { act } from 'react';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||||
|
import { mockCurrentWorkspace } from '~/testing/mock-data/users';
|
||||||
import { useDiscardDraftWorkflowSingleRecordAction } from '../useDiscardDraftWorkflowSingleRecordAction';
|
import { useDiscardDraftWorkflowSingleRecordAction } from '../useDiscardDraftWorkflowSingleRecordAction';
|
||||||
|
|
||||||
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
|
||||||
(item) => item.nameSingular === 'workflow',
|
(item) => item.nameSingular === 'workflow',
|
||||||
)!;
|
)!;
|
||||||
|
|
||||||
|
const mockedWorkflowEnabledFeatureFlag = {
|
||||||
|
id: '1',
|
||||||
|
key: FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
value: true,
|
||||||
|
workspaceId: '1',
|
||||||
|
};
|
||||||
|
|
||||||
const noDraftWorkflowMock = {
|
const noDraftWorkflowMock = {
|
||||||
__typename: 'Workflow',
|
__typename: 'Workflow',
|
||||||
id: 'workflowId',
|
id: 'workflowId',
|
||||||
@ -130,6 +140,10 @@ const noDraftWorkflowWrapper =
|
|||||||
recordStoreFamilyState(noDraftWorkflowMock.id),
|
recordStoreFamilyState(noDraftWorkflowMock.id),
|
||||||
noDraftWorkflowMock,
|
noDraftWorkflowMock,
|
||||||
);
|
);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -147,6 +161,10 @@ const draftWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
|
|||||||
recordStoreFamilyState(draftWorkflowMock.id),
|
recordStoreFamilyState(draftWorkflowMock.id),
|
||||||
draftWorkflowMock,
|
draftWorkflowMock,
|
||||||
);
|
);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -165,6 +183,10 @@ const draftWorkflowWithOneVersionWrapper =
|
|||||||
recordStoreFamilyState(draftWorkflowMockWithOneVersion.id),
|
recordStoreFamilyState(draftWorkflowMockWithOneVersion.id),
|
||||||
draftWorkflowMockWithOneVersion,
|
draftWorkflowMockWithOneVersion,
|
||||||
);
|
);
|
||||||
|
snapshot.set(currentWorkspaceState, {
|
||||||
|
...mockCurrentWorkspace,
|
||||||
|
featureFlags: [mockedWorkflowEnabledFeatureFlag],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,29 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||||
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
|
|
||||||
export const useFilteredObjectMetadataItems = () => {
|
export const useFilteredObjectMetadataItems = () => {
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isWorkflowToBeFiltered = (nameSingular: string) => {
|
||||||
|
return (
|
||||||
|
!isWorkflowEnabled &&
|
||||||
|
(nameSingular === CoreObjectNameSingular.Workflow ||
|
||||||
|
isWorkflowSubObjectMetadata(nameSingular))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const activeObjectMetadataItems = objectMetadataItems.filter(
|
const activeObjectMetadataItems = objectMetadataItems.filter(
|
||||||
({ isActive, isSystem }) => isActive && !isSystem,
|
({ isActive, isSystem, nameSingular }) =>
|
||||||
|
isActive && !isSystem && !isWorkflowToBeFiltered(nameSingular),
|
||||||
);
|
);
|
||||||
|
|
||||||
const alphaSortedActiveObjectMetadataItems = activeObjectMetadataItems.sort(
|
const alphaSortedActiveObjectMetadataItems = activeObjectMetadataItems.sort(
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec
|
|||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
|
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
||||||
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||||
|
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||||
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
import { ObjectMetadataItemIdentifier } from '../types/ObjectMetadataItemIdentifier';
|
||||||
|
|
||||||
export const useObjectMetadataItem = ({
|
export const useObjectMetadataItem = ({
|
||||||
@ -17,8 +21,23 @@ export const useObjectMetadataItem = ({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isWorkflowEnabled = useIsFeatureEnabled(
|
||||||
|
FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isWorkflowToBeFiltered =
|
||||||
|
!isWorkflowEnabled &&
|
||||||
|
(objectNameSingular === CoreObjectNameSingular.Workflow ||
|
||||||
|
isWorkflowSubObjectMetadata(objectNameSingular));
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
|
if (isWorkflowToBeFiltered) {
|
||||||
|
throw new Error(
|
||||||
|
'Workflow is not enabled. If you want to use it, please enable it in the lab.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDefined(objectMetadataItem)) {
|
if (!isDefined(objectMetadataItem)) {
|
||||||
throw new ObjectMetadataItemNotFoundError(
|
throw new ObjectMetadataItemNotFoundError(
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
|
|||||||
@ -2,16 +2,10 @@ import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queri
|
|||||||
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||||
import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState';
|
import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState';
|
||||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata';
|
|
||||||
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
||||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
|
||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
import {
|
import { ObjectMetadataItemsQuery } from '~/generated-metadata/graphql';
|
||||||
FeatureFlagKey,
|
|
||||||
ObjectMetadataItemsQuery,
|
|
||||||
} from '~/generated-metadata/graphql';
|
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
type FetchPolicy = 'network-only' | 'cache-first';
|
type FetchPolicy = 'network-only' | 'cache-first';
|
||||||
@ -20,9 +14,6 @@ export const useRefreshObjectMetadataItems = (
|
|||||||
fetchPolicy: FetchPolicy = 'cache-first',
|
fetchPolicy: FetchPolicy = 'cache-first',
|
||||||
) => {
|
) => {
|
||||||
const client = useApolloMetadataClient();
|
const client = useApolloMetadataClient();
|
||||||
const isWorkflowEnabled = useIsFeatureEnabled(
|
|
||||||
FeatureFlagKey.IsWorkflowEnabled,
|
|
||||||
);
|
|
||||||
|
|
||||||
const refreshObjectMetadataItems = async () => {
|
const refreshObjectMetadataItems = async () => {
|
||||||
const result = await client.query<ObjectMetadataItemsQuery>({
|
const result = await client.query<ObjectMetadataItemsQuery>({
|
||||||
@ -36,15 +27,7 @@ export const useRefreshObjectMetadataItems = (
|
|||||||
pagedObjectMetadataItems: result.data,
|
pagedObjectMetadataItems: result.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredObjectMetadataItems = objectMetadataItems.filter((object) => {
|
replaceObjectMetadataItemIfDifferent(objectMetadataItems);
|
||||||
return (
|
|
||||||
isWorkflowEnabled ||
|
|
||||||
(object.nameSingular !== CoreObjectNameSingular.Workflow &&
|
|
||||||
!isWorkflowSubObjectMetadata(object.nameSingular))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
replaceObjectMetadataItemIfDifferent(filteredObjectMetadataItems);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const replaceObjectMetadataItemIfDifferent = useRecoilCallback(
|
const replaceObjectMetadataItemIfDifferent = useRecoilCallback(
|
||||||
|
|||||||
@ -1,256 +0,0 @@
|
|||||||
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 { I18nFrontDecorator } from '~/testing/decorators/I18nFrontDecorator';
|
|
||||||
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: [
|
|
||||||
I18nFrontDecorator,
|
|
||||||
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('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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
...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('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: 'ACTIVE',
|
|
||||||
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('Deactivate')).toBeVisible();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const draftVersionWithPreviousActiveVersionWorkflowId =
|
|
||||||
'89c00f14-4ebd-4675-a098-cdf59eee372b';
|
|
||||||
|
|
||||||
export const DraftVersionWithPreviousActiveVersion: Story = {
|
|
||||||
args: {
|
|
||||||
workflowId: draftVersionWithPreviousActiveVersionWorkflowId,
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: {
|
|
||||||
handlers: [
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
...graphqlMocks.handlers,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
play: async () => {
|
|
||||||
const canvas = within(document.body);
|
|
||||||
|
|
||||||
expect(await canvas.findByText('Test')).toBeVisible();
|
|
||||||
expect(await canvas.findByText('Discard Draft')).toBeVisible();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -62,6 +62,12 @@ export const mockCurrentWorkspace: Workspace = {
|
|||||||
value: true,
|
value: true,
|
||||||
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '1492de61-5018-4368-8923-4f1eeaf988c6',
|
||||||
|
key: FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
value: true,
|
||||||
|
workspaceId: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6w',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
createdAt: '2023-04-26T10:23:42.33625+00:00',
|
createdAt: '2023-04-26T10:23:42.33625+00:00',
|
||||||
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
||||||
|
|||||||
@ -7,7 +7,10 @@ type FeatureFlagMetadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PublicFeatureFlag = {
|
export type PublicFeatureFlag = {
|
||||||
key: Extract<FeatureFlagKey, FeatureFlagKey.IsLocalizationEnabled>;
|
key: Extract<
|
||||||
|
FeatureFlagKey,
|
||||||
|
FeatureFlagKey.IsLocalizationEnabled | FeatureFlagKey.IsWorkflowEnabled
|
||||||
|
>;
|
||||||
metadata: FeatureFlagMetadata;
|
metadata: FeatureFlagMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -21,4 +24,12 @@ export const PUBLIC_FEATURE_FLAGS: PublicFeatureFlag[] = [
|
|||||||
imagePath: 'https://twenty.com/images/releases/labs/translation.png',
|
imagePath: 'https://twenty.com/images/releases/labs/translation.png',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: FeatureFlagKey.IsWorkflowEnabled,
|
||||||
|
metadata: {
|
||||||
|
label: 'Workflows',
|
||||||
|
description: 'Create custom workflows to automate your work.',
|
||||||
|
imagePath: 'https://twenty.com/images/lab/is-workflow-enabled.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user