CommandMenuItem overridable entity (#21486)
## Context Second PR of the overridable-entities track (after #21436 for views): command menu items become overridable so that edits on non-owned items are stored as overrides instead of mutating the row, and deletion/deactivation becomes reversible. ## What this does - `CommandMenuItemEntity` now extends `OverridableEntity<CommandMenuItemOverrides>` (adds `isActive` + `overrides`). All editable properties are overridable for now (to discuss). - **Update**: mutations on a command item not owned by the caller (standard items) are written into `overrides`; reads merge them in the DTO. The command palette edit mode (pin, reorder, shortLabel) now preserves standard values, "Reset label to default" gains true post-save semantics. - **Delete**: protected items are deactivated (`isActive = false`) instead of deleted; custom items still hard-delete. - **Object deactivate/enable toggle**: now flips `isActive` on the command item (merged into the main migration call) instead of delete/recreate; a create-if-missing fallback covers legacy deactivated objects. - **Front**: inactive command items are filtered out of the palette selector. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21486?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+3
-1
@@ -38,7 +38,9 @@ export const ALL_JSONB_PROPERTIES_WITH_SERIALIZED_RELATION_BY_METADATA_NAME = {
|
||||
configuration: 'configuration',
|
||||
overrides: 'overrides',
|
||||
},
|
||||
commandMenuItem: {},
|
||||
commandMenuItem: {
|
||||
overrides: 'overrides',
|
||||
},
|
||||
navigationMenuItem: {},
|
||||
rolePermissionFlag: {},
|
||||
permissionFlag: {},
|
||||
|
||||
+11
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface';
|
||||
@@ -10,6 +11,7 @@ import {
|
||||
FlatCreateCommandMenuItemAction,
|
||||
UniversalCreateCommandMenuItemAction,
|
||||
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/command-menu-item/types/workspace-migration-command-menu-item-action.type';
|
||||
import { fromUniversalOverridesToCommandMenuItemOverrides } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/command-menu-item/services/utils/from-universal-overrides-to-command-menu-item-overrides.util';
|
||||
import {
|
||||
WorkspaceMigrationActionRunnerArgs,
|
||||
WorkspaceMigrationActionRunnerContext,
|
||||
@@ -37,6 +39,14 @@ export class CreateCommandMenuItemActionHandlerService extends WorkspaceMigratio
|
||||
universalForeignKeyValues: action.flatEntity,
|
||||
});
|
||||
|
||||
const overrides = isDefined(action.flatEntity.universalOverrides)
|
||||
? fromUniversalOverridesToCommandMenuItemOverrides({
|
||||
universalOverrides: action.flatEntity.universalOverrides,
|
||||
flatObjectMetadataMaps: allFlatEntityMaps.flatObjectMetadataMaps,
|
||||
flatPageLayoutMaps: allFlatEntityMaps.flatPageLayoutMaps,
|
||||
})
|
||||
: null;
|
||||
|
||||
const emptyUniversalForeignKeyAggregators =
|
||||
getUniversalFlatEntityEmptyForeignKeyAggregators({
|
||||
metadataName: 'commandMenuItem',
|
||||
@@ -49,6 +59,7 @@ export class CreateCommandMenuItemActionHandlerService extends WorkspaceMigratio
|
||||
availabilityObjectMetadataId,
|
||||
frontComponentId,
|
||||
pageLayoutId,
|
||||
overrides,
|
||||
applicationId: flatApplication.id,
|
||||
id: action.id ?? v4(),
|
||||
workspaceId,
|
||||
|
||||
+22
-5
@@ -7,6 +7,7 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
|
||||
import { CommandMenuItemEntity } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
|
||||
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
|
||||
import { resolveUniversalUpdateRelationIdentifiersToIds } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-universal-update-relation-identifiers-to-ids.util';
|
||||
import { fromUniversalOverridesToCommandMenuItemOverrides } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/command-menu-item/services/utils/from-universal-overrides-to-command-menu-item-overrides.util';
|
||||
import {
|
||||
FlatUpdateCommandMenuItemAction,
|
||||
UniversalUpdateCommandMenuItemAction,
|
||||
@@ -31,11 +32,27 @@ export class UpdateCommandMenuItemActionHandlerService extends WorkspaceMigratio
|
||||
universalIdentifier: action.universalIdentifier,
|
||||
});
|
||||
|
||||
const update = resolveUniversalUpdateRelationIdentifiersToIds({
|
||||
metadataName: 'commandMenuItem',
|
||||
universalUpdate: action.update,
|
||||
allFlatEntityMaps,
|
||||
});
|
||||
const { universalOverrides, ...updateWithResolvedForeignKeys } =
|
||||
resolveUniversalUpdateRelationIdentifiersToIds({
|
||||
metadataName: 'commandMenuItem',
|
||||
universalUpdate: action.update,
|
||||
allFlatEntityMaps,
|
||||
});
|
||||
|
||||
const update =
|
||||
universalOverrides === undefined
|
||||
? updateWithResolvedForeignKeys
|
||||
: universalOverrides === null
|
||||
? { ...updateWithResolvedForeignKeys, overrides: null }
|
||||
: {
|
||||
...updateWithResolvedForeignKeys,
|
||||
overrides: fromUniversalOverridesToCommandMenuItemOverrides({
|
||||
universalOverrides,
|
||||
flatObjectMetadataMaps:
|
||||
allFlatEntityMaps.flatObjectMetadataMaps,
|
||||
flatPageLayoutMaps: allFlatEntityMaps.flatPageLayoutMaps,
|
||||
}),
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'update',
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { type FormatRecordSerializedRelationProperties } from 'twenty-shared/types';
|
||||
|
||||
import { type CommandMenuItemOverrides } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type';
|
||||
|
||||
type UniversalCommandMenuItemOverrides =
|
||||
FormatRecordSerializedRelationProperties<CommandMenuItemOverrides>;
|
||||
|
||||
export const fromUniversalOverridesToCommandMenuItemOverrides = ({
|
||||
universalOverrides,
|
||||
flatObjectMetadataMaps,
|
||||
flatPageLayoutMaps,
|
||||
}: {
|
||||
universalOverrides: UniversalCommandMenuItemOverrides;
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
flatPageLayoutMaps: FlatEntityMaps<FlatPageLayout>;
|
||||
}): CommandMenuItemOverrides => {
|
||||
const {
|
||||
availabilityObjectMetadataUniversalIdentifier,
|
||||
pageLayoutUniversalIdentifier,
|
||||
...scalarOverrides
|
||||
} = universalOverrides;
|
||||
|
||||
const overrides: CommandMenuItemOverrides = { ...scalarOverrides };
|
||||
|
||||
if (availabilityObjectMetadataUniversalIdentifier !== undefined) {
|
||||
if (availabilityObjectMetadataUniversalIdentifier === null) {
|
||||
overrides.availabilityObjectMetadataId = null;
|
||||
} else {
|
||||
const flatObjectMetadata =
|
||||
findFlatEntityByUniversalIdentifier<FlatObjectMetadata>({
|
||||
flatEntityMaps: flatObjectMetadataMaps,
|
||||
universalIdentifier: availabilityObjectMetadataUniversalIdentifier,
|
||||
});
|
||||
|
||||
overrides.availabilityObjectMetadataId = flatObjectMetadata?.id ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
if (pageLayoutUniversalIdentifier !== undefined) {
|
||||
if (pageLayoutUniversalIdentifier === null) {
|
||||
overrides.pageLayoutId = null;
|
||||
} else {
|
||||
const flatPageLayout =
|
||||
findFlatEntityByUniversalIdentifier<FlatPageLayout>({
|
||||
flatEntityMaps: flatPageLayoutMaps,
|
||||
universalIdentifier: pageLayoutUniversalIdentifier,
|
||||
});
|
||||
|
||||
overrides.pageLayoutId = flatPageLayout?.id ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return overrides;
|
||||
};
|
||||
Reference in New Issue
Block a user