Merge branch 'main' into improvement/model-remapping
This commit is contained in:
@@ -34,7 +34,7 @@ There are two ways to use this:
|
||||
```json
|
||||
"Umbraco": {
|
||||
"CMS": {
|
||||
"NewBackOffice":{
|
||||
"Security":{
|
||||
"BackOfficeHost": "http://localhost:5173",
|
||||
"AuthorizeCallbackPathName": "/"
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
|
||||
'\n We will send:\n <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
|
||||
},
|
||||
umbId: {
|
||||
editProfile: 'Edit your Umbraco ID profile',
|
||||
|
||||
@@ -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 <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
|
||||
'\n We will send:\n <ul>\n <li>Anonymized site ID, Umbraco version, and packages installed.</li>\n <li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, Backoffice external login providers, and Property Editors in use.</li>\n <li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li>\n <li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, whether the delivery API is enabled, and allows public access, and if you are in debug mode.</li>\n </ul>\n <em>We might change what we send on the Detailed level in the future. If so, it will be listed above.\n <br>By choosing "Detailed" you agree to current and future anonymized information being collected.</em>\n ',
|
||||
},
|
||||
umbId: {
|
||||
editProfile: 'Edit your Umbraco ID profile',
|
||||
|
||||
49
src/Umbraco.Web.UI.Client/src/css/rte-content.css
Normal file
49
src/Umbraco.Web.UI.Client/src/css/rte-content.css
Normal file
@@ -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);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export class UmbExtensionsElementInitializer<
|
||||
> {
|
||||
//
|
||||
#extensionRegistry;
|
||||
private _defaultElement?: string;
|
||||
#defaultElement?: string;
|
||||
#props?: Record<string, unknown>;
|
||||
|
||||
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;
|
||||
|
||||
@@ -510,6 +510,7 @@ export const data: Array<UmbMockDataTypeModel> = [
|
||||
{
|
||||
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<UmbMockDataTypeModel> = [
|
||||
},
|
||||
{
|
||||
alias: 'useInlineEditingAsDefault',
|
||||
value: true,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
alias: 'useLiveEditing',
|
||||
@@ -729,7 +730,7 @@ export const data: Array<UmbMockDataTypeModel> = [
|
||||
'+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<UmbMockDataTypeModel> = [
|
||||
'anchor',
|
||||
'table',
|
||||
'umbmediapicker',
|
||||
'umbmacro',
|
||||
'umbembeddialog',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -34,8 +34,18 @@ export const data: Array<UmbMockDocumentModel> = [
|
||||
alias: 'richTextEditor',
|
||||
culture: null,
|
||||
segment: null,
|
||||
value:
|
||||
'Some value for the RTE with an <a href="http://foo.com">external link</a> and an <a href="/{localLink:umb://document/c05da24d7740447b9cdcbd8ce2172e38}">internal link</a> foo foo <div class="umb-macro-holder TestMacro umb-macro-mce_1 mceNonEditable"><!-- <?UMBRACO_MACRO macroAlias="TestMacro" /> --><ins>Macro alias: <strong>TestMacro</strong></ins></div>',
|
||||
value: {
|
||||
blocks: {},
|
||||
markup: `
|
||||
<p>
|
||||
Some value for the RTE with an <a href="https://google.com">external link</a> and an <a href="/{localLink:umb://document/c05da24d7740447b9cdcbd8ce2172e38}">internal link</a> foo foo
|
||||
</p>
|
||||
<div class="umb-macro-holder TestMacro umb-macro-mce_1 mceNonEditable"><!-- <?UMBRACO_MACRO macroAlias="TestMacro" /> --><ins>Macro alias: <strong>TestMacro</strong></ins></div>
|
||||
<p>The following tests the embed plugin:</p>
|
||||
<div class="mceNonEditable umb-embed-holder" data-embed-height="240" data-embed-width="360" data-embed-constrain="false"><iframe width="360" height="240" src="https://www.youtube.com/embed/QRIWz9SotY4?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" title="Sleep Token - The Summoning"></iframe></div>
|
||||
<p>End of test content</p>
|
||||
`,
|
||||
},
|
||||
},
|
||||
{
|
||||
alias: 'email',
|
||||
@@ -176,6 +186,7 @@ export const data: Array<UmbMockDocumentModel> = [
|
||||
'Umbraco.BlockList': [
|
||||
{
|
||||
contentUdi: '1234',
|
||||
settingsUdi: '5678',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -186,7 +197,13 @@ export const data: Array<UmbMockDocumentModel> = [
|
||||
elementProperty: 'Hello world',
|
||||
},
|
||||
],
|
||||
settingsData: [],
|
||||
settingsData: [
|
||||
{
|
||||
udi: '5678',
|
||||
contentTypeKey: 'all-property-editors-document-type-id',
|
||||
elementProperty: 'Hello world',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -17,26 +17,6 @@ export const healthGroups: Array<HealthCheckGroupWithResultResponseModel & { nam
|
||||
{
|
||||
name: 'Configuration',
|
||||
checks: [
|
||||
{
|
||||
id: '1c6c0a39-d673-4794-b734-1bec45d6a363',
|
||||
results: [
|
||||
{
|
||||
message: `MacroErrors are set to 'Throw' which will prevent some or all pages in your site from loading
|
||||
completely if there are any errors in macros. Rectifying this will set the value to 'Inline'. `,
|
||||
resultType: StatusResultTypeModel.ERROR,
|
||||
readMoreLink: 'https://umbra.co/healthchecks-macro-errors',
|
||||
actions: [
|
||||
{
|
||||
healthCheckId: 'id123',
|
||||
name: 'Action name',
|
||||
alias: 'Action alias',
|
||||
description: 'Action description',
|
||||
valueRequired: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: '3e2f7b14-4b41-452b-9a30-e67fbc8e1206',
|
||||
results: [
|
||||
@@ -217,12 +197,6 @@ export const healthGroupsWithoutResult: HealthCheckGroupPresentationModel[] = [
|
||||
{
|
||||
name: 'Configuration',
|
||||
checks: [
|
||||
{
|
||||
id: 'd0f7599e-9b2a-4d9e-9883-81c7edc5616f',
|
||||
name: 'Macro errors',
|
||||
description:
|
||||
'Checks to make sure macro errors are not set to throw a YSOD (yellow screen of death), which would prevent certain or all pages from loading completely.',
|
||||
},
|
||||
{
|
||||
id: '3e2f7b14-4b41-452b-9a30-e67fbc8e1206',
|
||||
name: 'Notification Email Settings',
|
||||
|
||||
@@ -30,7 +30,7 @@ export const handlers = [
|
||||
{
|
||||
level: TelemetryLevelModel.DETAILED,
|
||||
description:
|
||||
'We will send:<ul><li>Anonymized site ID, umbraco version, and packages installed.</li><li>Number of: Root nodes, Content nodes, Macros, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.</li><li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li><li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.</li></ul><i>We might change what we send on the Detailed level in the future. If so, it will be listed above.<br>By choosing "Detailed" you agree to current and future anonymized information being collected.</i>',
|
||||
'We will send:<ul><li>Anonymized site ID, umbraco version, and packages installed.</li><li>Number of: Root nodes, Content nodes, Media, Document Types, Templates, Languages, Domains, User Group, Users, Members, and Property Editors in use.</li><li>System information: Webserver, server OS, server framework, server OS language, and database provider.</li><li>Configuration settings: Modelsbuilder mode, if custom Umbraco path exists, ASP environment, and if you are in debug mode.</li></ul><i>We might change what we send on the Detailed level in the future. If so, it will be listed above.<br>By choosing "Detailed" you agree to current and future anonymized information being collected.</i>',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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`<umb-ref-list-block .name=${this._label}></umb-ref-list-block>`;
|
||||
return html`<umb-ref-list-block .label=${this._label}></umb-ref-list-block>`;
|
||||
}
|
||||
|
||||
#renderInlineBlock() {
|
||||
return html`<umb-inline-list-block .name=${this._label}></umb-inline-list-block>`;
|
||||
return html`<umb-inline-list-block .label=${this._label}></umb-inline-list-block>`;
|
||||
}
|
||||
|
||||
#renderBlock() {
|
||||
return html`
|
||||
${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()}
|
||||
<umb-extension-slot
|
||||
type="blockEditorCustomView"
|
||||
default-element=${this._inlineEditingMode ? 'umb-inline-list-block' : 'umb-ref-list-block'}
|
||||
.props=${this._blockViewProps}
|
||||
>${this._inlineEditingMode ? this.#renderInlineBlock() : this.#renderRefBlock()}</umb-extension-slot
|
||||
>
|
||||
<uui-action-bar>
|
||||
${this._workspaceEditPath
|
||||
? html`<uui-button label="edit" compact href=${this._workspaceEditPath}>
|
||||
<uui-icon name="icon-edit"></uui-icon>
|
||||
</uui-button>`
|
||||
: ''}
|
||||
${this._workspaceEditPath && this._hasSettings
|
||||
? html`<uui-button label="Edit settings" compact href=${this._workspaceEditPath + '/view/settings'}>
|
||||
<uui-icon name="icon-settings"></uui-icon>
|
||||
</uui-button>`
|
||||
: ''}
|
||||
<uui-button label="delete" compact @click=${this.#requestDelete}>
|
||||
<uui-icon name="icon-remove"></uui-icon>
|
||||
</uui-button>
|
||||
|
||||
@@ -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 {
|
||||
}}>
|
||||
<uui-icon name="icon-document"></uui-icon>
|
||||
<uui-symbol-expand .open=${this._isOpen}></uui-symbol-expand>
|
||||
<span>${this._label}</span>
|
||||
<span>${this.label}</span>
|
||||
</button>
|
||||
${this._isOpen === true
|
||||
? html`<umb-block-workspace-view-edit-no-router></umb-block-workspace-view-edit-no-router>`
|
||||
@@ -82,6 +79,7 @@ export class UmbInlineListBlockElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
#accordion-button {
|
||||
display: flex;
|
||||
|
||||
@@ -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`<uui-ref-node border .name=${this.name ?? ''}></uui-ref-node>`;
|
||||
return html`<uui-ref-node border .name=${this.label ?? ''}></uui-ref-node>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
...UUIRefNodeElement.styles,
|
||||
css`
|
||||
:host {
|
||||
uui-ref-node {
|
||||
min-height: var(--uui-size-16);
|
||||
}
|
||||
`,
|
||||
|
||||
@@ -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<BlockWorkspaceHasSettingsConditionConfig>) {
|
||||
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,
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from './block-workspace-has-settings.condition.js';
|
||||
@@ -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<typeof UMB_BLOCK_MANAGER_CONTEXT, typeof UMB_BLOCK_MANAGER_CONTEXT.TYPE>
|
||||
>('UmbBlockContext');
|
||||
@@ -1 +1 @@
|
||||
export * from './block.context.js';
|
||||
export * from './block-entity.context.js';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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<LayoutDataType> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -41,6 +41,7 @@ export const manifests: Array<ManifestTypes> = [
|
||||
label: 'Content',
|
||||
pathname: 'content',
|
||||
icon: 'icon-document',
|
||||
blockElementManagerName: 'content',
|
||||
},
|
||||
conditions: [
|
||||
{
|
||||
@@ -48,5 +49,27 @@ export const manifests: Array<ManifestTypes> = [
|
||||
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,
|
||||
];
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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<UmbContentTypeModel>(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<UmbContentTypeModel>(this);
|
||||
|
||||
@state()
|
||||
_propertyStructure: Array<UmbPropertyTypeModel> = [];
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<UmbContentTypeModel>(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<UmbContentTypeModel>(this);
|
||||
|
||||
@state()
|
||||
_groups: Array<PropertyTypeContainerModelBaseModel> = [];
|
||||
|
||||
@@ -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` <umb-block-workspace-view-edit-properties
|
||||
.managerName=${this.#managerName}
|
||||
class="properties"
|
||||
container-type="Group"
|
||||
container-name=${groupName || ''}></umb-block-workspace-view-edit-properties>`
|
||||
: html` <uui-box .headline=${boxName || ''}
|
||||
><umb-block-workspace-view-edit-properties
|
||||
.managerName=${this.#managerName}
|
||||
class="properties"
|
||||
container-type="Group"
|
||||
container-name=${groupName || ''}></umb-block-workspace-view-edit-properties
|
||||
|
||||
@@ -1,23 +1,34 @@
|
||||
import { UMB_BLOCK_WORKSPACE_CONTEXT } from '../../block-workspace.context-token.js';
|
||||
import type { UmbBlockWorkspaceElementManagerNames } from '../../block-workspace.context.js';
|
||||
import type { UmbBlockWorkspaceViewEditTabElement } from './block-workspace-view-edit-tab.element.js';
|
||||
import { css, html, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, state, repeat, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type { UmbContentTypeModel } from '@umbraco-cms/backoffice/content-type';
|
||||
import { UmbContentTypeContainerStructureHelper } from '@umbraco-cms/backoffice/content-type';
|
||||
import type {
|
||||
UmbRoute,
|
||||
UmbRouterSlotChangeEvent,
|
||||
UmbRouterSlotInitEvent} from '@umbraco-cms/backoffice/router';
|
||||
import {
|
||||
encodeFolderName
|
||||
} from '@umbraco-cms/backoffice/router';
|
||||
import type { UmbRoute, UmbRouterSlotChangeEvent, UmbRouterSlotInitEvent } from '@umbraco-cms/backoffice/router';
|
||||
import { encodeFolderName } from '@umbraco-cms/backoffice/router';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import type { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import type { UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import type { ManifestWorkspaceView, UmbWorkspaceViewElement } from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
@customElement('umb-block-workspace-view-edit')
|
||||
export class UmbBlockWorkspaceViewEditElement extends UmbLitElement implements UmbWorkspaceViewElement {
|
||||
@property({ attribute: false })
|
||||
public get manifest(): ManifestWorkspaceView | undefined {
|
||||
return;
|
||||
}
|
||||
public set manifest(value: ManifestWorkspaceView | undefined) {
|
||||
this.#managerName = (value?.meta as any).blockElementManagerName ?? 'content';
|
||||
this.#setStructureManager();
|
||||
}
|
||||
#managerName?: UmbBlockWorkspaceElementManagerNames;
|
||||
#blockWorkspace?: typeof UMB_BLOCK_WORKSPACE_CONTEXT.TYPE;
|
||||
#tabsStructureHelper = new UmbContentTypeContainerStructureHelper<UmbContentTypeModel>(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<UmbContentTypeModel>(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;
|
||||
},
|
||||
|
||||
@@ -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`<slot></slot>`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<T extends UmbContentTypeMode
|
||||
|
||||
#structure?: UmbContentTypePropertyStructureManager<T>;
|
||||
|
||||
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<T extends UmbContentTypeMode
|
||||
|
||||
// Containers defined in data might be more than actual containers to display as we merge them by name.
|
||||
// Direct containers are the containers defining the total of this container(Multiple containers with the same name and type)
|
||||
private _ownerAlikeContainers: PropertyTypeContainerModelBaseModel[] = [];
|
||||
private _ownerAlikeContainers: UmbPropertyTypeContainerModel[] = [];
|
||||
// Owner containers are containers owned by the owner Content Type (The specific one up for editing)
|
||||
private _ownerContainers: PropertyTypeContainerModelBaseModel[] = [];
|
||||
private _ownerContainers: UmbPropertyTypeContainerModel[] = [];
|
||||
|
||||
// State containing the merged containers (only one pr. name):
|
||||
#containers = new UmbArrayState<PropertyTypeContainerModelBaseModel>([], (x) => x.id);
|
||||
#containers = new UmbArrayState<UmbPropertyTypeContainerModel>([], (x) => x.id);
|
||||
readonly containers = this.#containers.asObservable();
|
||||
|
||||
#hasProperties = new UmbBooleanState(false);
|
||||
@@ -53,7 +49,7 @@ export class UmbContentTypeContainerStructureHelper<T extends UmbContentTypeMode
|
||||
this._observeOwnerAlikeContainers();
|
||||
}
|
||||
|
||||
public setType(value?: PropertyContainerTypes) {
|
||||
public setType(value?: UmbPropertyContainerTypes) {
|
||||
if (this._ownerType === value) return;
|
||||
this._ownerType = value;
|
||||
this._observeOwnerAlikeContainers();
|
||||
@@ -62,7 +58,7 @@ export class UmbContentTypeContainerStructureHelper<T extends UmbContentTypeMode
|
||||
return this._ownerType;
|
||||
}
|
||||
|
||||
public setContainerChildType(value?: PropertyContainerTypes) {
|
||||
public setContainerChildType(value?: UmbPropertyContainerTypes) {
|
||||
if (this._childType === value) return;
|
||||
this._childType = value;
|
||||
this._observeOwnerAlikeContainers();
|
||||
@@ -173,7 +169,7 @@ export class UmbContentTypeContainerStructureHelper<T extends UmbContentTypeMode
|
||||
);
|
||||
}
|
||||
|
||||
private _insertGroupContainers = (groupContainers: PropertyTypeContainerModelBaseModel[]) => {
|
||||
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<T extends UmbContentTypeMode
|
||||
|
||||
/** Manipulate methods: */
|
||||
|
||||
async insertContainer(container: PropertyTypeContainerModelBaseModel, sortOrder = 0) {
|
||||
async insertContainer(container: UmbPropertyTypeContainerModel, sortOrder = 0) {
|
||||
await this.#init;
|
||||
if (!this.#structure) return false;
|
||||
|
||||
@@ -232,7 +228,7 @@ export class UmbContentTypeContainerStructureHelper<T extends UmbContentTypeMode
|
||||
return true;
|
||||
}
|
||||
|
||||
async partialUpdateContainer(containerId: string, partialUpdate: Partial<PropertyTypeContainerModelBaseModel>) {
|
||||
async partialUpdateContainer(containerId: string, partialUpdate: Partial<UmbPropertyTypeContainerModel>) {
|
||||
await this.#init;
|
||||
if (!this.#structure || !containerId || !partialUpdate) return;
|
||||
|
||||
|
||||
@@ -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<T extends UmbContentTypeModel
|
||||
|
||||
#structure?: UmbContentTypePropertyStructureManager<T>;
|
||||
|
||||
private _containerType?: PropertyContainerTypes;
|
||||
private _containerType?: UmbPropertyContainerTypes;
|
||||
private _isRoot?: boolean;
|
||||
private _containerName?: string;
|
||||
|
||||
@@ -29,8 +26,10 @@ export class UmbContentTypePropertyStructureHelper<T extends UmbContentTypeModel
|
||||
this.#propertyStructure.sortBy((a, b) => ((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<T>) {
|
||||
@@ -40,7 +39,7 @@ export class UmbContentTypePropertyStructureHelper<T extends UmbContentTypeModel
|
||||
this._observeGroupContainers();
|
||||
}
|
||||
|
||||
public setContainerType(value?: PropertyContainerTypes) {
|
||||
public setContainerType(value?: UmbPropertyContainerTypes) {
|
||||
if (this._containerType === value) return;
|
||||
this._containerType = value;
|
||||
this._observeGroupContainers();
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import type { UmbContentTypeModel, UmbPropertyTypeModel } from './types.js';
|
||||
import type {
|
||||
UmbContentTypeModel,
|
||||
UmbPropertyContainerTypes,
|
||||
UmbPropertyTypeContainerModel,
|
||||
UmbPropertyTypeModel,
|
||||
UmbPropertyTypeScaffoldModel,
|
||||
} from './types.js';
|
||||
import type { UmbDetailRepository } from '@umbraco-cms/backoffice/repository';
|
||||
import { UmbId } from '@umbraco-cms/backoffice/id';
|
||||
import type { PropertyTypeContainerModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import type { UmbControllerHost, UmbController } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { MappingFunction } from '@umbraco-cms/backoffice/observable-api';
|
||||
import {
|
||||
@@ -13,10 +18,6 @@ import {
|
||||
import { incrementString } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbBaseController } from '@umbraco-cms/backoffice/class-api';
|
||||
|
||||
export type PropertyContainerTypes = 'Group' | 'Tab';
|
||||
|
||||
// TODO: get this type from the repository, or use some generic type.
|
||||
// TODO: Make this a controller on its own:
|
||||
export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeModel> extends UmbBaseController {
|
||||
#init!: Promise<unknown>;
|
||||
|
||||
@@ -30,8 +31,10 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
x.flatMap((x) => x.containers ?? []),
|
||||
);
|
||||
|
||||
#containers: UmbArrayState<PropertyTypeContainerModelBaseModel> =
|
||||
new UmbArrayState<PropertyTypeContainerModelBaseModel>([], (x) => x.id);
|
||||
#containers: UmbArrayState<UmbPropertyTypeContainerModel> = new UmbArrayState<UmbPropertyTypeContainerModel>(
|
||||
[],
|
||||
(x) => x.id,
|
||||
);
|
||||
|
||||
constructor(host: UmbControllerHost, typeRepository: UmbDetailRepository<T>) {
|
||||
super(host);
|
||||
@@ -178,13 +181,13 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
async createContainer(
|
||||
contentTypeUnique: string | null,
|
||||
parentId: string | null = null,
|
||||
type: PropertyContainerTypes = 'Group',
|
||||
type: UmbPropertyContainerTypes = 'Group',
|
||||
sortOrder?: number,
|
||||
) {
|
||||
await this.#init;
|
||||
contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!;
|
||||
|
||||
const container: PropertyTypeContainerModelBaseModel = {
|
||||
const container: UmbPropertyTypeContainerModel = {
|
||||
id: UmbId.new(),
|
||||
parent: parentId ? { id: parentId } : null,
|
||||
name: '',
|
||||
@@ -205,7 +208,7 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
return container;
|
||||
}
|
||||
|
||||
async insertContainer(contentTypeUnique: string | null, container: PropertyTypeContainerModelBaseModel) {
|
||||
async insertContainer(contentTypeUnique: string | null, container: UmbPropertyTypeContainerModel) {
|
||||
await this.#init;
|
||||
contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!;
|
||||
|
||||
@@ -223,7 +226,7 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
|
||||
makeContainerNameUniqueForOwnerContentType(
|
||||
newName: string,
|
||||
containerType: PropertyContainerTypes = 'Tab',
|
||||
containerType: UmbPropertyContainerTypes = 'Tab',
|
||||
parentId: string | null = null,
|
||||
) {
|
||||
const ownerRootContainers = this.getOwnerContainers(containerType); //getRootContainers() can't differentiates between compositions and locals
|
||||
@@ -242,7 +245,7 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
async updateContainer(
|
||||
contentTypeUnique: string | null,
|
||||
containerId: string,
|
||||
partialUpdate: Partial<PropertyTypeContainerModelBaseModel>,
|
||||
partialUpdate: Partial<UmbPropertyTypeContainerModel>,
|
||||
) {
|
||||
await this.#init;
|
||||
contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!;
|
||||
@@ -273,13 +276,12 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
}
|
||||
|
||||
createPropertyScaffold(containerId: string | null = null, sortOrder?: number) {
|
||||
const property: UmbPropertyTypeModel = {
|
||||
const property: UmbPropertyTypeScaffoldModel = {
|
||||
id: UmbId.new(),
|
||||
containerId: containerId,
|
||||
container: containerId ? { id: containerId } : null,
|
||||
alias: '',
|
||||
name: '',
|
||||
description: '',
|
||||
dataTypeId: '',
|
||||
variesByCulture: false,
|
||||
variesBySegment: false,
|
||||
validation: {
|
||||
@@ -292,7 +294,7 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
labelOnTop: false,
|
||||
},
|
||||
sortOrder: sortOrder ?? 0,
|
||||
} as any; // Sort order was not allowed when this was written.
|
||||
};
|
||||
|
||||
return property;
|
||||
}
|
||||
@@ -301,11 +303,12 @@ export class UmbContentTypePropertyStructureManager<T extends UmbContentTypeMode
|
||||
await this.#init;
|
||||
contentTypeUnique = contentTypeUnique ?? this.#ownerContentTypeUnique!;
|
||||
|
||||
const property: UmbPropertyTypeModel = this.createPropertyScaffold(containerId, sortOrder);
|
||||
const property = this.createPropertyScaffold(containerId, sortOrder);
|
||||
|
||||
const properties = [
|
||||
const properties: Array<UmbPropertyTypeScaffoldModel | UmbPropertyTypeModel> = [
|
||||
...(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<T extends UmbContentTypeMode
|
||||
});
|
||||
}
|
||||
|
||||
rootContainers(containerType: PropertyContainerTypes) {
|
||||
rootContainers(containerType: UmbPropertyContainerTypes) {
|
||||
return this.#containers.asObservablePart((data) => {
|
||||
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<T extends UmbContentTypeMode
|
||||
return this.getOwnerContentType()?.containers?.filter((x) => 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);
|
||||
});
|
||||
|
||||
@@ -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<UmbPropertyTypeModel>;
|
||||
containers: Array<PropertyTypeContainerModelBaseModel>;
|
||||
containers: Array<UmbPropertyTypeContainerModel>;
|
||||
allowedContentTypes: Array<UmbContentTypeSortModel>;
|
||||
compositions: Array<UmbContentTypeCompositionModel>;
|
||||
}
|
||||
|
||||
export interface UmbPropertyTypeScaffoldModel extends Omit<UmbPropertyTypeModel, 'dataType'> {
|
||||
dataType?: UmbPropertyTypeModel['dataType'];
|
||||
}
|
||||
|
||||
export interface UmbPropertyTypeModel extends Omit<PropertyTypeModelBaseModel, 'dataType'> {
|
||||
dataType: { unique: string };
|
||||
}
|
||||
|
||||
@@ -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<
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<UmbPropertyEditorUiElement> {
|
||||
type: 'bockEditorCustomView';
|
||||
}
|
||||
@@ -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<ManifestTypes>
|
||||
| ManifestCondition
|
||||
| ManifestBlockEditorCustomView
|
||||
| ManifestCollection
|
||||
| ManifestCollectionView
|
||||
| ManifestCollectionAction
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './macro.service.js';
|
||||
@@ -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 <?UMBRACO_MACRO macroAlias="Map" />
|
||||
* 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 = `<?UMBRACO_MACRO macroAlias="${args.macroAlias}" `;
|
||||
|
||||
for (const [key, val] of Object.entries(args.macroParamsDictionary)) {
|
||||
//check for null
|
||||
const valOrEmpty = val ?? '';
|
||||
//need to detect if the val is a string or an object
|
||||
let keyVal;
|
||||
if (typeof valOrEmpty === 'string') {
|
||||
keyVal = `${key}="${valOrEmpty}"`;
|
||||
} else {
|
||||
//if it's not a string we'll send it through the json serializer
|
||||
const json = JSON.parse(valOrEmpty);
|
||||
//then we need to url encode it so that it's safe
|
||||
const encoded = encodeURIComponent(json);
|
||||
keyVal = `${key}="${encoded}"`;
|
||||
}
|
||||
|
||||
macroString += keyVal;
|
||||
}
|
||||
|
||||
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>(UmbMacroService.name);
|
||||
@@ -259,7 +259,7 @@ export class UmbPropertySettingsModalElement extends UmbModalBaseElement<
|
||||
.value=${this.value.description}></uui-textarea>
|
||||
</div>
|
||||
<umb-data-type-flow-input
|
||||
.value=${this.value.dataType.unique}
|
||||
.value=${this.value.dataType?.unique}
|
||||
@change=${this.#onDataTypeIdChange}></umb-data-type-flow-input>
|
||||
<hr />
|
||||
<div class="container">
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -66,21 +66,6 @@ const pluginManifests: Array<ManifestTinyMcePlugin> = [
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
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];
|
||||
|
||||
@@ -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<AstNode>) => {
|
||||
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 = `<!-- ${macroObject.syntax} -->`;
|
||||
//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}<ins>Macro alias: <strong>${macroObject.macroAlias}</strong></ins>`,
|
||||
);
|
||||
|
||||
//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');
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,6 @@ const config = new UmbPropertyEditorConfigCollection([
|
||||
'anchor',
|
||||
'table',
|
||||
'umbmediapicker',
|
||||
'umbmacro',
|
||||
'umbembeddialog',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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`<umb-document-type-workspace-view-edit-property
|
||||
data-umb-property-id=${ifDefined(property.id)}
|
||||
data-umb-property-id=${property.id}
|
||||
owner-document-type-id=${ifDefined(inheritedFromDocument?.unique)}
|
||||
owner-document-type-name=${ifDefined(inheritedFromDocument?.name)}
|
||||
?inherited=${property.container?.id !== this.containerId}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { generateAlias } from '@umbraco-cms/backoffice/utils';
|
||||
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
|
||||
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
|
||||
import type { UmbPropertyTypeModel, UmbPropertyTypeScaffoldModel } from '@umbraco-cms/backoffice/content-type';
|
||||
|
||||
/**
|
||||
* @element umb-document-type-workspace-view-edit-property
|
||||
@@ -22,22 +22,22 @@ import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type'
|
||||
*/
|
||||
@customElement('umb-document-type-workspace-view-edit-property')
|
||||
export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement {
|
||||
private _property?: UmbPropertyTypeModel | undefined;
|
||||
private _property?: UmbPropertyTypeModel | UmbPropertyTypeScaffoldModel | undefined;
|
||||
/**
|
||||
* Property, the data object for the property.
|
||||
* @type {UmbPropertyTypeModel}
|
||||
* @type {UmbPropertyTypeModel | UmbPropertyTypeScaffoldModel | undefined}
|
||||
* @attr
|
||||
* @default undefined
|
||||
*/
|
||||
@property({ type: Object })
|
||||
public get property(): UmbPropertyTypeModel | undefined {
|
||||
public get property(): UmbPropertyTypeModel | UmbPropertyTypeScaffoldModel | undefined {
|
||||
return this._property;
|
||||
}
|
||||
public set property(value: UmbPropertyTypeModel | undefined) {
|
||||
public set property(value: UmbPropertyTypeModel | UmbPropertyTypeScaffoldModel | undefined) {
|
||||
const oldValue = this._property;
|
||||
this._property = value;
|
||||
this.#modalRegistration.setUniquePathValue('propertyId', value?.id?.toString());
|
||||
this.setDataType(this._property?.dataType.unique);
|
||||
this.setDataType(this._property?.dataType?.unique);
|
||||
this.requestUpdate('property', oldValue);
|
||||
}
|
||||
|
||||
@@ -96,7 +96,10 @@ export class UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement {
|
||||
return { data: { documentTypeId }, value: propertyData };
|
||||
})
|
||||
.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 UmbDocumentTypeWorkspacePropertyElement extends UmbLitElement {
|
||||
renderPropertyTags() {
|
||||
return this.property
|
||||
? html`<div class="types">
|
||||
${this.property.dataType.unique ? html`<uui-tag look="default">${this._dataTypeName}</uui-tag>` : nothing}
|
||||
${this.property.dataType?.unique ? html`<uui-tag look="default">${this._dataTypeName}</uui-tag>` : nothing}
|
||||
${this.property.variesByCulture
|
||||
? html`<uui-tag look="default">
|
||||
<uui-icon name="icon-shuffle"></uui-icon> ${this.localize.term('contentTypeEditor_cultureVariantLabel')}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<PropertyTypeContainerModelBaseModel>;
|
||||
private _tabs?: Array<PropertyTypeContainerModelBaseModel>;
|
||||
|
||||
@state()
|
||||
private _routerPath?: string;
|
||||
|
||||
@@ -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<UmbMedi
|
||||
appearance: property.appearance,
|
||||
};
|
||||
}),
|
||||
containers: data.containers,
|
||||
containers: data.containers as UmbPropertyTypeContainerModel[],
|
||||
allowedContentTypes: data.allowedMediaTypes.map((allowedMediaType) => {
|
||||
return {
|
||||
contentType: { unique: allowedMediaType.mediaType.id },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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`<div class="types">
|
||||
${this.property.dataType.unique ? html`<uui-tag look="default">${this._dataTypeName}</uui-tag>` : nothing}
|
||||
${this.property.dataType?.unique ? html`<uui-tag look="default">${this._dataTypeName}</uui-tag>` : nothing}
|
||||
${this.property.variesByCulture
|
||||
? html`<uui-tag look="default">
|
||||
<uui-icon name="icon-shuffle"></uui-icon> ${this.localize.term('contentTypeEditor_cultureVariantLabel')}
|
||||
|
||||
@@ -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}>
|
||||
</uui-menu-item>
|
||||
|
||||
<!-- <li>
|
||||
<uui-menu-item class="insert-menu-item" label="Macro" title="Macro"> </uui-menu-item>
|
||||
</li> -->
|
||||
</umb-dropdown>
|
||||
</uui-button-group>
|
||||
`;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -256,12 +256,15 @@ export default class UmbTemplateQueryBuilderModalElement extends UmbModalBaseEle
|
||||
</uui-button>`
|
||||
: ''}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row query-results">
|
||||
<span id="results-count">
|
||||
${this._templateQuery?.resultCount ?? 0}
|
||||
<umb-localize key="template_itemsReturned">items returned, in</umb-localize>
|
||||
${this._templateQuery?.executionTime ?? 0} ms
|
||||
</span>
|
||||
${this._templateQuery?.sampleResults.map(
|
||||
(sample) => html`<span><uui-icon name=${sample.icon}></uui-icon>${sample.name}</span>`,
|
||||
) ?? ''}
|
||||
</div>
|
||||
<umb-code-block language="C#" copy>${this._templateQuery?.queryExpression ?? ''}</umb-code-block>
|
||||
</uui-box>
|
||||
@@ -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);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user