diff --git a/src/Umbraco.Web.UI.Client/docs/authentication.md b/src/Umbraco.Web.UI.Client/docs/authentication.md index 2b24ac2369..e0376e9c24 100644 --- a/src/Umbraco.Web.UI.Client/docs/authentication.md +++ b/src/Umbraco.Web.UI.Client/docs/authentication.md @@ -34,7 +34,7 @@ There are two ways to use this: ```json "Umbraco": { "CMS": { - "NewBackOffice":{ + "Security":{ "BackOfficeHost": "http://localhost:5173", "AuthorizeCallbackPathName": "/" }, diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index ff9685358a..98d7e231d3 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -31,7 +31,6 @@ "./extension-registry": "./dist-cms/packages/core/extension-registry/index.js", "./id": "./dist-cms/packages/core/id/index.js", "./localization": "./dist-cms/packages/core/localization/index.js", - "./macro": "./dist-cms/packages/core/macro/index.js", "./menu": "./dist-cms/packages/core/menu/index.js", "./modal": "./dist-cms/packages/core/modal/index.js", "./notification": "./dist-cms/packages/core/notification/index.js", diff --git a/src/Umbraco.Web.UI.Client/public-assets/css/rte-content.css b/src/Umbraco.Web.UI.Client/public-assets/css/rte-content.css deleted file mode 100644 index 34ea2b3c77..0000000000 --- a/src/Umbraco.Web.UI.Client/public-assets/css/rte-content.css +++ /dev/null @@ -1,42 +0,0 @@ -.umb-macro-holder { - border: 3px dotted var(--uui-palette-spanish-pink-light); - padding: 7px; - display: block; - margin: 3px; -} - -.umb-macro-holder.loading { - background: url(assets/img/loader.gif) right no-repeat; - background-size: 18px; - background-position-x: 99%; -} - -.umb-embed-holder { - position: relative; -} - -.umb-embed-holder>* { - user-select: none; - pointer-events: none; -} - -.umb-embed-holder[data-mce-selected] { - outline: 2px solid var(--uui-palette-spanish-pink-light); -} - -.umb-embed-holder::before { - z-index: 1000; - width: 100%; - height: 100%; - position: absolute; - content: ' '; -} - -.umb-embed-holder[data-mce-selected]::before { - background: rgba(0, 0, 0, 0.025); -} - -*[data-mce-selected='inline-boundary'] { - background: rgba(0, 0, 0, 0.025); - outline: 2px solid var(--uui-palette-spanish-pink-light); -} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts index d3b00b4443..9a5db47c5d 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/da-dk.ts @@ -3217,7 +3217,7 @@ export default { minimalLevelDescription: 'We will only send an anonymized site ID to let us know that the site exists.', basicLevelDescription: 'We will send an anonymized site ID, Umbraco version, and packages installed', detailedLevelDescription: - '\n We will send:\n \n We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
\n ', + '\n We will send:\n \n We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
\n ', }, umbId: { editProfile: 'Edit your Umbraco ID profile', diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts index 6dce152d56..1c05c9a743 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/en-us.ts @@ -1522,7 +1522,7 @@ export default { addGroup: 'Add group', inheritedFrom: 'Inherited from', addProperty: 'Add property', - editProperty : 'Edit property', + editProperty: 'Edit property', requiredLabel: 'Required label', enableListViewHeading: 'Enable list view', enableListViewDescription: @@ -2470,7 +2470,7 @@ export default { minimalLevelDescription: 'We will only send an anonymized site ID to let us know that the site exists.', basicLevelDescription: 'We will send an anonymized site ID, Umbraco version, and packages installed', detailedLevelDescription: - '\n We will send:\n \n We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
\n ', + '\n We will send:\n \n We might change what we send on the Detailed level in the future. If so, it will be listed above.\n
By choosing "Detailed" you agree to current and future anonymized information being collected.
\n ', }, umbId: { editProfile: 'Edit your Umbraco ID profile', diff --git a/src/Umbraco.Web.UI.Client/src/css/rte-content.css b/src/Umbraco.Web.UI.Client/src/css/rte-content.css new file mode 100644 index 0000000000..2e6d1c23dc --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/css/rte-content.css @@ -0,0 +1,49 @@ +.umb-macro-holder { + border: 3px dotted red; + padding: 7px; + margin: 3px; + display: block; + position: relative; +} + +.umb-macro-holder::after { + content: 'Macros are no longer supported. Please use the block picker instead.'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + background-color: rgba(0, 0, 0, 0.7); + padding: 10px; + border-radius: 5px; +} + +.umb-embed-holder { + position: relative; +} + +.umb-embed-holder > * { + user-select: none; + pointer-events: none; +} + +.umb-embed-holder[data-mce-selected] { + outline: 2px solid var(--uui-palette-spanish-pink-light); +} + +.umb-embed-holder::before { + z-index: 1000; + width: 100%; + height: 100%; + position: absolute; + content: ' '; +} + +.umb-embed-holder[data-mce-selected]::before { + background: rgba(0, 0, 0, 0.025); +} + +*[data-mce-selected='inline-boundary'] { + background: rgba(0, 0, 0, 0.025); + outline: 2px solid var(--uui-palette-spanish-pink-light); +} diff --git a/src/Umbraco.Web.UI.Client/src/libs/extension-api/controller/extensions-element-initializer.controller.ts b/src/Umbraco.Web.UI.Client/src/libs/extension-api/controller/extensions-element-initializer.controller.ts index d12714c73b..a40f574a34 100644 --- a/src/Umbraco.Web.UI.Client/src/libs/extension-api/controller/extensions-element-initializer.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/libs/extension-api/controller/extensions-element-initializer.controller.ts @@ -27,7 +27,7 @@ export class UmbExtensionsElementInitializer< > { // #extensionRegistry; - private _defaultElement?: string; + #defaultElement?: string; #props?: Record; public get properties() { @@ -50,7 +50,7 @@ export class UmbExtensionsElementInitializer< ) { super(host, extensionRegistry, type, filter, onChange); this.#extensionRegistry = extensionRegistry; - this._defaultElement = defaultElement; + this.#defaultElement = defaultElement; this._init(); } @@ -60,7 +60,7 @@ export class UmbExtensionsElementInitializer< this.#extensionRegistry, manifest.alias, this._extensionChanged, - this._defaultElement, + this.#defaultElement, ) as ControllerType; extController.properties = this.#props; diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts index 0f338311b2..f98be9245d 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/data-type/data-type.data.ts @@ -510,6 +510,7 @@ export const data: Array = [ { label: 'Mocked Block Type for Block List', contentElementTypeKey: '4f68ba66-6fb2-4778-83b8-6ab4ca3a7c5c', + settingsElementTypeKey: 'all-property-editors-document-type-id', icon: 'icon-server-alt', }, { @@ -549,7 +550,7 @@ export const data: Array = [ }, { alias: 'useInlineEditingAsDefault', - value: true, + value: false, }, { alias: 'useLiveEditing', @@ -729,7 +730,7 @@ export const data: Array = [ '+a[id|style|rel|data-id|data-udi|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-s[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],-sub[style|class],-sup[style|class],-blockquote[dir|style|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*],figure,figcaption,video[*],audio[*],picture[*],source[*],canvas[*]', }, { alias: 'invalidElements', value: 'font' }, - // { alias: 'stylesheets', value: ['/css/rte-content.css'] }, + { alias: 'stylesheets', value: [] }, { alias: 'toolbar', value: [ @@ -751,7 +752,6 @@ export const data: Array = [ 'anchor', 'table', 'umbmediapicker', - 'umbmacro', 'umbembeddialog', ], }, diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.data.ts index 5ec0aed8fb..fade893c0e 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/document/document.data.ts @@ -34,8 +34,18 @@ export const data: Array = [ alias: 'richTextEditor', culture: null, segment: null, - value: - 'Some value for the RTE with an external link and an internal link foo foo
Macro alias: TestMacro
', + value: { + blocks: {}, + markup: ` +

+ Some value for the RTE with an external link and an internal link foo foo +

+
Macro alias: TestMacro
+

The following tests the embed plugin:

+
+

End of test content

+ `, + }, }, { alias: 'email', @@ -176,6 +186,7 @@ export const data: Array = [ 'Umbraco.BlockList': [ { contentUdi: '1234', + settingsUdi: '5678', }, ], }, @@ -186,7 +197,13 @@ export const data: Array = [ elementProperty: 'Hello world', }, ], - settingsData: [], + settingsData: [ + { + udi: '5678', + contentTypeKey: 'all-property-editors-document-type-id', + elementProperty: 'Hello world', + }, + ], }, }, { diff --git a/src/Umbraco.Web.UI.Client/src/mocks/data/health-check.data.ts b/src/Umbraco.Web.UI.Client/src/mocks/data/health-check.data.ts index 0362118bf6..bfb85fb276 100644 --- a/src/Umbraco.Web.UI.Client/src/mocks/data/health-check.data.ts +++ b/src/Umbraco.Web.UI.Client/src/mocks/data/health-check.data.ts @@ -17,26 +17,6 @@ export const healthGroups: Array
  • Anonymized site ID, umbraco version, and packages installed.
  • Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.
  • System information: Webserver, server OS, server framework, server OS language, and database provider.
  • Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.
  • We might change what we send on the Detailed level in the future. If so, it will be listed above.
    By choosing "Detailed" you agree to current and future anonymized information being collected.
    ', + 'We will send:
    • Anonymized site ID, umbraco version, and packages installed.
    • Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.
    • System information: Webserver, server OS, server framework, server OS language, and database provider.
    • Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.
    We might change what we send on the Detailed level in the future. If so, it will be listed above.
    By choosing "Detailed" you agree to current and future anonymized information being collected.
    ', }, ], }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-block/block-list-block.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-block/block-list-block.element.ts index 6af4a4da1f..897f888b4c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-block/block-list-block.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/block-list-block/block-list-block.element.ts @@ -28,6 +28,9 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl @state() _contentUdi?: string; + @state() + _hasSettings = false; + @state() _label = ''; @@ -37,6 +40,12 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl @state() _inlineEditingMode?: boolean; + // TODO: Move type for the Block Properties, and use it on the Element Interface for the Manifest. + @state() + _blockViewProps: { + label?: string; + } = {}; + constructor() { super(); @@ -46,7 +55,11 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl this.observe(this.#context.contentUdi, (contentUdi) => { this._contentUdi = contentUdi; }); + this.observe(this.#context.blockTypeSettingsElementTypeKey, (blockTypeSettingsElementTypeKey) => { + this._hasSettings = !!blockTypeSettingsElementTypeKey; + }); this.observe(this.#context.label, (label) => { + this._blockViewProps.label = label; this._label = label; }); this.observe(this.#context.inlineEditingMode, (inlineEditingMode) => { @@ -70,22 +83,32 @@ export class UmbPropertyEditorUIBlockListBlockElement extends UmbLitElement impl } #renderRefBlock() { - return html``; + return html``; } #renderInlineBlock() { - return html``; + return html``; } #renderBlock() { return html` - ${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()} + ${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()} ${this._workspaceEditPath ? html` ` : ''} + ${this._workspaceEditPath && this._hasSettings + ? html` + + ` + : ''} diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/inline-list-block/inline-list-block.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/inline-list-block/inline-list-block.element.ts index c25d52faef..e177087318 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/inline-list-block/inline-list-block.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/inline-list-block/inline-list-block.element.ts @@ -3,7 +3,7 @@ import type { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../../block/index.js'; import { UMB_BLOCK_WORKSPACE_ALIAS } from '../../../block/index.js'; import { UmbExtensionsApiInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; -import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import '../../../block/workspace/views/edit/block-workspace-view-edit-no-router.element.js'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; @@ -17,8 +17,8 @@ export class UmbInlineListBlockElement extends UmbLitElement { #workspaceContext?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE; #contentUdi?: string; - @state() - _label = ''; + @property({ type: String }) + label?: string; @state() _isOpen = false; @@ -36,9 +36,6 @@ export class UmbInlineListBlockElement extends UmbLitElement { }, 'observeContentUdi', ); - this.observe(blockContext.label, (label) => { - this._label = label; - }); }); this.observe(umbExtensionsRegistry.getByTypeAndAlias('workspace', UMB_BLOCK_WORKSPACE_ALIAS), (manifest) => { if (manifest) { @@ -73,7 +70,7 @@ export class UmbInlineListBlockElement extends UmbLitElement { }}> - ${this._label} + ${this.label} ${this._isOpen === true ? html`` @@ -82,6 +79,7 @@ export class UmbInlineListBlockElement extends UmbLitElement { } static styles = [ + UmbTextStyles, css` #accordion-button { display: flex; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/ref-list-block/ref-list-block.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/ref-list-block/ref-list-block.element.ts index 7dc6d20276..dce78e9855 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/ref-list-block/ref-list-block.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block-list/components/ref-list-block/ref-list-block.element.ts @@ -1,6 +1,5 @@ import { UMB_BLOCK_LIST_CONTEXT } from '../../context/block-list.context-token.js'; import { css, customElement, html, property, state } from '@umbraco-cms/backoffice/external/lit'; -import { UUIRefNodeElement } from '@umbraco-cms/backoffice/external/uui'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; /** @@ -10,7 +9,7 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; export class UmbRefListBlockElement extends UmbLitElement { // @property({ type: String }) - name?: string; + label?: string; @state() _workspaceEditPath?: string; @@ -31,13 +30,12 @@ export class UmbRefListBlockElement extends UmbLitElement { render() { // href=${this._workspaceEditPath ?? '#'} - return html``; + return html``; } static styles = [ - ...UUIRefNodeElement.styles, css` - :host { + uui-ref-node { min-height: var(--uui-size-16); } `, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/block-workspace-has-settings.condition.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/block-workspace-has-settings.condition.ts new file mode 100644 index 0000000000..434cc1b455 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/block-workspace-has-settings.condition.ts @@ -0,0 +1,41 @@ +import { UMB_BLOCK_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/block'; +import { UmbBaseController } from '@umbraco-cms/backoffice/class-api'; +import type { + ManifestCondition, + UmbConditionConfigBase, + UmbConditionControllerArguments, + UmbExtensionCondition, +} from '@umbraco-cms/backoffice/extension-api'; + +export class UmbBlockWorkspaceHasSettingsCondition extends UmbBaseController implements UmbExtensionCondition { + config: BlockWorkspaceHasSettingsConditionConfig; + permitted = false; + #onChange: () => void; + + constructor(args: UmbConditionControllerArguments) { + super(args.host); + this.config = args.config; + this.#onChange = args.onChange; + + this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (context) => { + this.observe( + context.settings.contentTypeId, + (settingsContentTypeId) => { + this.permitted = !!settingsContentTypeId; + this.#onChange(); + }, + 'observeSettingsElementTypeId', + ); + }); + } +} + +export type BlockWorkspaceHasSettingsConditionConfig = + UmbConditionConfigBase<'Umb.Condition.BlockWorkspaceHasSettings'>; + +export const manifest: ManifestCondition = { + type: 'condition', + name: 'Block Has Settings Condition', + alias: 'Umb.Condition.BlockWorkspaceHasSettings', + api: UmbBlockWorkspaceHasSettingsCondition, +}; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/index.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/index.ts new file mode 100644 index 0000000000..0c6d9fc984 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/conditions/index.ts @@ -0,0 +1 @@ +export * from './block-workspace-has-settings.condition.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entity.context.ts similarity index 98% rename from src/Umbraco.Web.UI.Client/src/packages/block/block/context/block.context.ts rename to src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entity.context.ts index 7df7769388..9f9d417e10 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/block-entity.context.ts @@ -60,7 +60,7 @@ export abstract class UmbBlockContext< } constructor(host: UmbControllerHost, blockManagerContextToken: BlockManagerContextTokenType) { - super(host, UMB_BLOCK_CONTEXT.toString()); + super(host, UMB_BLOCK_ENTITY_CONTEXT.toString()); // Consume block manager: this.consumeContext(blockManagerContextToken, (manager) => { @@ -198,6 +198,6 @@ export abstract class UmbBlockContext< } } -export const UMB_BLOCK_CONTEXT = new UmbContextToken< +export const UMB_BLOCK_ENTITY_CONTEXT = new UmbContextToken< UmbBlockContext >('UmbBlockContext'); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/index.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/index.ts index 69c858f894..689c247d82 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/context/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/context/index.ts @@ -1 +1 @@ -export * from './block.context.js'; +export * from './block-entity.context.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/index.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/index.ts index 258f163605..abccb4df2a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/index.ts @@ -1,5 +1,6 @@ +export * from './conditions/index.js'; export * from './context/index.js'; export * from './manager/index.js'; export * from './modals/index.js'; -export * from './workspace/index.js'; export * from './types.js'; +export * from './workspace/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts index 2d9f9c9fa4..0ab646f59a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/manager/block-manager.context.ts @@ -4,13 +4,8 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState, UmbClassState, UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import { UmbDocumentTypeDetailRepository } from '@umbraco-cms/backoffice/document-type'; import { buildUdi, getKeyFromUdi } from '@umbraco-cms/backoffice/utils'; -import type { - UmbBlockTypeBaseModel, - UmbBlockWorkspaceData} from '@umbraco-cms/backoffice/block'; -import { - UMB_BLOCK_MANAGER_CONTEXT, - UMB_BLOCK_WORKSPACE_MODAL -} from '@umbraco-cms/backoffice/block'; +import type { UmbBlockTypeBaseModel, UmbBlockWorkspaceData } from '@umbraco-cms/backoffice/block'; +import { UMB_BLOCK_MANAGER_CONTEXT, UMB_BLOCK_WORKSPACE_MODAL } from '@umbraco-cms/backoffice/block'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/modal'; import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbId } from '@umbraco-cms/backoffice/id'; @@ -72,6 +67,7 @@ export abstract class UmbBlockManagerContext< constructor(host: UmbControllerHost) { super(host, UMB_BLOCK_MANAGER_CONTEXT); + // TODO: This might will need the property alias as part of the URL, to avoid collision if multiple of these Editor on same Node. // IDEA: Make a Workspace registration controller that can be used to register a workspace, which does both edit and create?. new UmbModalRouteRegistrationController(this, UMB_BLOCK_WORKSPACE_MODAL) .addAdditionalPath('block') diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/manifests.ts index e3939d3921..1582d740af 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/manifests.ts @@ -1,4 +1,5 @@ +import { manifest as blockWorkspaceHasSettingsConditionManifest } from './conditions/block-workspace-has-settings.condition.js'; import { manifests as modalManifests } from './modals/manifests.js'; import { manifests as workspaceManifests } from './workspace/manifests.js'; -export const manifests = [...modalManifests, ...workspaceManifests]; +export const manifests = [...modalManifests, ...workspaceManifests, blockWorkspaceHasSettingsConditionManifest]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index 7fe74f0be1..327498248a 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -10,6 +10,7 @@ import { UMB_BLOCK_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/block'; import { buildUdi } from '@umbraco-cms/backoffice/utils'; import { UMB_MODAL_CONTEXT } from '@umbraco-cms/backoffice/modal'; +export type UmbBlockWorkspaceElementManagerNames = 'content' | 'settings'; export class UmbBlockWorkspaceContext< LayoutDataType extends UmbBlockLayoutBaseModel = UmbBlockLayoutBaseModel, > extends UmbEditableWorkspaceContextBase { diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.element.ts index 0bcca9b580..5e080011fe 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.element.ts @@ -6,9 +6,9 @@ import type { UmbRoute } from '@umbraco-cms/backoffice/router'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import { UmbWorkspaceIsNewRedirectController } from '@umbraco-cms/backoffice/workspace'; -import type { UmbApi} from '@umbraco-cms/backoffice/extension-api'; +import type { UmbApi } from '@umbraco-cms/backoffice/extension-api'; import { UmbExtensionsApiInitializer, createExtensionApi } from '@umbraco-cms/backoffice/extension-api'; -import type { ManifestWorkspace} from '@umbraco-cms/backoffice/extension-registry'; +import type { ManifestWorkspace } from '@umbraco-cms/backoffice/extension-registry'; import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { decodeFilePath } from '@umbraco-cms/backoffice/utils'; @@ -31,7 +31,7 @@ export class UmbBlockWorkspaceElement extends UmbLitElement { createExtensionApi(manifest, [this, { manifest: manifest }]).then((context) => { if (context) { this.#gotWorkspaceContext(context); - // TODO: We need to recreate when ID changed? + // TODO: Do we need to recreate when ID changed? Or is that a responsibility of the context it self? new UmbExtensionsApiInitializer(this, umbExtensionsRegistry, 'workspaceContext', [ this, this.#workspaceContext, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts index 3afce80e47..9617a2bdcc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/manifests.ts @@ -41,6 +41,7 @@ export const manifests: Array = [ label: 'Content', pathname: 'content', icon: 'icon-document', + blockElementManagerName: 'content', }, conditions: [ { @@ -48,5 +49,27 @@ export const manifests: Array = [ match: UMB_BLOCK_WORKSPACE_ALIAS, }, ], - }, + } as any, + { + type: 'workspaceView', + alias: 'Umb.WorkspaceView.Block.Settings', + name: 'Block Workspace Settings View', + js: () => import('./views/edit/block-workspace-view-edit.element.js'), + weight: 1000, + meta: { + label: 'Settings', + pathname: 'settings', + icon: 'icon-settings', + blockElementManagerName: 'settings', + }, + conditions: [ + { + alias: 'Umb.Condition.WorkspaceAlias', + match: UMB_BLOCK_WORKSPACE_ALIAS, + }, + { + alias: 'Umb.Condition.BlockWorkspaceHasSettings', + }, + ], + } as any, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-no-router.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-no-router.element.ts index 3a216eb3c9..e6c7aa0e48 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-no-router.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-no-router.element.ts @@ -39,7 +39,6 @@ export class UmbBlockWorkspaceViewEditNoRouterElement extends UmbLitElement impl this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { this._workspaceContext = workspaceContext; - console.log('workspaceContext.content.structure', workspaceContext.content.structure); this._tabsStructureHelper.setStructureManager(workspaceContext.content.structure); this._observeRootGroups(); }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts index fb85953276..d35fa40231 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-properties.element.ts @@ -1,8 +1,9 @@ import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js'; +import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js'; import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { - PropertyContainerTypes, + UmbPropertyContainerTypes, UmbContentTypeModel, UmbPropertyTypeModel, } from '@umbraco-cms/backoffice/content-type'; @@ -11,24 +12,34 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @customElement('umb-block-workspace-view-edit-properties') export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement { + @property({ attribute: false }) + public get managerName(): UmbBlockWorkspaceElementManagerNames | undefined { + return this.#managerName; + } + public set managerName(value: UmbBlockWorkspaceElementManagerNames | undefined) { + this.#managerName = value; + this.#setStructureManager(); + } + #managerName?: UmbBlockWorkspaceElementManagerNames; + #blockWorkspace?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE; + #propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); + @property({ type: String, attribute: 'container-name', reflect: false }) public get containerName(): string | undefined { - return this._propertyStructureHelper.getContainerName(); + return this.#propertyStructureHelper.getContainerName(); } public set containerName(value: string | undefined) { - this._propertyStructureHelper.setContainerName(value); + this.#propertyStructureHelper.setContainerName(value); } @property({ type: String, attribute: 'container-type', reflect: false }) - public get containerType(): PropertyContainerTypes | undefined { - return this._propertyStructureHelper.getContainerType(); + public get containerType(): UmbPropertyContainerTypes | undefined { + return this.#propertyStructureHelper.getContainerType(); } - public set containerType(value: PropertyContainerTypes | undefined) { - this._propertyStructureHelper.setContainerType(value); + public set containerType(value: UmbPropertyContainerTypes | undefined) { + this.#propertyStructureHelper.setContainerType(value); } - _propertyStructureHelper = new UmbContentTypePropertyStructureHelper(this); - @state() _propertyStructure: Array = []; @@ -36,13 +47,23 @@ export class UmbBlockWorkspaceViewEditPropertiesElement extends UmbLitElement { super(); this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { - this._propertyStructureHelper.setStructureManager(workspaceContext.content.structure); - }); - this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { - this._propertyStructure = propertyStructure; + this.#blockWorkspace = workspaceContext; + this.#setStructureManager(); }); } + #setStructureManager() { + if (!this.#blockWorkspace || !this.#managerName) return; + this.#propertyStructureHelper.setStructureManager(this.#blockWorkspace[this.#managerName].structure); + this.observe( + this.#propertyStructureHelper.propertyStructure, + (propertyStructure) => { + this._propertyStructure = propertyStructure; + }, + 'observePropertyStructure', + ); + } + render() { return repeat( this._propertyStructure, diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts index 3cac991532..03a27f78bc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/views/edit/block-workspace-view-edit-tab.element.ts @@ -7,29 +7,42 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; import type { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; import './block-workspace-view-edit-properties.element.js'; +// eslint-disable-next-line import/order +import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js'; @customElement('umb-block-workspace-view-edit-tab') export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { - private _tabName?: string | undefined; + @property({ attribute: false }) + public get managerName(): UmbBlockWorkspaceElementManagerNames | undefined { + return this.#managerName; + } + public set managerName(value: UmbBlockWorkspaceElementManagerNames | undefined) { + this.#managerName = value; + this.#setStructureManager(); + } + #managerName?: UmbBlockWorkspaceElementManagerNames; + #blockWorkspace?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE; + #groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); @property({ type: String }) public get tabName(): string | undefined { - return this._groupStructureHelper.getName(); + return this.#groupStructureHelper.getName(); } public set tabName(value: string | undefined) { if (value === this._tabName) return; const oldValue = this._tabName; this._tabName = value; - this._groupStructureHelper.setName(value); + this.#groupStructureHelper.setName(value); this.requestUpdate('tabName', oldValue); } + private _tabName?: string | undefined; @property({ type: Boolean }) public get noTabName(): boolean { - return this._groupStructureHelper.getIsRoot(); + return this.#groupStructureHelper.getIsRoot(); } public set noTabName(value: boolean) { - this._groupStructureHelper.setIsRoot(value); + this.#groupStructureHelper.setIsRoot(value); } private _ownerTabId?: string | null; @@ -40,7 +53,7 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { public set ownerTabId(value: string | null | undefined) { if (value === this._ownerTabId) return; this._ownerTabId = value; - this._groupStructureHelper.setOwnerId(value); + this.#groupStructureHelper.setOwnerId(value); } /** @@ -50,8 +63,6 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { @property({ type: Boolean, reflect: false }) hideSingleGroup = false; - _groupStructureHelper = new UmbContentTypeContainerStructureHelper(this); - @state() _groups: Array = []; @@ -62,16 +73,30 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { super(); this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { - this._groupStructureHelper.setStructureManager(workspaceContext.content.structure); - }); - this.observe(this._groupStructureHelper.containers, (groups) => { - this._groups = groups; - }); - this.observe(this._groupStructureHelper.hasProperties, (hasProperties) => { - this._hasProperties = hasProperties; + this.#blockWorkspace = workspaceContext; + this.#setStructureManager(); }); } + #setStructureManager() { + if (!this.#blockWorkspace || !this.#managerName) return; + this.#groupStructureHelper.setStructureManager(this.#blockWorkspace[this.#managerName].structure); + this.observe( + this.#groupStructureHelper.containers, + (groups) => { + this._groups = groups; + }, + 'observeGroups', + ); + this.observe( + this.#groupStructureHelper.hasProperties, + (hasProperties) => { + this._hasProperties = hasProperties; + }, + 'observeHasProperties', + ); + } + render() { return html` ${this._hasProperties ? this.#renderPart(this._tabName) : ''} @@ -86,11 +111,13 @@ export class UmbBlockWorkspaceViewEditTabElement extends UmbLitElement { #renderPart(groupName: string | null | undefined, boxName?: string | null | undefined) { return this.hideSingleGroup && this._groups.length === 1 ? html` ` : html` (this); + + //@state() //private _hasRootProperties = false; + + @state() private _hasRootGroups = false; @state() @@ -32,44 +43,44 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U @state() private _activePath = ''; - private _workspaceContext?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE; - - private _tabsStructureHelper = new UmbContentTypeContainerStructureHelper(this); - constructor() { super(); - this._tabsStructureHelper.setIsRoot(true); - this._tabsStructureHelper.setContainerChildType('Tab'); - this.observe(this._tabsStructureHelper.containers, (tabs) => { - this._tabs = tabs; - this._createRoutes(); - }); + this.#tabsStructureHelper.setIsRoot(true); + this.#tabsStructureHelper.setContainerChildType('Tab'); // _hasRootProperties can be gotten via _tabsStructureHelper.hasProperties. But we do not support root properties currently. this.consumeContext(UMB_BLOCK_WORKSPACE_CONTEXT, (workspaceContext) => { - this._workspaceContext = workspaceContext; - this._tabsStructureHelper.setStructureManager(workspaceContext.content.structure); - this._observeRootGroups(); + this.#blockWorkspace = workspaceContext; + this.#setStructureManager(); }); } - private _observeRootGroups() { - if (!this._workspaceContext) return; + #setStructureManager() { + if (!this.#blockWorkspace || !this.#managerName) return; + this.#tabsStructureHelper.setStructureManager(this.#blockWorkspace[this.#managerName].structure); this.observe( - this._workspaceContext.content.structure.hasRootContainers('Group'), + this.#blockWorkspace![this.#managerName!].structure.hasRootContainers('Group'), (hasRootGroups) => { this._hasRootGroups = hasRootGroups; this._createRoutes(); }, - '_observeGroups', + 'observeGroups', + ); + this.observe( + this.#tabsStructureHelper.containers, + (tabs) => { + this._tabs = tabs; + this._createRoutes(); + }, + 'observeTabs', ); } private _createRoutes() { - if (!this._tabs || !this._workspaceContext) return; + if (!this._tabs || !this.#blockWorkspace) return; const routes: UmbRoute[] = []; if (this._tabs.length > 0) { @@ -79,10 +90,11 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U path: `tab/${encodeFolderName(tabName).toString()}`, component: () => import('./block-workspace-view-edit-tab.element.js'), setup: (component) => { + (component as UmbBlockWorkspaceViewEditTabElement).managerName = this.#managerName; (component as UmbBlockWorkspaceViewEditTabElement).tabName = tabName; // TODO: Consider if we can link these more simple, and not parse this on. // Instead have the structure manager looking at wether one of the OwnerALikecontainers is in the owner document. - (component as UmbBlockWorkspaceViewEditTabElement).ownerTabId = this._tabsStructureHelper.isOwnerContainer( + (component as UmbBlockWorkspaceViewEditTabElement).ownerTabId = this.#tabsStructureHelper.isOwnerContainer( tab.id!, ) ? tab.id @@ -97,6 +109,7 @@ export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements U path: '', component: () => import('./block-workspace-view-edit-tab.element.js'), setup: (component) => { + (component as UmbBlockWorkspaceViewEditTabElement).managerName = this.#managerName; (component as UmbBlockWorkspaceViewEditTabElement).noTabName = true; (component as UmbBlockWorkspaceViewEditTabElement).ownerTabId = null; }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/extension-slot/extension-slot.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/extension-slot/extension-slot.element.ts index 645ff5d263..155ab0333d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/extension-slot/extension-slot.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/extension-slot/extension-slot.element.ts @@ -1,6 +1,6 @@ import { type ManifestTypes, umbExtensionsRegistry } from '../../extension-registry/index.js'; import type { TemplateResult } from '@umbraco-cms/backoffice/external/lit'; -import { css, repeat, customElement, property, state } from '@umbraco-cms/backoffice/external/lit'; +import { css, repeat, customElement, property, state, html } from '@umbraco-cms/backoffice/external/lit'; import { type UmbExtensionElementInitializer, UmbExtensionsElementInitializer, @@ -122,11 +122,13 @@ export class UmbExtensionSlotElement extends UmbLitElement { } render() { - return repeat( - this._permittedExts, - (ext) => ext.alias, - (ext) => (this.renderMethod ? this.renderMethod(ext) : ext.component), - ); + return this._permittedExts.length > 0 + ? repeat( + this._permittedExts, + (ext) => ext.alias, + (ext) => (this.renderMethod ? this.renderMethod(ext) : ext.component), + ) + : html``; } static styles = css` diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.ts index 579cbf0b6d..76fe1fff55 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.defaults.ts @@ -1,6 +1,5 @@ import type { RawEditorOptions } from '@umbraco-cms/backoffice/external/tinymce'; -//These are absolutely required in order for the macros to render inline //we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce //so we don't have to specify all the normal elements again export const defaultFallbackConfig: RawEditorOptions = { @@ -23,7 +22,6 @@ export const defaultFallbackConfig: RawEditorOptions = { 'indent', 'link', 'umbmediapicker', - 'umbmacro', 'umbembeddialog', ], style_formats: [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.element.ts index b2b65be207..9546f892b6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/components/input-tiny-mce/input-tiny-mce.element.ts @@ -42,11 +42,11 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) { super.value = newValue; const newContent = newValue?.toString() ?? ''; - if(this.#editorRef && this.#editorRef.getContent() != newContent) { + if (this.#editorRef && this.#editorRef.getContent() != newContent) { this.#editorRef.setContent(newContent); } } - + get value(): FormDataEntryValue | FormData { return super.value; } @@ -179,6 +179,8 @@ export class UmbInputTinyMceElement extends FormControlMixin(UmbLitElement) { (stylesheetPath: string) => `${this.#serverUrl}/css/${stylesheetPath.replace(/\\/g, '/')}`, ) ?? []; + stylesheets.push('/umbraco/backoffice/css/rte-content.css'); + // create an object by merging the configuration onto the fallback config const configurationOptions: RawEditorOptions = { ...defaultFallbackConfig, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts index 9dbda290e9..b31fb3546c 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-container-structure-helper.class.ts @@ -1,9 +1,5 @@ -import type { - PropertyContainerTypes, - UmbContentTypePropertyStructureManager, -} from './content-type-structure-manager.class.js'; -import type { UmbContentTypeModel } from './types.js'; -import type { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api'; +import type { UmbContentTypePropertyStructureManager } from './content-type-structure-manager.class.js'; +import type { UmbContentTypeModel, UmbPropertyContainerTypes, UmbPropertyTypeContainerModel } from './types.js'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState, UmbBooleanState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -14,8 +10,8 @@ export class UmbContentTypeContainerStructureHelper; - private _ownerType?: PropertyContainerTypes = 'Tab'; - private _childType?: PropertyContainerTypes = 'Group'; + private _ownerType?: UmbPropertyContainerTypes = 'Tab'; + private _childType?: UmbPropertyContainerTypes = 'Group'; private _isRoot = false; /** * The owner id is the owning container (The container that is begin presented, the container is the parent of the child containers) @@ -26,12 +22,12 @@ export class UmbContentTypeContainerStructureHelper([], (x) => x.id); + #containers = new UmbArrayState([], (x) => x.id); readonly containers = this.#containers.asObservable(); #hasProperties = new UmbBooleanState(false); @@ -53,7 +49,7 @@ export class UmbContentTypeContainerStructureHelper { + private _insertGroupContainers = (groupContainers: UmbPropertyTypeContainerModel[]) => { groupContainers.forEach((group) => { if (group.name !== null && group.name !== undefined) { if (!this.#containers.getValue().find((x) => x.name === group.name)) { @@ -208,7 +204,7 @@ export class UmbContentTypeContainerStructureHelper) { + async partialUpdateContainer(containerId: string, partialUpdate: Partial) { await this.#init; if (!this.#structure || !containerId || !partialUpdate) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts index 3de23a6e24..e7fc0a1f34 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/content-type-property-structure-helper.class.ts @@ -1,8 +1,5 @@ -import type { - PropertyContainerTypes, - UmbContentTypePropertyStructureManager, -} from './content-type-structure-manager.class.js'; -import type { UmbContentTypeModel, UmbPropertyTypeModel } from './types.js'; +import type { UmbContentTypePropertyStructureManager } from './content-type-structure-manager.class.js'; +import type { UmbContentTypeModel, UmbPropertyContainerTypes, UmbPropertyTypeModel } from './types.js'; import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api'; import { UmbArrayState, UmbObserverController } from '@umbraco-cms/backoffice/observable-api'; @@ -13,7 +10,7 @@ export class UmbContentTypePropertyStructureHelper; - private _containerType?: PropertyContainerTypes; + private _containerType?: UmbPropertyContainerTypes; private _isRoot?: boolean; private _containerName?: string; @@ -29,8 +26,10 @@ export class UmbContentTypePropertyStructureHelper ((a as any).sortOrder ?? 0) - ((b as any).sortOrder ?? 0)); } - get ownerDocumentTypes() { - return this.#structure?.contentTypes; + async ownerDocumentTypes() { + await this.#init; + if (!this.#structure) return; + return this.#structure.contentTypes; } public setStructureManager(structure: UmbContentTypePropertyStructureManager) { @@ -40,7 +39,7 @@ export class UmbContentTypePropertyStructureHelper extends UmbBaseController { #init!: Promise; @@ -30,8 +31,10 @@ export class UmbContentTypePropertyStructureManager x.containers ?? []), ); - #containers: UmbArrayState = - new UmbArrayState([], (x) => x.id); + #containers: UmbArrayState = new UmbArrayState( + [], + (x) => x.id, + ); constructor(host: UmbControllerHost, typeRepository: UmbDetailRepository) { super(host); @@ -178,13 +181,13 @@ export class UmbContentTypePropertyStructureManager, + partialUpdate: Partial, ) { await this.#init; contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!; @@ -273,13 +276,12 @@ export class UmbContentTypePropertyStructureManager = [ ...(this.#contentTypes.getValue().find((x) => x.unique === contentTypeUnique)?.properties ?? []), ]; + properties.push(property); // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -448,27 +451,27 @@ export class UmbContentTypePropertyStructureManager { return data.filter((x) => x.parent === null && x.type === containerType); }); } - getRootContainers(containerType: PropertyContainerTypes) { + getRootContainers(containerType: UmbPropertyContainerTypes) { return this.#containers.getValue().filter((x) => x.parent === null && x.type === containerType); } - hasRootContainers(containerType: PropertyContainerTypes) { + hasRootContainers(containerType: UmbPropertyContainerTypes) { return this.#containers.asObservablePart((data) => { return data.filter((x) => x.parent === null && x.type === containerType).length > 0; }); } - ownerContainersOf(containerType: PropertyContainerTypes) { + ownerContainersOf(containerType: UmbPropertyContainerTypes) { return this.ownerContentTypeObservablePart((x) => x.containers?.filter((x) => x.type === containerType) ?? []); } - getOwnerContainers(containerType: PropertyContainerTypes, parentId: string | null = null) { + getOwnerContainers(containerType: UmbPropertyContainerTypes, parentId: string | null = null) { return this.getOwnerContentType()?.containers?.filter((x) => parentId ? x.parent?.id === parentId : x.parent === null && x.type === containerType, ); @@ -478,14 +481,14 @@ export class UmbContentTypePropertyStructureManager x.id === containerId); } - containersOfParentKey(parentId: string, containerType: PropertyContainerTypes) { + containersOfParentKey(parentId: string, containerType: UmbPropertyContainerTypes) { return this.#containers.asObservablePart((data) => { return data.filter((x) => x.parent?.id === parentId && x.type === containerType); }); } // In future this might need to take parentName(parentId lookup) into account as well? otherwise containers that share same name and type will always be merged, but their position might be different and they should not be merged. - containersByNameAndType(name: string, containerType: PropertyContainerTypes) { + containersByNameAndType(name: string, containerType: UmbPropertyContainerTypes) { return this.#containers.asObservablePart((data) => { return data.filter((x) => x.name === name && x.type === containerType); }); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/types.ts index a52488720e..0c953ace34 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content-type/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content-type/types.ts @@ -1,9 +1,18 @@ import type { - PropertyTypeContainerModelBaseModel, CompositionTypeModel, PropertyTypeModelBaseModel, + ReferenceByIdModel, } from '@umbraco-cms/backoffice/backend-api'; +export type UmbPropertyContainerTypes = 'Group' | 'Tab'; +export interface UmbPropertyTypeContainerModel { + id: string; + parent?: ReferenceByIdModel | null; + name?: string | null; + type: UmbPropertyContainerTypes; + sortOrder: number; +} + export interface UmbContentTypeModel { unique: string; parentUnique: string | null; @@ -17,11 +26,15 @@ export interface UmbContentTypeModel { isElement: boolean; // TODO: investigate if we need our own model for these properties: Array; - containers: Array; + containers: Array; allowedContentTypes: Array; compositions: Array; } +export interface UmbPropertyTypeScaffoldModel extends Omit { + dataType?: UmbPropertyTypeModel['dataType']; +} + export interface UmbPropertyTypeModel extends Omit { dataType: { unique: string }; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/data-type/modals/data-type-picker-flow/data-type-picker-flow-data-type-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/data-type/modals/data-type-picker-flow/data-type-picker-flow-data-type-picker-modal.element.ts index eee0bfad33..eb853a72f4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/data-type/modals/data-type-picker-flow/data-type-picker-flow-data-type-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/data-type/modals/data-type-picker-flow/data-type-picker-flow-data-type-picker-modal.element.ts @@ -5,10 +5,9 @@ import { css, html, customElement, state, repeat, when } from '@umbraco-cms/back import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import type { UmbDataTypePickerFlowDataTypePickerModalData, - UmbDataTypePickerFlowDataTypePickerModalValue} from '@umbraco-cms/backoffice/modal'; -import { - UmbModalBaseElement, + UmbDataTypePickerFlowDataTypePickerModalValue, } from '@umbraco-cms/backoffice/modal'; +import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal'; @customElement('umb-data-type-picker-flow-data-type-picker-modal') export class UmbDataTypePickerFlowDataTypePickerModalElement extends UmbModalBaseElement< diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts index 4931a9977e..de68f3e1cd 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/manifests.ts @@ -1,4 +1,5 @@ -import { manifest as switchConditionManifest } from './switch.condition.js'; +import { manifest as menuAliasConditionManifest } from './menu-alias.condition.js'; import { manifest as sectionAliasConditionManifest } from './section-alias.condition.js'; +import { manifest as switchConditionManifest } from './switch.condition.js'; -export const manifests = [switchConditionManifest, sectionAliasConditionManifest]; +export const manifests = [menuAliasConditionManifest, sectionAliasConditionManifest, switchConditionManifest]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts index 74dc170c54..24801fd5e7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/conditions/types.ts @@ -2,6 +2,7 @@ import type { CollectionAliasConditionConfig } from '../../collection/collection import type { SectionAliasConditionConfig } from './section-alias.condition.js'; import type { SwitchConditionConfig } from './switch.condition.js'; import type { UserPermissionConditionConfig } from '@umbraco-cms/backoffice/user-permission'; +import type { BlockWorkspaceHasSettingsConditionConfig } from '@umbraco-cms/backoffice/block'; import type { WorkspaceAliasConditionConfig, WorkspaceEntityTypeConditionConfig, @@ -16,6 +17,7 @@ export type ConditionTypes = | CollectionAliasConditionConfig | SectionAliasConditionConfig | WorkspaceAliasConditionConfig + | BlockWorkspaceHasSettingsConditionConfig | WorkspaceEntityTypeConditionConfig | SwitchConditionConfig | UserPermissionConditionConfig diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts new file mode 100644 index 0000000000..da338c1c27 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/block-editor-custom-view.model.ts @@ -0,0 +1,6 @@ +import type { UmbPropertyEditorUiElement } from '../interfaces/index.js'; +import type { ManifestElement } from '@umbraco-cms/backoffice/extension-api'; + +export interface ManifestBlockEditorCustomView extends ManifestElement { + type: 'bockEditorCustomView'; +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts index c5378f48cd..768e0f6b88 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/extension-registry/models/index.ts @@ -1,3 +1,4 @@ +import type { ManifestBlockEditorCustomView } from './block-editor-custom-view.model.js'; import type { ManifestCollection } from './collection.models.js'; import type { ManifestCollectionView } from './collection-view.model.js'; import type { ManifestDashboard } from './dashboard.model.js'; @@ -40,6 +41,7 @@ import type { ManifestEntryPoint, } from '@umbraco-cms/backoffice/extension-api'; +export type * from './block-editor-custom-view.model.js'; export type * from './collection.models.js'; export type * from './collection-action.model.js'; export type * from './collection-view.model.js'; @@ -79,6 +81,7 @@ export type * from './workspace.model.js'; export type ManifestTypes = | ManifestBundle | ManifestCondition + | ManifestBlockEditorCustomView | ManifestCollection | ManifestCollectionView | ManifestCollectionAction diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/index.ts index a5e6406910..58bc8ce5a7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/index.ts @@ -15,7 +15,6 @@ export * from './entity-action/index.js'; export * from './entity-bulk-action/index.js'; export * from './extension-registry/index.js'; export * from './id/index.js'; -export * from './macro/index.js'; export * from './menu/index.js'; export * from './modal/index.js'; export * from './notification/index.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/macro/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/macro/index.ts deleted file mode 100644 index f8f2528b5a..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/macro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './macro.service.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/macro/macro.service.ts b/src/Umbraco.Web.UI.Client/src/packages/core/macro/macro.service.ts deleted file mode 100644 index fb94a58260..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/macro/macro.service.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; - -export interface MacroSyntaxData { - macroAlias: string; - macroParamsDictionary: { [key: string]: string }; - syntax?: string; -} - -export class UmbMacroService { - /** parses the special macro syntax like - * and returns an object with the macro alias and it's parameters - * */ - parseMacroSyntax(syntax = '') { - //This regex will match an alias of anything except characters that are quotes or new lines (for legacy reasons, when new macros are created - // their aliases are cleaned an invalid chars are stripped) - const expression = - /(<\?UMBRACO_MACRO (?:.+?)?macroAlias=["']([^"'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i; - const match = expression.exec(syntax); - - if (!match || match.length < 3) { - return null; - } - - const macroAlias = match[2]; - - //this will leave us with just the parameters - const paramsChunk = match[1] - .trim() - .replace(new RegExp(`UMBRACO_MACRO macroAlias=["']${macroAlias}["']`), '') - .trim(); - const paramExpression = /(\w+?)=['"]([\s\S]*?)['"]/g; - - const returnVal: MacroSyntaxData = { - macroAlias, - macroParamsDictionary: {}, - }; - - let paramMatch; - while ((paramMatch = paramExpression.exec(paramsChunk))) { - returnVal.macroParamsDictionary[paramMatch[1]] = paramMatch[2]; - } - - return returnVal; - } - - /** - * generates the syntax for inserting a macro into a rich text editor - this is the very old umbraco style syntax * - * @param {MacroSyntaxData} args an object containing the macro alias and it's parameter values - */ - generateMacroSyntax(args: MacroSyntaxData) { - let macroString = `'; - - return macroString; - } - - /** - * generates the syntax for inserting a macro into an mvc template * - * @param {object} args an object containing the macro alias and it's parameter values - */ - generateMvcSyntax(args: MacroSyntaxData) { - let macroString = `@await Umbraco.RenderMacroAsync("${args.macroAlias}"`; - let hasParams = false; - let paramString = ''; - - if (args.macroParamsDictionary) { - paramString = ', new {'; - - for (const [key, val] of Object.entries(args.macroParamsDictionary)) { - hasParams = true; - - const keyVal = `${key}="${val ? val : ''}", `; - - paramString += keyVal; - } - - //remove the last , and trailing whitespace - paramString = paramString.trimEnd().replace(/,*$/, ''); - paramString += '}'; - } - - if (hasParams) { - macroString += paramString; - } - - macroString += ')'; - - return macroString; - } - - collectValueData(macro: any, macroParams: any, renderingEngine: any) { - const macroParamsDictionary: { [key: string]: string } = {}; - const macroAlias = macro.alias; - if (!macroAlias) { - throw 'The macro object does not contain an alias'; - } - - macroParams.forEach((item: any) => { - let val = item.value; - if (item.value !== null && item.value !== undefined && typeof item.value !== 'string') { - try { - val = JSON.parse(val); - } catch (e) { - // not json - } - } - - //each value needs to be xml escaped!! since the value get's stored as an xml attribute - macroParamsDictionary[item.alias] = encodeURIComponent(val); - }); - - let syntax; - - //get the syntax based on the rendering engine - if (renderingEngine && renderingEngine.toLowerCase() === 'mvc') { - syntax = this.generateMvcSyntax({ macroAlias, macroParamsDictionary }); - } else { - syntax = this.generateMacroSyntax({ macroAlias, macroParamsDictionary }); - } - - return { - macroParamsDictionary, - macroAlias, - syntax, - } as MacroSyntaxData; - } -} - -export const UMB_MACRO_SERVICE_CONTEXT = new UmbContextToken(UmbMacroService.name); diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts index 3677994fe1..d973b5bbf2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/common/property-settings/property-settings-modal.element.ts @@ -259,7 +259,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement< .value=${this.value.description}>
    diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/property-settings-modal.token.ts b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/property-settings-modal.token.ts index 9a4d50d9c7..b7b10fe12d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/property-settings-modal.token.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/modal/token/property-settings-modal.token.ts @@ -1,10 +1,10 @@ -import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbPropertyTypeModel, UmbPropertyTypeScaffoldModel } from '@umbraco-cms/backoffice/content-type'; import { UmbModalToken } from '@umbraco-cms/backoffice/modal'; export type UmbPropertySettingsModalData = { documentTypeId: string; }; -export type UmbPropertySettingsModalValue = UmbPropertyTypeModel; +export type UmbPropertySettingsModalValue = UmbPropertyTypeModel | UmbPropertyTypeScaffoldModel; export const UMB_PROPERTY_SETTINGS_MODAL = new UmbModalToken< UmbPropertySettingsModalData, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/manifests.ts index f4d4718e08..c714dcbde2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/manifests.ts @@ -66,21 +66,6 @@ const pluginManifests: Array = [ ], }, }, - { - type: 'tinyMcePlugin', - alias: 'Umb.TinyMcePlugin.MacroPicker', - name: 'Macro Picker TinyMCE Plugin', - js: () => import('./tiny-mce-macropicker.plugin.js'), - meta: { - toolbar: [ - { - alias: 'umbmacro', - label: 'Macro', - icon: 'preferences', - }, - ], - }, - }, ]; export const manifests = [...pluginManifests]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/tiny-mce-macropicker.plugin.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/tiny-mce-macropicker.plugin.ts deleted file mode 100644 index 9413c42e17..0000000000 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/plugins/tiny-mce-macropicker.plugin.ts +++ /dev/null @@ -1,210 +0,0 @@ -import type { MacroSyntaxData} from '@umbraco-cms/backoffice/macro'; -import { UmbMacroService } from '@umbraco-cms/backoffice/macro'; -import type { TinyMcePluginArguments} from '@umbraco-cms/backoffice/components'; -import { UmbTinyMcePluginBase } from '@umbraco-cms/backoffice/components'; -import type { UmbModalManagerContext } from '@umbraco-cms/backoffice/modal'; -import { UMB_CONFIRM_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; -import type { AstNode } from '@umbraco-cms/backoffice/external/tinymce'; - -interface DialogData { - richTextEditor: boolean; - macroData?: MacroSyntaxData | null; - activeMacroElement?: HTMLElement; -} - -// TODO => This is a quick transplant of the existing macro plugin - needs to be finished, and need to -// determine how to replicate the existing macro service -export default class UmbTinyMceMacroPickerPlugin extends UmbTinyMcePluginBase { - #macroService = new UmbMacroService(); - - #modalContext?: UmbModalManagerContext; - - constructor(args: TinyMcePluginArguments) { - super(args); - - this.consumeContext(UMB_MODAL_MANAGER_CONTEXT, (modalContext) => { - this.#modalContext = modalContext; - }); - - /** Adds custom rules for the macro plugin and custom serialization */ - this.editor.on('preInit', () => { - //this is requires so that we tell the serializer that a 'div' is actually allowed in the root, - // otherwise the cleanup will strip it out - this.editor.serializer.addRules('div'); - - /** This checks if the div is a macro container, if so, checks if its wrapped in a p tag and then unwraps it (removes p tag) */ - this.editor.serializer.addNodeFilter('div', (nodes: Array) => { - for (let i = 0; i < nodes.length; i++) { - if (nodes[i].attr('class') === 'umb-macro-holder' && nodes[i].parent?.name.toLowerCase() === 'p') { - nodes[i].parent?.unwrap(); - } - } - }); - }); - - /** when the contents load we need to find any macros declared and load in their content */ - this.editor.on('SetContent', () => { - //get all macro divs and load their content - this.editor.dom.select('.umb-macro-holder.mceNonEditable').forEach((macroElement: HTMLElement) => { - this.#loadMacroContent(macroElement as HTMLDivElement, null); - }); - }); - - /** Adds the button instance */ - this.editor.ui.registry.addButton('umbmacro', { - icon: 'preferences', - tooltip: 'Insert macro', - - /** The insert macro button click event handler */ - onAction: () => { - let dialogData: DialogData = { - //flag for use in rte so we only show macros flagged for the editor - richTextEditor: true, - }; - - //when we click we could have a macro already selected and in that case we'll want to edit the current parameters - //so we'll need to extract them and submit them to the dialog. - const activeMacroElement = this.#getRealMacroElem(); - if (activeMacroElement) { - //we have a macro selected so we'll need to parse it's alias and parameters - const comment = Array.from(activeMacroElement.childNodes).find((x) => x.nodeType === 8); - if (!comment) { - throw 'Cannot parse the current macro, the syntax in the editor is invalid'; - } - - const syntax = comment.textContent?.trim(); - const parsed = this.#macroService?.parseMacroSyntax(syntax); - - dialogData = { - richTextEditor: false, - macroData: parsed, - activeMacroElement, //pass the active element along so we can retrieve it later - }; - } - - this.#showMacroPicker(dialogData); - }, - }); - } - - /** loads in the macro content async from the server */ - #loadMacroContent(macroDiv?: HTMLDivElement, macroData?: MacroSyntaxData | null) { - //if we don't have the macroData, then we'll need to parse it from the macro div - if (!macroData && macroDiv) { - const comment = Array.from(macroDiv.childNodes).find((x) => x.nodeType === 8); - - if (!comment) { - throw 'Cannot parse the current macro, the syntax in the editor is invalid'; - } - - const syntax = comment.textContent?.trim(); - const parsed = this.#macroService?.parseMacroSyntax(syntax); - macroData = parsed; - } - - //show the throbber - macroDiv?.classList.add('loading'); - - // Add the contenteditable="false" attribute - // As just the CSS class of .mceNonEditable is not working by itself?! - macroDiv?.setAttribute('contenteditable', 'false'); - - // TODO => macro data service? - // const contentId = $routeParams.id; - - // //need to wrap in safe apply since this might be occuring outside of angular - // angularHelper.safeApply($rootScope, function () { - // tryExecuteAndNotify(this, macroResource - // .getMacroResultAsHtmlForEditor(macroData.macroAlias, contentId, macroData.macroParamsDictionary)) - // .then(function (htmlResult) { - // $macroDiv.removeClass('loading'); - // htmlResult = htmlResult.trim(); - // if (htmlResult !== '') { - // const wasDirty = editor.isDirty(); - // const $ins = macroDiv?.querySelector('ins'); - // $ins.html(htmlResult); - // if (!wasDirty) { - // editor.undoManager.clear(); - // } - // } - // }); - // }); - } - - #insertInEditor(macroObject: MacroSyntaxData, activeMacroElement?: HTMLElement) { - //Important note: the TinyMce plugin "noneditable" is used here so that the macro cannot be edited, - // for this to work the mceNonEditable class needs to come last and we also need to use the attribute contenteditable = false - // (even though all the docs and examples say that is not necessary) - - //put the macro syntax in comments, we will parse this out on the server side to be used - //for persisting. - const macroSyntaxComment = ``; - //create an id class for this element so we can re-select it after inserting - const uniqueId = 'umb-macro-' + this.editor.dom.uniqueId(); - let macroDiv = this.editor.dom.create( - 'div', - { - class: `umb-macro-holder ${macroObject.macroAlias} ${uniqueId} mceNonEditable`, - contenteditable: 'false', - }, - `${macroSyntaxComment}Macro alias: ${macroObject.macroAlias}`, - ); - - //if there's an activeMacroElement then replace it, otherwise set the contents of the selected node - if (activeMacroElement) { - activeMacroElement.replaceWith(macroDiv); //directly replaces the html node - } else { - this.editor.selection.setNode(macroDiv); - } - - macroDiv = this.editor.dom.select('div.umb-macro-holder.' + uniqueId)[0] as HTMLDivElement; - this.editor.setDirty(true); - - //async load the macro content - this.#loadMacroContent(macroDiv, macroObject); - } - - /** - * Because the macro got wrapped in a P tag because of the way 'enter' works in older versions of Umbraco, this - * method will return the macro element if not wrapped in a p, or the p if the macro - * element is the only one inside of it even if we are deep inside an element inside the macro - */ - #getRealMacroElem() { - // Ask the editor for the currently selected element - const element = this.editor?.selection.getNode() as HTMLElement; - if (!element) { - return null; - } - - const e = element.closest('.umb-macro-holder'); - if (!e || e === null) return null; - - if (e.parentNode?.nodeName === 'P') { - //now check if we're the only element - if (element.parentNode?.childNodes.length === 1) { - return e.parentNode as HTMLElement; - } - } - - return e as HTMLElement; - } - - // TODO => depends on macro picker, which doesn't exist, just showing a generic modal for now - async #showMacroPicker(dialogData: DialogData) { - const modalHandler = this.#modalContext?.open(UMB_CONFIRM_MODAL, { - data: { - headline: 'Macro picker', - content: 'Yet to be implemented', - }, - }); - - if (!modalHandler) return; - - const result = await modalHandler.onSubmit(); - if (!result) return; - - // TODO => object here should be the response from the modal - this.#insertInEditor({} as MacroSyntaxData, dialogData.activeMacroElement); - this.editor.dispatch('Change'); - } -} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.stories.ts b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.stories.ts index b7671b7cde..a9d56a33d2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.stories.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/property-editor/uis/tiny-mce/property-editor-ui-tiny-mce.stories.ts @@ -39,7 +39,6 @@ const config = new UmbPropertyEditorConfigCollection([ 'anchor', 'table', 'umbmediapicker', - 'umbmacro', 'umbembeddialog', ], }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-modal/workspace-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-modal/workspace-modal.element.ts index de53c48aa7..e5c77d98da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-modal/workspace-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/workspace-modal/workspace-modal.element.ts @@ -1,5 +1,5 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { CSSResultGroup} from '@umbraco-cms/backoffice/external/lit'; +import type { CSSResultGroup } from '@umbraco-cms/backoffice/external/lit'; import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit'; import type { UmbWorkspaceData } from '@umbraco-cms/backoffice/modal'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/document-type-detail.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/document-type-detail.server.data-source.ts index 47fbbe5a62..5e998568a0 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/document-type-detail.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/repository/detail/document-type-detail.server.data-source.ts @@ -9,6 +9,7 @@ import type { import { DocumentTypeResource } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import type { UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type'; /** * A data source for the Document Type that fetches data from the server @@ -109,7 +110,7 @@ export class UmbDocumentTypeDetailServerDataSource implements UmbDetailDataSourc appearance: property.appearance, }; }), - containers: data.containers, + containers: data.containers as UmbPropertyTypeContainerModel[], allowedContentTypes: data.allowedDocumentTypes.map((allowedDocumentType) => { return { contentType: { unique: allowedDocumentType.documentType.id }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts index dec6391e3c..5cdda1e821 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/views/design/document-type-workspace-view-edit-properties.element.ts @@ -3,7 +3,7 @@ import './document-type-workspace-view-edit-property.element.js'; import type { UmbDocumentTypeDetailModel } from '../../../types.js'; import { css, html, customElement, property, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { PropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbPropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type'; import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @@ -80,10 +80,10 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle } @property({ type: String, attribute: 'container-type', reflect: false }) - public get containerType(): PropertyContainerTypes | undefined { + public get containerType(): UmbPropertyContainerTypes | undefined { return this._propertyStructureHelper.getContainerType(); } - public set containerType(value: PropertyContainerTypes | undefined) { + public set containerType(value: UmbPropertyContainerTypes | undefined) { this._propertyStructureHelper.setContainerType(value); } @@ -104,7 +104,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle constructor() { super(); - this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => { + this.consumeContext(UMB_WORKSPACE_CONTEXT, async (workspaceContext) => { this._propertyStructureHelper.setStructureManager( (workspaceContext as UmbDocumentTypeWorkspaceContext).structure, ); @@ -116,6 +116,15 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle }, '_observeIsSorting', ); + const docTypesObservable = await this._propertyStructureHelper.ownerDocumentTypes(); + if (!docTypesObservable) return; + this.observe( + docTypesObservable, + (documents) => { + this._ownerDocumentTypes = documents; + }, + 'observeOwnerDocumentTypes', + ); }); this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { this._propertyStructure = propertyStructure; @@ -134,7 +143,10 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle return { data: { documentTypeId }, value: propertyData }; }) .onSubmit((value) => { - this.#addProperty(value); + if (!value.dataType) { + throw new Error('No data type selected'); + } + this.#addProperty(value as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { this._modalRouteNewProperty = routeBuilder(null); @@ -150,19 +162,6 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle } } - connectedCallback(): void { - super.connectedCallback(); - const doctypes = this._propertyStructureHelper.ownerDocumentTypes; - if (!doctypes) return; - this.observe( - doctypes, - (documents) => { - this._ownerDocumentTypes = documents; - }, - 'observeOwnerDocumentTypes', - ); - } - async #addProperty(propertyData: UmbPropertyTypeModel) { const propertyPlaceholder = await this._propertyStructureHelper.addProperty(this._containerId); if (!propertyPlaceholder) return; @@ -182,7 +181,7 @@ export class UmbDocumentTypeWorkspaceViewEditPropertiesElement extends UmbLitEle ); return html` { - this._partialUpdate(result); + if (!result.dataType) { + throw new Error('No dataType found on property'); + } + this._partialUpdate(result as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { this._modalRoute = routeBuilder(null); @@ -295,7 +298,7 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement { renderPropertyTags() { return this.property ? html`
    - ${this.property.dataType.unique ? html`${this._dataTypeName}` : nothing} + ${this.property.dataType?.unique ? html`${this._dataTypeName}` : nothing} ${this.property.variesByCulture ? html` ${this.localize.term('contentTypeEditor_cultureVariantLabel')} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts index a4dd018e79..5862165faf 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit-properties.element.ts @@ -1,7 +1,7 @@ import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '../../document-workspace.context-token.js'; import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { PropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbPropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type'; import { UmbLitElement } from '@umbraco-cms/internal/lit-element'; @@ -16,10 +16,10 @@ export class UmbDocumentWorkspaceViewEditPropertiesElement extends UmbLitElement } @property({ type: String, attribute: 'container-type', reflect: false }) - public get containerType(): PropertyContainerTypes | undefined { + public get containerType(): UmbPropertyContainerTypes | undefined { return this._propertyStructureHelper.getContainerType(); } - public set containerType(value: PropertyContainerTypes | undefined) { + public set containerType(value: UmbPropertyContainerTypes | undefined) { this._propertyStructureHelper.setContainerType(value); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts index 5ea21b444f..68a60a2bc6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/views/edit/document-workspace-view-edit.element.ts @@ -11,14 +11,17 @@ import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension- @customElement('umb-document-workspace-view-edit') export class UmbDocumentWorkspaceViewEditElement extends UmbLitElement implements UmbWorkspaceViewElement { + //@state() //private _hasRootProperties = false; + + @state() private _hasRootGroups = false; @state() private _routes: UmbRoute[] = []; @state() - _tabs?: Array; + private _tabs?: Array; @state() private _routerPath?: string; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/detail/media-type-detail.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/detail/media-type-detail.server.data-source.ts index 70336a6464..dfffd71962 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/detail/media-type-detail.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/repository/detail/media-type-detail.server.data-source.ts @@ -6,6 +6,7 @@ import type { CreateMediaTypeRequestModel, UpdateMediaTypeRequestModel } from '@ import { MediaTypeResource } from '@umbraco-cms/backoffice/backend-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources'; +import type { UmbPropertyTypeContainerModel } from '@umbraco-cms/backoffice/content-type'; /** * A data source for the Media Type that fetches data from the server @@ -96,7 +97,7 @@ export class UmbMediaTypeServerDataSource implements UmbDetailDataSource { return { contentType: { unique: allowedMediaType.mediaType.id }, diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-properties.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-properties.element.ts index 9213ec0e76..81cb48d322 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-properties.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-properties.element.ts @@ -3,7 +3,7 @@ import './media-type-workspace-view-edit-property.element.js'; import type { UmbMediaTypeDetailModel } from '../../../types.js'; import { css, html, customElement, property, state, repeat, ifDefined } from '@umbraco-cms/backoffice/external/lit'; import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; -import type { PropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; +import type { UmbPropertyContainerTypes, UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'; import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type'; import type { UmbSorterConfig } from '@umbraco-cms/backoffice/sorter'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; @@ -80,10 +80,10 @@ export class UmbMediaTypeWorkspaceViewEditPropertiesElement extends UmbLitElemen } @property({ type: String, attribute: 'container-type', reflect: false }) - public get containerType(): PropertyContainerTypes | undefined { + public get containerType(): UmbPropertyContainerTypes | undefined { return this._propertyStructureHelper.getContainerType(); } - public set containerType(value: PropertyContainerTypes | undefined) { + public set containerType(value: UmbPropertyContainerTypes | undefined) { this._propertyStructureHelper.setContainerType(value); } @@ -104,7 +104,7 @@ export class UmbMediaTypeWorkspaceViewEditPropertiesElement extends UmbLitElemen constructor() { super(); - this.consumeContext(UMB_WORKSPACE_CONTEXT, (workspaceContext) => { + this.consumeContext(UMB_WORKSPACE_CONTEXT, async (workspaceContext) => { this._propertyStructureHelper.setStructureManager((workspaceContext as UmbMediaTypeWorkspaceContext).structure); this.observe( (workspaceContext as UmbMediaTypeWorkspaceContext).isSorting, @@ -114,6 +114,16 @@ export class UmbMediaTypeWorkspaceViewEditPropertiesElement extends UmbLitElemen }, '_observeIsSorting', ); + + const mediaTypesObservable = await this._propertyStructureHelper.ownerDocumentTypes(); + if (!mediaTypesObservable) return; + this.observe( + mediaTypesObservable, + (medias) => { + this._ownerMediaTypes = medias; + }, + 'observeOwnerMediaTypes', + ); }); this.observe(this._propertyStructureHelper.propertyStructure, (propertyStructure) => { this._propertyStructure = propertyStructure; @@ -132,7 +142,10 @@ export class UmbMediaTypeWorkspaceViewEditPropertiesElement extends UmbLitElemen return { data: { documentTypeId: mediaTypeId }, value: propertyData }; //TODO: Should we have a separate modal for mediaTypes? }) .onSubmit((value) => { - this.#addProperty(value); + if (!value.dataType) { + throw new Error('No data type selected'); + } + this.#addProperty(value as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { this._modalRouteNewProperty = routeBuilder(null); @@ -147,19 +160,6 @@ export class UmbMediaTypeWorkspaceViewEditPropertiesElement extends UmbLitElemen } } - connectedCallback(): void { - super.connectedCallback(); - const mediaTypes = this._propertyStructureHelper.ownerDocumentTypes; //TODO: Should we have a separate propertyStructureHelper for mediaTypes? - if (!mediaTypes) return; - this.observe( - mediaTypes, - (medias) => { - this._ownerMediaTypes = medias; - }, - 'observeOwnerMediaTypes', - ); - } - async #addProperty(propertyData: UmbPropertyTypeModel) { const propertyPlaceholder = await this._propertyStructureHelper.addProperty(this._containerId); if (!propertyPlaceholder) return; diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts index 7091901fb6..eda5094e00 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media-types/workspace/views/design/media-type-workspace-view-edit-property.element.ts @@ -96,7 +96,10 @@ export class UmbMediaTypeWorkspacePropertyElement extends UmbLitElement { return { data: { documentTypeId: mediaTypeId }, value: propertyData }; //TODO: Should we have a separate modal for mediaTypes? }) .onSubmit((result) => { - this._partialUpdate(result); + if (!result.dataType) { + throw new Error('No dataType found on property'); + } + this._partialUpdate(result as UmbPropertyTypeModel); }) .observeRouteBuilder((routeBuilder) => { this._modalRoute = routeBuilder(null); @@ -295,7 +298,7 @@ export class UmbMediaTypeWorkspacePropertyElement extends UmbLitElement { renderPropertyTags() { return this.property ? html`
    - ${this.property.dataType.unique ? html`${this._dataTypeName}` : nothing} + ${this.property.dataType?.unique ? html`${this._dataTypeName}` : nothing} ${this.property.variesByCulture ? html` ${this.localize.term('contentTypeEditor_cultureVariantLabel')} diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/components/insert-menu/templating-insert-menu.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/components/insert-menu/templating-insert-menu.element.ts index f557da0f13..8b22e1bfae 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/components/insert-menu/templating-insert-menu.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/components/insert-menu/templating-insert-menu.element.ts @@ -61,9 +61,6 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement { break; } - case CodeSnippetType.macro: { - throw new Error('Not implemented'); - } } } @@ -131,10 +128,6 @@ export class UmbTemplatingInsertMenuElement extends UmbLitElement { title="Dictionary item" @click=${this.#openInsertDictionaryItemModal}> - - `; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/insert-choose-type-sidebar.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/insert-choose-type-sidebar.element.ts index 4da80658ee..07589ef9f6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/modals/insert-choose-type-sidebar.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/modals/insert-choose-type-sidebar.element.ts @@ -3,7 +3,8 @@ import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit'; import type { UmbModalManagerContext, UmbModalContext, - UmbDictionaryItemPickerModalValue} from '@umbraco-cms/backoffice/modal'; + UmbDictionaryItemPickerModalValue, +} from '@umbraco-cms/backoffice/modal'; import { UMB_MODAL_MANAGER_CONTEXT, UMB_PARTIAL_VIEW_PICKER_MODAL, @@ -18,7 +19,6 @@ export interface ChooseInsertTypeModalData { export enum CodeSnippetType { partialView = 'partialView', dictionaryItem = 'dictionaryItem', - macro = 'macro', } export interface UmbChooseInsertTypeModalValue { value: string | UmbDictionaryItemPickerModalValue; diff --git a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts index 8b9db9f3ff..feeb5fb90e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/templating/templates/modals/query-builder/query-builder-modal.element.ts @@ -256,12 +256,15 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle ` : ''}
    -
    +
    ${this._templateQuery?.resultCount ?? 0} items returned, in ${this._templateQuery?.executionTime ?? 0} ms + ${this._templateQuery?.sampleResults.map( + (sample) => html`${sample.name}`, + ) ?? ''}
    ${this._templateQuery?.queryExpression ?? ''} @@ -318,6 +321,16 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle #results-count { font-weight: bold; } + .query-results { + flex-direction: column; + align-items: flex-start; + gap: 0; + } + .query-results span { + display: flex; + align-items: center; + gap: var(--uui-size-1); + } `, ]; } diff --git a/src/Umbraco.Web.UI.Client/tsconfig.json b/src/Umbraco.Web.UI.Client/tsconfig.json index 32eebda0fa..3fc9c765ce 100644 --- a/src/Umbraco.Web.UI.Client/tsconfig.json +++ b/src/Umbraco.Web.UI.Client/tsconfig.json @@ -72,7 +72,6 @@ "@umbraco-cms/backoffice/server-file-system": ["src/packages/core/server-file-system"], "@umbraco-cms/backoffice/id": ["src/packages/core/id"], "@umbraco-cms/backoffice/localization": ["src/packages/core/localization"], - "@umbraco-cms/backoffice/macro": ["src/packages/core/macro"], "@umbraco-cms/backoffice/menu": ["src/packages/core/menu"], "@umbraco-cms/backoffice/modal": ["src/packages/core/modal"], "@umbraco-cms/backoffice/notification": ["src/packages/core/notification"], diff --git a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs index bf590c8ec3..7a42fd4133 100644 --- a/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs +++ b/src/Umbraco.Web.UI.Client/web-test-runner.config.mjs @@ -72,7 +72,6 @@ export default { '@umbraco-cms/backoffice/server-file-system': './src/packages/core/server-file-system/index.ts', '@umbraco-cms/backoffice/id': './src/packages/core/id/index.ts', '@umbraco-cms/backoffice/localization': './src/packages/core/localization/index.ts', - '@umbraco-cms/backoffice/macro': './src/packages/core/macro/index.ts', '@umbraco-cms/backoffice/menu': './src/packages/core/menu/index.ts', '@umbraco-cms/backoffice/modal': './src/packages/core/modal/index.ts', '@umbraco-cms/backoffice/notification': './src/packages/core/notification/index.ts',