diff --git a/packages/twenty-front/src/loading/hooks/useUserOrMetadataLoading.ts b/packages/twenty-front/src/loading/hooks/useUserOrMetadataLoading.ts deleted file mode 100644 index b35cdb3dd..000000000 --- a/packages/twenty-front/src/loading/hooks/useUserOrMetadataLoading.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useRecoilValue } from 'recoil'; - -import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState'; -import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; - -export const useUserOrMetadataLoading = () => { - const isCurrentUserLoaded = useRecoilValue(isCurrentUserLoadedState); - const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - - return !isCurrentUserLoaded || objectMetadataItems.length === 0; -}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter.tsx new file mode 100644 index 000000000..35dc9b070 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter.tsx @@ -0,0 +1,8 @@ +import { WorkflowRunActionEffect } from '@/action-menu/actions/global-actions/workflow-run-actions/components/WorkflowRunActionEffect'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; + +export const GlobalActionMenuEntriesSetter = () => { + const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED'); + + return <>{isWorkflowEnabled && }; +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/global-actions/workflow-run-actions/components/WorkflowRunActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/global-actions/workflow-run-actions/components/WorkflowRunActionEffect.tsx new file mode 100644 index 000000000..7a9f78d86 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/global-actions/workflow-run-actions/components/WorkflowRunActionEffect.tsx @@ -0,0 +1,68 @@ +import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; +import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; +import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; +import { useAllActiveWorkflowVersions } from '@/workflow/hooks/useAllActiveWorkflowVersions'; +import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion'; + +import { useTheme } from '@emotion/react'; +import { useEffect } from 'react'; +import { IconSettingsAutomation } from 'twenty-ui'; +import { capitalize } from '~/utils/string/capitalize'; + +export const WorkflowRunActionEffect = () => { + const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); + + const { records: activeWorkflowVersions } = useAllActiveWorkflowVersions({ + triggerType: 'MANUAL', + }); + + const { runWorkflowVersion } = useRunWorkflowVersion(); + + const { enqueueSnackBar } = useSnackBar(); + + const theme = useTheme(); + + useEffect(() => { + for (const [ + index, + activeWorkflowVersion, + ] of activeWorkflowVersions.entries()) { + addActionMenuEntry({ + type: 'workflow-run', + key: `workflow-run-${activeWorkflowVersion.id}`, + label: capitalize(activeWorkflowVersion.workflow.name), + position: index, + Icon: IconSettingsAutomation, + onClick: async () => { + await runWorkflowVersion(activeWorkflowVersion.id); + + enqueueSnackBar('', { + variant: SnackBarVariant.Success, + title: `${capitalize(activeWorkflowVersion.workflow.name)} starting...`, + icon: ( + + ), + }); + }, + }); + } + + return () => { + for (const activeWorkflowVersion of activeWorkflowVersions) { + removeActionMenuEntry(`workflow-run-${activeWorkflowVersion.id}`); + } + }; + }, [ + activeWorkflowVersions, + addActionMenuEntry, + enqueueSnackBar, + removeActionMenuEntry, + runWorkflowVersion, + theme.snackBar.success.color, + ]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index e82002fdd..2bcc8400d 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -6,6 +6,7 @@ import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-sto import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; const globalRecordActionEffects = [ExportRecordsActionEffect]; @@ -29,6 +30,8 @@ export const RecordActionMenuEntriesSetter = () => { objectId: contextStoreCurrentObjectMetadataId ?? '', }); + const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED'); + if (!objectMetadataItem) { throw new Error( `Object metadata item not found for id ${contextStoreCurrentObjectMetadataId}`, @@ -56,7 +59,7 @@ export const RecordActionMenuEntriesSetter = () => { objectMetadataItem={objectMetadataItem} /> ))} - {contextStoreNumberOfSelectedRecords === 1 && ( + {contextStoreNumberOfSelectedRecords === 1 && isWorkflowEnabled && ( diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionEffect.tsx index abca99701..9c8d509e3 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionEffect.tsx @@ -5,7 +5,7 @@ import { recordStoreFamilyState } from '@/object-record/record-store/states/reco import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { useAllActiveWorkflowVersionsForObject } from '@/workflow/hooks/useAllActiveWorkflowVersionsForObject'; +import { useAllActiveWorkflowVersions } from '@/workflow/hooks/useAllActiveWorkflowVersions'; import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion'; import { useTheme } from '@emotion/react'; @@ -34,11 +34,10 @@ export const WorkflowRunRecordActionEffect = ({ recordStoreFamilyState(selectedRecordId ?? ''), ); - const { records: activeWorkflowVersions } = - useAllActiveWorkflowVersionsForObject({ - objectNameSingular: objectMetadataItem.nameSingular, - triggerType: 'MANUAL', - }); + const { records: activeWorkflowVersions } = useAllActiveWorkflowVersions({ + objectMetadataItem, + triggerType: 'MANUAL', + }); const { runWorkflowVersion } = useRunWorkflowVersion(); @@ -57,7 +56,7 @@ export const WorkflowRunRecordActionEffect = ({ ] of activeWorkflowVersions.entries()) { addActionMenuEntry({ type: 'workflow-run', - key: `workflow-run-${activeWorkflowVersion.workflow.name}`, + key: `workflow-run-${activeWorkflowVersion.id}`, label: capitalize(activeWorkflowVersion.workflow.name), position: index, Icon: IconSettingsAutomation, @@ -84,9 +83,7 @@ export const WorkflowRunRecordActionEffect = ({ return () => { for (const activeWorkflowVersion of activeWorkflowVersions) { - removeActionMenuEntry( - `workflow-run-${activeWorkflowVersion.workflow.name}`, - ); + removeActionMenuEntry(`workflow-run-${activeWorkflowVersion.id}`); } }; }, [ diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx index 95df542d9..baa2be8b9 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordIndexActionMenu.tsx @@ -1,3 +1,4 @@ +import { GlobalActionMenuEntriesSetter } from '@/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter'; import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; import { RecordIndexActionMenuBar } from '@/action-menu/components/RecordIndexActionMenuBar'; @@ -27,6 +28,7 @@ export const RecordIndexActionMenu = () => { + )} diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx index 6ce6218e0..d92ae5603 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenu.tsx @@ -1,3 +1,4 @@ +import { GlobalActionMenuEntriesSetter } from '@/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter'; import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; @@ -47,6 +48,7 @@ export const RecordShowActionMenu = ({ /> + )} diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx index c4399a42a..510104926 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenu.tsx @@ -1,3 +1,4 @@ +import { GlobalActionMenuEntriesSetter } from '@/action-menu/actions/global-actions/components/GlobalActionMenuEntriesSetter'; import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; import { RecordShowRightDrawerActionMenuBar } from '@/action-menu/components/RecordShowRightDrawerActionMenuBar'; @@ -23,6 +24,7 @@ export const RecordShowRightDrawerActionMenu = () => { + )} diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenuBar.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenuBar.tsx index 85ab16ab0..8f9540e4d 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenuBar.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowRightDrawerActionMenuBar.tsx @@ -6,9 +6,14 @@ export const RecordShowRightDrawerActionMenuBar = () => { const actionMenuEntries = useRecoilComponentValueV2( actionMenuEntriesComponentSelector, ); + + const standardActionMenuEntries = actionMenuEntries.filter( + (actionMenuEntry) => actionMenuEntry.type === 'standard', + ); + return ( <> - {actionMenuEntries.map((actionMenuEntry) => ( + {standardActionMenuEntries.map((actionMenuEntry) => ( ))} diff --git a/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersions.ts b/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersions.ts new file mode 100644 index 000000000..06e709721 --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersions.ts @@ -0,0 +1,71 @@ +import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; +import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; +import { + Workflow, + WorkflowTriggerType, + WorkflowVersion, +} from '@/workflow/types/Workflow'; +import { isDefined } from 'twenty-ui'; + +export const useAllActiveWorkflowVersions = ({ + objectMetadataItem, + triggerType, +}: { + objectMetadataItem?: ObjectMetadataItem; + triggerType: WorkflowTriggerType; +}) => { + const filters = [ + { + status: { + eq: 'ACTIVE', + }, + }, + { + trigger: { + like: `%"type": "${triggerType}"%`, + }, + }, + ]; + + if (isDefined(objectMetadataItem)) { + filters.push({ + trigger: { + like: `%"objectType": "${objectMetadataItem.nameSingular}"%`, + }, + }); + } + + const { objectMetadataItem: workflowVersionObjectMetadataItem } = + useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + }); + + const { records } = useFindManyRecords< + WorkflowVersion & { workflow: Workflow } + >({ + objectNameSingular: CoreObjectNameSingular.WorkflowVersion, + filter: { + and: filters, + }, + recordGqlFields: { + ...generateDepthOneRecordGqlFields({ + objectMetadataItem: workflowVersionObjectMetadataItem, + }), + workflow: true, + }, + }); + + // TODO: refactor when we can use 'not like' in the RawJson filter + if (!isDefined(objectMetadataItem)) { + return { + records: records.filter( + (record) => !isDefined(record.trigger?.settings.objectType), + ), + }; + } + + return { records }; +}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersionsForObject.ts b/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersionsForObject.ts deleted file mode 100644 index 2ab48de46..000000000 --- a/packages/twenty-front/src/modules/workflow/hooks/useAllActiveWorkflowVersionsForObject.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; -import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; -import { - Workflow, - WorkflowTriggerType, - WorkflowVersion, -} from '@/workflow/types/Workflow'; - -export const useAllActiveWorkflowVersionsForObject = ({ - objectNameSingular, - triggerType, -}: { - objectNameSingular: string; - triggerType: WorkflowTriggerType; -}) => { - const { objectMetadataItem } = useObjectMetadataItem({ - objectNameSingular, - }); - - const { records } = useFindManyRecords< - WorkflowVersion & { workflow: Workflow } - >({ - objectNameSingular: CoreObjectNameSingular.WorkflowVersion, - filter: { - and: [ - { - status: { - eq: 'ACTIVE', - }, - }, - { - trigger: { - like: `%"type": "${triggerType}"%`, - }, - }, - { - trigger: { - like: `%"objectType": "${objectNameSingular}"%`, - }, - }, - ], - }, - recordGqlFields: { - ...generateDepthOneRecordGqlFields({ objectMetadataItem }), - workflow: true, - }, - }); - - return { records }; -}; diff --git a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.ts b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.ts index fe1a9ed78..5e037f573 100644 --- a/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.ts +++ b/packages/twenty-front/src/modules/workflow/hooks/useRunWorkflowVersion.ts @@ -17,7 +17,7 @@ export const useRunWorkflowVersion = () => { const runWorkflowVersion = async ( workflowVersionId: string, - payload: Record, + payload?: Record, ) => { await mutate({ variables: { input: { workflowVersionId, payload } }, diff --git a/packages/twenty-front/src/modules/workflow/types/Workflow.ts b/packages/twenty-front/src/modules/workflow/types/Workflow.ts index 7942379ba..6905e796e 100644 --- a/packages/twenty-front/src/modules/workflow/types/Workflow.ts +++ b/packages/twenty-front/src/modules/workflow/types/Workflow.ts @@ -65,6 +65,7 @@ export type WorkflowDatabaseEventTrigger = BaseTrigger & { eventName: string; input?: object; outputSchema: object; + objectType?: string; }; };