1d755983ff
# Email editor for Compose campaigns
## Short version
Campaign bodies are currently plain rich text. This PR turns the
composer into an email editor: a centered email canvas with section,
column, button, divider, image and raw-HTML blocks, each editable
through a settings side panel, rendered to email-safe HTML per recipient
at send time. Modelled on Resend's Broadcast editor.
**Product**
- Email canvas with page/body styling (background, width, padding,
corner radius, border, text colour, alignment)
- Blocks: section, 2/3 columns, button, divider, raw HTML, images —
insertable from a floating left rail or the slash menu
- A **section is a container whose typography cascades to its
contents**, so one part of an email can have its own look
- Block settings panel focuses whatever you select and shows its
effective values
- Per-recipient variables (`{{firstName}}`, `{{lastName}}`,
`{{fullName}}`, `{{email}}`, `{{personId}}`) usable in text,
button/link/image URLs, image labels and raw HTML
- Image upload by drag-drop, paste or file picker
**Technical**
- Presets now declare **capabilities** instead of surfaces forking the
editor; the UI derives itself from loaded extensions
- Editor behavior lives in `twenty-front`; the versioned email-document
schema and structural traversal live in `twenty-shared`; rendering lives
in `twenty-emails` — HTML is produced server-side per recipient
- Section typography cascade is **resolved at render time**, not left to
CSS: react-email hardcodes `fontSize`/`lineHeight` on every paragraph
and Outlook ignores `inherit`
- Logic vendored from Resend (MIT); all controls rebuilt on `twenty-ui`
+ Linaria
**Also fixes:** the unsubscribe footer was being appended *after*
`</html>`, outside the document, where Gmail strips it — legally
significant since unsubscribe is required.
---
## Detailed version
### Product requirements
**Problem.** The Compose campaign body was a single rich-text field.
Marketing email needs layout — banded sections, columns, call-to-action
buttons, images with links — and it needs that layout to survive
Outlook, which means table-based HTML rather than the divs a text editor
produces. It also needs per-recipient personalisation.
**Reference.** Resend's Broadcast editor, chosen because it solves the
same problem (TipTap authoring → react-email output) and is MIT
licensed.
#### What a user can now do
| Area | Capability |
|---|---|
| Canvas | Email renders as a centered page with its own background,
width, padding, corner radius and border |
| Blocks | Section, 2/3 columns, button, divider, raw HTML, image |
| Insertion | Floating left rail (pointer-first) or the `/` slash menu
(keyboard-first) |
| Sections | Own text colour, font size, line height, letter spacing and
alignment, cascading to everything inside |
| Images | Upload by drag-drop, paste or picker; link URL, alt text,
width, spacing, border |
| Raw HTML | Edited as source in the panel, previewed on the canvas with
scripts neutralised |
| Variables | `{{firstName}}`, `{{lastName}}`, `{{fullName}}`,
`{{email}}`, `{{personId}}` in text, button URLs, link hrefs and raw
HTML |
| Settings panel | Follows selection; shows effective values; opens
automatically when a block is clicked |
#### Deliberate product decisions
- **Variables display as literal placeholders**, not prose labels, so
the syntax is copyable into HTML blocks and button URLs by hand.
- **Sections inherit until they override.** The panel shows what
actually renders rather than blank fields, but writes nothing until you
edit — so changing the body text colour still flows into sections.
- **Headings keep their own scale** inside a styled section; only
colour, family and spacing cascade, otherwise every heading would
collapse to body size.
- **Clicking a block opens its settings**, but only on whole-node
selections, so typing inside a section does not reopen a panel you just
closed.
### Technical strategy
#### 1. Capability presets (the foundation)
Per-surface variation previously worked by **forking**: three separate
`useEditor` call sites with hardcoded extension arrays. Inside the
shared tree there was no variation at all — all five surfaces received a
byte-identical extension list, and presets controlled only sizing,
chrome and serialization format. Adding email blocks that way meant
either leaking section/column nodes into the record rich-text field and
workflow email body, or writing a fourth fork.
Now:
- a preset declares a **capability list** (`basicMarks`, `headings`,
`lists`, `links`, `images`, `campaignVariables`, `slashCommand`,
`blocks`, `mentions`)
- capabilities resolve to extensions through a factory registry
- the UI derives itself from the loaded extensions via
`hasEditorExtension` — no capability list is prop-drilled into a menu,
because the `Editor` already knows what it can do
The acceptance test was collapsing the AI chat fork into an `aiChat`
preset with no visible change to that composer. `campaignBody` is the
only preset opting into the shared `EMAIL_DOCUMENT_CAPABILITIES` today.
Workflow email keeps its current field UI, but can opt into the same
canvas, block settings and image uploader later without adding another
schema or renderer.
#### 2. Schema / renderer split
The hard constraint: **our HTML is produced server-side, per recipient,
at send time**, because variables substitute into nodes rather than into
a serialized string. That rules out Resend's
`renderToReactEmail`-on-the-extension pattern.
```
twenty-front TipTap extensions + node views + shared email settings UI
twenty-shared versioned email-document schema + structural traversal
twenty-emails react-email renderers (imported by twenty-server)
twenty-server surface-specific variable resolution, validation, send
```
Logic was **vendored, not depended on** — Resend's TipTap is 3.17
against our 3.4, and their UI is Radix. We copied the schema/serializer
approach and rebuilt every control on `twenty-ui` + Linaria.
#### 3. Section typography cascade
The subtle part, and the one that would have silently shipped broken.
Section typography *looks* like it should cascade via CSS. It does not:
```js
// react-email's Text
style: { fontSize: "14px", lineHeight: "24px", ...style, ...margins }
```
Every paragraph re-declares `fontSize` and `lineHeight`, overriding any
enclosing section. `inherit` is not a fix either — Outlook's Word engine
ignores it.
So the cascade is **resolved in the renderer**: the tree walk threads
the enclosing section's typography down and writes computed values
explicitly onto each text node. Nested sections refine what they
inherit.
Verified against real rendered output:
| | rendered |
|---|---|
| paragraph inside section | `font-size:22px; color:rgb(255,0,0);
letter-spacing:2px` |
| h1 inside section | `font-size:32px` (own scale) + section colour and
spacing |
| paragraph outside | `font-size:14px`, no colour — untouched |
#### 4. Storage
`bodyTemplate` stays serialized TipTap JSON in a `TEXT` column. Block
attributes are ProseMirror node attrs, so richer blocks add keys to JSON
already being serialized — no migration, and it flows into the existing
500 ms debounced draft save unchanged.
Since the feature has not shipped, the legacy HTML-string body path was
removed rather than maintained. That is a tightening, not just a
deletion: `bodyTemplate` is writable through the record API, and the old
fallback would interpolate an arbitrary string and email it as markup. A
body that is neither empty nor a valid TipTap document is now rejected
at the send gate.
#### 5. Image hosting
Inline assets use an `EmailImage` file folder with
`ignoreExpirationToken: true` and immutable cache headers, because
recipients' mail clients never authenticate and may open an email years
later. The shared uploader returns `{ fileId, url }`; the image node
keeps both the durable file identity and its delivery URL so
ownership/lifecycle or URL resolution can evolve later without a
document migration. The server verifies the uploaded bytes and only
accepts GIF, JPEG, PNG and WebP.
This is intentionally separate from workflow/email **attachments**.
Attachments remain private files that the server reads and embeds as
MIME parts at send time; inline images need a durable recipient-facing
URL. A future workflow canvas should reuse `useUploadEmailImage` for
inline content while keeping its existing attachment control unchanged.
Adding the folder requires three registrations — the folder config, the
route guard's `SUPPORTED_FILE_FOLDERS`, and `DIRECT_UPLOAD_FILE_FOLDERS`
in the upload service.
### Bugs fixed along the way
- **Unsubscribe footer was appended after `</html>`**, outside the
document, where Gmail strips it. Legally significant, since an
unsubscribe link is required. Now inserted before `</body>`.
- **Body text colour never reached the email.**
- **`onImageUpload` was declared but never passed** by any production
call site, so drag-drop and paste image upload were inert everywhere
outside Storybook.
- **Message lists were not user-facing**, so members could not be added
from the list page.
- **Image resize wrote an undeclared `width` attribute** that TipTap
silently dropped.
- **The text bubble menu appeared over selected atom blocks** with
nothing to format.
### Review notes / known limitations
**Security posture to check.** Anything in `EmailImage` is readable by
anyone holding the URL, forever. The server now enforces an image-only
MIME allowlist from sniffed bytes, but it cannot determine whether the
image itself is confidential. This remains a deliberate trade-off for
recipient-visible inline assets.
**Test gap.** The section typography cascade has no regression test:
react-email's `render()` hangs under Jest (tried 60s), and
`twenty-emails` has no test target at all. Verified by rendering through
the built package instead. Adding a test target there is worthwhile
follow-up.
**Sending needs configuration.** `EMAILING_DOMAIN_DRIVER` defaults to
`LOG`, which fakes a messageId, reports any domain as verified, and only
logs — a campaign reaches "sent" with nothing delivered. Real sending
needs `AWS_SES`.
**Unrelated platform bug found.** The pinned "Create new record" command
throws on viewless objects like `messageListMember`, because
`recordIndexId` derives from the current view.
**Not done.** Panel chrome from the reference: breadcrumb (`Page style /
Section`), collapsible groups, per-side spacing grid, and a
variable-insert button inside link fields. All presentation over the
same data.
**Deferred.** Drag-to-reorder blocks.
`@tiptap/extension-drag-handle-react@3.4.2` matches our pinned versions
exactly, so no upgrade is needed, but its behaviour around atom node
views (HTML block, image) is unverified and belongs in its own change.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23657?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: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
1095 lines
46 KiB
TypeScript
1095 lines
46 KiB
TypeScript
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
|
|
|
|
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';
|
|
|
|
export const STANDARD_COMMAND_MENU_ITEMS = {
|
|
navigateToNextRecord: {
|
|
universalIdentifier: '3db2457d-8e96-4b8e-94c9-ed95d3f95738',
|
|
label: 'Navigate to next ${capitalize(objectMetadataItem.labelSingular)}',
|
|
icon: 'IconChevronDown',
|
|
isPinned: true,
|
|
position: 1,
|
|
shortLabel: null,
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and not isInSidePanel and objectMetadataItem.nameSingular != "messageCampaign"',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATE_TO_NEXT_RECORD,
|
|
hotKeys: null,
|
|
},
|
|
navigateToPreviousRecord: {
|
|
universalIdentifier: 'ec10f871-415b-420b-8150-7e09f6f04833',
|
|
label:
|
|
'Navigate to previous ${capitalize(objectMetadataItem.labelSingular)}',
|
|
icon: 'IconChevronUp',
|
|
isPinned: true,
|
|
position: 2,
|
|
shortLabel: null,
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and not isInSidePanel and objectMetadataItem.nameSingular != "messageCampaign"',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATE_TO_PREVIOUS_RECORD,
|
|
hotKeys: null,
|
|
},
|
|
createNewRecord: {
|
|
universalIdentifier: '08d255bf-58cd-47a5-bd82-78c5c58592f1',
|
|
label: 'Create new ${capitalize(objectMetadataItem.labelSingular)}',
|
|
icon: 'IconPlus',
|
|
isPinned: true,
|
|
position: 3,
|
|
shortLabel: 'New ${capitalize(objectMetadataItem.labelSingular)}',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and objectPermissions.canUpdateObjectRecords and not hasAnySoftDeleteFilterOnView and objectMetadataItem.isUICreatable and objectMetadataItem.isUIEditable and not objectMetadataItem.isRemote',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.CREATE_NEW_RECORD,
|
|
hotKeys: null,
|
|
},
|
|
deleteRecords: {
|
|
universalIdentifier: 'd5a55d57-ed1d-4791-89b8-53b7e121d69d',
|
|
label: 'Delete ${capitalize(objectMetadataLabel)}',
|
|
icon: 'IconTrash',
|
|
isPinned: false,
|
|
position: 4,
|
|
shortLabel: 'Delete',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and not hasAnySoftDeleteFilterOnView and objectPermissions.canSoftDeleteObjectRecords and (isSelectAll or noneDefined(selectedRecords, "deletedAt"))',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DELETE_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
restoreRecords: {
|
|
universalIdentifier: '2d733846-8cc5-4314-ab79-916ae0801baa',
|
|
label: 'Restore ${capitalize(objectMetadataLabel)}',
|
|
icon: 'IconRefresh',
|
|
isPinned: true,
|
|
position: 5,
|
|
shortLabel: 'Restore',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and (isSelectAll or everyDefined(selectedRecords, "deletedAt")) and objectPermissions.canSoftDeleteObjectRecords and (pageType == "RECORD_PAGE" or hasAnySoftDeleteFilterOnView)',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.RESTORE_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
destroyRecords: {
|
|
universalIdentifier: '0ea2ebc4-02ca-4d15-b424-5352b9e487df',
|
|
label: 'Permanently destroy ${capitalize(objectMetadataLabel)}',
|
|
icon: 'IconTrashX',
|
|
isPinned: false,
|
|
position: 6,
|
|
shortLabel: 'Destroy',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and objectPermissions.canDestroyObjectRecords and (isSelectAll or everyDefined(selectedRecords, "deletedAt")) and (pageType == "RECORD_PAGE" or hasAnySoftDeleteFilterOnView)',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DESTROY_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
addToFavorites: {
|
|
universalIdentifier: '38bf80c3-bd55-4753-80ba-38aa66429a03',
|
|
label: 'Add to Favorites',
|
|
icon: 'IconHeart',
|
|
isPinned: true,
|
|
position: 7,
|
|
shortLabel: null,
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'arrayLength(favoriteRecordIds) < numberOfSelectedRecords and noneDefined(selectedRecords, "deletedAt") and not hasAnySoftDeleteFilterOnView and objectMetadataItem.nameSingular != "messageCampaign"',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.ADD_TO_FAVORITES,
|
|
hotKeys: null,
|
|
},
|
|
removeFromFavorites: {
|
|
universalIdentifier: '3ea42507-44fa-4895-a36d-cbfef7355a50',
|
|
label: 'Remove from Favorites',
|
|
icon: 'IconHeartOff',
|
|
isPinned: true,
|
|
position: 8,
|
|
shortLabel: null,
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'arrayLength(favoriteRecordIds) == numberOfSelectedRecords and noneDefined(selectedRecords, "deletedAt") and not hasAnySoftDeleteFilterOnView and objectMetadataItem.nameSingular != "messageCampaign"',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.REMOVE_FROM_FAVORITES,
|
|
hotKeys: null,
|
|
},
|
|
exportNoteToPdf: {
|
|
universalIdentifier: '86c8f3aa-9276-4c16-8cff-e295e34fbaf0',
|
|
label: 'Export to PDF',
|
|
icon: 'IconFileExport',
|
|
isPinned: false,
|
|
position: 9,
|
|
shortLabel: 'Export',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and (objectMetadataItem.nameSingular == "note" or objectMetadataItem.nameSingular == "task") and someNonEmptyString(selectedRecords, "bodyV2.blocknote")',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EXPORT_NOTE_TO_PDF,
|
|
hotKeys: null,
|
|
},
|
|
exportRecords: {
|
|
universalIdentifier: 'c6f5c54d-d52b-4e75-8188-2190d77126f2',
|
|
label: 'Export ${capitalize(objectMetadataLabel)}',
|
|
icon: 'IconFileExport',
|
|
isPinned: false,
|
|
position: 10,
|
|
shortLabel: 'Export',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression: 'permissionFlags.EXPORT_CSV',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EXPORT_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
updateMultipleRecords: {
|
|
universalIdentifier: '2e080651-f098-4a78-bea9-7a70002dc57c',
|
|
label: 'Update ${capitalize(objectMetadataItem.labelPlural)}',
|
|
icon: 'IconEdit',
|
|
isPinned: true,
|
|
position: 11,
|
|
shortLabel: 'Update',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 2 and objectPermissions.canUpdateObjectRecords',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.UPDATE_MULTIPLE_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
mergeMultipleRecords: {
|
|
universalIdentifier: '6c14eb04-8e7e-4d47-93c0-8ec4834e2e60',
|
|
label: 'Merge ${capitalize(objectMetadataItem.labelPlural)}',
|
|
icon: 'IconArrowMerge',
|
|
isPinned: false,
|
|
position: 12,
|
|
shortLabel: 'Merge',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'not isSelectAll and numberOfSelectedRecords >= 2 and isDefined(objectMetadataItem.duplicateCriteria) and objectPermissions.canUpdateObjectRecords and objectPermissions.canDestroyObjectRecords and numberOfSelectedRecords <= 9',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.MERGE_MULTIPLE_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
importRecords: {
|
|
universalIdentifier: 'a2dc9de7-4798-422e-bb55-bfad7b9bdbe8',
|
|
label: 'Import ${capitalize(objectMetadataItem.labelPlural)}',
|
|
icon: 'IconFileImport',
|
|
isPinned: false,
|
|
position: 13,
|
|
shortLabel: 'Import',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and not hasAnySoftDeleteFilterOnView and permissionFlags.IMPORT_CSV',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.IMPORT_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
exportView: {
|
|
universalIdentifier: '80680f2a-c426-48b3-a839-c63a6183dc4b',
|
|
label: 'Export View',
|
|
icon: 'IconFileExport',
|
|
isPinned: false,
|
|
position: 14,
|
|
shortLabel: 'Export',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and permissionFlags.EXPORT_CSV',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EXPORT_VIEW,
|
|
hotKeys: null,
|
|
},
|
|
seeDeletedRecords: {
|
|
universalIdentifier: 'd63c21c3-9785-4750-be87-5f36269b8e0d',
|
|
label: 'See deleted ${capitalize(objectMetadataItem.labelPlural)}',
|
|
icon: 'IconRotate2',
|
|
isPinned: false,
|
|
position: 15,
|
|
shortLabel: 'Deleted ${capitalize(objectMetadataItem.labelPlural)}',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and not hasAnySoftDeleteFilterOnView',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_DELETED_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
createNewView: {
|
|
universalIdentifier: '6ec7c339-e167-431d-bec6-d1c737df677c',
|
|
label: 'Create View',
|
|
icon: 'IconLayout',
|
|
isPinned: false,
|
|
position: 16,
|
|
shortLabel: 'Create View',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and not hasAnySoftDeleteFilterOnView',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.CREATE_NEW_VIEW,
|
|
hotKeys: null,
|
|
},
|
|
hideDeletedRecords: {
|
|
universalIdentifier: '1420db7f-0fba-49e2-b23e-4b7caa0fafa0',
|
|
label: 'Hide deleted ${capitalize(objectMetadataItem.labelPlural)}',
|
|
icon: 'IconEyeOff',
|
|
isPinned: false,
|
|
position: 17,
|
|
shortLabel: 'Hide deleted',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and hasAnySoftDeleteFilterOnView',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.HIDE_DELETED_RECORDS,
|
|
hotKeys: null,
|
|
},
|
|
editRecordPageLayout: {
|
|
universalIdentifier: 'd9794c67-1799-424f-8871-5ea771dd4a6d',
|
|
label: 'Edit Layout',
|
|
icon: 'IconPencil',
|
|
isPinned: false,
|
|
position: 18,
|
|
shortLabel: 'Edit Layout',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and not isLayoutCustomizationModeEnabled and noneDefined(selectedRecords, "deletedAt") and objectPermissions.canUpdateObjectRecords and objectMetadataItem.nameSingular != "dashboard"',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EDIT_RECORD_PAGE_LAYOUT,
|
|
hotKeys: null,
|
|
},
|
|
editDashboardLayout: {
|
|
universalIdentifier: 'b9b53bbc-3129-4eb9-8344-c3f9628ffa7d',
|
|
label: 'Edit Dashboard',
|
|
icon: 'IconPencil',
|
|
isPinned: true,
|
|
position: 19,
|
|
shortLabel: 'Edit',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and not isDashboardPageLayoutInEditMode and not isLayoutCustomizationModeEnabled and noneDefined(selectedRecords, "deletedAt") and everyDefined(selectedRecords, "pageLayoutId") and objectPermissions.canUpdateObjectRecords',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.dashboard.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EDIT_DASHBOARD_LAYOUT,
|
|
hotKeys: null,
|
|
},
|
|
saveDashboardLayout: {
|
|
universalIdentifier: '18b23908-f816-42ab-bc0a-eb5fae29c695',
|
|
label: 'Save Dashboard',
|
|
icon: 'IconDeviceFloppy',
|
|
isPinned: true,
|
|
position: 20,
|
|
shortLabel: 'Save',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and isDashboardPageLayoutInEditMode and noneDefined(selectedRecords, "deletedAt") and everyDefined(selectedRecords, "pageLayoutId") and objectPermissions.canUpdateObjectRecords',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.dashboard.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SAVE_DASHBOARD_LAYOUT,
|
|
hotKeys: null,
|
|
},
|
|
cancelDashboardLayout: {
|
|
universalIdentifier: '030ecd01-0aaf-4e6d-8400-105996548887',
|
|
label: 'Cancel Edition',
|
|
icon: 'IconCancel',
|
|
isPinned: true,
|
|
position: 21,
|
|
shortLabel: 'Cancel',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and isDashboardPageLayoutInEditMode and noneDefined(selectedRecords, "deletedAt") and everyDefined(selectedRecords, "pageLayoutId") and objectPermissions.canUpdateObjectRecords',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.dashboard.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.CANCEL_DASHBOARD_LAYOUT,
|
|
hotKeys: null,
|
|
},
|
|
duplicateDashboard: {
|
|
universalIdentifier: '2ee07307-60ce-41ef-bfee-7c718f67557e',
|
|
label: 'Duplicate Dashboard',
|
|
icon: 'IconCopyPlus',
|
|
isPinned: false,
|
|
position: 22,
|
|
shortLabel: 'Duplicate',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'noneDefined(selectedRecords, "deletedAt") and objectPermissions.canUpdateObjectRecords',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.dashboard.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DUPLICATE_DASHBOARD,
|
|
hotKeys: null,
|
|
},
|
|
activateWorkflow: {
|
|
universalIdentifier: '44f19c85-0fd0-482f-a14e-da513c60b1b3',
|
|
label: 'Activate Workflow',
|
|
icon: 'IconPower',
|
|
isPinned: true,
|
|
position: 23,
|
|
shortLabel: 'Activate',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "currentVersion.trigger") and everyDefined(selectedRecords, "currentVersion.steps") and every(selectedRecords, "currentVersion.steps.length") and (everyEquals(selectedRecords, "currentVersion.status", "DRAFT") or includesNone(selectedRecords, "statuses", "ACTIVE")) and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.ACTIVATE_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
deactivateWorkflow: {
|
|
universalIdentifier: '57f21a06-a17a-47b1-a123-90d90dbdf0b7',
|
|
label: 'Deactivate Workflow',
|
|
icon: 'IconPlayerPause',
|
|
isPinned: true,
|
|
position: 24,
|
|
shortLabel: 'Deactivate',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyEquals(selectedRecords, "currentVersion.status", "ACTIVE") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DEACTIVATE_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
discardDraftWorkflow: {
|
|
universalIdentifier: '4c227f2e-03bb-4a66-9b13-49f263264f4a',
|
|
label: 'Discard Draft',
|
|
icon: 'IconNoteOff',
|
|
isPinned: true,
|
|
position: 25,
|
|
shortLabel: 'Discard Draft',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'every(selectedRecords, "lastPublishedVersionId") and everyEquals(selectedRecords, "currentVersion.status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DISCARD_DRAFT_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
testWorkflow: {
|
|
universalIdentifier: 'f85d552a-87a3-4667-99f7-71b47917539c',
|
|
label: 'Test Workflow',
|
|
icon: 'IconPlayerPlay',
|
|
isPinned: true,
|
|
position: 26,
|
|
shortLabel: 'Test',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "currentVersion.trigger") and everyDefined(selectedRecords, "currentVersion.steps") and every(selectedRecords, "currentVersion.steps.length") and ((everyEquals(selectedRecords, "currentVersion.trigger.type", "MANUAL") and noneDefined(selectedRecords, "currentVersion.trigger.settings.objectType")) or everyEquals(selectedRecords, "currentVersion.trigger.type", "WEBHOOK") or everyEquals(selectedRecords, "currentVersion.trigger.type", "CRON")) and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.TEST_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
seeActiveVersionWorkflow: {
|
|
universalIdentifier: '31790508-75ff-4e4c-a768-83bd1b0718e0',
|
|
label: 'See Active Version',
|
|
icon: 'IconVersions',
|
|
isPinned: false,
|
|
position: 27,
|
|
shortLabel: 'See Active Version',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'includesEvery(selectedRecords, "statuses", "ACTIVE") and includesEvery(selectedRecords, "statuses", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_ACTIVE_VERSION_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
seeRunsWorkflow: {
|
|
universalIdentifier: 'e57efc2d-00a2-493a-b76c-f2dabd23a5eb',
|
|
label: 'See Runs',
|
|
icon: 'IconHistoryToggle',
|
|
isPinned: true,
|
|
position: 28,
|
|
shortLabel: 'See Runs',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_RUNS_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
seeVersionsWorkflow: {
|
|
universalIdentifier: '92781d24-b875-4282-8cdb-d127f04a5c7d',
|
|
label: 'See Versions History',
|
|
icon: 'IconVersions',
|
|
isPinned: false,
|
|
position: 29,
|
|
shortLabel: 'See Versions',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_VERSIONS_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
addNodeWorkflow: {
|
|
universalIdentifier: '818117fa-6cad-4ebc-83c1-40f4afc28d94',
|
|
label: 'Add a Node',
|
|
icon: 'IconPlus',
|
|
isPinned: true,
|
|
position: 30,
|
|
shortLabel: 'Add a Node',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and everyDefined(selectedRecords, "currentVersion.trigger") and everyDefined(selectedRecords, "currentVersion.steps") and every(selectedRecords, "currentVersion.steps.length") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.ADD_NODE_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
tidyUpWorkflow: {
|
|
universalIdentifier: '1f3a3cab-161a-4775-af47-11be4d0bf411',
|
|
label: 'Tidy up Workflow',
|
|
icon: 'IconReorder',
|
|
isPinned: false,
|
|
position: 31,
|
|
shortLabel: 'Tidy up',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and everyDefined(selectedRecords, "currentVersion.trigger") and everyDefined(selectedRecords, "currentVersion.steps") and every(selectedRecords, "currentVersion.steps.length") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.TIDY_UP_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
duplicateWorkflow: {
|
|
universalIdentifier: '91094438-b4c2-46ad-a23b-8af4b23ba514',
|
|
label: 'Duplicate Workflow',
|
|
icon: 'IconCopy',
|
|
isPinned: false,
|
|
position: 32,
|
|
shortLabel: 'Duplicate',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "currentVersion") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflow.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.DUPLICATE_WORKFLOW,
|
|
hotKeys: null,
|
|
},
|
|
seeVersionWorkflowRun: {
|
|
universalIdentifier: 'cc3a065c-c89e-40ac-9449-4272c55b1bb8',
|
|
label: 'See Version',
|
|
icon: 'IconVersions',
|
|
isPinned: true,
|
|
position: 33,
|
|
shortLabel: 'See Version',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowRun.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_VERSION_WORKFLOW_RUN,
|
|
hotKeys: null,
|
|
},
|
|
seeWorkflowWorkflowRun: {
|
|
universalIdentifier: '9d9cc62d-3543-45c3-93f3-23d2d8979f2b',
|
|
label: 'See Workflow',
|
|
icon: 'IconSettingsAutomation',
|
|
isPinned: true,
|
|
position: 34,
|
|
shortLabel: 'See Workflow',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowRun.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_WORKFLOW_WORKFLOW_RUN,
|
|
hotKeys: null,
|
|
},
|
|
stopWorkflowRun: {
|
|
universalIdentifier: '4c186606-9515-4561-a1eb-9a072b4f5e58',
|
|
label: 'Stop',
|
|
icon: 'IconPlayerStop',
|
|
isPinned: true,
|
|
position: 35,
|
|
shortLabel: 'Stop',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'isSelectAll or someEquals(selectedRecords, "status", "NOT_STARTED") or someEquals(selectedRecords, "status", "ENQUEUED") or someEquals(selectedRecords, "status", "RUNNING")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowRun.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.STOP_WORKFLOW_RUN,
|
|
hotKeys: null,
|
|
},
|
|
retryWorkflowRun: {
|
|
universalIdentifier: '99b97c50-b31b-411a-a532-ec05402123c0',
|
|
label: 'Retry',
|
|
icon: 'IconRefresh',
|
|
isPinned: true,
|
|
position: 36,
|
|
shortLabel: 'Retry',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'someEquals(selectedRecords, "status", "FAILED")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowRun.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.RETRY_WORKFLOW_RUN,
|
|
hotKeys: null,
|
|
},
|
|
seeRunsWorkflowVersion: {
|
|
universalIdentifier: '44e305c7-4f0a-45ec-803f-6471b56455cb',
|
|
label: 'See Runs',
|
|
icon: 'IconHistoryToggle',
|
|
isPinned: true,
|
|
position: 37,
|
|
shortLabel: 'See Runs',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "workflow")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowVersion.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_RUNS_WORKFLOW_VERSION,
|
|
hotKeys: null,
|
|
},
|
|
seeWorkflowWorkflowVersion: {
|
|
universalIdentifier: 'b43052db-023e-4083-9b63-2c2dfbfd1320',
|
|
label: 'See Workflow',
|
|
icon: 'IconSettingsAutomation',
|
|
isPinned: true,
|
|
position: 38,
|
|
shortLabel: 'See Workflow',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "workflow.id")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowVersion.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_WORKFLOW_WORKFLOW_VERSION,
|
|
hotKeys: null,
|
|
},
|
|
useAsDraftWorkflowVersion: {
|
|
universalIdentifier: '483c0c1d-ea4d-4a4d-8a59-2dcf9f8e38f6',
|
|
label: 'Use as Draft',
|
|
icon: 'IconPencil',
|
|
isPinned: true,
|
|
position: 39,
|
|
shortLabel: 'Use as Draft',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'noneEquals(selectedRecords, "status", "DRAFT")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowVersion.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.USE_AS_DRAFT_WORKFLOW_VERSION,
|
|
hotKeys: null,
|
|
},
|
|
seeVersionsWorkflowVersion: {
|
|
universalIdentifier: '1d4abeb7-2750-4af7-9a92-fbadd2a9e4ba',
|
|
label: 'See Versions History',
|
|
icon: 'IconVersions',
|
|
isPinned: false,
|
|
position: 40,
|
|
shortLabel: 'See Versions',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'everyDefined(selectedRecords, "workflow")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.workflowVersion.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEE_VERSIONS_WORKFLOW_VERSION,
|
|
hotKeys: null,
|
|
},
|
|
searchRecords: {
|
|
universalIdentifier: 'fa24e25e-68f8-4548-82ff-c7b5168b7c7d',
|
|
label: 'Search',
|
|
icon: 'IconSearch',
|
|
isPinned: false,
|
|
position: 41,
|
|
shortLabel: 'Search',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEARCH_RECORDS,
|
|
hotKeys: ['/'],
|
|
},
|
|
searchRecordsFallback: {
|
|
universalIdentifier: 'c659890c-7266-46c9-bfe1-75cefff8b6d0',
|
|
label: 'Search',
|
|
icon: 'IconSearch',
|
|
isPinned: false,
|
|
position: 42,
|
|
shortLabel: 'Search',
|
|
availabilityType: CommandMenuItemAvailabilityType.FALLBACK,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEARCH_RECORDS_FALLBACK,
|
|
hotKeys: ['/'],
|
|
},
|
|
askAi: {
|
|
universalIdentifier: 'ce5fb54d-2b19-4dd1-b7b4-9532a1761a41',
|
|
label: 'Ask AI',
|
|
icon: 'IconSparkles',
|
|
isPinned: false,
|
|
position: 43,
|
|
shortLabel: 'Ask AI',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.AI',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.ASK_AI,
|
|
hotKeys: ['@'],
|
|
},
|
|
viewPreviousAiChats: {
|
|
universalIdentifier: '3084c3c9-cc23-4dad-9e00-92025f5cba7a',
|
|
label: 'View Previous AI Chats',
|
|
icon: 'IconHistory',
|
|
isPinned: false,
|
|
position: 44,
|
|
shortLabel: 'Previous AI Chats',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.AI',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.VIEW_PREVIOUS_AI_CHATS,
|
|
hotKeys: null,
|
|
},
|
|
replyToEmailThread: {
|
|
universalIdentifier: '8f015cbd-c764-434e-a6c6-bb7581b4be44',
|
|
label: 'Reply',
|
|
icon: 'IconArrowBackUp',
|
|
isPinned: true,
|
|
position: 45,
|
|
shortLabel: 'Reply',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression: 'numberOfSelectedRecords == 1',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.messageThread.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.REPLY_TO_EMAIL_THREAD,
|
|
hotKeys: null,
|
|
},
|
|
composeEmail: {
|
|
universalIdentifier: '96457c5a-b028-4d48-94e3-27f4c41296b8',
|
|
label: 'Compose Email',
|
|
icon: 'IconMail',
|
|
isPinned: false,
|
|
position: 46,
|
|
shortLabel: 'Compose',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.SEND_EMAIL_TOOL',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_EMAIL,
|
|
hotKeys: null,
|
|
},
|
|
composeCampaign: {
|
|
universalIdentifier: '30473656-e7cb-42e0-b198-6c4e8b906106',
|
|
label: 'Compose Campaign',
|
|
icon: 'IconSend',
|
|
isPinned: false,
|
|
position: 66,
|
|
shortLabel: 'Campaign',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'featureFlags.IS_EMAIL_GROUP_ENABLED',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_CAMPAIGN,
|
|
hotKeys: null,
|
|
},
|
|
composeCampaignPinned: {
|
|
universalIdentifier: '7ad6f0c7-ac02-4062-b5cf-1f36e1664bc8',
|
|
label: 'Create new Campaign',
|
|
icon: 'IconPlus',
|
|
isPinned: true,
|
|
position: 67,
|
|
shortLabel: 'New Campaign',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL_OBJECT_CONTEXT,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "INDEX_PAGE" and featureFlags.IS_EMAIL_GROUP_ENABLED',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.messageCampaign.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_CAMPAIGN,
|
|
hotKeys: null,
|
|
},
|
|
sendMessageCampaign: {
|
|
universalIdentifier: 'b08f4ccd-070b-460f-a4b6-6d0c14f1c44d',
|
|
label: 'Send Campaign',
|
|
icon: 'IconSend',
|
|
isPinned: true,
|
|
position: 68,
|
|
shortLabel: 'Send',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and everyEquals(selectedRecords, "status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.messageCampaign.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEND_MESSAGE_CAMPAIGN,
|
|
hotKeys: null,
|
|
},
|
|
sendMessageCampaignTest: {
|
|
universalIdentifier: 'a6e6fd08-2c75-4d43-8795-1baafbac165e',
|
|
label: 'Send Test Email',
|
|
icon: 'IconMail',
|
|
isPinned: true,
|
|
position: 69,
|
|
shortLabel: 'Test',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and everyEquals(selectedRecords, "status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.messageCampaign.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.SEND_MESSAGE_CAMPAIGN_TEST,
|
|
hotKeys: null,
|
|
},
|
|
emailBlockSettings: {
|
|
universalIdentifier: '5c8a2f41-97be-4f3d-9a46-2f18d17f30a2',
|
|
label: 'Block Settings',
|
|
icon: 'IconAdjustments',
|
|
isPinned: true,
|
|
position: 70,
|
|
shortLabel: 'Design',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'pageType == "RECORD_PAGE" and numberOfSelectedRecords == 1 and everyEquals(selectedRecords, "status", "DRAFT") and noneDefined(selectedRecords, "deletedAt")',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.messageCampaign.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.EMAIL_BLOCK_SETTINGS,
|
|
hotKeys: null,
|
|
},
|
|
goToSettings: {
|
|
universalIdentifier: 'ef9aba44-0068-453e-930a-f8c182af18ee',
|
|
label: 'Go to Settings',
|
|
icon: 'IconSettings',
|
|
isPinned: false,
|
|
position: 47,
|
|
shortLabel: 'Settings',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: ['G', 'S'],
|
|
payload: { path: '/settings/profile' },
|
|
},
|
|
goToSettingsExperience: {
|
|
universalIdentifier: 'bceb0328-c018-48ba-80d8-a1a97dc0a8ba',
|
|
label: 'Go to Experience Settings',
|
|
icon: 'IconColorSwatch',
|
|
isPinned: false,
|
|
position: 48,
|
|
shortLabel: 'Experience',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/experience' },
|
|
},
|
|
goToSettingsAccounts: {
|
|
universalIdentifier: '447a65cc-8535-408e-9c48-db24affb7530',
|
|
label: 'Go to Accounts Settings',
|
|
icon: 'IconAt',
|
|
isPinned: false,
|
|
position: 49,
|
|
shortLabel: 'Accounts',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/accounts' },
|
|
},
|
|
goToSettingsAccountsEmails: {
|
|
universalIdentifier: '4feab22c-165f-4d13-81ca-c9eb6082ca50',
|
|
label: 'Go to Emails Settings',
|
|
icon: 'IconMail',
|
|
isPinned: false,
|
|
position: 50,
|
|
shortLabel: 'Emails',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/accounts/emails' },
|
|
},
|
|
goToSettingsAccountsCalendars: {
|
|
universalIdentifier: '3267ec0e-9dee-4d9b-8f1b-6005bfd90202',
|
|
label: 'Go to Calendars Settings',
|
|
icon: 'IconCalendarEvent',
|
|
isPinned: false,
|
|
position: 51,
|
|
shortLabel: 'Calendars',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/accounts/calendars' },
|
|
},
|
|
goToSettingsGeneral: {
|
|
universalIdentifier: 'ad68e516-96ea-455a-a838-c59788e88c23',
|
|
label: 'Go to General Settings',
|
|
icon: 'IconSettings',
|
|
isPinned: false,
|
|
position: 52,
|
|
shortLabel: 'General',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/general' },
|
|
},
|
|
goToSettingsObjects: {
|
|
universalIdentifier: '9302bfeb-f6cd-4858-ab5b-5f70f4d358c4',
|
|
label: 'Go to Data Model Settings',
|
|
icon: 'IconHierarchy2',
|
|
isPinned: false,
|
|
position: 53,
|
|
shortLabel: 'Data Model',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.DATA_MODEL',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/objects' },
|
|
},
|
|
goToSettingsMembers: {
|
|
universalIdentifier: 'fb4d9f1b-5b13-49d9-8353-80041719d411',
|
|
label: 'Go to Members Settings',
|
|
icon: 'IconUsers',
|
|
isPinned: false,
|
|
position: 54,
|
|
shortLabel: 'Members',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE_MEMBERS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/members' },
|
|
},
|
|
goToSettingsRoles: {
|
|
universalIdentifier: '4050f307-c592-4c9f-ad91-89cde330fbf7',
|
|
label: 'Go to Roles Settings',
|
|
icon: 'IconLock',
|
|
isPinned: false,
|
|
position: 55,
|
|
shortLabel: 'Roles',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE_MEMBERS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/members#roles' },
|
|
},
|
|
goToSettingsDomains: {
|
|
universalIdentifier: '2d071684-fb5e-4222-b560-4c7ab2597fb4',
|
|
label: 'Go to Domains Settings',
|
|
icon: 'IconWorld',
|
|
isPinned: false,
|
|
position: 56,
|
|
shortLabel: 'Domains',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/domains' },
|
|
},
|
|
goToSettingsBilling: {
|
|
universalIdentifier: 'f46a0fb9-14e9-4d48-801d-c33bdd543f74',
|
|
label: 'Go to Billing Settings',
|
|
icon: 'IconCurrencyDollar',
|
|
isPinned: false,
|
|
position: 57,
|
|
shortLabel: 'Billing',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/billing' },
|
|
},
|
|
goToSettingsApiWebhooks: {
|
|
universalIdentifier: 'ed2c2fde-1e7a-4a42-ba63-221eaa7c9759',
|
|
label: 'Go to MCP & APIs Settings',
|
|
icon: 'IconPlug',
|
|
isPinned: false,
|
|
position: 58,
|
|
shortLabel: 'MCP & APIs',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.API_KEYS_AND_WEBHOOKS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/api-webhooks' },
|
|
},
|
|
goToSettingsApplications: {
|
|
universalIdentifier: '44db6d7a-79ac-485e-b3da-da8776bd7777',
|
|
label: 'Go to Apps Settings',
|
|
icon: 'IconApps',
|
|
isPinned: false,
|
|
position: 59,
|
|
shortLabel: 'Apps',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.APPLICATIONS',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/applications' },
|
|
},
|
|
goToSettingsAI: {
|
|
universalIdentifier: '3eaec228-809d-452d-b5ef-7b777398c538',
|
|
label: 'Go to AI Settings',
|
|
icon: 'IconSparkles',
|
|
isPinned: false,
|
|
position: 60,
|
|
shortLabel: 'AI',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/ai' },
|
|
},
|
|
goToSettingsSecurity: {
|
|
universalIdentifier: '358e69b2-0789-44e2-add7-bdef68413be8',
|
|
label: 'Go to Security Settings',
|
|
icon: 'IconKey',
|
|
isPinned: false,
|
|
position: 61,
|
|
shortLabel: 'Security',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: 'permissionFlags.SECURITY',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/security' },
|
|
},
|
|
goToSettingsAdminPanel: {
|
|
universalIdentifier: 'dd22798b-fca6-42af-ba3b-0d48f263afbd',
|
|
label: 'Go to Admin Panel Settings',
|
|
icon: 'IconServer',
|
|
isPinned: false,
|
|
position: 62,
|
|
shortLabel: 'Admin Panel',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression:
|
|
'canImpersonate or canAccessFullAdminPanel',
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/admin-panel' },
|
|
},
|
|
goToSettingsUpdates: {
|
|
universalIdentifier: '5d1ba354-0090-4a42-9a43-601461b26068',
|
|
label: 'Go to Community Settings',
|
|
icon: 'IconUsers',
|
|
isPinned: false,
|
|
position: 63,
|
|
shortLabel: 'Community',
|
|
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
|
conditionalAvailabilityExpression: null,
|
|
availabilityObjectMetadataUniversalIdentifier: null,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.NAVIGATION,
|
|
hotKeys: null,
|
|
payload: { path: '/settings/community' },
|
|
},
|
|
composeEmailToPerson: {
|
|
universalIdentifier: 'f01d4b8b-2b4e-4ae0-9c6f-0b9a9a3e5b21',
|
|
label: 'Send Email',
|
|
icon: 'IconMail',
|
|
isPinned: true,
|
|
position: 64,
|
|
shortLabel: 'Send Email',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords >= 1 and permissionFlags.SEND_EMAIL_TOOL',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.person.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_EMAIL,
|
|
hotKeys: null,
|
|
},
|
|
composeEmailToCompany: {
|
|
universalIdentifier: 'a76d3ab8-4c3a-4e5d-8a4a-1f5d6e7f8a90',
|
|
label: 'Send Email',
|
|
icon: 'IconMail',
|
|
isPinned: true,
|
|
position: 65,
|
|
shortLabel: 'Send Email',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords == 1 and permissionFlags.SEND_EMAIL_TOOL',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.company.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_EMAIL,
|
|
hotKeys: null,
|
|
},
|
|
composeEmailToOpportunity: {
|
|
universalIdentifier: 'b3e7c9f2-5d6e-4f7a-8b9c-0d1e2f3a4b5c',
|
|
label: 'Send Email',
|
|
icon: 'IconMail',
|
|
isPinned: true,
|
|
position: 66,
|
|
shortLabel: 'Send Email',
|
|
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
|
conditionalAvailabilityExpression:
|
|
'numberOfSelectedRecords == 1 and permissionFlags.SEND_EMAIL_TOOL',
|
|
availabilityObjectMetadataUniversalIdentifier:
|
|
STANDARD_OBJECTS.opportunity.universalIdentifier,
|
|
frontComponentUniversalIdentifier: null,
|
|
engineComponentKey: EngineComponentKey.COMPOSE_EMAIL,
|
|
hotKeys: null,
|
|
},
|
|
} as const;
|