Create command menu items for workflows with manual trigger (#18746)

- Automatically create and sync command menu items for all workflows
with a manual trigger
- Refactor `useCommandMenuItemsFromBackend`
- Prefill a _Quick Lead_ workflow command menu item during workspace
setup and dev seeding
- Add a ready prop to `HeadlessEngineCommandWrapperEffect` to prevent
premature execution when async data hasn't loaded yet

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Raphaël Bosi
2026-03-22 23:52:43 +01:00
committed by GitHub
parent d16b94bde6
commit c107d804d2
29 changed files with 1277 additions and 860 deletions
@@ -0,0 +1,69 @@
import { type EntityManager } from 'typeorm';
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
import { QUICK_LEAD_WORKFLOW_VERSION_ID } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows';
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
const QUICK_LEAD_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER =
'a1b2c3d4-e5f6-7890-abcd-1234567890ab';
export const prefillWorkflowCommandMenuItems = async (
entityManager: EntityManager,
workspaceId: string,
) => {
const applicationRow = await entityManager
.createQueryBuilder()
.select('app.id')
.from('core.application', 'app')
.where('app.universalIdentifier = :universalIdentifier', {
universalIdentifier: TWENTY_STANDARD_APPLICATION.universalIdentifier,
})
.andWhere('app.workspaceId = :workspaceId', { workspaceId })
.getRawOne();
if (!applicationRow) {
return;
}
await entityManager
.createQueryBuilder()
.insert()
.into('core.commandMenuItem', [
'workspaceId',
'universalIdentifier',
'applicationId',
'workflowVersionId',
'frontComponentId',
'engineComponentKey',
'label',
'icon',
'shortLabel',
'position',
'isPinned',
'availabilityType',
'conditionalAvailabilityExpression',
'availabilityObjectMetadataId',
'hotKeys',
])
.values([
{
workspaceId,
universalIdentifier: QUICK_LEAD_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER,
applicationId: applicationRow.app_id,
workflowVersionId: QUICK_LEAD_WORKFLOW_VERSION_ID,
frontComponentId: null,
engineComponentKey: null,
label: 'Quick Lead',
icon: 'IconUserPlus',
shortLabel: 'Quick Lead',
position: 100,
isPinned: false,
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
conditionalAvailabilityExpression: null,
availabilityObjectMetadataId: null,
hotKeys: null,
},
])
.orIgnore()
.execute();
};
@@ -9,8 +9,9 @@ import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
import { generateObjectRecordFields } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields';
const QUICK_LEAD_WORKFLOW_ID = '8b213cac-a68b-4ffe-817a-3ec994e9932d';
const QUICK_LEAD_WORKFLOW_VERSION_ID = 'ac67974f-c524-4288-9d88-af8515400b68';
export const QUICK_LEAD_WORKFLOW_ID = '8b213cac-a68b-4ffe-817a-3ec994e9932d';
export const QUICK_LEAD_WORKFLOW_VERSION_ID =
'ac67974f-c524-4288-9d88-af8515400b68';
export const prefillWorkflows = async (
entityManager: EntityManager,
@@ -5,11 +5,13 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { prefillCompanies } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-companies';
import { prefillPeople } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-people';
import { prefillWorkflowCommandMenuItems } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflow-command-menu-items';
import { prefillWorkflows } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workflows';
export const standardObjectsPrefillData = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
) => {
@@ -24,5 +26,7 @@ export const standardObjectsPrefillData = async (
flatObjectMetadataMaps,
flatFieldMetadataMaps,
);
await prefillWorkflowCommandMenuItems(entityManager, workspaceId);
});
};