fix static files value

This commit is contained in:
Niels Lyngsø
2024-07-02 16:07:33 +02:00
parent dd82a70641
commit 8569ef17f4
16 changed files with 178 additions and 58 deletions

View File

@@ -1,12 +1,9 @@
import { UmbBlockGridEntriesContext } from '../../context/block-grid-entries.context.js';
import type { UmbBlockGridEntryElement } from '../block-grid-entry/index.js';
import {
getAccumulatedValueOfIndex,
getInterpolatedIndexOfPositionInWeightMap,
isWithinRect,
} from '@umbraco-cms/backoffice/utils';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
import { html, customElement, state, repeat, css, property, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import '../block-grid-entry/index.js';
@@ -17,6 +14,9 @@ import {
type UmbFormControlValidatorConfig,
} from '@umbraco-cms/backoffice/validation';
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
import { UmbBlockGridEntriesContext } from '../../context/block-grid-entries.context.js';
import type { UmbBlockGridEntryElement } from '../block-grid-entry/index.js';
import type { UmbBlockGridLayoutModel } from '@umbraco-cms/backoffice/block-grid';
/**
* Notice this utility method is not really shareable with others as it also takes areas into account. [NL]
@@ -210,6 +210,7 @@ export class UmbBlockGridEntriesElement extends UmbFormControlMixin(UmbLitElemen
this.observe(
manager.layoutStylesheet,
(stylesheet) => {
if (!stylesheet) return;
if (this._styleElement && this._styleElement.href === stylesheet) return;
this._styleElement = document.createElement('link');
this._styleElement.setAttribute('rel', 'stylesheet');

View File

@@ -1,6 +1,10 @@
import { UmbArrayState, appendToFrozenArray, pushAtToUniqueArray } from '@umbraco-cms/backoffice/observable-api';
import { removeInitialSlashFromPath, transformServerPathToClientPath } from '@umbraco-cms/backoffice/utils';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbBlockGridLayoutModel, UmbBlockGridTypeModel } from '../types.js';
import type { UmbBlockGridWorkspaceData } from '../index.js';
import { UmbArrayState, appendToFrozenArray, pushAtToUniqueArray } from '@umbraco-cms/backoffice/observable-api';
import { type UmbBlockDataType, UmbBlockManagerContext } from '@umbraco-cms/backoffice/block';
import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type';
@@ -13,17 +17,34 @@ export class UmbBlockGridManagerContext<
BlockLayoutType extends UmbBlockGridLayoutModel = UmbBlockGridLayoutModel,
> extends UmbBlockManagerContext<UmbBlockGridTypeModel, UmbBlockGridLayoutModel> {
//
#initAppUrl: Promise<void>;
#appUrl?: string;
#blockGroups = new UmbArrayState(<Array<UmbBlockTypeGroup>>[], (x) => x.key);
public readonly blockGroups = this.#blockGroups.asObservable();
layoutStylesheet = this._editorConfiguration.asObservablePart(
(x) => (x?.getValueByAlias('layoutStylesheet') as string) ?? UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET,
);
layoutStylesheet = this._editorConfiguration.asObservablePart((x) => {
if (!x) return undefined;
const layoutStylesheet = x.getValueByAlias<string>('layoutStylesheet');
if (!layoutStylesheet) return UMB_BLOCK_GRID_DEFAULT_LAYOUT_STYLESHEET;
if (layoutStylesheet) {
// Cause we await initAppUrl in setting the _editorConfiguration, we can trust the appUrl begin here.
return this.#appUrl! + removeInitialSlashFromPath(transformServerPathToClientPath(layoutStylesheet));
}
return undefined;
});
gridColumns = this._editorConfiguration.asObservablePart((x) => {
const value = x?.getValueByAlias('gridColumns') as string | undefined;
return parseInt(value && value !== '' ? value : '12');
});
override setEditorConfiguration(configs: UmbPropertyEditorConfigCollection) {
this.#initAppUrl.then(() => {
// we await initAppUrl, So the appUrl begin here is available when retrieving the layoutStylesheet.
this._editorConfiguration.setValue(configs);
});
}
setBlockGroups(blockGroups: Array<UmbBlockTypeGroup>) {
this.#blockGroups.setValue(blockGroups);
}
@@ -31,6 +52,14 @@ export class UmbBlockGridManagerContext<
return this.#blockGroups.value;
}
constructor(host: UmbControllerHost) {
super(host);
this.#initAppUrl = this.getContext(UMB_APP_CONTEXT).then((appContext) => {
this.#appUrl = appContext.getServerUrl() + appContext.getBackofficePath();
});
}
create(
contentElementTypeKey: string,
partialLayoutEntry?: Omit<BlockLayoutType, 'contentUdi'>,

View File

@@ -1,7 +1,7 @@
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { manifests as componentManifests } from './components/manifests.js';
import { manifests as propertyEditorManifests } from './property-editors/manifests.js';
import { manifests as workspaceManifests } from './workspace/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes> = [
...workspaceManifests,

View File

@@ -1,5 +1,5 @@
import { manifest as blockGridSchemaManifest } from './Umbraco.BlockGrid.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { manifest as blockGridSchemaManifest } from './Umbraco.BlockGrid.js';
export const UMB_BLOCK_GRID_PROPERTY_EDITOR_ALIAS = 'Umbraco.BlockGrid';
@@ -55,6 +55,12 @@ export const manifests: Array<ManifestTypes> = [
label: 'Layout Stylesheet',
description: 'Override default stylesheet for backoffice layout.',
propertyEditorUiAlias: 'Umb.PropertyEditorUi.BlockGridLayoutStylesheet',
config: [
{
alias: 'singleItemMode',
value: true,
},
],
},
],
},

View File

@@ -1,16 +1,16 @@
import { UmbBlockGridManagerContext } from '../../context/block-grid-manager.context.js';
import { UMB_BLOCK_GRID_PROPERTY_EDITOR_ALIAS } from './manifests.js';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { html, customElement, property, state, css, type PropertyValueMap } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type';
import type { UmbBlockGridTypeModel, UmbBlockGridValueModel } from '@umbraco-cms/backoffice/block-grid';
import '../../components/block-grid-entries/index.js';
import { observeMultiple } from '@umbraco-cms/backoffice/observable-api';
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
import { UmbBlockGridManagerContext } from '../../context/block-grid-manager.context.js';
import { UMB_BLOCK_GRID_PROPERTY_EDITOR_ALIAS } from './manifests.js';
import type { UmbBlockTypeGroup } from '@umbraco-cms/backoffice/block-type';
import type { UmbBlockGridTypeModel, UmbBlockGridValueModel } from '@umbraco-cms/backoffice/block-grid';
/**
* @element umb-property-editor-ui-block-grid

View File

@@ -3,7 +3,7 @@
import type { UmbInputStaticFileElement } from '@umbraco-cms/backoffice/static-file';
// eslint-disable-next-line import/no-duplicates
import '@umbraco-cms/backoffice/static-file';
import { html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/extension-registry';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import {
@@ -11,29 +11,61 @@ import {
type UmbPropertyEditorConfigCollection,
} from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { UmbServerFilePathUniqueSerializer } from '@umbraco-cms/backoffice/server-file-system';
import type { UmbNumberRangeValueType } from '@umbraco-cms/backoffice/models';
@customElement('umb-property-editor-ui-block-grid-layout-stylesheet')
export class UmbPropertyEditorUIBlockGridLayoutStylesheetElement
extends UmbLitElement
implements UmbPropertyEditorUiElement
{
private _value: Array<string> = [];
#pickableFilter = (item: any) => item.unique.endsWith('css');
#singleItemMode = false;
// TODO: get rid of UmbServerFilePathUniqueSerializer in v.15 [NL]
#serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer();
@property({ type: Array })
public set value(value: Array<string>) {
this._value = value || [];
}
public get value(): Array<string> {
return this._value;
}
private _pickableFilter = (item: any) => item.unique.endsWith('css');
@state()
private _value?: string | Array<string>;
@property({ attribute: false })
public config?: UmbPropertyEditorConfigCollection;
public set value(value: string | Array<string> | undefined) {
if (Array.isArray(value)) {
this._value = value.map((unique) => this.#serverFilePathUniqueSerializer.toUnique(unique));
} else if (value) {
this._value = this.#serverFilePathUniqueSerializer.toUnique(value);
} else {
this._value = undefined;
}
}
public get value(): string | Array<string> | undefined {
if (Array.isArray(this._value)) {
return this._value.map((unique) => this.#serverFilePathUniqueSerializer.toServerPath(unique) ?? '');
} else if (this._value) {
return this.#serverFilePathUniqueSerializer.toServerPath(this._value) ?? '';
} else {
return undefined;
}
}
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this.#singleItemMode = config?.getValueByAlias<boolean>('singleItemMode') ?? false;
const validationLimit = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this._limitMin = validationLimit?.min ?? 0;
this._limitMax = this.#singleItemMode ? 1 : validationLimit?.max ?? Infinity;
}
@state()
private _limitMin: number = 0;
@state()
private _limitMax: number = Infinity;
private _onChange(event: CustomEvent) {
this.value = (event.target as UmbInputStaticFileElement).selection;
if (this.#singleItemMode) {
this._value = (event.target as UmbInputStaticFileElement).selection[0];
} else {
this._value = (event.target as UmbInputStaticFileElement).selection;
}
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}
@@ -42,10 +74,10 @@ export class UmbPropertyEditorUIBlockGridLayoutStylesheetElement
return html`
<umb-input-static-file
@change=${this._onChange}
.pickableFilter=${this._pickableFilter}
.selection=${this._value}
.min=${0}
.max=${1}></umb-input-static-file>
.pickableFilter=${this.#pickableFilter}
.selection=${this._value ? (Array.isArray(this._value) ? this._value : [this._value]) : []}
.min=${this._limitMin}
.max=${this._limitMax}></umb-input-static-file>
<br />
<a href="/umbraco/backoffice/assets/css/umbraco-blockgridlayout.css">Link to default layout stylesheet</a>
`;

View File

@@ -1,3 +1,4 @@
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
import { manifest as blockGridAreaTypePermission } from './block-grid-area-type-permission/manifests.js';
import { manifest as blockGridAreasConfigEditor } from './block-grid-areas-config/manifests.js';
import { manifest as blockGridColumnSpan } from './block-grid-column-span/manifests.js';
@@ -5,7 +6,6 @@ import { manifests as blockGridEditorManifests } from './block-grid-editor/manif
import { manifest as blockGridGroupConfiguration } from './block-grid-group-configuration/manifests.js';
import { manifest as blockGridLayoutStylesheet } from './block-grid-layout-stylesheet/manifests.js';
import { manifest as blockGridTypeConfiguration } from './block-grid-type-configuration/manifests.js';
import type { ManifestTypes } from '@umbraco-cms/backoffice/extension-registry';
export const manifests: Array<ManifestTypes> = [
blockGridAreaTypePermission,

View File

@@ -5,10 +5,15 @@ import {
import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
import { UmbRepositoryItemsManager } from '@umbraco-cms/backoffice/repository';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_APP_CONTEXT } from '@umbraco-cms/backoffice/app';
import { removeInitialSlashFromPath, transformServerPathToClientPath } from '@umbraco-cms/backoffice/utils';
@customElement('umb-block-type-card')
export class UmbBlockTypeCardElement extends UmbLitElement {
//
#init: Promise<void>;
#appUrl?: string;
#itemManager = new UmbRepositoryItemsManager<UmbDocumentTypeItemModel>(
this,
UMB_DOCUMENT_TYPE_ITEM_REPOSITORY_ALIAS,
@@ -19,7 +24,18 @@ export class UmbBlockTypeCardElement extends UmbLitElement {
href?: string;
@property({ type: String, attribute: false })
iconFile?: string;
public set iconFile(value: string | undefined) {
value = transformServerPathToClientPath(value);
if (value) {
this.#init.then(() => {
this._iconFile = this.#appUrl! + removeInitialSlashFromPath(value);
});
} else {
this._iconFile = undefined;
}
}
@state()
private _iconFile?: string | undefined;
@property({ type: String, attribute: false })
iconColor?: string;
@@ -55,6 +71,10 @@ export class UmbBlockTypeCardElement extends UmbLitElement {
constructor() {
super();
this.#init = this.getContext(UMB_APP_CONTEXT).then((appContext) => {
this.#appUrl = appContext.getServerUrl() + appContext.getBackofficePath();
});
this.observe(this.#itemManager.items, (items) => {
const item = items[0];
if (item) {
@@ -73,8 +93,8 @@ export class UmbBlockTypeCardElement extends UmbLitElement {
.name=${this._name ?? 'Unknown'}
.description=${this._description}
.background=${this.backgroundColor}>
${this.iconFile
? html`<img src=${this.iconFile} alt="" />`
${this._iconFile
? html`<img src=${this._iconFile} alt="" />`
: html`<umb-icon name=${this._fallbackIcon ?? ''} style="color:${this.iconColor}"></umb-icon>`}
<slot name="actions" slot="actions"> </slot>
</uui-card-block-type>

View File

@@ -1,16 +1,16 @@
import type { UmbTreeItemContext } from '../tree-item-context.interface.js';
import { UMB_TREE_CONTEXT, type UmbDefaultTreeContext } from '../../default/index.js';
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
import { UmbRequestReloadTreeItemChildrenEvent } from '../../entity-actions/reload-tree-item-children/index.js';
import { map } from '@umbraco-cms/backoffice/external/rxjs';
import { UMB_SECTION_CONTEXT, UMB_SECTION_SIDEBAR_CONTEXT } from '@umbraco-cms/backoffice/section';
import type { UmbSectionContext, UmbSectionSidebarContext } from '@umbraco-cms/backoffice/section';
import type { ManifestTreeItem } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UmbArrayState, UmbBooleanState, UmbObjectState, UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import type { UmbTreeItemContext } from '../tree-item-context.interface.js';
import { UMB_TREE_CONTEXT, type UmbDefaultTreeContext } from '../../default/index.js';
import type { UmbTreeItemModel, UmbTreeRootModel } from '../../types.js';
import { UmbRequestReloadTreeItemChildrenEvent } from '../../entity-actions/reload-tree-item-children/index.js';
import { UMB_SECTION_CONTEXT, UMB_SECTION_SIDEBAR_CONTEXT } from '@umbraco-cms/backoffice/section';
import type { UmbSectionContext, UmbSectionSidebarContext } from '@umbraco-cms/backoffice/section';
import type { ManifestTreeItem } from '@umbraco-cms/backoffice/extension-registry';
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
import { UMB_ACTION_EVENT_CONTEXT, type UmbActionEventContext } from '@umbraco-cms/backoffice/action';
import {
UmbRequestReloadChildrenOfEntityEvent,
@@ -407,6 +407,7 @@ export abstract class UmbTreeItemContextBase<
// TODO: use router context
constructPath(pathname: string, entityType: string, unique: string | null) {
// TODO: Encode uniques [NL]
return `section/${pathname}/workspace/${entityType}/edit/${unique}`;
}

View File

@@ -11,7 +11,9 @@ export * from './path/has-own-opener.function.js';
export * from './path/path-decode.function.js';
export * from './path/path-encode.function.js';
export * from './path/path-folder-name.function.js';
export * from './path/remove-initial-slash-from-path.function.js';
export * from './path/stored-path.function.js';
export * from './path/transform-server-path-to-client-path.function.js';
export * from './path/umbraco-path.function.js';
export * from './path/url-pattern-to-string.function.js';
export * from './selection-manager/selection.manager.js';

View File

@@ -0,0 +1,3 @@
export function removeInitialSlashFromPath(path: string) {
return path.startsWith('/') ? path.slice(1) : path;
}

View File

@@ -0,0 +1,11 @@
type StringMaybeUndefined = string | undefined;
export function transformServerPathToClientPath<T extends StringMaybeUndefined>(path: T): T {
if (path?.indexOf('~/') === 0) {
path = path.slice(1) as T;
}
if (path?.indexOf('/wwwroot/') === 0) {
path = path.slice(8) as T;
}
return path;
}

View File

@@ -141,7 +141,7 @@ export class UmbInputStaticFileElement extends UmbFormControlMixin<string | unde
if (!item.unique) return;
return html`
<uui-ref-node name=${item.name} .detail=${this.#serializer.toServerPath(item.unique) || ''}>
<!-- TODO: implement is trashed <uui-tag size="s" slot="tag" color="danger">Trashed</uui-tag> -->
<!-- TODO: implement is trashed, if we cant retrieve the item on the server (but only ask the server if we need to anyway...). <uui-tag size="s" slot="tag" color="danger">Trashed</uui-tag> -->
<uui-action-bar slot="actions">
<uui-button
label=${this.localize.term('general_remove')}

View File

@@ -8,40 +8,55 @@ import {
type UmbPropertyEditorConfigCollection,
} from '@umbraco-cms/backoffice/property-editor';
import '../../components/input-static-file/index.js';
import { UmbServerFilePathUniqueSerializer } from '@umbraco-cms/backoffice/server-file-system';
@customElement('umb-property-editor-ui-static-file-picker')
export class UmbPropertyEditorUIStaticFilePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
private _singleItemMode = false;
#singleItemMode = false;
// TODO: get rid of UmbServerFilePathUniqueSerializer in v.15 [NL]
#serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer();
@state()
private _value?: string | Array<string>;
@property({ attribute: false })
public set value(value: string | Array<string> | undefined) {
this._value = value;
if (Array.isArray(value)) {
this._value = value.map((unique) => this.#serverFilePathUniqueSerializer.toUnique(unique));
} else if (value) {
this._value = this.#serverFilePathUniqueSerializer.toUnique(value);
} else {
this._value = undefined;
}
}
public get value() {
return this._value;
public get value(): string | Array<string> | undefined {
if (Array.isArray(this._value)) {
return this._value.map((unique) => this.#serverFilePathUniqueSerializer.toServerPath(unique) ?? '');
} else if (this._value) {
return this.#serverFilePathUniqueSerializer.toServerPath(this._value) ?? '';
} else {
return undefined;
}
}
public set config(config: UmbPropertyEditorConfigCollection | undefined) {
this._singleItemMode = config?.getValueByAlias<boolean>('singleItemMode') ?? false;
this.#singleItemMode = config?.getValueByAlias<boolean>('singleItemMode') ?? false;
const validationLimit = config?.getValueByAlias<UmbNumberRangeValueType>('validationLimit');
this._limitMin = validationLimit?.min;
this._limitMax = validationLimit?.max;
this._limitMin = validationLimit?.min ?? 0;
this._limitMax = this.#singleItemMode ? 1 : validationLimit?.max ?? Infinity;
}
@state()
private _limitMin?: number;
private _limitMin: number = 0;
@state()
private _limitMax?: number;
private _limitMax: number = Infinity;
private _onChange(event: CustomEvent) {
if (this._singleItemMode) {
this.value = (event.target as UmbInputStaticFileElement).selection[0];
if (this.#singleItemMode) {
this._value = (event.target as UmbInputStaticFileElement).selection[0];
} else {
this.value = (event.target as UmbInputStaticFileElement).selection;
this._value = (event.target as UmbInputStaticFileElement).selection;
}
this.dispatchEvent(new UmbPropertyValueChangeEvent());
}

View File

@@ -6,7 +6,6 @@ import { UmbStylesheetWorkspaceEditorElement } from './stylesheet-workspace-edit
import {
type UmbSubmittableWorkspaceContext,
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceRouteManager,
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
} from '@umbraco-cms/backoffice/workspace';
@@ -64,6 +63,7 @@ export class UmbStylesheetWorkspaceContext
path: 'edit/:unique',
component: UmbStylesheetWorkspaceEditorElement,
setup: (component: PageComponent, info: IRoutingInfo) => {
// TODO: Decode uniques [NL]
const unique = info.match.params.unique;
this.load(unique);
},

View File

@@ -14,6 +14,8 @@ export class UmbPropertyEditorUITinyMceStylesheetsConfigurationElement
extends UmbLitElement
implements UmbPropertyEditorUiElement
{
#serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer();
@property({ type: Array })
public set value(value: Array<string>) {
if (!value) return;
@@ -28,8 +30,6 @@ export class UmbPropertyEditorUITinyMceStylesheetsConfigurationElement
@property({ type: Object, attribute: false })
public config?: UmbPropertyEditorConfigCollection;
#serverFilePathUniqueSerializer = new UmbServerFilePathUniqueSerializer();
#onChange(event: CustomEvent) {
const target = event.target as UmbStylesheetInputElement;
this.#value = target.selection ?? [];