From 91b54e7e6876e6ede269a64dd1ce24375d002693 Mon Sep 17 00:00:00 2001 From: Thomas Trompette Date: Fri, 17 Oct 2025 11:19:39 +0200 Subject: [PATCH] Remove iterator feature flag (#15165) As title --- .../src/generated-metadata/graphql.ts | 1 - .../twenty-front/src/generated/graphql.ts | 1 - .../hooks/useRunWorkflowRecordActions.tsx | 8 +- .../utils/isGlobalManualTrigger.ts | 12 +- .../CommandMenuWorkflowSelectAction.tsx | 7 +- ...ndMenuWorkflowSelectTriggerTypeContent.tsx | 6 - ...ActiveWorkflowVersionsWithManualTrigger.ts | 26 +- .../workflow/hooks/useStepsOutputSchema.ts | 39 +-- .../components/WorkflowRunStepNodeDetail.tsx | 21 +- .../components/WorkflowStepDetail.tsx | 18 +- .../WorkflowEditTriggerManualDeprecated.tsx | 244 ------------------ ...alTriggerDefaultSettingsDeprecated.test.ts | 73 ------ .../getTriggerDefaultDefinition.test.ts | 36 +-- ...tManualTriggerDefaultSettingsDeprecated.ts | 49 ---- .../utils/getTriggerDefaultDefinition.ts | 17 +- .../constants/public-feature-flag.const.ts | 9 - .../enums/feature-flag-key.enum.ts | 1 - .../workspace-entity-manager.spec.ts | 2 - .../core/utils/seed-feature-flags.util.ts | 5 - .../prefill-workflows.ts | 6 +- .../workflow-schema.workspace-service.ts | 21 +- 21 files changed, 30 insertions(+), 572 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/components/WorkflowEditTriggerManualDeprecated.tsx delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/utils/__tests__/getManualTriggerDefaultSettingsDeprecated.test.ts delete mode 100644 packages/twenty-front/src/modules/workflow/workflow-trigger/utils/getManualTriggerDefaultSettingsDeprecated.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index ee43152eb1..87120e6c94 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1265,7 +1265,6 @@ export enum FeatureFlagKey { IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED', IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED', IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED', - IS_WORKFLOW_ITERATOR_ENABLED = 'IS_WORKFLOW_ITERATOR_ENABLED', IS_WORKSPACE_MIGRATION_V2_ENABLED = 'IS_WORKSPACE_MIGRATION_V2_ENABLED' } diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index f4db30588d..17c3725c13 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -1229,7 +1229,6 @@ export enum FeatureFlagKey { IS_RELATION_CONNECT_ENABLED = 'IS_RELATION_CONNECT_ENABLED', IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED', IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED', - IS_WORKFLOW_ITERATOR_ENABLED = 'IS_WORKFLOW_ITERATOR_ENABLED', IS_WORKSPACE_MIGRATION_V2_ENABLED = 'IS_WORKSPACE_MIGRATION_V2_ENABLED' } diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx index a35d66f485..3b229db619 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/run-workflow-actions/hooks/useRunWorkflowRecordActions.tsx @@ -11,11 +11,9 @@ import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion'; import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { COMMAND_MENU_DEFAULT_ICON } from '@/workflow/workflow-trigger/constants/CommandMenuDefaultIcon'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilCallback } from 'recoil'; import { capitalize, isDefined } from 'twenty-shared/utils'; import { useIcons } from 'twenty-ui/display'; -import { FeatureFlagKey } from '~/generated/graphql'; export const useRunWorkflowRecordActions = ({ objectMetadataItem, @@ -25,9 +23,6 @@ export const useRunWorkflowRecordActions = ({ skip?: boolean; }) => { const { getIcon } = useIcons(); - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); const contextStoreTargetedRecordsRule = useRecoilComponentValue( contextStoreTargetedRecordsRuleComponentState, ); @@ -55,7 +50,6 @@ export const useRunWorkflowRecordActions = ({ >, ) => { if ( - isIteratorEnabled && isDefined(activeWorkflowVersion?.trigger) && isBulkRecordsManualTrigger(activeWorkflowVersion.trigger) ) { @@ -91,7 +85,7 @@ export const useRunWorkflowRecordActions = ({ } } }, - [runWorkflowVersion, isIteratorEnabled, objectMetadataItem], + [runWorkflowVersion, objectMetadataItem], ); return activeWorkflowVersions diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/utils/isGlobalManualTrigger.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/utils/isGlobalManualTrigger.ts index f9d087f4df..173143d6a4 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/utils/isGlobalManualTrigger.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/utils/isGlobalManualTrigger.ts @@ -1,17 +1,15 @@ import { type WorkflowTrigger } from '@/workflow/types/Workflow'; import { isDefined } from 'twenty-shared/utils'; -export const isGlobalManualTrigger = ( - trigger: WorkflowTrigger, - isIteratorEnabled: boolean, -) => { +export const isGlobalManualTrigger = (trigger: WorkflowTrigger) => { if (trigger.type !== 'MANUAL') { return false; } - if (isIteratorEnabled && isDefined(trigger.settings?.availability)) { - return trigger.settings.availability.type === 'GLOBAL'; + // Legacy support for manual triggers without availability + if (!isDefined(trigger.settings?.availability)) { + return !isDefined(trigger.settings?.objectType); } - return !isDefined(trigger.settings.objectType); + return trigger.settings.availability.type === 'GLOBAL'; }; diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx index bc63b9cccc..b2c9a87640 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/action/components/CommandMenuWorkflowSelectAction.tsx @@ -17,9 +17,6 @@ export const CommandMenuWorkflowSelectAction = ({ onActionSelected: (actionType: WorkflowActionType) => void; }) => { const isAiEnabled = useIsFeatureEnabled(FeatureFlagKey.IS_AI_ENABLED); - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); const { t } = useLingui(); @@ -49,9 +46,7 @@ export const CommandMenuWorkflowSelectAction = ({ {t`Flow`} action.type !== 'ITERATOR' || isIteratorEnabled, - )} + actions={FLOW_ACTIONS} onClick={onActionSelected} /> diff --git a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx index 9fbb7922bd..6ce5b8ac9a 100644 --- a/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx +++ b/packages/twenty-front/src/modules/command-menu/pages/workflow/trigger-type/components/CommandMenuWorkflowSelectTriggerTypeContent.tsx @@ -12,12 +12,10 @@ import { DATABASE_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/Da import { OTHER_TRIGGER_TYPES } from '@/workflow/workflow-trigger/constants/OtherTriggerTypes'; import { useUpdateWorkflowVersionTrigger } from '@/workflow/workflow-trigger/hooks/useUpdateWorkflowVersionTrigger'; import { getTriggerDefaultDefinition } from '@/workflow/workflow-trigger/utils/getTriggerDefaultDefinition'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useTheme } from '@emotion/react'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; import { useIcons } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; -import { FeatureFlagKey } from '~/generated/graphql'; export const CommandMenuWorkflowSelectTriggerTypeContent = ({ workflow, @@ -34,9 +32,6 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({ workflowSelectedNodeComponentState, ); const { openWorkflowEditStepInCommandMenu } = useWorkflowCommandMenu(); - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); const handleTriggerTypeClick = ({ type, @@ -53,7 +48,6 @@ export const CommandMenuWorkflowSelectTriggerTypeContent = ({ defaultLabel, type, activeNonSystemObjectMetadataItems, - isIteratorEnabled, }), ); diff --git a/packages/twenty-front/src/modules/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger.ts b/packages/twenty-front/src/modules/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger.ts index 930e8c9d27..872376730b 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger.ts @@ -6,9 +6,7 @@ import { type ManualTriggerWorkflowVersion, type Workflow, } from '@/workflow/types/Workflow'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from '~/generated/graphql'; export const useActiveWorkflowVersionsWithManualTrigger = ({ objectMetadataItem, @@ -17,10 +15,6 @@ export const useActiveWorkflowVersionsWithManualTrigger = ({ objectMetadataItem?: ObjectMetadataItem; skip?: boolean; }) => { - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); - const filters = [ { status: { @@ -34,20 +28,12 @@ export const useActiveWorkflowVersionsWithManualTrigger = ({ }, ]; - const objectTypeFilter = isIteratorEnabled - ? { - trigger: { - like: `%"objectNameSingular": "${objectMetadataItem?.nameSingular}"%`, - }, - } - : { - trigger: { - like: `%"objectType": "${objectMetadataItem?.nameSingular}"%`, - }, - }; - if (isDefined(objectMetadataItem)) { - filters.push(objectTypeFilter); + filters.push({ + trigger: { + like: `%"objectNameSingular": "${objectMetadataItem?.nameSingular}"%`, + }, + }); } const { records } = useFindManyRecords< @@ -79,7 +65,7 @@ export const useActiveWorkflowVersionsWithManualTrigger = ({ (record) => record.status === 'ACTIVE' && isDefined(record.trigger) && - isGlobalManualTrigger(record.trigger, isIteratorEnabled), + isGlobalManualTrigger(record.trigger), ), }; } diff --git a/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts b/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts index 7cbb686077..5f8ec90939 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useStepsOutputSchema.ts @@ -1,47 +1,18 @@ import { stepsOutputSchemaFamilyState } from '@/workflow/states/stepsOutputSchemaFamilyState'; -import { - type WorkflowActionType, - type WorkflowVersion, -} from '@/workflow/types/Workflow'; +import { type WorkflowVersion } from '@/workflow/types/Workflow'; import { getStepOutputSchemaFamilyStateKey } from '@/workflow/utils/getStepOutputSchemaFamilyStateKey'; import { getActionIcon } from '@/workflow/workflow-steps/workflow-actions/utils/getActionIcon'; import { getTriggerDefaultLabel } from '@/workflow/workflow-trigger/utils/getTriggerDefaultLabel'; import { getTriggerIcon } from '@/workflow/workflow-trigger/utils/getTriggerIcon'; -import { isFindRecordsOutputSchema } from '@/workflow/workflow-variables/types/guards/isFindRecordsOutputSchema'; import { type OutputSchemaV2, type StepOutputSchemaV2, } from '@/workflow/workflow-variables/types/StepOutputSchemaV2'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { TRIGGER_STEP_ID } from 'twenty-shared/workflow'; -import { FeatureFlagKey } from '~/generated/graphql'; -const getFilteredOutputSchema = ({ - stepType, - outputSchema, - isIteratorEnabled, -}: { - stepType: WorkflowActionType; - outputSchema: OutputSchemaV2; - isIteratorEnabled: boolean; -}) => { - if (!isIteratorEnabled && isFindRecordsOutputSchema(stepType, outputSchema)) { - const filteredOutputSchema = { - ...outputSchema, - all: undefined, - }; - - return filteredOutputSchema; - } - - return outputSchema; -}; export const useStepsOutputSchema = () => { - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); const populateStepsOutputSchema = useRecoilCallback( ({ set }) => (workflowVersion: WorkflowVersion) => { @@ -51,11 +22,7 @@ export const useStepsOutputSchema = () => { name: step.name, type: step.type, icon: getActionIcon(step.type), - outputSchema: getFilteredOutputSchema({ - stepType: step.type, - outputSchema: step.settings?.outputSchema as OutputSchemaV2, - isIteratorEnabled, - }), + outputSchema: step.settings?.outputSchema as OutputSchemaV2, }; set( @@ -92,7 +59,7 @@ export const useStepsOutputSchema = () => { ); } }, - [isIteratorEnabled], + [], ); const deleteStepsOutputSchema = useRecoilCallback( diff --git a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx index d6aa9f6882..57d9ed19fc 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx +++ b/packages/twenty-front/src/modules/workflow/workflow-steps/components/WorkflowRunStepNodeDetail.tsx @@ -19,11 +19,8 @@ import { WorkflowEditActionIterator } from '@/workflow/workflow-steps/workflow-a import { WorkflowEditTriggerCronForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerCronForm'; import { WorkflowEditTriggerDatabaseEventForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerDatabaseEventForm'; import { WorkflowEditTriggerManual } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerManual'; -import { WorkflowEditTriggerManualDeprecated } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerManualDeprecated'; import { WorkflowEditTriggerWebhookForm } from '@/workflow/workflow-trigger/components/WorkflowEditTriggerWebhookForm'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from '~/generated/graphql'; type WorkflowRunStepNodeDetailProps = { stepId: string; @@ -44,10 +41,6 @@ export const WorkflowRunStepNodeDetail = ({ steps, }); - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); - if (!isDefined(stepDefinition) || !isDefined(stepDefinition.definition)) { return null; } @@ -67,20 +60,8 @@ export const WorkflowRunStepNodeDetail = ({ ); } case 'MANUAL': { - if (isIteratorEnabled) { - return ( - - ); - } - return ( - { - const isIteratorEnabled = useIsFeatureEnabled( - FeatureFlagKey.IS_WORKFLOW_ITERATOR_ENABLED, - ); const stepDefinition = getStepDefinitionOrThrow({ stepId, trigger, @@ -74,18 +68,8 @@ export const WorkflowStepDetail = ({ ); } case 'MANUAL': { - if (isIteratorEnabled) { - return ( - - ); - } - return ( - void; - }; -}; - -const StyledLabel = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.xs}; - font-weight: ${({ theme }) => theme.font.weight.semiBold}; - margin-bottom: ${({ theme }) => theme.spacing(1)}; -`; - -const StyledDescription = styled.span` - color: ${({ theme }) => theme.font.color.light}; - font-size: ${({ theme }) => theme.font.size.sm}; - margin-top: ${({ theme }) => theme.spacing(0.25)}; -`; - -const StyledIconPickerContainer = styled.div` - display: flex; - flex-direction: column; -`; - -export const WorkflowEditTriggerManualDeprecated = ({ - trigger, - triggerOptions, -}: WorkflowEditTriggerManualDeprecatedProps) => { - const theme = useTheme(); - - const { t } = useLingui(); - - const { getIcon } = useIcons(); - - const { activeNonSystemObjectMetadataItems } = - useFilteredObjectMetadataItems(); - - const availableMetadata: Array> = - activeNonSystemObjectMetadataItems.map((item) => ({ - label: item.labelPlural, - value: item.nameSingular, - Icon: getIcon(item.icon), - })); - - const objectType = trigger.settings.objectType; - - const manualTriggerAvailability: WorkflowManualTriggerAvailability = - isDefined(objectType) ? 'WHEN_RECORD_SELECTED' : 'EVERYWHERE'; - - const headerTitle = trigger.name ?? getTriggerDefaultLabel(trigger); - - const headerIcon = getTriggerIcon(trigger); - - const headerType = getTriggerHeaderType(trigger); - - const availabilityDescriptions = { - WHEN_RECORD_SELECTED: t`The selected record(s) will be passed to your workflow`, - EVERYWHERE: t`Open the ⌘K to trigger this workflow`, - }; - - return ( - <> - { - if (triggerOptions.readonly === true) { - return; - } - - triggerOptions.onTriggerUpdate({ - ...trigger, - name: newName, - }); - }} - Icon={getIcon(headerIcon)} - iconColor={getTriggerIconColor({ theme, triggerType: trigger.type })} - initialTitle={headerTitle} - headerType={headerType} - disabled={triggerOptions.readonly} - /> - - { - if (triggerOptions.readonly === true) { - e.stopPropagation(); - e.preventDefault(); - } - }} - > - {t`Command Icon`} - - {t`The icon your workflow trigger will display in the command menu`} - - } - onChange={({ iconKey }) => { - if (triggerOptions.readonly === true) { - return; - } - - triggerOptions.onTriggerUpdate({ - ...trigger, - settings: { - ...trigger.settings, - icon: iconKey, - }, - }); - }} - /> - - { - if (triggerOptions.readonly === true) { - return; - } - - triggerOptions.onTriggerUpdate({ - ...trigger, - settings: { - ...trigger.settings, - availability: { - objectNameSingular: updatedObject, - type: 'SINGLE_RECORD', - }, - objectType: updatedObject, - outputSchema: {}, - }, - }); - }} - dropdownOffset={{ y: parseInt(theme.spacing(1), 10) }} - dropdownWidth={GenericDropdownContentWidth.ExtraLarge} - /> - ) : null} - - {manualTriggerAvailability === 'WHEN_RECORD_SELECTED' ? ( -