From 2368dad9ad1ef4e597a7a96c56fca161fe90c7c3 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Tue, 4 Feb 2025 15:25:04 +0100 Subject: [PATCH] Enable workflow in lab (#9997) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Capture d’écran 2025-02-04 à 14 11 56 --- ...ActivateWorkflowSingleRecordAction.test.ts | 14 + ...activateWorkflowSingleRecordAction.test.ts | 18 ++ ...ardDraftWorkflowSingleRecordAction.test.ts | 22 ++ .../hooks/useFilteredObjectMetadataItems.ts | 19 +- .../hooks/useObjectMetadataItem.ts | 19 ++ .../hooks/useRefreshObjectMetadataItem.ts | 21 +- .../RecordShowPageWorkflowHeader.stories.tsx | 256 ------------------ .../src/testing/mock-data/users.ts | 6 + .../constants/public-feature-flag.const.ts | 13 +- 9 files changed, 111 insertions(+), 277 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workflow/components/__stories__/RecordShowPageWorkflowHeader.stories.tsx diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useActivateWorkflowSingleRecordAction.test.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useActivateWorkflowSingleRecordAction.test.ts index ba8c40ad9..150d62dbd 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useActivateWorkflowSingleRecordAction.test.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useActivateWorkflowSingleRecordAction.test.ts @@ -1,15 +1,25 @@ +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; +import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; +import { mockCurrentWorkspace } from '~/testing/mock-data/users'; import { useActivateWorkflowSingleRecordAction } from '../useActivateWorkflowSingleRecordAction'; const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find( (item) => item.nameSingular === 'workflow', )!; +const mockedWorkflowEnabledFeatureFlag = { + id: '1', + key: FeatureFlagKey.IsWorkflowEnabled, + value: true, + workspaceId: '1', +}; + const baseWorkflowMock = { __typename: 'Workflow', id: 'workflowId', @@ -116,6 +126,10 @@ const createWrapper = (workflow: { }, onInitializeRecoilSnapshot: (snapshot) => { snapshot.set(recordStoreFamilyState(workflow.id), workflow); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDeactivateWorkflowSingleRecordAction.test.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDeactivateWorkflowSingleRecordAction.test.ts index 4faa84f12..a8323cefc 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDeactivateWorkflowSingleRecordAction.test.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDeactivateWorkflowSingleRecordAction.test.ts @@ -1,14 +1,24 @@ +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; +import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; +import { mockCurrentWorkspace } from '~/testing/mock-data/users'; import { useDeactivateWorkflowSingleRecordAction } from '../useDeactivateWorkflowSingleRecordAction'; const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find( (item) => item.nameSingular === 'workflow', )!; +const mockedWorkflowEnabledFeatureFlag = { + id: '1', + key: FeatureFlagKey.IsWorkflowEnabled, + value: true, + workspaceId: '1', +}; + const activeWorkflowMock = { __typename: 'Workflow', id: 'workflowId', @@ -72,6 +82,10 @@ const activeWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper( recordStoreFamilyState(activeWorkflowMock.id), activeWorkflowMock, ); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }, ); @@ -91,6 +105,10 @@ const deactivatedWorkflowWrapper = recordStoreFamilyState(deactivatedWorkflowMock.id), deactivatedWorkflowMock, ); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDiscardDraftWorkflowSingleRecordAction.test.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDiscardDraftWorkflowSingleRecordAction.test.ts index 4157e5f8a..5c686c3f4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDiscardDraftWorkflowSingleRecordAction.test.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/hooks/__tests__/useDiscardDraftWorkflowSingleRecordAction.test.ts @@ -1,15 +1,25 @@ +import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { renderHook } from '@testing-library/react'; import { act } from 'react'; +import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems'; +import { mockCurrentWorkspace } from '~/testing/mock-data/users'; import { useDiscardDraftWorkflowSingleRecordAction } from '../useDiscardDraftWorkflowSingleRecordAction'; const workflowMockObjectMetadataItem = generatedMockObjectMetadataItems.find( (item) => item.nameSingular === 'workflow', )!; +const mockedWorkflowEnabledFeatureFlag = { + id: '1', + key: FeatureFlagKey.IsWorkflowEnabled, + value: true, + workspaceId: '1', +}; + const noDraftWorkflowMock = { __typename: 'Workflow', id: 'workflowId', @@ -130,6 +140,10 @@ const noDraftWorkflowWrapper = recordStoreFamilyState(noDraftWorkflowMock.id), noDraftWorkflowMock, ); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }); @@ -147,6 +161,10 @@ const draftWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ recordStoreFamilyState(draftWorkflowMock.id), draftWorkflowMock, ); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }); @@ -165,6 +183,10 @@ const draftWorkflowWithOneVersionWrapper = recordStoreFamilyState(draftWorkflowMockWithOneVersion.id), draftWorkflowMockWithOneVersion, ); + snapshot.set(currentWorkspaceState, { + ...mockCurrentWorkspace, + featureFlags: [mockedWorkflowEnabledFeatureFlag], + }); }, }); diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts index c6dd05e4a..eb947c622 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useFilteredObjectMetadataItems.ts @@ -1,12 +1,29 @@ import { useRecoilValue } from 'recoil'; 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 = () => { const objectMetadataItems = useRecoilValue(objectMetadataItemsState); + const isWorkflowEnabled = useIsFeatureEnabled( + FeatureFlagKey.IsWorkflowEnabled, + ); + + const isWorkflowToBeFiltered = (nameSingular: string) => { + return ( + !isWorkflowEnabled && + (nameSingular === CoreObjectNameSingular.Workflow || + isWorkflowSubObjectMetadata(nameSingular)) + ); + }; + const activeObjectMetadataItems = objectMetadataItems.filter( - ({ isActive, isSystem }) => isActive && !isSystem, + ({ isActive, isSystem, nameSingular }) => + isActive && !isSystem && !isWorkflowToBeFiltered(nameSingular), ); const alphaSortedActiveObjectMetadataItems = activeObjectMetadataItems.sort( diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts index 5247be17c..a3a5df952 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts @@ -5,6 +5,10 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; 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'; 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); + if (isWorkflowToBeFiltered) { + throw new Error( + 'Workflow is not enabled. If you want to use it, please enable it in the lab.', + ); + } + if (!isDefined(objectMetadataItem)) { throw new ObjectMetadataItemNotFoundError( objectNameSingular, diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItem.ts index e959e627a..f1e9eec68 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItem.ts @@ -2,16 +2,10 @@ import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queri import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient'; import { isAppWaitingForFreshObjectMetadataState } from '@/object-metadata/states/isAppWaitingForFreshObjectMetadataState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isWorkflowSubObjectMetadata } from '@/object-metadata/utils/isWorkflowSubObjectMetadata'; import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilCallback } from 'recoil'; -import { - FeatureFlagKey, - ObjectMetadataItemsQuery, -} from '~/generated-metadata/graphql'; +import { ObjectMetadataItemsQuery } from '~/generated-metadata/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; type FetchPolicy = 'network-only' | 'cache-first'; @@ -20,9 +14,6 @@ export const useRefreshObjectMetadataItems = ( fetchPolicy: FetchPolicy = 'cache-first', ) => { const client = useApolloMetadataClient(); - const isWorkflowEnabled = useIsFeatureEnabled( - FeatureFlagKey.IsWorkflowEnabled, - ); const refreshObjectMetadataItems = async () => { const result = await client.query({ @@ -36,15 +27,7 @@ export const useRefreshObjectMetadataItems = ( pagedObjectMetadataItems: result.data, }); - const filteredObjectMetadataItems = objectMetadataItems.filter((object) => { - return ( - isWorkflowEnabled || - (object.nameSingular !== CoreObjectNameSingular.Workflow && - !isWorkflowSubObjectMetadata(object.nameSingular)) - ); - }); - - replaceObjectMetadataItemIfDifferent(filteredObjectMetadataItems); + replaceObjectMetadataItemIfDifferent(objectMetadataItems); }; const replaceObjectMetadataItemIfDifferent = useRecoilCallback( diff --git a/packages/twenty-front/src/modules/workflow/components/__stories__/RecordShowPageWorkflowHeader.stories.tsx b/packages/twenty-front/src/modules/workflow/components/__stories__/RecordShowPageWorkflowHeader.stories.tsx deleted file mode 100644 index 40cc12512..000000000 --- a/packages/twenty-front/src/modules/workflow/components/__stories__/RecordShowPageWorkflowHeader.stories.tsx +++ /dev/null @@ -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 = { - title: 'Modules/Workflow/RecordShowPageWorkflowHeader', - component: RecordShowPageWorkflowHeader, - decorators: [ - I18nFrontDecorator, - ComponentDecorator, - ObjectMetadataItemsDecorator, - SnackBarDecorator, - ], - parameters: { - container: { width: 728 }, - }, -}; - -export default meta; -type Story = StoryObj; - -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(); - }, -}; diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 187504385..8761be8ec 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -62,6 +62,12 @@ export const mockCurrentWorkspace: Workspace = { value: true, 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', updatedAt: '2023-04-26T10:23:42.33625+00:00', diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts index c62484429..2f312b6ac 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts @@ -7,7 +7,10 @@ type FeatureFlagMetadata = { }; export type PublicFeatureFlag = { - key: Extract; + key: Extract< + FeatureFlagKey, + FeatureFlagKey.IsLocalizationEnabled | FeatureFlagKey.IsWorkflowEnabled + >; metadata: FeatureFlagMetadata; }; @@ -21,4 +24,12 @@ export const PUBLIC_FEATURE_FLAGS: PublicFeatureFlag[] = [ 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', + }, + }, ];