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
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { isDefined } from 'twenty-shared/utils';
import { type QueryRunner } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import {
@@ -87,6 +88,7 @@ export class CommandMenuItemService {
async create(
input: CreateCommandMenuItemInput,
workspaceId: string,
queryRunner?: QueryRunner,
): Promise<CommandMenuItemDTO> {
const { flatObjectMetadataMaps, flatFrontComponentMaps } =
await this.workspaceManyOrAllFlatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
@@ -124,6 +126,7 @@ export class CommandMenuItemService {
isSystemBuild: false,
applicationUniversalIdentifier:
workspaceCustomFlatApplication.universalIdentifier,
queryRunner,
},
);
@@ -153,6 +156,7 @@ export class CommandMenuItemService {
async update(
input: UpdateCommandMenuItemInput,
workspaceId: string,
queryRunner?: QueryRunner,
): Promise<CommandMenuItemDTO> {
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
@@ -191,6 +195,7 @@ export class CommandMenuItemService {
isSystemBuild: false,
applicationUniversalIdentifier:
workspaceCustomFlatApplication.universalIdentifier,
queryRunner,
},
);
@@ -217,7 +222,11 @@ export class CommandMenuItemService {
);
}
async delete(id: string, workspaceId: string): Promise<CommandMenuItemDTO> {
async delete(
id: string,
workspaceId: string,
queryRunner?: QueryRunner,
): Promise<CommandMenuItemDTO> {
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{ workspaceId },
@@ -251,6 +260,7 @@ export class CommandMenuItemService {
isSystemBuild: false,
applicationUniversalIdentifier:
workspaceCustomFlatApplication.universalIdentifier,
queryRunner,
},
);