[COMMAND MENU ITEMS] Add engine component key (#18554)
## PR Description In the process of migrating all the existing commands to the backend, we stumbled across a couple of problems that made us reconsider the full migration. This PR introduces a way for command menu items to bypass front components and to directly reference a frontend component from twenty front. It: - Introduces a `engineFrontComponentKey` field on `CommandMenuItem` as an alternative to `frontComponentId` and `workflowVersionId`, allowing command menu items to reference frontend components by key directly rather than requiring a FrontComponent entity - Updates the DB constraint to allow exactly one of `workflowVersionId`, `frontComponentId`, or `engineFrontComponentKey` ### All standard command menu items from the frontend which use `standardFrontComponentKey` These are all commands that execute a GraphQL query or a mutation. Two mains concerned have been raised that made us go with this (temporary) architecture instead: - If those commands are part of the standard application, they can only alter objects from that application and not custom objects. - We would need to implement a way to trigger optimistic rendering from the front components, which might take some time to implement. List: - Create new record - Delete (single record) - Delete records (multiple) - Restore record - Restore records (multiple) - Permanently destroy record - Permanently destroy records (multiple) - Add to favorites - Remove from favorites - Merge records - Duplicate Dashboard - Save Dashboard - Save Page Layout - Activate Workflow - Deactivate Workflow - Discard Draft (workflow) - Test Workflow - Tidy up workflow - Duplicate Workflow - Stop (workflow run) - Use as draft (workflow version) --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+8
-12
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
Field,
|
||||
Float,
|
||||
HideField,
|
||||
ObjectType,
|
||||
registerEnumType,
|
||||
} from '@nestjs/graphql';
|
||||
import { Field, Float, HideField, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
@@ -18,13 +12,10 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
import { FrontComponentDTO } from 'src/engine/metadata-modules/front-component/dtos/front-component.dto';
|
||||
|
||||
registerEnumType(CommandMenuItemAvailabilityType, {
|
||||
name: 'CommandMenuItemAvailabilityType',
|
||||
});
|
||||
|
||||
@ObjectType('CommandMenuItem')
|
||||
export class CommandMenuItemDTO {
|
||||
@IsUUID()
|
||||
@@ -45,6 +36,11 @@ export class CommandMenuItemDTO {
|
||||
@Field(() => FrontComponentDTO, { nullable: true })
|
||||
frontComponent?: FrontComponentDTO | null;
|
||||
|
||||
@IsEnum(EngineComponentKey)
|
||||
@IsOptional()
|
||||
@Field(() => EngineComponentKey, { nullable: true })
|
||||
engineComponentKey?: EngineComponentKey;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
|
||||
+7
-1
@@ -11,7 +11,8 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
|
||||
@InputType()
|
||||
export class CreateCommandMenuItemInput {
|
||||
@@ -25,6 +26,11 @@ export class CreateCommandMenuItemInput {
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
frontComponentId?: string;
|
||||
|
||||
@IsEnum(EngineComponentKey)
|
||||
@IsOptional()
|
||||
@Field(() => EngineComponentKey, { nullable: true })
|
||||
engineComponentKey?: EngineComponentKey;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
|
||||
+7
-1
@@ -11,7 +11,8 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
|
||||
@InputType()
|
||||
export class UpdateCommandMenuItemInput {
|
||||
@@ -54,4 +55,9 @@ export class UpdateCommandMenuItemInput {
|
||||
@IsOptional()
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
availabilityObjectMetadataId?: string;
|
||||
|
||||
@IsEnum(EngineComponentKey)
|
||||
@IsOptional()
|
||||
@Field(() => EngineComponentKey, { nullable: true })
|
||||
engineComponentKey?: EngineComponentKey;
|
||||
}
|
||||
|
||||
+12
-9
@@ -11,16 +11,12 @@ import {
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum';
|
||||
import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum';
|
||||
import { FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
|
||||
export enum CommandMenuItemAvailabilityType {
|
||||
GLOBAL = 'GLOBAL',
|
||||
RECORD_SELECTION = 'RECORD_SELECTION',
|
||||
FALLBACK = 'FALLBACK',
|
||||
}
|
||||
|
||||
@Entity({ name: 'commandMenuItem', schema: 'core' })
|
||||
@Index('IDX_COMMAND_MENU_ITEM_WORKFLOW_VERSION_ID_WORKSPACE_ID', [
|
||||
'workflowVersionId',
|
||||
@@ -34,8 +30,8 @@ export enum CommandMenuItemAvailabilityType {
|
||||
'availabilityObjectMetadataId',
|
||||
])
|
||||
@Check(
|
||||
'CHK_command_menu_item_workflow_or_front_component',
|
||||
'("workflowVersionId" IS NOT NULL AND "frontComponentId" IS NULL) OR ("workflowVersionId" IS NULL AND "frontComponentId" IS NOT NULL)',
|
||||
'CHK_CMD_MENU_ITEM_WF_OR_FC_OR_ENGINE_KEY',
|
||||
'("workflowVersionId" IS NOT NULL AND "frontComponentId" IS NULL AND "engineComponentKey" IS NULL) OR ("workflowVersionId" IS NULL AND "frontComponentId" IS NOT NULL AND "engineComponentKey" IS NULL) OR ("workflowVersionId" IS NULL AND "frontComponentId" IS NULL AND "engineComponentKey" IS NOT NULL)',
|
||||
)
|
||||
export class CommandMenuItemEntity
|
||||
extends SyncableEntity
|
||||
@@ -57,6 +53,13 @@ export class CommandMenuItemEntity
|
||||
@JoinColumn({ name: 'frontComponentId' })
|
||||
frontComponent: Relation<FrontComponentEntity> | null;
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: Object.values(EngineComponentKey),
|
||||
nullable: true,
|
||||
})
|
||||
engineComponentKey: EngineComponentKey | null;
|
||||
|
||||
@Column({ nullable: false })
|
||||
label: string;
|
||||
|
||||
@@ -74,7 +77,7 @@ export class CommandMenuItemEntity
|
||||
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: CommandMenuItemAvailabilityType,
|
||||
enum: Object.values(CommandMenuItemAvailabilityType),
|
||||
nullable: false,
|
||||
default: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
})
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
export enum CommandMenuItemAvailabilityType {
|
||||
GLOBAL = 'GLOBAL',
|
||||
RECORD_SELECTION = 'RECORD_SELECTION',
|
||||
FALLBACK = 'FALLBACK',
|
||||
}
|
||||
|
||||
registerEnumType(CommandMenuItemAvailabilityType, {
|
||||
name: 'CommandMenuItemAvailabilityType',
|
||||
});
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
import { registerEnumType } from '@nestjs/graphql';
|
||||
|
||||
export enum EngineComponentKey {
|
||||
CREATE_NEW_RECORD = 'CREATE_NEW_RECORD',
|
||||
DELETE_SINGLE_RECORD = 'DELETE_SINGLE_RECORD',
|
||||
DELETE_MULTIPLE_RECORDS = 'DELETE_MULTIPLE_RECORDS',
|
||||
RESTORE_SINGLE_RECORD = 'RESTORE_SINGLE_RECORD',
|
||||
RESTORE_MULTIPLE_RECORDS = 'RESTORE_MULTIPLE_RECORDS',
|
||||
DESTROY_SINGLE_RECORD = 'DESTROY_SINGLE_RECORD',
|
||||
DESTROY_MULTIPLE_RECORDS = 'DESTROY_MULTIPLE_RECORDS',
|
||||
ADD_TO_FAVORITES = 'ADD_TO_FAVORITES',
|
||||
REMOVE_FROM_FAVORITES = 'REMOVE_FROM_FAVORITES',
|
||||
MERGE_MULTIPLE_RECORDS = 'MERGE_MULTIPLE_RECORDS',
|
||||
DUPLICATE_DASHBOARD = 'DUPLICATE_DASHBOARD',
|
||||
DUPLICATE_WORKFLOW = 'DUPLICATE_WORKFLOW',
|
||||
ACTIVATE_WORKFLOW = 'ACTIVATE_WORKFLOW',
|
||||
DEACTIVATE_WORKFLOW = 'DEACTIVATE_WORKFLOW',
|
||||
DISCARD_DRAFT_WORKFLOW = 'DISCARD_DRAFT_WORKFLOW',
|
||||
TEST_WORKFLOW = 'TEST_WORKFLOW',
|
||||
STOP_WORKFLOW_RUN = 'STOP_WORKFLOW_RUN',
|
||||
USE_AS_DRAFT_WORKFLOW_VERSION = 'USE_AS_DRAFT_WORKFLOW_VERSION',
|
||||
SAVE_RECORD_PAGE_LAYOUT = 'SAVE_RECORD_PAGE_LAYOUT',
|
||||
SAVE_DASHBOARD_LAYOUT = 'SAVE_DASHBOARD_LAYOUT',
|
||||
TIDY_UP_WORKFLOW = 'TIDY_UP_WORKFLOW',
|
||||
}
|
||||
|
||||
registerEnumType(EngineComponentKey, {
|
||||
name: 'EngineComponentKey',
|
||||
});
|
||||
Reference in New Issue
Block a user