fix(front): only show Discard Draft when workflow has a published version (#23756)
## Problem Draft workflows expose a **Discard Draft** action, but it fails when the draft is the *only* version of the workflow. The backend refuses the delete with `The initial version of a workflow can not be deleted` (guard in `validateWorkflowVersionForDeleteOne`), yet the action was still shown. The display condition and the delete-guard disagreed: - Display condition: `every(selectedRecords, "versions.length")` -> truthy when there is **at least one** version. - Delete guard: forbids deletion unless **another** non-deleted version exists. So a workflow whose only version is a draft showed the button, and clicking it hit a `FORBIDDEN` error. ## Fix Show the action only when the workflow has a published version to fall back to, which mirrors the backend guard: ``` every(selectedRecords, "lastPublishedVersionId") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt") ``` `lastPublishedVersionId` is a plain scalar already on the workflow. `every` (truthiness) is used rather than `everyDefined` because the field is an empty string for never-published workflows, and `everyDefined` would treat `""` as present. The command-menu evaluator reads records straight from the store, and the index/table view only fetches visible columns, so the enrichment provider now also backfills `lastPublishedVersionId` (already fetched by `useWorkflowsWithCurrentVersions`) to keep the condition reliable outside the record show page. ## Existing workspaces The standard-application full sync only runs at workspace creation, so editing the constant alone would fix new workspaces but leave existing ones showing the broken button. A `2.27.0` workspace upgrade command re-syncs the `discardDraftWorkflow` availability expression for existing workspaces, updating it only when it still equals the legacy `versions.length` value (so custom expressions are left untouched). Mirrors the existing 2-23 command-menu-item sync pattern. ## Notes - The `>`-style "more than one version" comparison is not expressible in the current `conditionalAvailabilityExpression` grammar (comparison operators only reach top-level scalars like `numberOfSelectedRecords`, not per-record paths). Gating on `lastPublishedVersionId` achieves the same intent without adding a parser helper. ## Test - Fresh workflow (single draft) -> Discard Draft hidden. - Publish, then edit to create a new draft -> Discard Draft shown and works. - Unit test on the sync-operations builder: updates the legacy expression, no-ops when already synced / custom / missing.
This commit is contained in:
+2
@@ -42,6 +42,8 @@ export const CommandMenuContextProviderWithWorkflowEnrichment = ({
|
|||||||
currentVersion: workflowWithCurrentVersion.currentVersion,
|
currentVersion: workflowWithCurrentVersion.currentVersion,
|
||||||
versions: workflowWithCurrentVersion.versions,
|
versions: workflowWithCurrentVersion.versions,
|
||||||
statuses: workflowWithCurrentVersion.statuses,
|
statuses: workflowWithCurrentVersion.statuses,
|
||||||
|
lastPublishedVersionId:
|
||||||
|
workflowWithCurrentVersion.lastPublishedVersionId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
+15
-2
@@ -2,10 +2,23 @@ import { Module } from '@nestjs/common';
|
|||||||
|
|
||||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||||
import { RepairOrphanCoreWorkflowVersionsCommand } from 'src/database/commands/upgrade-version-command/2-28/2-28-workspace-command-1785600000000-repair-orphan-core-workflow-versions.command';
|
import { RepairOrphanCoreWorkflowVersionsCommand } from 'src/database/commands/upgrade-version-command/2-28/2-28-workspace-command-1785600000000-repair-orphan-core-workflow-versions.command';
|
||||||
|
import { SyncDiscardDraftWorkflowAvailabilityExpressionCommand } from 'src/database/commands/upgrade-version-command/2-28/2-28-workspace-command-1786000000000-sync-discard-draft-workflow-availability-expression.command';
|
||||||
|
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||||
|
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/workspace-migration-runner.module';
|
||||||
|
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [WorkspaceCacheModule, WorkspaceIteratorModule],
|
imports: [
|
||||||
providers: [RepairOrphanCoreWorkflowVersionsCommand],
|
ApplicationModule,
|
||||||
|
WorkspaceCacheModule,
|
||||||
|
WorkspaceMigrationModule,
|
||||||
|
WorkspaceMigrationRunnerModule,
|
||||||
|
WorkspaceIteratorModule,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
RepairOrphanCoreWorkflowVersionsCommand,
|
||||||
|
SyncDiscardDraftWorkflowAvailabilityExpressionCommand,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class V2_28_UpgradeVersionCommandModule {}
|
export class V2_28_UpgradeVersionCommandModule {}
|
||||||
|
|||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
import { Command } from 'nest-commander';
|
||||||
|
|
||||||
|
import { ProvisionedWorkspaceCommandRunner } from 'src/database/commands/command-runners/provisioned-workspace.command-runner';
|
||||||
|
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||||
|
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||||
|
import { buildDiscardDraftWorkflowCommandMenuItemsToUpdate } from 'src/database/commands/upgrade-version-command/2-28/utils/build-sync-discard-draft-workflow-availability-expression-sync-operations.util';
|
||||||
|
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||||
|
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||||
|
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||||
|
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||||
|
|
||||||
|
@RegisteredWorkspaceCommand('2.28.0', 1786000000000)
|
||||||
|
@Command({
|
||||||
|
name: 'upgrade:2-28:sync-discard-draft-workflow-availability-expression',
|
||||||
|
description:
|
||||||
|
'Gate the "Discard Draft" workflow command menu item on lastPublishedVersionId so it is hidden when the draft is the only version in existing workspaces',
|
||||||
|
})
|
||||||
|
export class SyncDiscardDraftWorkflowAvailabilityExpressionCommand extends ProvisionedWorkspaceCommandRunner {
|
||||||
|
constructor(
|
||||||
|
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||||
|
private readonly applicationService: ApplicationService,
|
||||||
|
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||||
|
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||||
|
) {
|
||||||
|
super(workspaceIteratorService);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async runOnWorkspace({
|
||||||
|
workspaceId,
|
||||||
|
options,
|
||||||
|
}: RunOnWorkspaceArgs): Promise<void> {
|
||||||
|
const isDryRun = options.dryRun ?? false;
|
||||||
|
|
||||||
|
const { flatCommandMenuItemMaps } =
|
||||||
|
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||||
|
'flatCommandMenuItemMaps',
|
||||||
|
]);
|
||||||
|
|
||||||
|
const commandMenuItemsToUpdate =
|
||||||
|
buildDiscardDraftWorkflowCommandMenuItemsToUpdate({
|
||||||
|
existingFlatCommandMenuItemMaps: flatCommandMenuItemMaps,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (commandMenuItemsToUpdate.length === 0) {
|
||||||
|
this.logger.log(
|
||||||
|
`"Discard Draft" workflow command menu item availability expression already synced for workspace ${workspaceId}, skipping`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`${isDryRun ? '[DRY RUN] ' : ''}Syncing "Discard Draft" workflow command menu item availability expression for workspace ${workspaceId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isDryRun) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { twentyStandardFlatApplication } =
|
||||||
|
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||||
|
{ workspaceId },
|
||||||
|
);
|
||||||
|
|
||||||
|
const validateAndBuildResult =
|
||||||
|
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunLegacyWorkspaceMigration(
|
||||||
|
{
|
||||||
|
allFlatEntityOperationByMetadataName: {
|
||||||
|
commandMenuItem: {
|
||||||
|
flatEntityToCreate: [],
|
||||||
|
flatEntityToDelete: [],
|
||||||
|
flatEntityToUpdate: commandMenuItemsToUpdate,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
workspaceId,
|
||||||
|
applicationUniversalIdentifier:
|
||||||
|
twentyStandardFlatApplication.universalIdentifier,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (validateAndBuildResult.status === 'fail') {
|
||||||
|
this.logger.error(
|
||||||
|
`Failed to sync "Discard Draft" workflow command menu item availability expression:\n${JSON.stringify(validateAndBuildResult, null, 2)}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`Failed to sync "Discard Draft" workflow command menu item availability expression for workspace ${workspaceId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`Successfully synced "Discard Draft" workflow command menu item availability expression for workspace ${workspaceId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+149
@@ -0,0 +1,149 @@
|
|||||||
|
import { TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER } from 'twenty-shared/application';
|
||||||
|
|
||||||
|
import {
|
||||||
|
buildDiscardDraftWorkflowCommandMenuItemsToUpdate,
|
||||||
|
LEGACY_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION,
|
||||||
|
} from 'src/database/commands/upgrade-version-command/2-28/utils/build-sync-discard-draft-workflow-availability-expression-sync-operations.util';
|
||||||
|
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
|
||||||
|
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||||
|
import { STANDARD_COMMAND_MENU_ITEMS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant';
|
||||||
|
|
||||||
|
const APPLICATION_ID = 'application-id';
|
||||||
|
const WORKSPACE_ID = 'workspace-id';
|
||||||
|
const CREATED_AT = '2026-08-01T00:00:00.000Z';
|
||||||
|
|
||||||
|
const DISCARD_DRAFT_WORKFLOW_DEFINITION =
|
||||||
|
STANDARD_COMMAND_MENU_ITEMS.discardDraftWorkflow;
|
||||||
|
|
||||||
|
// Independent literal so a regression in the standard definition is caught here
|
||||||
|
// rather than silently accepted by asserting the value against itself.
|
||||||
|
const EXPECTED_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION =
|
||||||
|
'every(selectedRecords, "lastPublishedVersionId") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")';
|
||||||
|
|
||||||
|
const buildFlatCommandMenuItemMaps = (
|
||||||
|
flatCommandMenuItems: FlatCommandMenuItem[],
|
||||||
|
): FlatEntityMaps<FlatCommandMenuItem> => ({
|
||||||
|
byUniversalIdentifier: Object.fromEntries(
|
||||||
|
flatCommandMenuItems.map((flatCommandMenuItem) => [
|
||||||
|
flatCommandMenuItem.universalIdentifier,
|
||||||
|
flatCommandMenuItem,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
universalIdentifierById: Object.fromEntries(
|
||||||
|
flatCommandMenuItems.map((flatCommandMenuItem) => [
|
||||||
|
flatCommandMenuItem.id,
|
||||||
|
flatCommandMenuItem.universalIdentifier,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
universalIdentifiersByApplicationId: {
|
||||||
|
[APPLICATION_ID]: flatCommandMenuItems.map(
|
||||||
|
(flatCommandMenuItem) => flatCommandMenuItem.universalIdentifier,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const buildDiscardDraftWorkflowCommandMenuItem = ({
|
||||||
|
conditionalAvailabilityExpression,
|
||||||
|
}: {
|
||||||
|
conditionalAvailabilityExpression: string | null;
|
||||||
|
}): FlatCommandMenuItem => ({
|
||||||
|
id: 'discard-draft-workflow-command-menu-item-id',
|
||||||
|
universalIdentifier: DISCARD_DRAFT_WORKFLOW_DEFINITION.universalIdentifier,
|
||||||
|
applicationId: APPLICATION_ID,
|
||||||
|
applicationUniversalIdentifier:
|
||||||
|
TWENTY_STANDARD_APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||||
|
workspaceId: WORKSPACE_ID,
|
||||||
|
label: DISCARD_DRAFT_WORKFLOW_DEFINITION.label,
|
||||||
|
shortLabel: DISCARD_DRAFT_WORKFLOW_DEFINITION.shortLabel,
|
||||||
|
icon: DISCARD_DRAFT_WORKFLOW_DEFINITION.icon,
|
||||||
|
position: DISCARD_DRAFT_WORKFLOW_DEFINITION.position,
|
||||||
|
isPinned: DISCARD_DRAFT_WORKFLOW_DEFINITION.isPinned,
|
||||||
|
availabilityType: DISCARD_DRAFT_WORKFLOW_DEFINITION.availabilityType,
|
||||||
|
conditionalAvailabilityExpression,
|
||||||
|
frontComponentId: null,
|
||||||
|
frontComponentUniversalIdentifier: null,
|
||||||
|
engineComponentKey: DISCARD_DRAFT_WORKFLOW_DEFINITION.engineComponentKey,
|
||||||
|
payload: null,
|
||||||
|
hotKeys: null,
|
||||||
|
workflowVersionId: null,
|
||||||
|
availabilityObjectMetadataId: 'workflow-object-metadata-id',
|
||||||
|
availabilityObjectMetadataUniversalIdentifier:
|
||||||
|
DISCARD_DRAFT_WORKFLOW_DEFINITION.availabilityObjectMetadataUniversalIdentifier,
|
||||||
|
pageLayoutId: null,
|
||||||
|
pageLayoutUniversalIdentifier: null,
|
||||||
|
isActive: true,
|
||||||
|
isSystemSideEffect: false,
|
||||||
|
overrides: null,
|
||||||
|
universalOverrides: null,
|
||||||
|
createdAt: CREATED_AT,
|
||||||
|
updatedAt: CREATED_AT,
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('buildDiscardDraftWorkflowCommandMenuItemsToUpdate', () => {
|
||||||
|
it('rewrites the legacy versions.length gate to the lastPublishedVersionId gate', () => {
|
||||||
|
const legacyDiscardDraftWorkflowCommandMenuItem =
|
||||||
|
buildDiscardDraftWorkflowCommandMenuItem({
|
||||||
|
conditionalAvailabilityExpression:
|
||||||
|
LEGACY_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildDiscardDraftWorkflowCommandMenuItemsToUpdate({
|
||||||
|
existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([
|
||||||
|
legacyDiscardDraftWorkflowCommandMenuItem,
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0]).toMatchObject({
|
||||||
|
id: legacyDiscardDraftWorkflowCommandMenuItem.id,
|
||||||
|
conditionalAvailabilityExpression:
|
||||||
|
EXPECTED_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('syncs to the lastPublishedVersionId gate defined in the standard command menu item', () => {
|
||||||
|
expect(
|
||||||
|
DISCARD_DRAFT_WORKFLOW_DEFINITION.conditionalAvailabilityExpression,
|
||||||
|
).toBe(EXPECTED_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not update the command menu item when the expression is already synced', () => {
|
||||||
|
const syncedDiscardDraftWorkflowCommandMenuItem =
|
||||||
|
buildDiscardDraftWorkflowCommandMenuItem({
|
||||||
|
conditionalAvailabilityExpression:
|
||||||
|
EXPECTED_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION,
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildDiscardDraftWorkflowCommandMenuItemsToUpdate({
|
||||||
|
existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([
|
||||||
|
syncedDiscardDraftWorkflowCommandMenuItem,
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not update an unrelated custom availability expression', () => {
|
||||||
|
const customDiscardDraftWorkflowCommandMenuItem =
|
||||||
|
buildDiscardDraftWorkflowCommandMenuItem({
|
||||||
|
conditionalAvailabilityExpression:
|
||||||
|
'everyEquals(selectedRecords, "currentVersion.status", "DRAFT")',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildDiscardDraftWorkflowCommandMenuItemsToUpdate({
|
||||||
|
existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([
|
||||||
|
customDiscardDraftWorkflowCommandMenuItem,
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not update when the discard draft workflow command menu item is missing', () => {
|
||||||
|
const result = buildDiscardDraftWorkflowCommandMenuItemsToUpdate({
|
||||||
|
existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([]),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
|
||||||
|
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||||
|
import { STANDARD_COMMAND_MENU_ITEMS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant';
|
||||||
|
|
||||||
|
export const LEGACY_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION =
|
||||||
|
'every(selectedRecords, "versions.length") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")';
|
||||||
|
|
||||||
|
const DISCARD_DRAFT_WORKFLOW_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER =
|
||||||
|
STANDARD_COMMAND_MENU_ITEMS.discardDraftWorkflow.universalIdentifier;
|
||||||
|
|
||||||
|
const DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION =
|
||||||
|
STANDARD_COMMAND_MENU_ITEMS.discardDraftWorkflow
|
||||||
|
.conditionalAvailabilityExpression;
|
||||||
|
|
||||||
|
export const buildDiscardDraftWorkflowCommandMenuItemsToUpdate = ({
|
||||||
|
existingFlatCommandMenuItemMaps,
|
||||||
|
}: {
|
||||||
|
existingFlatCommandMenuItemMaps: FlatEntityMaps<FlatCommandMenuItem>;
|
||||||
|
}): FlatCommandMenuItem[] => {
|
||||||
|
const existingDiscardDraftWorkflowCommandMenuItem =
|
||||||
|
existingFlatCommandMenuItemMaps.byUniversalIdentifier[
|
||||||
|
DISCARD_DRAFT_WORKFLOW_COMMAND_MENU_ITEM_UNIVERSAL_IDENTIFIER
|
||||||
|
];
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isDefined(existingDiscardDraftWorkflowCommandMenuItem) ||
|
||||||
|
existingDiscardDraftWorkflowCommandMenuItem.conditionalAvailabilityExpression !==
|
||||||
|
LEGACY_DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION
|
||||||
|
) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...existingDiscardDraftWorkflowCommandMenuItem,
|
||||||
|
conditionalAvailabilityExpression:
|
||||||
|
DISCARD_DRAFT_WORKFLOW_AVAILABILITY_EXPRESSION,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
+1
-1
@@ -379,7 +379,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
|||||||
shortLabel: 'Discard Draft',
|
shortLabel: 'Discard Draft',
|
||||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||||
conditionalAvailabilityExpression:
|
conditionalAvailabilityExpression:
|
||||||
'every(selectedRecords, "versions.length") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
'every(selectedRecords, "lastPublishedVersionId") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
||||||
availabilityObjectMetadataUniversalIdentifier:
|
availabilityObjectMetadataUniversalIdentifier:
|
||||||
STANDARD_OBJECTS.workflow.universalIdentifier,
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
||||||
frontComponentUniversalIdentifier: null,
|
frontComponentUniversalIdentifier: null,
|
||||||
|
|||||||
Reference in New Issue
Block a user