Merge remote-tracking branch 'origin/main' into feature/property-editor-ui-config-collection
# Conflicts: # src/packages/core/workspace/workspace-property/workspace-property.context.ts
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
"Backoffice",
|
||||
"combobox",
|
||||
"Elementable",
|
||||
"invariantable",
|
||||
"Niels",
|
||||
"pickable",
|
||||
"Registrator",
|
||||
"templating",
|
||||
"tinymce",
|
||||
"umbraco",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
export const manifests = [
|
||||
{
|
||||
type: 'section',
|
||||
alias: 'MyBundle.Section.Custom',
|
||||
name: 'Custom Section',
|
||||
js: '/App_Plugins/section.js',
|
||||
weight: 1,
|
||||
meta: {
|
||||
label: 'My Bundle Section',
|
||||
pathname: 'my-custom-bundle',
|
||||
},
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "My Package Name",
|
||||
"version": "1.0.0",
|
||||
"extensions": [
|
||||
{
|
||||
"type": "bundle",
|
||||
"alias": "My.Package.Bundle",
|
||||
"name": "My Package Bundle",
|
||||
"js": "/App_Plugins/custom-bundle-package/index.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
console.log('Hello from the custom entrypoint file!');
|
||||
export default function () {
|
||||
console.log('Hello from the custom entrypoint inside the default function!');
|
||||
export function onInit() {
|
||||
console.log('Hello from the custom entrypoint inside the onInit function!');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbBackofficeContext, UMB_BACKOFFICE_CONTEXT_TOKEN } from './backoffice.context.js';
|
||||
import { UmbExtensionInitializer } from './extension-initializer.controller.js';
|
||||
import { UmbServerExtensionRegistrator } from './server-extension-registrator.controller.js';
|
||||
import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import {
|
||||
@@ -28,14 +28,28 @@ const CORE_PACKAGES = [
|
||||
|
||||
@customElement('umb-backoffice')
|
||||
export class UmbBackofficeElement extends UmbLitElement {
|
||||
|
||||
/**
|
||||
* Backoffice extension registry.
|
||||
* This enables to register and unregister extensions via DevTools, or just via querying this element via the DOM.
|
||||
* @type {UmbExtensionsRegistry}
|
||||
*/
|
||||
public extensionRegistry = umbExtensionsRegistry;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.provideContext(UMB_BACKOFFICE_CONTEXT_TOKEN, new UmbBackofficeContext(this));
|
||||
new UmbBundleExtensionInitializer(this, umbExtensionsRegistry);
|
||||
new UmbEntryPointExtensionInitializer(this, umbExtensionsRegistry);
|
||||
new UmbServerExtensionRegistrator(this, umbExtensionsRegistry);
|
||||
|
||||
// So far local packages are this simple to registerer, so no need for a manager to do that:
|
||||
CORE_PACKAGES.forEach(async (packageImport) => {
|
||||
const packageModule = await packageImport;
|
||||
umbExtensionsRegistry.registerMany(packageModule.extensions);
|
||||
});
|
||||
|
||||
const extensionInitializer = new UmbExtensionInitializer(this, umbExtensionsRegistry);
|
||||
extensionInitializer.setLocalPackages(CORE_PACKAGES);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,44 +1,22 @@
|
||||
import { Subject } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { PackageResource, OpenAPI } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbBaseController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBackofficeExtensionRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
|
||||
import { ManifestBase, isManifestJSType } from '@umbraco-cms/backoffice/extension-api';
|
||||
|
||||
// TODO: consider if this can be replaced by the new extension controllers.
|
||||
// TODO: consider if this can be replaced by the new extension controllers
|
||||
// TODO: move local part out of this, and name something with server.
|
||||
export class UmbExtensionInitializer extends UmbBaseController {
|
||||
export class UmbServerExtensionRegistrator extends UmbBaseController {
|
||||
#extensionRegistry: UmbBackofficeExtensionRegistry;
|
||||
#unobserve = new Subject<void>();
|
||||
#localPackages: Array<Promise<any>> = [];
|
||||
#apiBaseUrl = OpenAPI.BASE;
|
||||
|
||||
constructor(host: UmbControllerHost, extensionRegistry: UmbBackofficeExtensionRegistry) {
|
||||
super(host, UmbExtensionInitializer.name);
|
||||
super(host, UmbServerExtensionRegistrator.name);
|
||||
this.#extensionRegistry = extensionRegistry;
|
||||
}
|
||||
|
||||
setLocalPackages(localPackages: Array<Promise<any>>) {
|
||||
this.#localPackages = localPackages;
|
||||
this.#loadLocalPackages();
|
||||
}
|
||||
|
||||
hostConnected(): void {
|
||||
// TODO: This was before in hostConnected(), but I don't see the reason to wait. lets just do it right away.
|
||||
this.#loadServerPackages();
|
||||
}
|
||||
|
||||
hostDisconnected(): void {
|
||||
this.#unobserve.next();
|
||||
this.#unobserve.complete();
|
||||
}
|
||||
|
||||
async #loadLocalPackages() {
|
||||
this.#localPackages.forEach(async (packageImport) => {
|
||||
const packageModule = await packageImport;
|
||||
this.#extensionRegistry.registerMany(packageModule.extensions);
|
||||
});
|
||||
}
|
||||
|
||||
async #loadServerPackages() {
|
||||
/* TODO: we need a new endpoint here, to remove the dependency on the package repository, to get the modules available for the backoffice scope
|
||||
/ we will need a similar endpoint for the login, installer etc at some point.
|
||||
@@ -1,15 +1,16 @@
|
||||
import type { ManifestBase, ManifestBundle } from './types.js';
|
||||
import { loadExtension } from './load-extension.function.js';
|
||||
import { UmbExtensionRegistry } from './registry/extension.registry.js';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export class UmbBundleExtensionInitializer {
|
||||
export class UmbBundleExtensionInitializer extends UmbBaseController {
|
||||
#extensionRegistry;
|
||||
#bundleMap = new Map();
|
||||
|
||||
constructor(host: UmbControllerHostElement, extensionRegistry: UmbExtensionRegistry<ManifestBundle>) {
|
||||
super(host);
|
||||
this.#extensionRegistry = extensionRegistry;
|
||||
extensionRegistry.extensionsOfType('bundle').subscribe((bundles) => {
|
||||
this.observe(extensionRegistry.extensionsOfType('bundle'), (bundles) => {
|
||||
// Unregister removed bundles:
|
||||
this.#bundleMap.forEach((existingBundle) => {
|
||||
if (!bundles.find((b) => b.alias === existingBundle.alias)) {
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
import { UmbBaseController } from '../controller-api/controller.class.js';
|
||||
import type { ManifestEntryPoint } from './types.js';
|
||||
import { hasInitExport } from './has-init-export.function.js';
|
||||
import { loadExtension } from './load-extension.function.js';
|
||||
import { UmbExtensionRegistry } from './registry/extension.registry.js';
|
||||
import { UmbElement } from '@umbraco-cms/backoffice/element-api';
|
||||
|
||||
export class UmbEntryPointExtensionInitializer {
|
||||
export class UmbEntryPointExtensionInitializer extends UmbBaseController {
|
||||
|
||||
#host;
|
||||
#extensionRegistry;
|
||||
#entryPointMap = new Map();
|
||||
|
||||
constructor(host: UmbElement, extensionRegistry: UmbExtensionRegistry<ManifestEntryPoint>) {
|
||||
super(host);
|
||||
this.#host = host;
|
||||
this.#extensionRegistry = extensionRegistry;
|
||||
extensionRegistry.extensionsOfType('entryPoint').subscribe((entryPoints) => {
|
||||
this.observe(extensionRegistry.extensionsOfType('entryPoint'), (entryPoints) => {
|
||||
entryPoints.forEach((entryPoint) => {
|
||||
if (this.#entryPointMap.has(entryPoint.alias)) return;
|
||||
this.#entryPointMap.set(entryPoint.alias, entryPoint);
|
||||
|
||||
@@ -8,6 +8,18 @@ export const manifestDevelopmentHandler = rest.get(umbracoPath('/package/manifes
|
||||
// Respond with a 200 status code
|
||||
ctx.status(200),
|
||||
ctx.json<PackageManifestResponse>([
|
||||
{
|
||||
name: 'My Package Name',
|
||||
version: '1.0.0',
|
||||
extensions: [
|
||||
{
|
||||
type: 'bundle',
|
||||
alias: 'My.Package.Bundle',
|
||||
name: 'My Package Bundle',
|
||||
js: '/App_Plugins/custom-bundle-package/index.js',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Named Package',
|
||||
version: '1.0.0',
|
||||
|
||||
@@ -51,12 +51,12 @@ export class UmbCollectionSelectionActionsElement extends UmbLitElement {
|
||||
// TODO: Make sure it only updates on length change.
|
||||
this.observe(this._collectionContext.items, (mediaItems) => {
|
||||
this._nodesLength = mediaItems.length;
|
||||
});
|
||||
}, 'observeItem');
|
||||
|
||||
this.observe(this._collectionContext.selection, (selection) => {
|
||||
this._selectionLength = selection.length;
|
||||
this._selection = selection;
|
||||
});
|
||||
}, 'observeSelection');
|
||||
}
|
||||
|
||||
private _renderSelectionCount() {
|
||||
@@ -74,6 +74,7 @@ export class UmbCollectionSelectionActionsElement extends UmbLitElement {
|
||||
(bulkActions) => {
|
||||
this._entityBulkActions = bulkActions;
|
||||
}
|
||||
, 'observeEntityBulkActions'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,22 @@
|
||||
import { html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import {
|
||||
PropertyEditorConfigDefaultData,
|
||||
PropertyEditorConfigProperty,
|
||||
umbExtensionsRegistry,
|
||||
} from '@umbraco-cms/backoffice/extension-registry';
|
||||
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT } from '@umbraco-cms/backoffice/property-editor';
|
||||
import { UMB_DATA_TYPE_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/data-type';
|
||||
|
||||
/**
|
||||
* @element umb-property-editor-config
|
||||
* @description - Element for displaying the configuration for a Property Editor based on a Property Editor UI Alias and a Property Editor Model alias.
|
||||
* @element umb-property-editor-config
|
||||
* @description - Element for displaying the configuration for a Property Editor based on a Property Editor UI Alias and a Property Editor Model alias.
|
||||
* This element requires a UMB_DATA_TYPE_WORKSPACE_CONTEXT to be present.
|
||||
*/
|
||||
@customElement('umb-property-editor-config')
|
||||
export class UmbPropertyEditorConfigElement extends UmbLitElement {
|
||||
/**
|
||||
* Property Editor UI Alias. The element will render configuration for a Property Editor UI with this alias.
|
||||
* @type {string}
|
||||
* @attr
|
||||
* @default ''
|
||||
*/
|
||||
private _propertyEditorUiAlias = '';
|
||||
@property({ type: String, attribute: 'property-editor-ui-alias' })
|
||||
public get propertyEditorUiAlias(): string {
|
||||
return this._propertyEditorUiAlias;
|
||||
}
|
||||
public set propertyEditorUiAlias(value: string) {
|
||||
const oldVal = this._propertyEditorUiAlias;
|
||||
this._propertyEditorUiAlias = value;
|
||||
this.requestUpdate('propertyEditorUiAlias', oldVal);
|
||||
this._observePropertyEditorUIConfig();
|
||||
}
|
||||
|
||||
// TODO: Make this element generic, so its not bound to DATA-TYPEs. This will require moving some functionality of Data-Type-Context to this. and this might need to self provide a variant Context for its inner property editor UIs.
|
||||
#variantContext?: typeof UMB_DATA_TYPE_VARIANT_CONTEXT.TYPE;
|
||||
|
||||
/**
|
||||
* Data. The element will render configuration editors with values from this data.
|
||||
@@ -46,62 +31,17 @@ export class UmbPropertyEditorConfigElement extends UmbLitElement {
|
||||
@state()
|
||||
private _properties: Array<PropertyEditorConfigProperty> = [];
|
||||
|
||||
private _propertyEditorSchemaConfigDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
private _propertyEditorUISettingsDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
|
||||
private _configDefaultData?: Array<PropertyEditorConfigDefaultData>;
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
private _propertyEditorSchemaConfigProperties: Array<PropertyEditorConfigProperty> = [];
|
||||
private _propertyEditorUISettingsProperties: Array<PropertyEditorConfigProperty> = [];
|
||||
this.consumeContext(UMB_DATA_TYPE_VARIANT_CONTEXT, (instance) => {
|
||||
this.#variantContext = instance;
|
||||
this.observe(this.#variantContext.properties, (properties) => {
|
||||
this._properties = properties as Array<PropertyEditorConfigProperty>;
|
||||
}, 'observeProperties');
|
||||
});
|
||||
|
||||
private _observePropertyEditorUIConfig() {
|
||||
if (!this._propertyEditorUiAlias) return;
|
||||
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', this.propertyEditorUiAlias),
|
||||
(manifest) => {
|
||||
this._observePropertyEditorSchemaConfig(
|
||||
manifest?.meta.propertyEditorSchemaAlias || UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT
|
||||
);
|
||||
this._propertyEditorUISettingsProperties = manifest?.meta.settings?.properties || [];
|
||||
this._propertyEditorUISettingsDefaultData = manifest?.meta.settings?.defaultData || [];
|
||||
this._mergeConfigProperties();
|
||||
this._mergeConfigDefaultData();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _observePropertyEditorSchemaConfig(propertyEditorSchemaAlias: string) {
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorSchema', propertyEditorSchemaAlias),
|
||||
(manifest) => {
|
||||
this._propertyEditorSchemaConfigProperties = manifest?.meta.settings?.properties || [];
|
||||
this._propertyEditorSchemaConfigDefaultData = manifest?.meta.settings?.defaultData || [];
|
||||
this._mergeConfigProperties();
|
||||
this._mergeConfigDefaultData();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _mergeConfigProperties() {
|
||||
this._properties = [...this._propertyEditorSchemaConfigProperties, ...this._propertyEditorUISettingsProperties];
|
||||
}
|
||||
|
||||
private _mergeConfigDefaultData() {
|
||||
this._configDefaultData = [
|
||||
...this._propertyEditorSchemaConfigDefaultData,
|
||||
...this._propertyEditorUISettingsDefaultData,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored value for a property. It will render the default value from the configuration if no value is stored in the database.
|
||||
*/
|
||||
private _getValue(property: PropertyEditorConfigProperty) {
|
||||
const value = this.data.find((data) => data.alias === property.alias)?.value;
|
||||
if (value) return value;
|
||||
const defaultValue = this._configDefaultData?.find((data) => data.alias === property.alias)?.value;
|
||||
return defaultValue ?? null;
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -115,7 +55,6 @@ export class UmbPropertyEditorConfigElement extends UmbLitElement {
|
||||
description="${ifDefined(property.description)}"
|
||||
alias="${property.alias}"
|
||||
property-editor-ui-alias="${property.propertyEditorUiAlias}"
|
||||
.value=${this._getValue(property)}
|
||||
.config=${property.config}></umb-workspace-property>
|
||||
`
|
||||
)}
|
||||
|
||||
@@ -2,8 +2,6 @@ import { UmbPropertyEditorConfig } from '../../property-editor/index.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, html, ifDefined, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbDataTypeRepository } from '@umbraco-cms/backoffice/data-type';
|
||||
import { UMB_DOCUMENT_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/document';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { DataTypeResponseModel, PropertyTypeModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
@@ -19,7 +17,6 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
|
||||
this._property = value;
|
||||
if (this._property?.dataTypeId !== oldProperty?.dataTypeId) {
|
||||
this._observeDataType(this._property?.dataTypeId);
|
||||
this._observeProperty();
|
||||
}
|
||||
}
|
||||
private _property?: PropertyTypeModelBaseModel;
|
||||
@@ -33,53 +30,6 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
|
||||
private _dataTypeRepository: UmbDataTypeRepository = new UmbDataTypeRepository(this);
|
||||
private _dataTypeObserver?: UmbObserverController<DataTypeResponseModel | undefined>;
|
||||
|
||||
@state()
|
||||
private _value?: unknown;
|
||||
|
||||
/**
|
||||
* propertyVariantId. A VariantID to identify which the variant of this properties value.
|
||||
* @public
|
||||
* @type {UmbVariantId}
|
||||
* @attr
|
||||
* @default undefined
|
||||
*/
|
||||
@property({ type: Object, attribute: false })
|
||||
public get propertyVariantId(): UmbVariantId | undefined {
|
||||
return this._propertyVariantId;
|
||||
}
|
||||
public set propertyVariantId(value: UmbVariantId | undefined) {
|
||||
const oldValue = this._propertyVariantId;
|
||||
if (value && oldValue?.equal(value)) return;
|
||||
this._propertyVariantId = value;
|
||||
this._observeProperty();
|
||||
this.requestUpdate('propertyVariantId', oldValue);
|
||||
}
|
||||
private _propertyVariantId?: UmbVariantId | undefined;
|
||||
|
||||
private _workspaceContext?: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this._workspaceContext = workspaceContext;
|
||||
this._observeProperty();
|
||||
});
|
||||
}
|
||||
|
||||
private _observePropertyValue?: UmbObserverController<unknown>;
|
||||
private _observeProperty() {
|
||||
if (!this._workspaceContext || !this.property || !this._property?.alias) return;
|
||||
|
||||
this._observePropertyValue?.destroy();
|
||||
this._observePropertyValue = this.observe(
|
||||
this._workspaceContext.propertyValueByAlias(this._property.alias, this._propertyVariantId),
|
||||
(value) => {
|
||||
this._value = value;
|
||||
},
|
||||
'_observePropertyValue'
|
||||
);
|
||||
}
|
||||
|
||||
private async _observeDataType(dataTypeId?: string) {
|
||||
this._dataTypeObserver?.destroy();
|
||||
if (dataTypeId) {
|
||||
@@ -115,8 +65,6 @@ export class UmbPropertyTypeBasedPropertyElement extends UmbLitElement {
|
||||
label=${ifDefined(this._property?.name)}
|
||||
description=${ifDefined(this._property?.description || undefined)}
|
||||
property-editor-ui-alias=${ifDefined(this._propertyEditorUiAlias)}
|
||||
.value=${this._value}
|
||||
.propertyVariantId=${this.propertyVariantId}
|
||||
.config=${this._dataTypeData}></umb-workspace-property>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { UmbVariantId } from '../../variant/variant-id.class.js';
|
||||
import { UUIInputElement, UUIInputEvent } from '@umbraco-cms/backoffice/external/uui';
|
||||
import { css, html, nothing, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import {
|
||||
UmbWorkspaceVariantContext,
|
||||
UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN,
|
||||
UmbWorkspaceSplitViewContext,
|
||||
UMB_WORKSPACE_SPLIT_VIEW_CONTEXT,
|
||||
UMB_VARIANT_CONTEXT,
|
||||
ActiveVariant,
|
||||
isNameablePropertySetContext,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
import { DocumentVariantResponseModel, ContentStateModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
@customElement('umb-variant-selector')
|
||||
export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
// TODO: not jet used:
|
||||
@property()
|
||||
alias!: string;
|
||||
|
||||
@state()
|
||||
_variants: Array<DocumentVariantResponseModel> = [];
|
||||
@@ -21,12 +21,13 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
@state()
|
||||
_activeVariants: Array<ActiveVariant> = [];
|
||||
|
||||
@property()
|
||||
@property({attribute: false})
|
||||
public get _activeVariantsCultures(): string[] {
|
||||
return this._activeVariants.map((el) => el.culture ?? '') ?? [];
|
||||
}
|
||||
|
||||
private _variantContext?: UmbWorkspaceVariantContext;
|
||||
#splitViewContext?: UmbWorkspaceSplitViewContext;
|
||||
#variantContext?: typeof UMB_VARIANT_CONTEXT.TYPE;
|
||||
|
||||
@state()
|
||||
private _name?: string;
|
||||
@@ -46,18 +47,21 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.consumeContext<UmbWorkspaceVariantContext>(UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN, (instance) => {
|
||||
this._variantContext = instance;
|
||||
this.consumeContext(UMB_WORKSPACE_SPLIT_VIEW_CONTEXT, (instance) => {
|
||||
this.#splitViewContext = instance;
|
||||
this._observeVariants();
|
||||
this._observeActiveVariants();
|
||||
});
|
||||
this.consumeContext(UMB_VARIANT_CONTEXT, (instance) => {
|
||||
this.#variantContext = instance;
|
||||
this._observeVariantContext();
|
||||
});
|
||||
}
|
||||
|
||||
private async _observeVariants() {
|
||||
if (!this._variantContext) return;
|
||||
if (!this.#splitViewContext) return;
|
||||
|
||||
const workspaceContext = this._variantContext.getWorkspaceContext();
|
||||
const workspaceContext = this.#splitViewContext.getWorkspaceContext();
|
||||
if (workspaceContext) {
|
||||
this.observe(
|
||||
workspaceContext.variants,
|
||||
@@ -72,9 +76,9 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private async _observeActiveVariants() {
|
||||
if (!this._variantContext) return;
|
||||
if (!this.#splitViewContext) return;
|
||||
|
||||
const workspaceContext = this._variantContext.getWorkspaceContext();
|
||||
const workspaceContext = this.#splitViewContext.getWorkspaceContext();
|
||||
if (workspaceContext) {
|
||||
this.observe(
|
||||
workspaceContext.splitView.activeVariantsInfo,
|
||||
@@ -89,31 +93,20 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private async _observeVariantContext() {
|
||||
if (!this._variantContext) return;
|
||||
if (!this.#variantContext) return;
|
||||
|
||||
const variantId = this.#variantContext.getVariantId();
|
||||
this._culture = variantId.culture;
|
||||
this._segment = variantId.segment;
|
||||
this.updateVariantDisplayName();
|
||||
|
||||
this.observe(
|
||||
this._variantContext.name,
|
||||
this.#variantContext.name,
|
||||
(name) => {
|
||||
this._name = name;
|
||||
},
|
||||
'_name'
|
||||
);
|
||||
this.observe(
|
||||
this._variantContext.culture,
|
||||
(culture) => {
|
||||
this._culture = culture;
|
||||
this.updateVariantDisplayName();
|
||||
},
|
||||
'_culture'
|
||||
);
|
||||
this.observe(
|
||||
this._variantContext.segment,
|
||||
(segment) => {
|
||||
this._segment = segment;
|
||||
this.updateVariantDisplayName();
|
||||
},
|
||||
'_segment'
|
||||
);
|
||||
}
|
||||
|
||||
private updateVariantDisplayName() {
|
||||
@@ -130,9 +123,8 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
if (event instanceof UUIInputEvent) {
|
||||
const target = event.composedPath()[0] as UUIInputElement;
|
||||
|
||||
if (typeof target?.value === 'string') {
|
||||
// TODO: create a setName method on EntityWorkspace:
|
||||
this._variantContext?.setName(target.value);
|
||||
if (typeof target?.value === 'string' && this.#variantContext && isNameablePropertySetContext(this.#variantContext)) {
|
||||
this.#variantContext.setName(target.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,17 +141,17 @@ export class UmbVariantSelectorElement extends UmbLitElement {
|
||||
}
|
||||
|
||||
private _switchVariant(variant: DocumentVariantResponseModel) {
|
||||
this._variantContext?.switchVariant(variant);
|
||||
this.#splitViewContext?.switchVariant(UmbVariantId.Create(variant));
|
||||
this._close();
|
||||
}
|
||||
|
||||
private _openSplitView(variant: DocumentVariantResponseModel) {
|
||||
this._variantContext?.openSplitView(variant);
|
||||
this.#splitViewContext?.openSplitView(UmbVariantId.Create(variant));
|
||||
this._close();
|
||||
}
|
||||
|
||||
private _closeSplitView() {
|
||||
this._variantContext?.closeSplitView();
|
||||
this.#splitViewContext?.closeSplitView();
|
||||
}
|
||||
|
||||
private _isVariantActive(culture: string) {
|
||||
|
||||
@@ -12,6 +12,5 @@ type Story = StoryObj<UmbVariantSelectorElement>;
|
||||
|
||||
export const Overview: Story = {
|
||||
args: {
|
||||
alias: 'myAlias',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -313,6 +313,58 @@ export class UmbContentTypePropertyStructureManager<R extends UmbDetailRepositor
|
||||
this.#documentTypes.updateOne(documentTypeId, { properties });
|
||||
}
|
||||
|
||||
// TODO: Refactor: These property methods, should maybe be named without structure in their name.
|
||||
async propertyStructureById(
|
||||
propertyId: string
|
||||
) {
|
||||
await this.#init;
|
||||
return this.#documentTypes.asObservablePart((docTypes) => {
|
||||
for (const docType of docTypes) {
|
||||
const foundProp = docType.properties?.find((property) => property.id === propertyId);
|
||||
if(foundProp) {
|
||||
return foundProp;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
async propertyStructureByAlias(
|
||||
propertyAlias: string
|
||||
) {
|
||||
await this.#init;
|
||||
return this.#documentTypes.asObservablePart((docTypes) => {
|
||||
for (const docType of docTypes) {
|
||||
const foundProp = docType.properties?.find((property) => property.alias === propertyAlias);
|
||||
if(foundProp) {
|
||||
return foundProp;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
async getPropertyStructureById(propertyId: string) {
|
||||
await this.#init;
|
||||
for (const docType of this.#documentTypes.getValue()) {
|
||||
const foundProp = docType.properties?.find((property) => property.id === propertyId);
|
||||
if(foundProp) {
|
||||
return foundProp;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
async getPropertyStructureByAlias(propertyAlias: string) {
|
||||
await this.#init;
|
||||
for (const docType of this.#documentTypes.getValue()) {
|
||||
const foundProp = docType.properties?.find((property) => property.alias === propertyAlias);
|
||||
if(foundProp) {
|
||||
return foundProp;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rootDocumentTypeName() {
|
||||
return this.#documentTypes.asObservablePart((docTypes) => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN } from '../../../workspace/workspace-variant/workspace-variant.context.js';
|
||||
import { UMB_WORKSPACE_PROPERTY_CONTEXT_TOKEN } from '../../../workspace/workspace-property/workspace-property.context.js';
|
||||
import { html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
@@ -13,7 +12,6 @@ import type { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/
|
||||
*/
|
||||
@customElement('umb-property-editor-ui-block-grid')
|
||||
export class UmbPropertyEditorUIBlockGridElement extends UmbLitElement implements UmbPropertyEditorExtensionElement {
|
||||
private _variantContext?: typeof UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN.TYPE;
|
||||
|
||||
@property()
|
||||
value = '';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './repository.interface.js';
|
||||
@@ -0,0 +1,12 @@
|
||||
export interface UmbRepository<EntityType = unknown> {
|
||||
|
||||
/**
|
||||
* Get the type of the entity
|
||||
*
|
||||
* @public
|
||||
* @type {EntityType}
|
||||
* @returns undefined
|
||||
*/
|
||||
readonly ENTITY_TYPE: EntityType;
|
||||
|
||||
}
|
||||
@@ -1,15 +1,21 @@
|
||||
export type variantObject = { culture?: string | null; segment?: string | null };
|
||||
|
||||
export const INVARIANT_CULTURE = 'invariant';
|
||||
|
||||
export class UmbVariantId {
|
||||
public static Create(variantData: variantObject): UmbVariantId {
|
||||
return Object.freeze(new UmbVariantId(variantData));
|
||||
}
|
||||
|
||||
public static CreateInvariant(): UmbVariantId {
|
||||
return Object.freeze(new UmbVariantId({}));
|
||||
}
|
||||
|
||||
public readonly culture: string | null = null;
|
||||
public readonly segment: string | null = null;
|
||||
|
||||
constructor(variantData: variantObject) {
|
||||
this.culture = (variantData.culture === 'invariant' ? null : variantData.culture) ?? null;
|
||||
this.culture = (variantData.culture === INVARIANT_CULTURE ? null : variantData.culture) ?? null;
|
||||
this.segment = variantData.segment ?? null;
|
||||
}
|
||||
|
||||
@@ -22,13 +28,26 @@ export class UmbVariantId {
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return (this.culture || 'invariant') + (this.segment ? `_${this.segment}` : '');
|
||||
return (this.culture || INVARIANT_CULTURE) + (this.segment ? `_${this.segment}` : '');
|
||||
}
|
||||
|
||||
public toCultureString(): string {
|
||||
return (this.culture || INVARIANT_CULTURE);
|
||||
}
|
||||
|
||||
public toSegmentString(): string {
|
||||
return (this.segment || '');
|
||||
}
|
||||
|
||||
public isInvariant(): boolean {
|
||||
return this.culture === null && this.segment === null;
|
||||
}
|
||||
|
||||
public toObject(): variantObject {
|
||||
return { culture: this.culture, segment: this.segment };
|
||||
}
|
||||
|
||||
// TODO: needs localization option:
|
||||
public toDifferencesString(variantId: UmbVariantId): string {
|
||||
let r = '';
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
export * from './variant-context/index.js';
|
||||
export * from './workspace-action-menu/index.js';
|
||||
export * from './workspace-action/index.js';
|
||||
export * from './workspace-alias.condition.js';
|
||||
export * from './workspace-context/index.js';
|
||||
export * from './workspace-editor/index.js';
|
||||
export * from './workspace-footer/index.js';
|
||||
@@ -8,5 +10,4 @@ export * from './workspace-modal/index.js';
|
||||
export * from './workspace-property-layout/workspace-property-layout.element.js';
|
||||
export * from './workspace-property/index.js';
|
||||
export * from './workspace-split-view-manager.class.js';
|
||||
export * from './workspace-variant/index.js';
|
||||
export * from './workspace-alias.condition.js';
|
||||
export * from './workspace-split-view/index.js';
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from './variant-context.interface.js';
|
||||
export * from './variant-context.token.js';
|
||||
export * from './nameable-variant-context.interface.js';
|
||||
export * from './nameable-variant-context.token.js';
|
||||
export * from './invariant-workspace-variant-context.js';
|
||||
@@ -0,0 +1,63 @@
|
||||
import { DocumentVariantResponseModel } from "@umbraco-cms/backoffice/backend-api";
|
||||
import { UmbBaseController, UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
|
||||
import { UmbObjectState } from "@umbraco-cms/backoffice/observable-api";
|
||||
import { UmbVariantId } from "@umbraco-cms/backoffice/variant";
|
||||
import { UMB_VARIANT_CONTEXT, UmbVariantContext, UmbInvariantableWorkspaceContextInterface } from "@umbraco-cms/backoffice/workspace";
|
||||
|
||||
export class UmbInvariantWorkspaceVariantContext<WorkspaceType extends UmbInvariantableWorkspaceContextInterface= UmbInvariantableWorkspaceContextInterface> extends UmbBaseController implements UmbVariantContext {
|
||||
|
||||
protected _workspace: WorkspaceType;
|
||||
|
||||
#currentVariant = new UmbObjectState<DocumentVariantResponseModel | undefined>(undefined);
|
||||
currentVariant = this.#currentVariant.asObservable();
|
||||
|
||||
name = this.#currentVariant.asObservablePart((x) => x?.name);
|
||||
culture = this.#currentVariant.asObservablePart((x) => x?.culture);
|
||||
segment = this.#currentVariant.asObservablePart((x) => x?.segment);
|
||||
|
||||
// default data:
|
||||
|
||||
getVariantId() {
|
||||
return UmbVariantId.CreateInvariant();
|
||||
}
|
||||
getType() {
|
||||
return this._workspace.getEntityType();
|
||||
}
|
||||
getUnique() {
|
||||
return this._workspace.getEntityId();
|
||||
}
|
||||
getName() {
|
||||
return this._workspace.getName();
|
||||
}
|
||||
setName(name: string) {
|
||||
this._workspace.setName(name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
constructor(host: UmbControllerHost, workspace: WorkspaceType) {
|
||||
// The controller alias, is a very generic name cause we want only one of these for this controller host.
|
||||
super(host, 'variantContext');
|
||||
this._workspace = workspace;
|
||||
|
||||
this.provideContext(UMB_VARIANT_CONTEXT, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
* Ideally do not use these methods, its better to communicate directly with the workspace, but if you do not know the property variant id, then this will figure it out for you. So good for externals to set or get values of a property.
|
||||
*/
|
||||
async propertyValueByAlias<ReturnType = unknown>(propertyAlias: string) {
|
||||
return this._workspace.propertyValueByAlias<ReturnType>(propertyAlias);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
* Ideally do not use these methods, its better to communicate directly with the workspace, but if you do not know the property variant id, then this will figure it out for you. So good for externals to set or get values of a property.
|
||||
*/
|
||||
async setPropertyValue(propertyAlias: string, value: unknown) {
|
||||
return this._workspace.setPropertyValue(propertyAlias, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { UmbVariantContext } from "./variant-context.interface.js";
|
||||
|
||||
/**
|
||||
* A variant context with ability to set the name of it.
|
||||
*/
|
||||
export interface UmbNameableVariantContext extends UmbVariantContext {
|
||||
setName(name:string): void
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { type UmbVariantContext } from "./variant-context.interface.js";
|
||||
import { UmbNameableVariantContext } from "./nameable-variant-context.interface.js";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
|
||||
export const isNameablePropertySetContext = (context: UmbVariantContext): context is UmbNameableVariantContext => 'setName' in context;
|
||||
|
||||
export const UMB_NAMEABLE_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbNameableVariantContext>(
|
||||
"UmbVariantContext",
|
||||
isNameablePropertySetContext);
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { UmbVariantId } from "../../variant/variant-id.class.js";
|
||||
import type { Observable } from "@umbraco-cms/backoffice/external/rxjs";
|
||||
|
||||
/**
|
||||
* A variant context, represents a set of properties.
|
||||
* This can take form as many, so to list a few:
|
||||
* - A specific variant of content
|
||||
* - Content that does not vary
|
||||
* - A block.
|
||||
* - A DataType configuration.
|
||||
*
|
||||
* The base type of this holds a Name and some Properties.
|
||||
* Some might be enriches with Variant Info, like culture and segment.
|
||||
* Others might have saved publishing status.
|
||||
* Also setting the name is an additional feature.
|
||||
*/
|
||||
export interface UmbVariantContext {
|
||||
|
||||
getType(): string;
|
||||
getUnique(): string | undefined;
|
||||
//getUniqueName(): string;
|
||||
getVariantId: (() => UmbVariantId);
|
||||
|
||||
getName(): string | undefined;
|
||||
readonly name: Observable<string | undefined>;
|
||||
|
||||
destroy(): void;
|
||||
|
||||
// Property methods:
|
||||
propertyVariantId?: ((propertyAlias: string) => Promise<Observable<UmbVariantId | undefined>>);
|
||||
propertyValueByAlias<ReturnType = unknown>(propertyAlias: string): Promise<Observable<ReturnType | undefined>>;
|
||||
setPropertyValue(propertyAlias: string, value: unknown): Promise<void>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { type UmbVariantContext } from "./variant-context.interface.js";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
|
||||
export const UMB_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext>("UmbVariantContext");
|
||||
@@ -1,7 +1,10 @@
|
||||
export * from './entity-manager-controller.js';
|
||||
export * from './workspace-context.js';
|
||||
export * from './property-structure-workspace-context.interface.js';
|
||||
export * from './publishable-workspace-context.interface.js';
|
||||
export * from './saveable-workspace-context.interface.js';
|
||||
export * from './variant-workspace-context.token.js';
|
||||
export * from './workspace-context.interface.js';
|
||||
export * from './workspace-entity-context.interface.js';
|
||||
export * from './workspace-invariantable-entity-context.interface.js';
|
||||
export * from './workspace-variable-entity-context.interface.js';
|
||||
export * from './workspace-context.js';
|
||||
export * from './workspace-context.token.js';
|
||||
export * from './workspace-invariantable-context.interface.js';
|
||||
export * from './workspace-variantable-context.interface.js';
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { UmbWorkspaceContextInterface } from './workspace-context.interface.js';
|
||||
import { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import type { ValueModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export interface UmbPropertyStructureWorkspaceContextInterface<EntityType = unknown>
|
||||
extends UmbWorkspaceContextInterface<EntityType> {
|
||||
|
||||
propertyStructureById(id: string): Promise<Observable<ValueModelBaseModel | undefined>>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { UmbSaveableWorkspaceContextInterface } from './saveable-workspace-context.interface.js';
|
||||
|
||||
export interface UmbPublishableWorkspaceContextInterface<EntityType = unknown>
|
||||
extends UmbSaveableWorkspaceContextInterface<EntityType> {
|
||||
//getData(): EntityType | undefined;
|
||||
publish(): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { UmbWorkspaceContextInterface } from './workspace-context.interface.js';
|
||||
|
||||
export interface UmbSaveableWorkspaceContextInterface<EntityType = unknown>
|
||||
extends UmbWorkspaceContextInterface<EntityType> {
|
||||
//getData(): EntityType | undefined;
|
||||
save(): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { UmbWorkspaceContextInterface } from './workspace-context.interface.js';
|
||||
import type { UmbVariantableWorkspaceContextInterface } from './workspace-variantable-context.interface.js';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import type { UmbEntityBase } from '@umbraco-cms/backoffice/models';
|
||||
|
||||
export const UMB_VARIANT_WORKSPACE_CONTEXT_TOKEN = new UmbContextToken<UmbWorkspaceContextInterface<UmbEntityBase>, UmbVariantableWorkspaceContextInterface<UmbEntityBase>>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbVariantableWorkspaceContextInterface => 'variants' in context,
|
||||
);
|
||||
@@ -1,17 +1,19 @@
|
||||
import { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
export interface UmbWorkspaceContextInterface<DataType = unknown> {
|
||||
destroy(): void;
|
||||
workspaceAlias: string;
|
||||
repository: any; // TODO: add type
|
||||
|
||||
save(): Promise<void>;
|
||||
// TODO: temp solution to bubble validation errors to the UI
|
||||
setValidationErrors?(errorMap: any): void;
|
||||
|
||||
getEntityId(): string | undefined; // Consider if this should go away now that we have getUnique()
|
||||
// TODO: should we consider another name than entity type. File system files are not entities but still have this type.
|
||||
getEntityType(): string;
|
||||
|
||||
isNew: Observable<boolean | undefined>;
|
||||
getIsNew(): boolean | undefined;
|
||||
setIsNew(value: boolean): void;
|
||||
getEntityId(): string | undefined; // COnsider if this should go away now that we have getUnique()
|
||||
// TODO: should we consider another name than entity type. File system files are not entities but still have this type.
|
||||
getEntityType(): string;
|
||||
getData(): DataType | undefined;
|
||||
save(): Promise<void>;
|
||||
destroy(): void;
|
||||
// TODO: temp solution to bubble validation errors to the UI
|
||||
setValidationErrors?(errorMap: any): void;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UmbEntityWorkspaceContextInterface } from './workspace-entity-context.interface.js';
|
||||
import { UmbSaveableWorkspaceContextInterface } from './saveable-workspace-context.interface.js';
|
||||
import { UmbBaseController, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBooleanState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbEntityBase } from '@umbraco-cms/backoffice/models';
|
||||
@@ -12,13 +12,13 @@ If so we need to align on a interface that all of these implements. otherwise co
|
||||
*/
|
||||
export abstract class UmbWorkspaceContext<RepositoryType, EntityType extends UmbEntityBase>
|
||||
extends UmbBaseController
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType>
|
||||
{
|
||||
public readonly host: UmbControllerHostElement;
|
||||
public readonly workspaceAlias: string;
|
||||
public readonly repository: RepositoryType;
|
||||
|
||||
// TODO: We could make a base type for workspace modal data, and use this here: As well as a base for the result, to make sure we always include the unique.
|
||||
// TODO: We could make a base type for workspace modal data, and use this here: As well as a base for the result, to make sure we always include the unique (instead of the object type)
|
||||
public readonly modalContext?: UmbModalContext<{ preset: object }>;
|
||||
|
||||
#isNew = new UmbBooleanState(undefined);
|
||||
@@ -60,4 +60,5 @@ export abstract class UmbWorkspaceContext<RepositoryType, EntityType extends Umb
|
||||
abstract getEntityType(): string; // TODO: consider of this should be on the repository because a repo is responsible for one entity type
|
||||
abstract getData(): EntityType | undefined;
|
||||
abstract save(): Promise<void>;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import type { UmbWorkspaceContextInterface } from './workspace-context.interface.js';
|
||||
|
||||
export interface UmbEntityWorkspaceContextInterface<EntityType = unknown>
|
||||
extends UmbWorkspaceContextInterface<EntityType> {
|
||||
getEntityType(): string; // TODO: consider of this should be on the repository because a repo is responsible for one entity type
|
||||
//getData(): EntityType | undefined;
|
||||
save(): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { UmbVariantId } from '../../variant/variant-id.class.js';
|
||||
import { UmbVariantContext } from '../variant-context/variant-context.interface.js';
|
||||
import type { UmbSaveableWorkspaceContextInterface } from './saveable-workspace-context.interface.js';
|
||||
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
export interface UmbInvariantableWorkspaceContextInterface<T = unknown>
|
||||
extends UmbSaveableWorkspaceContextInterface<T> {
|
||||
|
||||
// Name:
|
||||
getName(): string | undefined;
|
||||
setName(name: string): void;
|
||||
|
||||
// Property:
|
||||
propertyValueByAlias<ReturnType = unknown>(alias: string): Promise<Observable<ReturnType | undefined>>;
|
||||
getPropertyValue<ReturnType = unknown>(alias: string): ReturnType;
|
||||
setPropertyValue(alias: string, value: unknown): Promise<void>;
|
||||
|
||||
createVariantContext(host: UmbControllerHost, variantId?: UmbVariantId): UmbVariantContext;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { UmbEntityWorkspaceContextInterface } from './workspace-entity-context.interface.js';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import type { ValueModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export interface UmbWorkspaceInvariantableEntityContextInterface<T = unknown>
|
||||
extends UmbEntityWorkspaceContextInterface<T> {
|
||||
getName(): void;
|
||||
setName(name: string): void;
|
||||
|
||||
propertyDataByAlias(alias: string): Observable<ValueModelBaseModel | undefined>;
|
||||
propertyValueByAlias(alias: string): Observable<any | undefined>;
|
||||
getPropertyValue(alias: string): void;
|
||||
setPropertyValue(alias: string, value: unknown): void;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import type { UmbWorkspaceSplitViewManager } from '../workspace-split-view-manager.class.js';
|
||||
import type { UmbEntityWorkspaceContextInterface } from './workspace-entity-context.interface.js';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { ValueModelBaseModel, VariantResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
export interface UmbWorkspaceVariableEntityContextInterface<T = unknown> extends UmbEntityWorkspaceContextInterface<T> {
|
||||
variants: Observable<Array<VariantResponseModelBaseModel>>;
|
||||
|
||||
splitView: UmbWorkspaceSplitViewManager;
|
||||
|
||||
getName(variantId?: UmbVariantId): void;
|
||||
setName(name: string, variantId?: UmbVariantId): void;
|
||||
|
||||
getVariant(variantId: UmbVariantId): VariantResponseModelBaseModel | undefined;
|
||||
|
||||
propertyDataByAlias(alias: string, variantId?: UmbVariantId): Observable<ValueModelBaseModel | undefined>;
|
||||
propertyValueByAlias(alias: string, variantId?: UmbVariantId): Observable<any | undefined>;
|
||||
getPropertyValue(alias: string, variantId?: UmbVariantId): void;
|
||||
setPropertyValue(alias: string, value: unknown, variantId?: UmbVariantId): void;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { UmbWorkspaceSplitViewManager } from '../workspace-split-view-manager.class.js';
|
||||
import { UmbVariantContext } from '../variant-context/variant-context.interface.js';
|
||||
import type { UmbSaveableWorkspaceContextInterface } from './saveable-workspace-context.interface.js';
|
||||
import type { Observable } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import type { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { VariantResponseModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
|
||||
export interface UmbVariantableWorkspaceContextInterface<EntityType = unknown> extends UmbSaveableWorkspaceContextInterface<EntityType> {
|
||||
|
||||
// Name:
|
||||
getName(variantId?: UmbVariantId): string | undefined;
|
||||
setName(name: string, variantId?: UmbVariantId): void;
|
||||
|
||||
// Variant:
|
||||
variants: Observable<Array<VariantResponseModelBaseModel>>;
|
||||
splitView: UmbWorkspaceSplitViewManager;
|
||||
getVariant(variantId: UmbVariantId): VariantResponseModelBaseModel | undefined;
|
||||
|
||||
// Property:
|
||||
// This one is async cause it needs to structure to provide this data:
|
||||
propertyValueByAlias<ReturnValue = unknown>(alias: string, variantId?: UmbVariantId): Promise<Observable<ReturnValue | undefined>>;
|
||||
getPropertyValue<ReturnValue = unknown>(alias: string, variantId?: UmbVariantId): ReturnValue | undefined;
|
||||
setPropertyValue(alias: string, value: unknown, variantId?: UmbVariantId): Promise<void>;
|
||||
//propertyDataByAlias(alias: string, variantId?: UmbVariantId): Observable<ValueModelBaseModel | undefined>;
|
||||
|
||||
createVariantContext(host: UmbControllerHost, variantId?: UmbVariantId): UmbVariantContext;
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
import { UmbWorkspaceVariableEntityContextInterface } from '../workspace-context/workspace-variable-entity-context.interface.js';
|
||||
import { UmbPropertyEditorExtensionElement } from '../../extension-registry/interfaces/property-editor-ui-extension-element.interface.js';
|
||||
import { type WorkspacePropertyData } from '../types/workspace-property-data.type.js';
|
||||
import { UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN, UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UMB_VARIANT_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbBaseController, type UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
UmbClassState,
|
||||
UmbObjectState,
|
||||
@@ -12,14 +11,12 @@ import {
|
||||
UmbBasicState,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import {
|
||||
UmbContextConsumerController,
|
||||
UmbContextProviderController,
|
||||
UmbContextToken,
|
||||
} from '@umbraco-cms/backoffice/context-api';
|
||||
import { UmbPropertyEditorConfigCollection } from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
export class UmbWorkspacePropertyContext<ValueType = any> {
|
||||
#host: UmbControllerHostElement;
|
||||
export class UmbWorkspacePropertyContext<ValueType = any> extends UmbBaseController {
|
||||
|
||||
private _providerController: UmbContextProviderController;
|
||||
|
||||
@@ -43,52 +40,77 @@ export class UmbWorkspacePropertyContext<ValueType = any> {
|
||||
return this._editor.getValue();
|
||||
}
|
||||
|
||||
#workspaceVariantId?: UmbVariantId;
|
||||
|
||||
// property variant ID:
|
||||
#variantId = new UmbClassState<UmbVariantId | undefined>(undefined);
|
||||
public readonly variantId = this.#variantId.asObservable();
|
||||
|
||||
private _variantDifference = new UmbStringState(undefined);
|
||||
public readonly variantDifference = this._variantDifference.asObservable();
|
||||
|
||||
private _workspaceContext?: UmbWorkspaceVariableEntityContextInterface;
|
||||
private _workspaceVariantConsumer?: UmbContextConsumerController<typeof UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN.TYPE>;
|
||||
#variantContext?: typeof UMB_VARIANT_CONTEXT.TYPE;
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
this.#host = host;
|
||||
new UmbContextConsumerController(host, UMB_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this._workspaceContext = workspaceContext as UmbWorkspaceVariableEntityContextInterface;
|
||||
super(host);
|
||||
|
||||
this.consumeContext(UMB_VARIANT_CONTEXT, (variantContext) => {
|
||||
this.#variantContext = variantContext;
|
||||
this._generateVariantDifferenceString();
|
||||
this._observeProperty();
|
||||
});
|
||||
|
||||
this.observe(this.alias, () => {
|
||||
this._observeProperty();
|
||||
});
|
||||
|
||||
this._providerController = new UmbContextProviderController(host, UMB_WORKSPACE_PROPERTY_CONTEXT_TOKEN, this);
|
||||
|
||||
this.configValues.subscribe((configValues) => {
|
||||
this.observe(this.configValues, (configValues) => {
|
||||
this.#configCollection.next(configValues ? new UmbPropertyEditorConfigCollection(configValues) : undefined);
|
||||
});
|
||||
|
||||
this.variantId.subscribe((propertyVariantId) => {
|
||||
if (propertyVariantId) {
|
||||
if (!this._workspaceVariantConsumer) {
|
||||
this._workspaceVariantConsumer = new UmbContextConsumerController(
|
||||
this.#host,
|
||||
UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN,
|
||||
(workspaceVariantContext) => {
|
||||
new UmbObserverController(this.#host, workspaceVariantContext.variantId, (workspaceVariantId) => {
|
||||
this.#workspaceVariantId = workspaceVariantId;
|
||||
this._generateVariantDifferenceString();
|
||||
});
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this._generateVariantDifferenceString();
|
||||
}
|
||||
}
|
||||
this.observe(this.variantId, () => {
|
||||
this._generateVariantDifferenceString();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private _observePropertyVariant?: UmbObserverController<UmbVariantId | undefined>;
|
||||
private _observePropertyValue?: UmbObserverController<ValueType | undefined>;
|
||||
private async _observeProperty() {
|
||||
const alias = this.#data.getValue().alias;
|
||||
if (!this.#variantContext || !alias) return;
|
||||
|
||||
const variantIdSubject = await this.#variantContext.propertyVariantId?.(alias) ?? undefined;
|
||||
this._observePropertyVariant?.destroy();
|
||||
if(variantIdSubject) {
|
||||
this._observePropertyVariant = this.observe(
|
||||
variantIdSubject,
|
||||
(variantId) => {
|
||||
this.#variantId.next(variantId);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Verify if we need to optimize runtime by parsing the propertyVariantID, cause this method retrieves it again:
|
||||
const subject = await this.#variantContext.propertyValueByAlias<ValueType>(alias)
|
||||
|
||||
this._observePropertyValue?.destroy();
|
||||
if(subject) {
|
||||
this._observePropertyValue = this.observe(
|
||||
subject,
|
||||
(value) => {
|
||||
// Note: Do not try to compare new / old value, as it can of any type. We trust the UmbObjectState in doing such.
|
||||
this.#data.update({ value });
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _generateVariantDifferenceString() {
|
||||
if(!this.#variantContext) return;
|
||||
const contextVariantId = this.#variantContext.getVariantId?.() ?? undefined;
|
||||
this._variantDifference.next(
|
||||
this.#workspaceVariantId ? this.#variantId.getValue()?.toDifferencesString(this.#workspaceVariantId) : ''
|
||||
contextVariantId ? this.#variantId.getValue()?.toDifferencesString(contextVariantId) : ''
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,16 +124,10 @@ export class UmbWorkspacePropertyContext<ValueType = any> {
|
||||
this.#data.update({ description });
|
||||
}
|
||||
public setValue(value: WorkspacePropertyData<ValueType>['value']) {
|
||||
// Note: Do not try to compare new / old value, as it can of any type. We trust the UmbObjectState in doing such.
|
||||
this.#data.update({ value });
|
||||
}
|
||||
public changeValue(value: WorkspacePropertyData<ValueType>['value']) {
|
||||
this.setValue(value);
|
||||
|
||||
const alias = this.#data.getValue().alias;
|
||||
if (alias) {
|
||||
this._workspaceContext?.setPropertyValue(alias, value, this.#variantId.getValue());
|
||||
}
|
||||
if (!this.#variantContext || !alias) return;
|
||||
|
||||
this.#variantContext?.setPropertyValue(alias, value);
|
||||
}
|
||||
public setConfig(config: WorkspacePropertyData<ValueType>['config'] | undefined) {
|
||||
this.#data.update({ config });
|
||||
|
||||
@@ -2,7 +2,6 @@ import { type UmbPropertyEditorConfig } from '../../property-editor/index.js';
|
||||
import { UmbWorkspacePropertyContext } from './workspace-property.context.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, html, customElement, property, state, ifDefined } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import { createExtensionElement } from '@umbraco-cms/backoffice/extension-api';
|
||||
import { ManifestPropertyEditorUi, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UmbObserverController } from '@umbraco-cms/backoffice/observable-api';
|
||||
@@ -66,18 +65,6 @@ export class UmbWorkspacePropertyElement extends UmbLitElement {
|
||||
this._observePropertyEditorUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Property Value, this is the value stored in the property.
|
||||
* @public
|
||||
* @type {unknown}
|
||||
* @attr
|
||||
* @default undefined
|
||||
*/
|
||||
@property({ attribute: false })
|
||||
public set value(value: unknown) {
|
||||
this._propertyContext.setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Config. Configuration to pass to the Property Editor UI. This is also the configuration data stored on the Data Type.
|
||||
* @public
|
||||
@@ -90,19 +77,6 @@ export class UmbWorkspacePropertyElement extends UmbLitElement {
|
||||
this._propertyContext.setConfig(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* PropertyVariantId. A Variant ID to identify which variant its value is stored on.
|
||||
* @public
|
||||
* @type {UmbVariantId}
|
||||
* @attr
|
||||
* @default null
|
||||
*/
|
||||
@property({ type: Object, attribute: false })
|
||||
public set propertyVariantId(value: UmbVariantId | undefined) {
|
||||
this._propertyContext.setVariantId(value);
|
||||
//this._variantDisplayName = value?.toString();
|
||||
}
|
||||
|
||||
@state()
|
||||
private _variantDifference?: string;
|
||||
|
||||
@@ -147,7 +121,7 @@ export class UmbWorkspacePropertyElement extends UmbLitElement {
|
||||
const target = e.composedPath()[0] as any;
|
||||
|
||||
//this.value = target.value; // Sets value in context.
|
||||
this._propertyContext.changeValue(target.value);
|
||||
this._propertyContext.setValue(target.value);
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -234,8 +208,8 @@ export class UmbWorkspacePropertyElement extends UmbLitElement {
|
||||
? html`<umb-property-action-menu
|
||||
slot="property-action-menu"
|
||||
id="property-action-menu"
|
||||
.propertyEditorUiAlias="${this._propertyEditorUiAlias}"
|
||||
.value="${this._value}"></umb-property-action-menu>`
|
||||
.propertyEditorUiAlias=${this._propertyEditorUiAlias}
|
||||
.value=${this._value}></umb-property-action-menu>`
|
||||
: ''}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './workspace-split-view.context.js';
|
||||
export * from './workspace-split-view.element.js';
|
||||
@@ -0,0 +1,107 @@
|
||||
import { UmbVariantContext } from '../variant-context/index.js';
|
||||
import { UMB_VARIANT_WORKSPACE_CONTEXT_TOKEN } from '../index.js';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import {
|
||||
UmbContextToken,
|
||||
} from '@umbraco-cms/backoffice/context-api';
|
||||
import { UmbBaseController, UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
UmbNumberState,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
|
||||
|
||||
export class UmbWorkspaceSplitViewContext extends UmbBaseController {
|
||||
|
||||
#workspaceContext?: typeof UMB_VARIANT_WORKSPACE_CONTEXT_TOKEN.TYPE;
|
||||
public getWorkspaceContext() {
|
||||
return this.#workspaceContext;
|
||||
}
|
||||
|
||||
#variantContext?: UmbVariantContext;
|
||||
|
||||
#index = new UmbNumberState(undefined);
|
||||
index = this.#index.asObservable();
|
||||
|
||||
//#variantId = new UmbClassState<UmbVariantId | undefined>(undefined);
|
||||
//variantId = this.#variantId.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHost) {
|
||||
super(host);
|
||||
|
||||
this.consumeContext(UMB_VARIANT_WORKSPACE_CONTEXT_TOKEN, (context) => {
|
||||
this.#workspaceContext = context;
|
||||
this._observeVariant();
|
||||
});
|
||||
|
||||
this.observe(this.#index, () => {
|
||||
this._observeVariant();
|
||||
});
|
||||
|
||||
|
||||
this.provideContext(UMB_WORKSPACE_SPLIT_VIEW_CONTEXT, this);
|
||||
}
|
||||
|
||||
private _observeVariant() {
|
||||
if (!this.#workspaceContext) return;
|
||||
|
||||
const index = this.#index.getValue();
|
||||
if (index === undefined) return;
|
||||
|
||||
// TODO: Should splitView be put into its own context?... a split view manager context? one which might have a reference to the workspace context, so we still can ask that about how to create the variant context.
|
||||
this.observe(
|
||||
this.#workspaceContext.splitView.activeVariantByIndex(index),
|
||||
async (activeVariantInfo) => {
|
||||
if (!activeVariantInfo) return;
|
||||
|
||||
// TODO: Ask workspace context to create the specific variant context.
|
||||
|
||||
this.#variantContext?.destroy();
|
||||
const variantId = UmbVariantId.Create(activeVariantInfo);
|
||||
this.#variantContext = this.#workspaceContext?.createVariantContext(this, variantId);
|
||||
},
|
||||
'_observeActiveVariant'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public switchVariant(variant: UmbVariantId) {
|
||||
const index = this.#index.value;
|
||||
if (index === undefined) return;
|
||||
this.#workspaceContext?.splitView.switchVariant(index, variant);
|
||||
}
|
||||
|
||||
public closeSplitView() {
|
||||
const index = this.#index.value;
|
||||
if (index === undefined) return;
|
||||
this.#workspaceContext?.splitView.closeSplitView(index);
|
||||
}
|
||||
|
||||
public openSplitView(variant: UmbVariantId) {
|
||||
this.#workspaceContext?.splitView.openSplitView(variant);
|
||||
}
|
||||
|
||||
public getSplitViewIndex() {
|
||||
return this.#index.getValue();
|
||||
}
|
||||
public setSplitViewIndex(index: number) {
|
||||
this.#index.next(index);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* concept this class could have methods to set and get the culture and segment of the active variant? just by using the index.
|
||||
*/
|
||||
|
||||
/*
|
||||
public destroy(): void {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export const UMB_WORKSPACE_SPLIT_VIEW_CONTEXT = new UmbContextToken<UmbWorkspaceSplitViewContext>(
|
||||
'umbWorkspaceSplitViewContext'
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbWorkspaceVariantContext } from './workspace-variant.context.js';
|
||||
import { UmbWorkspaceSplitViewContext } from './workspace-split-view.context.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { css, html, customElement, property } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
/**
|
||||
@@ -9,8 +9,8 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
* As well breadcrumbs etc.
|
||||
*
|
||||
*/
|
||||
@customElement('umb-workspace-variant')
|
||||
export class UmbWorkspaceVariantContentElement extends UmbLitElement {
|
||||
@customElement('umb-workspace-split-view')
|
||||
export class UmbWorkspaceSplitViewElement extends UmbLitElement {
|
||||
// TODO: stop prop drilling this alias. Instead use the workspace context.
|
||||
@property()
|
||||
alias!: string;
|
||||
@@ -20,19 +20,14 @@ export class UmbWorkspaceVariantContentElement extends UmbLitElement {
|
||||
|
||||
@property({ type: Number })
|
||||
public set splitViewIndex(index: number) {
|
||||
this._splitViewIndex = index;
|
||||
this.variantContext.setSplitViewIndex(index);
|
||||
this.splitViewContext.setSplitViewIndex(index);
|
||||
}
|
||||
|
||||
@state()
|
||||
private _splitViewIndex = 0;
|
||||
|
||||
variantContext = new UmbWorkspaceVariantContext(this);
|
||||
splitViewContext = new UmbWorkspaceSplitViewContext(this);
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<umb-workspace-editor
|
||||
.splitViewIndex=${this._splitViewIndex.toString()}
|
||||
alias=${this.alias}
|
||||
.hideNavigation=${!this.displayNavigation}
|
||||
.enforceNoFooter=${true}>
|
||||
@@ -67,10 +62,10 @@ export class UmbWorkspaceVariantContentElement extends UmbLitElement {
|
||||
];
|
||||
}
|
||||
|
||||
export default UmbWorkspaceVariantContentElement;
|
||||
export default UmbWorkspaceSplitViewElement;
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-workspace-variant': UmbWorkspaceVariantContentElement;
|
||||
'umb-workspace-split-view': UmbWorkspaceSplitViewElement;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './variantable-property/variantable-property.element.js';
|
||||
export * from './workspace-variant.context.js';
|
||||
export * from './workspace-variant.element.js';
|
||||
@@ -1,76 +0,0 @@
|
||||
import { UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN } from '../workspace-variant.context.js';
|
||||
import { UmbTextStyles } from "@umbraco-cms/backoffice/style";
|
||||
import { css, html, customElement, property, state } from '@umbraco-cms/backoffice/external/lit';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import type { PropertyTypeModelBaseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
|
||||
@customElement('umb-variantable-property')
|
||||
export class UmbVariantablePropertyElement extends UmbLitElement {
|
||||
private _property?: PropertyTypeModelBaseModel | undefined;
|
||||
@property({ type: Object, attribute: false })
|
||||
public get property(): PropertyTypeModelBaseModel | undefined {
|
||||
return this._property;
|
||||
}
|
||||
public set property(property: PropertyTypeModelBaseModel | undefined) {
|
||||
this._property = property;
|
||||
this._updatePropertyVariantId();
|
||||
}
|
||||
|
||||
private _variantContext?: typeof UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN.TYPE;
|
||||
|
||||
@state()
|
||||
private _workspaceVariantId?: UmbVariantId;
|
||||
|
||||
@state()
|
||||
private _propertyVariantId?: UmbVariantId;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.consumeContext(UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN, (workspaceContext) => {
|
||||
this._variantContext = workspaceContext;
|
||||
this._observeVariantContext();
|
||||
});
|
||||
}
|
||||
|
||||
private _observeVariantContext() {
|
||||
if (!this._variantContext || !this.property) return;
|
||||
this.observe(this._variantContext.variantId, (variantId) => {
|
||||
this._workspaceVariantId = variantId;
|
||||
this._updatePropertyVariantId();
|
||||
});
|
||||
}
|
||||
|
||||
private _updatePropertyVariantId() {
|
||||
if (this._workspaceVariantId && this.property) {
|
||||
const newVariantId = UmbVariantId.Create({
|
||||
culture: this.property.variesByCulture ? this._workspaceVariantId.culture : null,
|
||||
segment: this.property.variesBySegment ? this._workspaceVariantId.segment : null,
|
||||
});
|
||||
if (!this._propertyVariantId || !newVariantId.equal(this._propertyVariantId)) {
|
||||
this._propertyVariantId = newVariantId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`<umb-property-type-based-property
|
||||
.property=${this._property}
|
||||
.propertyVariantId=${this._propertyVariantId}></umb-property-type-based-property>`;
|
||||
}
|
||||
|
||||
static styles = [
|
||||
UmbTextStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'umb-variantable-property': UmbVariantablePropertyElement;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { Meta, StoryObj } from '@storybook/web-components';
|
||||
import './variantable-property.element.js';
|
||||
import type { UmbVariantablePropertyElement } from './variantable-property.element.js';
|
||||
|
||||
const meta: Meta<UmbVariantablePropertyElement> = {
|
||||
title: 'Components/Variantable Property',
|
||||
component: 'umb-variantable-property',
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<UmbVariantablePropertyElement>;
|
||||
|
||||
export const Overview: Story = {
|
||||
args: {
|
||||
property: {
|
||||
name: 'Header',
|
||||
alias: 'headerAlias',
|
||||
appearance: {
|
||||
labelOnTop: false,
|
||||
},
|
||||
description: 'This is a description',
|
||||
variesByCulture: true,
|
||||
variesBySegment: true,
|
||||
validation: {
|
||||
mandatory: true,
|
||||
mandatoryMessage: 'This is a mandatory message',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,131 +0,0 @@
|
||||
import { UmbWorkspaceVariableEntityContextInterface } from '../workspace-context/workspace-variable-entity-context.interface.js';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import {
|
||||
UmbContextConsumerController,
|
||||
UmbContextProviderController,
|
||||
UmbContextToken,
|
||||
} from '@umbraco-cms/backoffice/context-api';
|
||||
import { UMB_WORKSPACE_CONTEXT } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import {
|
||||
UmbClassState,
|
||||
UmbNumberState,
|
||||
UmbObjectState,
|
||||
UmbObserverController,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import { DocumentVariantResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
|
||||
//type EntityType = DocumentModel;
|
||||
|
||||
export class UmbWorkspaceVariantContext {
|
||||
#host: UmbControllerHostElement;
|
||||
|
||||
#workspaceContext?: UmbWorkspaceVariableEntityContextInterface;
|
||||
public getWorkspaceContext() {
|
||||
return this.#workspaceContext;
|
||||
}
|
||||
|
||||
#index = new UmbNumberState(undefined);
|
||||
index = this.#index.asObservable();
|
||||
|
||||
#currentVariant = new UmbObjectState<DocumentVariantResponseModel | undefined>(undefined);
|
||||
currentVariant = this.#currentVariant.asObservable();
|
||||
|
||||
name = this.#currentVariant.asObservablePart((x) => x?.name);
|
||||
culture = this.#currentVariant.asObservablePart((x) => x?.culture);
|
||||
segment = this.#currentVariant.asObservablePart((x) => x?.segment);
|
||||
|
||||
#variantId = new UmbClassState<UmbVariantId | undefined>(undefined);
|
||||
variantId = this.#variantId.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
this.#host = host;
|
||||
|
||||
new UmbContextProviderController(host, UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN.toString(), this);
|
||||
|
||||
// How do we ensure this connects to a document workspace context? and not just any other context? (We could start providing workspace contexts twice, under the general name and under a specific name)
|
||||
// TODO: Figure out if this is the best way to consume the context or if it can be strongly typed with an UmbContextToken
|
||||
new UmbContextConsumerController(host, UMB_WORKSPACE_CONTEXT, (context) => {
|
||||
this.#workspaceContext = context as UmbWorkspaceVariableEntityContextInterface;
|
||||
this._observeVariant();
|
||||
});
|
||||
|
||||
new UmbObserverController(host, this.#index, () => {
|
||||
this._observeVariant();
|
||||
});
|
||||
}
|
||||
|
||||
public switchVariant(variant: DocumentVariantResponseModel) {
|
||||
const index = this.#index.value;
|
||||
if (index === undefined) return;
|
||||
this.#workspaceContext?.splitView.switchVariant(index, new UmbVariantId(variant));
|
||||
}
|
||||
|
||||
public closeSplitView() {
|
||||
const index = this.#index.value;
|
||||
if (index === undefined) return;
|
||||
this.#workspaceContext?.splitView.closeSplitView(index);
|
||||
}
|
||||
|
||||
public openSplitView(variant: DocumentVariantResponseModel) {
|
||||
this.#workspaceContext?.splitView.openSplitView(new UmbVariantId(variant));
|
||||
}
|
||||
|
||||
private _setVariantId(variantId: UmbVariantId) {
|
||||
this.#variantId.next(variantId);
|
||||
return variantId;
|
||||
}
|
||||
|
||||
private _observeVariant() {
|
||||
if (!this.#workspaceContext) return;
|
||||
|
||||
const index = this.#index.getValue();
|
||||
if (index === undefined) return;
|
||||
|
||||
new UmbObserverController(
|
||||
this.#host,
|
||||
this.#workspaceContext.splitView.activeVariantByIndex(index),
|
||||
async (activeVariantInfo) => {
|
||||
if (!activeVariantInfo) return;
|
||||
const variantId = this._setVariantId(UmbVariantId.Create(activeVariantInfo));
|
||||
const currentVariant = await this.#workspaceContext?.getVariant(variantId);
|
||||
this.#currentVariant.next(currentVariant);
|
||||
},
|
||||
'_observeActiveVariant'
|
||||
);
|
||||
}
|
||||
|
||||
public changeVariant(culture: string | null, segment: string | null) {
|
||||
const index = this.#index.getValue();
|
||||
if (index === undefined) return;
|
||||
this.#workspaceContext?.splitView.setActiveVariant(index, culture, segment);
|
||||
}
|
||||
|
||||
public getSplitViewIndex() {
|
||||
return this.#index.getValue();
|
||||
}
|
||||
public setSplitViewIndex(index: number) {
|
||||
this.#index.next(index);
|
||||
}
|
||||
|
||||
public setName(newName: string) {
|
||||
const variantId = this.#variantId.getValue();
|
||||
if (!this.#workspaceContext || !variantId) return;
|
||||
this.#workspaceContext.setName(newName, variantId);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* concept this class could have methods to set and get the culture and segment of the active variant? just by using the index.
|
||||
*/
|
||||
|
||||
/*
|
||||
public destroy(): void {
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export const UMB_WORKSPACE_VARIANT_CONTEXT_TOKEN = new UmbContextToken<UmbWorkspaceVariantContext>(
|
||||
'umbWorkspaceVariantContext'
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbDictionaryRepository } from '../repository/dictionary.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { DictionaryItemResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
@@ -7,7 +7,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbDictionaryWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbDictionaryRepository, DictionaryItemResponseModel>
|
||||
implements UmbEntityWorkspaceContextInterface<DictionaryItemResponseModel | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<DictionaryItemResponseModel | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<DictionaryItemResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -86,7 +86,7 @@ export class UmbDictionaryWorkspaceContext
|
||||
}
|
||||
|
||||
|
||||
export const UMB_DICTIONARY_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbDictionaryWorkspaceContext>(
|
||||
export const UMB_DICTIONARY_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbDictionaryWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbDictionaryWorkspaceContext => context.getEntityType?.() === 'dictionary-item'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbDocumentTypeRepository } from '../repository/document-type.repository.js';
|
||||
import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type';
|
||||
import { UmbWorkspaceContext, UmbEntityWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbWorkspaceContext, UmbSaveableWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
|
||||
import type {
|
||||
ContentTypeCompositionModel,
|
||||
ContentTypeSortModel,
|
||||
@@ -12,7 +12,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
type EntityType = DocumentTypeResponseModel;
|
||||
export class UmbDocumentTypeWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbDocumentTypeRepository, EntityType>
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
// Draft is located in structure manager
|
||||
|
||||
@@ -157,7 +157,7 @@ export class UmbDocumentTypeWorkspaceContext
|
||||
}
|
||||
|
||||
|
||||
export const UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbDocumentTypeWorkspaceContext>(
|
||||
export const UMB_DOCUMENT_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbDocumentTypeWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbDocumentTypeWorkspaceContext => context.getEntityType?.() === 'document-type'
|
||||
);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { UmbDocumentVariantContext } from "./document-variant-context.js";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
import { UmbVariantContext } from "@umbraco-cms/backoffice/workspace";
|
||||
|
||||
export const IsDocumentVariantContext = (context: UmbVariantContext): context is UmbDocumentVariantContext => context.getType() === 'document';
|
||||
|
||||
export const UMB_DOCUMENT_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbDocumentVariantContext>(
|
||||
"UmbVariantContext",
|
||||
IsDocumentVariantContext);
|
||||
@@ -0,0 +1,112 @@
|
||||
import { UmbDocumentWorkspaceContext } from "../workspace/index.js";
|
||||
import { DocumentVariantResponseModel, PropertyTypeModelBaseModel } from "@umbraco-cms/backoffice/backend-api";
|
||||
import { UmbBaseController, UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
|
||||
import { map } from "@umbraco-cms/backoffice/external/rxjs";
|
||||
import { UmbObjectState } from "@umbraco-cms/backoffice/observable-api";
|
||||
import { UmbVariantId } from "@umbraco-cms/backoffice/variant";
|
||||
import { UMB_VARIANT_CONTEXT, UmbVariantContext } from "@umbraco-cms/backoffice/workspace";
|
||||
|
||||
// TODO: This code can be split into a UmbContentTypeVariantContext, leaving just the publishing state and methods to this class.
|
||||
export class UmbDocumentVariantContext extends UmbBaseController implements UmbVariantContext {
|
||||
|
||||
#workspace: UmbDocumentWorkspaceContext;
|
||||
#variantId: UmbVariantId;
|
||||
public getVariantId() {
|
||||
return this.#variantId;
|
||||
}
|
||||
|
||||
#currentVariant = new UmbObjectState<DocumentVariantResponseModel | undefined>(undefined);
|
||||
currentVariant = this.#currentVariant.asObservable();
|
||||
|
||||
name = this.#currentVariant.asObservablePart((x) => x?.name);
|
||||
culture = this.#currentVariant.asObservablePart((x) => x?.culture);
|
||||
segment = this.#currentVariant.asObservablePart((x) => x?.segment);
|
||||
|
||||
// TODO: Refactor: Make a properties observable. (with such I think i mean a property value object array.. array with object with properties, alias, value, culture and segment)
|
||||
// TO make such happen I think we need to maintain all properties and their value of this object.
|
||||
// This will actually make it simpler if multiple are watching the same property.
|
||||
// But it will also mean that we wil watch all properties and their structure, for variantID, all the time for all of the properties.
|
||||
|
||||
|
||||
getType(): string {
|
||||
return this.#workspace.getEntityType();
|
||||
}
|
||||
getUnique(): string | undefined {
|
||||
return this.#workspace.getEntityId();
|
||||
}
|
||||
getName(): string | undefined {
|
||||
return this.#workspace.getName(this.#variantId);
|
||||
}
|
||||
setName(name: string) {
|
||||
this.#workspace.setName(name, this.#variantId);
|
||||
}
|
||||
getVariantInfo() {
|
||||
return this.#workspace.getVariant(this.#variantId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
constructor(host: UmbControllerHost, workspace: UmbDocumentWorkspaceContext, variantId?: UmbVariantId) {
|
||||
// The controller alias, is a very generic name cause we want only one of these for this controller host.
|
||||
super(host, 'variantContext');
|
||||
this.#workspace = workspace;
|
||||
this.#variantId = variantId ?? UmbVariantId.CreateInvariant();
|
||||
|
||||
this.observe(
|
||||
this.#workspace.variantById(this.#variantId),
|
||||
async (variantInfo) => {
|
||||
if (!variantInfo) return;
|
||||
this.#currentVariant.next(variantInfo);
|
||||
},
|
||||
'_observeActiveVariant'
|
||||
);
|
||||
|
||||
// TODO: Refactor: use the document dataset context token.
|
||||
this.provideContext(UMB_VARIANT_CONTEXT, this);
|
||||
}
|
||||
|
||||
|
||||
#createPropertyVariantId(property:PropertyTypeModelBaseModel) {
|
||||
return UmbVariantId.Create({
|
||||
culture: property.variesByCulture ? this.#variantId.culture : null,
|
||||
segment: property.variesBySegment ? this.#variantId.segment : null,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
* Ideally do not use these methods, its better to communicate directly with the workspace, but if you do not know the property variant id, then this will figure it out for you. So good for externals to set or get values of a property.
|
||||
*/
|
||||
async propertyVariantId(propertyAlias: string) {
|
||||
return (await this.#workspace.structure.propertyStructureByAlias(propertyAlias)).pipe(map((property) => property ? this.#createPropertyVariantId(property) : undefined));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
* Ideally do not use these methods, its better to communicate directly with the workspace, but if you do not know the property variant id, then this will figure it out for you. So good for externals to set or get values of a property.
|
||||
*/
|
||||
async propertyValueByAlias<ReturnType = unknown>(propertyAlias: string) {
|
||||
await this.#workspace.isLoaded();
|
||||
return (await this.#workspace.structure.propertyStructureByAlias(propertyAlias)).pipe(map((property) => property?.alias ? this.#workspace.getPropertyValue<ReturnType>(property.alias, this.#createPropertyVariantId(property)) : undefined));
|
||||
}
|
||||
|
||||
// TODO: Refactor: Not used currently, but should investigate if we can implement this, to spare some energy.
|
||||
async propertyValueByAliasAndCulture<ReturnType = unknown>(propertyAlias: string, propertyVariantId: UmbVariantId) {
|
||||
return this.#workspace.propertyValueByAlias<ReturnType>(propertyAlias, propertyVariantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write proper JSDocs here.
|
||||
* Ideally do not use these methods, its better to communicate directly with the workspace, but if you do not know the property variant id, then this will figure it out for you. So good for externals to set or get values of a property.
|
||||
*/
|
||||
async setPropertyValue(propertyAlias: string, value: unknown) {
|
||||
// This is not reacting to if the property variant settings changes while running.
|
||||
const property = await this.#workspace.structure.getPropertyStructureByAlias(propertyAlias);
|
||||
if(property) {
|
||||
const variantId = this.#createPropertyVariantId(property);
|
||||
|
||||
// This is not reacting to if the property variant settings changes while running.
|
||||
this.#workspace.setPropertyValue(propertyAlias, value, variantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@customElement('umb-document-workspace-editor')
|
||||
export class UmbDocumentWorkspaceEditorElement extends UmbLitElement {
|
||||
//private _defaultVariant?: VariantViewModelBaseModel;
|
||||
|
||||
// TODO: Refactor: when having a split view/variants context token, we can rename the split view/variants component to a generic and make this component generic as well.
|
||||
private splitViewElement = new UmbDocumentWorkspaceSplitViewElement();
|
||||
|
||||
@state()
|
||||
|
||||
@@ -5,17 +5,16 @@ import { ActiveVariant } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbLitElement } from '@umbraco-cms/internal/lit-element';
|
||||
@customElement('umb-document-workspace-split-view')
|
||||
export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement {
|
||||
// TODO: Refactor: use the split view context token:
|
||||
private _workspaceContext?: typeof UMB_DOCUMENT_WORKSPACE_CONTEXT.TYPE;
|
||||
|
||||
@state()
|
||||
_unique?: string;
|
||||
|
||||
@state()
|
||||
_variants?: Array<ActiveVariant>;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// TODO: Refactor: use a split view workspace context token:
|
||||
this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (context) => {
|
||||
this._workspaceContext = context;
|
||||
this._observeActiveVariantInfo();
|
||||
@@ -41,10 +40,10 @@ export class UmbDocumentWorkspaceSplitViewElement extends UmbLitElement {
|
||||
(view) =>
|
||||
view.index + '_' + (view.culture ?? '') + '_' + (view.segment ?? '') + '_' + this._variants!.length,
|
||||
(view) => html`
|
||||
<umb-workspace-variant
|
||||
<umb-workspace-split-view
|
||||
alias="Umb.Workspace.Document"
|
||||
.splitViewIndex=${view.index}
|
||||
.displayNavigation=${view.index === this._variants!.length - 1}></umb-workspace-variant>
|
||||
.displayNavigation=${view.index === this._variants!.length - 1}></umb-workspace-split-view>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { UmbDocumentRepository } from '../repository/document.repository.js';
|
||||
import { UmbDocumentTypeRepository } from '../../document-types/repository/document-type.repository.js';
|
||||
import { UmbDocumentVariantContext } from '../variant-context/document-variant-context.js';
|
||||
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
|
||||
import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type';
|
||||
import {
|
||||
UmbEntityWorkspaceContextInterface,
|
||||
UmbSaveableWorkspaceContextInterface,
|
||||
UmbWorkspaceContext,
|
||||
UmbWorkspaceSplitViewManager,
|
||||
UmbWorkspaceVariableEntityContextInterface,
|
||||
UmbVariantableWorkspaceContextInterface,
|
||||
type UmbVariantContext,
|
||||
} from '@umbraco-cms/backoffice/workspace';
|
||||
import type { CreateDocumentRequestModel, DocumentResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import {
|
||||
@@ -15,34 +17,36 @@ import {
|
||||
UmbObjectState,
|
||||
UmbObserverController,
|
||||
} from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbControllerHost, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
// TODO: should this context be called DocumentDraft instead of workspace? or should the draft be part of this?
|
||||
// TODO: Should we have a DocumentStructureContext and maybe even a DocumentDraftContext?
|
||||
|
||||
type EntityType = DocumentResponseModel;
|
||||
export class UmbDocumentWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbDocumentRepository, EntityType>
|
||||
implements UmbWorkspaceVariableEntityContextInterface<EntityType | undefined>
|
||||
implements UmbVariantableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
/**
|
||||
* The document is the current stored version of the document.
|
||||
* For now lets not share this publicly as it can become confusing.
|
||||
* TODO: Use this to compare, for variants with changes.
|
||||
* TODO: This concept is to be able to compare if there is changes since the saved one.
|
||||
*/
|
||||
#document = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
//#persistedData = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
|
||||
/**
|
||||
* The document is the current state/draft version of the document.
|
||||
*/
|
||||
#draft = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
readonly unique = this.#draft.asObservablePart((data) => data?.id);
|
||||
readonly documentTypeKey = this.#draft.asObservablePart((data) => data?.contentTypeId);
|
||||
#currentData = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
#getDataPromise?: Promise<any>;
|
||||
public isLoaded() {
|
||||
return this.#getDataPromise;
|
||||
}
|
||||
|
||||
readonly variants = this.#draft.asObservablePart((data) => data?.variants || []);
|
||||
readonly urls = this.#draft.asObservablePart((data) => data?.urls || []);
|
||||
readonly templateId = this.#draft.asObservablePart((data) => data?.templateId || null);
|
||||
readonly unique = this.#currentData.asObservablePart((data) => data?.id);
|
||||
readonly documentTypeKey = this.#currentData.asObservablePart((data) => data?.contentTypeId);
|
||||
|
||||
readonly variants = this.#currentData.asObservablePart((data) => data?.variants || []);
|
||||
readonly urls = this.#currentData.asObservablePart((data) => data?.urls || []);
|
||||
readonly templateId = this.#currentData.asObservablePart((data) => data?.templateId || null);
|
||||
|
||||
readonly structure;
|
||||
readonly splitView;
|
||||
@@ -61,27 +65,28 @@ export class UmbDocumentWorkspaceContext
|
||||
}
|
||||
|
||||
async load(entityId: string) {
|
||||
const { data } = await this.repository.requestById(entityId);
|
||||
this.#getDataPromise = this.repository.requestById(entityId);
|
||||
const { data } = await this.#getDataPromise;
|
||||
if (!data) return undefined;
|
||||
|
||||
this.setIsNew(false);
|
||||
this.#document.next(data);
|
||||
this.#draft.next(data);
|
||||
//this.#persisted.next(data);
|
||||
this.#currentData.next(data);
|
||||
return data || undefined;
|
||||
}
|
||||
|
||||
async create(documentTypeKey: string, parentId: string | null) {
|
||||
const { data } = await this.repository.createScaffold(documentTypeKey, { parentId });
|
||||
this.#getDataPromise = this.repository.createScaffold(documentTypeKey, { parentId });
|
||||
const { data } = await this.#getDataPromise;
|
||||
if (!data) return undefined;
|
||||
|
||||
this.setIsNew(true);
|
||||
this.#document.next(data);
|
||||
this.#draft.next(data);
|
||||
this.#currentData.next(data);
|
||||
return data || undefined;
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.#draft.getValue() || {};
|
||||
return this.#currentData.getValue() || {};
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -102,12 +107,16 @@ export class UmbDocumentWorkspaceContext
|
||||
return this.getData().contentTypeId;
|
||||
}
|
||||
|
||||
variantById(variantId: UmbVariantId) {
|
||||
return this.#currentData.asObservablePart((data) => data?.variants?.find((x) => variantId.compare(x)));
|
||||
}
|
||||
|
||||
getVariant(variantId: UmbVariantId) {
|
||||
return this.#draft.getValue()?.variants?.find((x) => variantId.compare(x));
|
||||
return this.#currentData.getValue()?.variants?.find((x) => variantId.compare(x));
|
||||
}
|
||||
|
||||
getName(variantId?: UmbVariantId) {
|
||||
const variants = this.#draft.getValue()?.variants;
|
||||
const variants = this.#currentData.getValue()?.variants;
|
||||
if (!variants) return;
|
||||
if (variantId) {
|
||||
return variants.find((x) => variantId.compare(x))?.name;
|
||||
@@ -117,67 +126,67 @@ export class UmbDocumentWorkspaceContext
|
||||
}
|
||||
|
||||
setName(name: string, variantId?: UmbVariantId) {
|
||||
const oldVariants = this.#draft.getValue()?.variants || [];
|
||||
const oldVariants = this.#currentData.getValue()?.variants || [];
|
||||
const variants = partialUpdateFrozenArray(
|
||||
oldVariants,
|
||||
{ name },
|
||||
variantId ? (x) => variantId.compare(x) : () => true
|
||||
);
|
||||
this.#draft.update({ variants });
|
||||
this.#currentData.update({ variants });
|
||||
}
|
||||
|
||||
propertyValuesOf(variantId?: UmbVariantId) {
|
||||
return this.#draft.asObservablePart((data) =>
|
||||
variantId ? data?.values?.filter((x) => variantId.compare(x)) : data?.values
|
||||
);
|
||||
async propertyStructureById(propertyId: string) {
|
||||
return this.structure.propertyStructureById(propertyId);
|
||||
}
|
||||
|
||||
propertyDataByAlias(propertyAlias: string, variantId?: UmbVariantId) {
|
||||
return this.#draft.asObservablePart((data) =>
|
||||
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true))
|
||||
);
|
||||
}
|
||||
propertyValueByAlias(propertyAlias: string, variantId?: UmbVariantId) {
|
||||
return this.#draft.asObservablePart(
|
||||
async propertyValueByAlias<PropertyValueType = unknown>(propertyAlias: string, variantId?: UmbVariantId) {
|
||||
return this.#currentData.asObservablePart(
|
||||
(data) =>
|
||||
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true))?.value
|
||||
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x) : true))?.value as PropertyValueType
|
||||
);
|
||||
}
|
||||
|
||||
getPropertyValue(alias: string, variantId?: UmbVariantId): void {
|
||||
const currentData = this.#draft.value;
|
||||
/**
|
||||
* Get the current value of the property with the given alias and variantId.
|
||||
* @param alias
|
||||
* @param variantId
|
||||
* @returns The value or undefined if not set or found.
|
||||
*/
|
||||
getPropertyValue<ReturnType = unknown>(alias: string, variantId?: UmbVariantId) {
|
||||
const currentData = this.#currentData.value;
|
||||
if (currentData) {
|
||||
const newDataSet = currentData.values?.find(
|
||||
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true)
|
||||
);
|
||||
return newDataSet?.value;
|
||||
return newDataSet?.value as ReturnType;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
setPropertyValue(alias: string, value: unknown, variantId?: UmbVariantId) {
|
||||
async setPropertyValue<PropertyValueType = unknown>(alias: string, value: PropertyValueType, variantId?: UmbVariantId) {
|
||||
const entry = { ...variantId?.toObject(), alias, value };
|
||||
const currentData = this.#draft.value;
|
||||
const currentData = this.#currentData.value;
|
||||
if (currentData) {
|
||||
const values = appendToFrozenArray(
|
||||
currentData.values || [],
|
||||
entry,
|
||||
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true)
|
||||
);
|
||||
this.#draft.update({ values });
|
||||
this.#currentData.update({ values });
|
||||
}
|
||||
}
|
||||
|
||||
async save() {
|
||||
if (!this.#draft.value) return;
|
||||
if (!this.#draft.value.id) return;
|
||||
if (!this.#currentData.value) return;
|
||||
if (!this.#currentData.value.id) return;
|
||||
|
||||
if (this.getIsNew()) {
|
||||
// TODO: typescript hack until we get the create type
|
||||
const value = this.#draft.value as CreateDocumentRequestModel & { id: string };
|
||||
const value = this.#currentData.value as CreateDocumentRequestModel & { id: string };
|
||||
if ((await this.repository.create(value)).data !== undefined) {
|
||||
this.setIsNew(false);
|
||||
}
|
||||
} else {
|
||||
await this.repository.save(this.#draft.value.id, this.#draft.value);
|
||||
await this.repository.save(this.#currentData.value.id, this.#currentData.value);
|
||||
}
|
||||
|
||||
this.saveComplete(this.getData());
|
||||
@@ -199,8 +208,12 @@ export class UmbDocumentWorkspaceContext
|
||||
}
|
||||
*/
|
||||
|
||||
public createVariantContext(host: UmbControllerHost, variantId: UmbVariantId) {
|
||||
return new UmbDocumentVariantContext(host, this, variantId);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.#draft.complete();
|
||||
this.#currentData.complete();
|
||||
this.structure.destroy();
|
||||
super.destroy();
|
||||
}
|
||||
@@ -209,7 +222,8 @@ export class UmbDocumentWorkspaceContext
|
||||
export default UmbDocumentWorkspaceContext;
|
||||
|
||||
|
||||
export const UMB_DOCUMENT_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbDocumentWorkspaceContext>(
|
||||
export const UMB_DOCUMENT_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbDocumentWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
// TODO: Refactor: make a better generic way to identify workspaces, maybe workspaceType or workspaceAlias?.
|
||||
(context): context is UmbDocumentWorkspaceContext => context.getEntityType?.() === 'document'
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@ export class UmbDocumentWorkspaceViewEditPropertiesElement extends UmbLitElement
|
||||
return repeat(
|
||||
this._propertyStructure,
|
||||
(property) => property.alias,
|
||||
(property) => html`<umb-variantable-property class="property" .property=${property}></umb-variantable-property> `
|
||||
(property) => html`<umb-property-type-based-property class="property" .property=${property}></umb-property-type-based-property> `
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ export class UmbDocumentWorkspaceViewEditElement
|
||||
if (!this._routes || !this._tabs) return;
|
||||
return html`
|
||||
<umb-body-layout header-fit-height>
|
||||
${this._routerPath && (this._tabs.length > 0 || this._hasRootGroups)
|
||||
${this._routerPath && (this._tabs.length > 1 || (this._tabs.length === 1 && this._hasRootGroups))
|
||||
? html` <uui-tab-group slot="header">
|
||||
${this._hasRootGroups && this._tabs.length > 0
|
||||
? html`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbMediaTypeRepository } from '../repository/media-type.repository.js';
|
||||
import type { MediaTypeDetails } from '../types.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -8,7 +8,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
type EntityType = MediaTypeDetails;
|
||||
export class UmbMediaTypeWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbMediaTypeRepository, EntityType>
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<MediaTypeDetails | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -64,7 +64,7 @@ export class UmbMediaTypeWorkspaceContext
|
||||
}
|
||||
|
||||
|
||||
export const UMB_MEDIA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbMediaTypeWorkspaceContext>(
|
||||
export const UMB_MEDIA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMediaTypeWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMediaTypeWorkspaceContext => context.getEntityType?.() === 'media-type'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbMediaRepository } from '../repository/media.repository.js';
|
||||
import type { MediaDetails } from '../index.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { appendToFrozenArray, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -8,7 +8,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
type EntityType = MediaDetails;
|
||||
export class UmbMediaWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbMediaRepository, EntityType>
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -83,7 +83,7 @@ export class UmbMediaWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEDIA_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbMediaWorkspaceContext>(
|
||||
export const UMB_MEDIA_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMediaWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMediaWorkspaceContext => context.getEntityType?.() === 'media'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbMemberGroupRepository } from '../repository/member-group.repository.js';
|
||||
import type { MemberGroupDetails } from '../types.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -8,7 +8,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
type EntityType = MemberGroupDetails;
|
||||
export class UmbMemberGroupWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbMemberGroupRepository, EntityType>
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -67,7 +67,7 @@ export class UmbMemberGroupWorkspaceContext
|
||||
|
||||
|
||||
|
||||
export const UMB_MEMBER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbMemberGroupWorkspaceContext>(
|
||||
export const UMB_MEMBER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMemberGroupWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMemberGroupWorkspaceContext => context.getEntityType?.() === 'member-group'
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbMemberTypeRepository } from '../repository/member-type.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -9,7 +9,7 @@ type EntityType = any;
|
||||
|
||||
export class UmbMemberTypeWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbMemberTypeRepository, EntityType>
|
||||
implements UmbEntityWorkspaceContextInterface<EntityType | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<EntityType | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<EntityType | undefined>(undefined);
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
@@ -75,7 +75,7 @@ export class UmbMemberTypeWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEMBER_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbMemberTypeWorkspaceContext>(
|
||||
export const UMB_MEMBER_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMemberTypeWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMemberTypeWorkspaceContext => context.getEntityType?.() === 'member-type'
|
||||
);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { UmbMemberRepository } from '../repository/member.repository.js';
|
||||
import type { MemberDetails } from '../types.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbMemberWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbMemberRepository, MemberDetails>
|
||||
implements UmbEntityWorkspaceContextInterface<MemberDetails | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<MemberDetails | undefined>
|
||||
{
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.Member', new UmbMemberRepository(host));
|
||||
@@ -37,7 +37,7 @@ export class UmbMemberWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_MEMBER_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbMemberWorkspaceContext>(
|
||||
export const UMB_MEMBER_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbMemberWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbMemberWorkspaceContext => context.getEntityType?.() === 'member'
|
||||
);
|
||||
|
||||
@@ -40,13 +40,13 @@ export const manifests: Array<ManifestTypes> = [
|
||||
{
|
||||
type: 'headerApp',
|
||||
kind: 'button',
|
||||
alias: 'Umb.HeaderApp.HackDemo',
|
||||
name: 'Header App Search',
|
||||
alias: 'My.HeaderApp.Wand',
|
||||
name: 'My Header App',
|
||||
weight: 10,
|
||||
meta: {
|
||||
label: 'Hack Demo',
|
||||
icon: 'document',
|
||||
href: '/section/content/workspace/document/edit/c05da24d-7740-447b-9cdc-bd8ce2172e38/en-us/view/content/tab/Local%20blog%20tab',
|
||||
label: 'My Header App',
|
||||
icon: 'wand',
|
||||
href: '/section/content/workspace/document/edit/c05da24d-7740-447b-9cdc-bd8ce2172e38',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,3 +3,4 @@ import './components/index.js';
|
||||
export type { UmbDataTypeModel } from './models.js';
|
||||
export * from './entities.js';
|
||||
export * from './repository/index.js';
|
||||
export * from './variant-context/index.js';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { UmbDataTypeVariantContext } from "./data-type-variant-context.js";
|
||||
import { UmbVariantContext } from "@umbraco-cms/backoffice/workspace";
|
||||
import { UmbContextToken } from "@umbraco-cms/backoffice/context-api";
|
||||
|
||||
export const isDataTypeVariantContext = (context: UmbVariantContext): context is UmbDataTypeVariantContext => ('properties' in context && context.getType() === 'data-type');
|
||||
|
||||
export const UMB_DATA_TYPE_VARIANT_CONTEXT = new UmbContextToken<UmbVariantContext, UmbDataTypeVariantContext>(
|
||||
"UmbVariantContext", isDataTypeVariantContext);
|
||||
@@ -0,0 +1,16 @@
|
||||
import { UmbDataTypeWorkspaceContext } from "../workspace/data-type-workspace.context.js";
|
||||
import { UmbControllerHost } from "@umbraco-cms/backoffice/controller-api";
|
||||
import { UmbInvariantWorkspaceVariantContext } from "@umbraco-cms/backoffice/workspace";
|
||||
|
||||
export class UmbDataTypeVariantContext extends UmbInvariantWorkspaceVariantContext<UmbDataTypeWorkspaceContext> {
|
||||
|
||||
|
||||
properties = this._workspace.properties
|
||||
|
||||
// default data:
|
||||
|
||||
constructor(host: UmbControllerHost, workspace: UmbDataTypeWorkspaceContext) {
|
||||
super(host, workspace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './data-type-variant-context.token.js';
|
||||
export * from './data-type-variant-context.js';
|
||||
@@ -23,6 +23,7 @@ export class UmbDataTypeWorkspaceEditorElement extends UmbLitElement {
|
||||
|
||||
this.consumeContext(UMB_DATA_TYPE_WORKSPACE_CONTEXT, (workspaceContext) => {
|
||||
this.#workspaceContext = workspaceContext;
|
||||
this.#workspaceContext?.createVariantContext(this);
|
||||
this.#observeIsNew();
|
||||
this.#observeName();
|
||||
});
|
||||
|
||||
@@ -1,27 +1,112 @@
|
||||
import { UmbDataTypeRepository } from '../repository/data-type.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbDataTypeVariantContext } from '../variant-context/data-type-variant-context.js';
|
||||
import { UmbInvariantableWorkspaceContextInterface, UmbWorkspaceContext, UmbWorkspaceContextInterface } from '@umbraco-cms/backoffice/workspace';
|
||||
import type { DataTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { appendToFrozenArray, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { appendToFrozenArray, UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHost, UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
import { Observable, combineLatest, map } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
import { PropertyEditorConfigDefaultData, PropertyEditorConfigProperty, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry';
|
||||
import { UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT } from '@umbraco-cms/backoffice/property-editor';
|
||||
|
||||
export class UmbDataTypeWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbDataTypeRepository, DataTypeResponseModel>
|
||||
implements UmbEntityWorkspaceContextInterface<DataTypeResponseModel | undefined>
|
||||
implements UmbInvariantableWorkspaceContextInterface<DataTypeResponseModel | undefined>
|
||||
{
|
||||
// TODO: revisit. temp solution because the create and response models are different.
|
||||
#data = new UmbObjectState<DataTypeResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
#getDataPromise?: Promise<any>;
|
||||
|
||||
name = this.#data.asObservablePart((data) => data?.name);
|
||||
id = this.#data.asObservablePart((data) => data?.id);
|
||||
|
||||
propertyEditorUiAlias = this.#data.asObservablePart((data) => data?.propertyEditorUiAlias);
|
||||
propertyEditorSchemaAlias = this.#data.asObservablePart((data) => data?.propertyEditorAlias);
|
||||
|
||||
#properties = new UmbObjectState<Array<PropertyEditorConfigProperty> | undefined>(undefined);
|
||||
properties: Observable<Array<PropertyEditorConfigProperty> | undefined> = this.#properties.asObservable();
|
||||
|
||||
private _propertyEditorSchemaConfigDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
private _propertyEditorUISettingsDefaultData: Array<PropertyEditorConfigDefaultData> = [];
|
||||
|
||||
private _propertyEditorSchemaConfigProperties?: Array<PropertyEditorConfigProperty>;
|
||||
private _propertyEditorUISettingsProperties?: Array<PropertyEditorConfigProperty>;
|
||||
|
||||
private _configDefaultData?: Array<PropertyEditorConfigDefaultData>;
|
||||
|
||||
#defaults = new UmbArrayState<PropertyEditorConfigDefaultData>([], (entry) => entry.alias);
|
||||
defaults = this.#defaults.asObservable();
|
||||
|
||||
constructor(host: UmbControllerHostElement) {
|
||||
super(host, 'Umb.Workspace.DataType', new UmbDataTypeRepository(host));
|
||||
|
||||
this.observe(this.propertyEditorUiAlias, (propertyEditorUiAlias) => {
|
||||
if (!propertyEditorUiAlias) {
|
||||
// No property editor ui alias, so we clean up and reset the properties.
|
||||
this.removeControllerByAlias('propertyEditorUiAlias');
|
||||
this._propertyEditorUISettingsProperties = [];
|
||||
this._propertyEditorUISettingsDefaultData = [];
|
||||
this._mergeConfigProperties();
|
||||
this._mergeConfigDefaultData();
|
||||
return;
|
||||
}
|
||||
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', propertyEditorUiAlias),
|
||||
(manifest) => {
|
||||
this._observePropertyEditorSchemaConfig(
|
||||
manifest?.meta.propertyEditorSchemaAlias || UMB_PROPERTY_EDITOR_SCHEMA_ALIAS_DEFAULT
|
||||
);
|
||||
this._propertyEditorUISettingsProperties = manifest?.meta.settings?.properties || [];
|
||||
this._propertyEditorUISettingsDefaultData = manifest?.meta.settings?.defaultData || [];
|
||||
this._mergeConfigProperties();
|
||||
this._mergeConfigDefaultData();
|
||||
}
|
||||
, 'observePropertyEditorUiAlias'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private _observePropertyEditorSchemaConfig(propertyEditorSchemaAlias: string) {
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorSchema', propertyEditorSchemaAlias),
|
||||
(manifest) => {
|
||||
this._propertyEditorSchemaConfigProperties = manifest?.meta.settings?.properties || [];
|
||||
this._propertyEditorSchemaConfigDefaultData = manifest?.meta.settings?.defaultData || [];
|
||||
this._mergeConfigProperties();
|
||||
this._mergeConfigDefaultData();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _mergeConfigProperties() {
|
||||
if(this._propertyEditorSchemaConfigProperties && this._propertyEditorUISettingsProperties) {
|
||||
this.#properties.next([...this._propertyEditorSchemaConfigProperties, ...this._propertyEditorUISettingsProperties]);
|
||||
}
|
||||
}
|
||||
|
||||
private _mergeConfigDefaultData() {
|
||||
if(!this._propertyEditorSchemaConfigDefaultData || !this._propertyEditorUISettingsDefaultData) return;
|
||||
|
||||
this._configDefaultData = [
|
||||
...this._propertyEditorSchemaConfigDefaultData,
|
||||
...this._propertyEditorUISettingsDefaultData,
|
||||
];
|
||||
this.#defaults.next(this._configDefaultData);
|
||||
}
|
||||
|
||||
public getPropertyDefaultValue(alias: string) {
|
||||
return this._configDefaultData?.find((x) => x.alias === alias)?.value;
|
||||
}
|
||||
|
||||
createVariantContext(host: UmbControllerHost): UmbDataTypeVariantContext {
|
||||
return new UmbDataTypeVariantContext(host, this);
|
||||
}
|
||||
|
||||
async load(id: string) {
|
||||
const { data } = await this.repository.requestById(id);
|
||||
this.#getDataPromise = this.repository.requestById(id);
|
||||
const { data } = await this.#getDataPromise;
|
||||
if (data) {
|
||||
this.setIsNew(false);
|
||||
this.#data.update(data);
|
||||
@@ -29,7 +114,8 @@ export class UmbDataTypeWorkspaceContext
|
||||
}
|
||||
|
||||
async create(parentId: string | null) {
|
||||
let { data } = await this.repository.createScaffold(parentId);
|
||||
this.#getDataPromise = this.repository.createScaffold(parentId);
|
||||
let { data } = await this.#getDataPromise;
|
||||
if (this.modalContext) {
|
||||
data = { ...data, ...this.modalContext.data.preset };
|
||||
}
|
||||
@@ -52,6 +138,9 @@ export class UmbDataTypeWorkspaceContext
|
||||
return 'data-type';
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.#data.getValue()?.name;
|
||||
}
|
||||
setName(name: string) {
|
||||
this.#data.update({ name });
|
||||
}
|
||||
@@ -63,8 +152,29 @@ export class UmbDataTypeWorkspaceContext
|
||||
this.#data.update({ propertyEditorUiAlias: alias });
|
||||
}
|
||||
|
||||
async propertyValueByAlias<ReturnType = unknown>(propertyAlias: string) {
|
||||
await this.#getDataPromise;
|
||||
|
||||
// TODO: Merge map..
|
||||
|
||||
return combineLatest([
|
||||
this.#data.asObservablePart((data) => data?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType),
|
||||
this.#defaults.asObservablePart((defaults) => defaults?.find((x) => x.alias === propertyAlias)?.value as ReturnType),
|
||||
]).pipe(
|
||||
map(([value, defaultValue]) => {
|
||||
return (value ?? defaultValue);
|
||||
})
|
||||
);
|
||||
//return this.#data.asObservablePart((data) => data?.values?.find((x) => x.alias === propertyAlias)?.value ?? this.getPropertyDefaultValue(propertyAlias) as ReturnType);
|
||||
}
|
||||
|
||||
getPropertyValue<ReturnType = unknown>(propertyAlias: string) {
|
||||
return this.#data.getValue()?.values?.find((x) => x.alias === propertyAlias)?.value as ReturnType ?? this.getPropertyDefaultValue(propertyAlias) as ReturnType;
|
||||
}
|
||||
|
||||
// TODO: its not called a property in the model, but we do consider this way in our front-end
|
||||
setPropertyValue(alias: string, value: unknown) {
|
||||
async setPropertyValue(alias: string, value: unknown) {
|
||||
await this.#getDataPromise;
|
||||
const entry = { alias: alias, value: value };
|
||||
|
||||
const currentData = this.#data.value;
|
||||
@@ -97,7 +207,7 @@ export class UmbDataTypeWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_DATA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbDataTypeWorkspaceContext>(
|
||||
export const UMB_DATA_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbWorkspaceContextInterface, UmbDataTypeWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbDataTypeWorkspaceContext => context.getEntityType?.() === 'data-type'
|
||||
);
|
||||
|
||||
@@ -73,7 +73,7 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement
|
||||
if (!propertyEditorSchema) return;
|
||||
this._setPropertyEditorUiAlias(propertyEditorSchema.meta.defaultPropertyEditorUiAlias ?? undefined);
|
||||
},
|
||||
'_observepropertyEditorSchemaForDefaultUI'
|
||||
'_observePropertyEditorSchemaForDefaultUI'
|
||||
);
|
||||
} else {
|
||||
this._setPropertyEditorUiAlias(undefined);
|
||||
@@ -103,8 +103,8 @@ export class UmbDataTypeDetailsWorkspaceViewEditElement
|
||||
return;
|
||||
}
|
||||
|
||||
// remove the '_observepropertyEditorSchemaForDefaultUI' controller, as we do not want to observe for default value anymore:
|
||||
this.removeControllerByAlias('_observepropertyEditorSchemaForDefaultUI');
|
||||
// remove the '_observePropertyEditorSchemaForDefaultUI' controller, as we do not want to observe for default value anymore:
|
||||
this.removeControllerByAlias('_observePropertyEditorSchemaForDefaultUI');
|
||||
|
||||
this.observe(
|
||||
umbExtensionsRegistry.getByTypeAndAlias('propertyEditorUi', propertyEditorUiAlias),
|
||||
|
||||
@@ -76,7 +76,7 @@ export class UmbExtensionRootWorkspaceElement extends UmbLitElement {
|
||||
<uui-table-row>
|
||||
<uui-table-cell>${extension.type}</uui-table-cell>
|
||||
<uui-table-cell>
|
||||
${isManifestElementNameType(extension) ? extension.name : `[Custom extension] ${extension.name}`}
|
||||
${extension.name}
|
||||
</uui-table-cell>
|
||||
<uui-table-cell>${extension.alias}</uui-table-cell>
|
||||
<uui-table-cell>${extension.weight ? extension.weight : ''} </uui-table-cell>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbLanguageRepository } from '../../repository/language.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { ApiError, LanguageResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -7,7 +7,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbLanguageWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbLanguageRepository, LanguageResponseModel>
|
||||
implements UmbEntityWorkspaceContextInterface
|
||||
implements UmbSaveableWorkspaceContextInterface
|
||||
{
|
||||
#data = new UmbObjectState<LanguageResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -103,7 +103,7 @@ export class UmbLanguageWorkspaceContext
|
||||
}
|
||||
|
||||
|
||||
export const UMB_LANGUAGE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbLanguageWorkspaceContext>(
|
||||
export const UMB_LANGUAGE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbLanguageWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbLanguageWorkspaceContext => context.getEntityType?.() === 'language'
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { UmbRelationTypeRepository } from '../repository/relation-type.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import type { RelationTypeBaseModel, RelationTypeResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -7,7 +7,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbRelationTypeWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbRelationTypeRepository, RelationTypeResponseModel>
|
||||
implements UmbEntityWorkspaceContextInterface<RelationTypeResponseModel | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<RelationTypeResponseModel | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<RelationTypeResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -79,7 +79,7 @@ export class UmbRelationTypeWorkspaceContext
|
||||
|
||||
|
||||
|
||||
export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbRelationTypeWorkspaceContext>(
|
||||
export const UMB_RELATION_TYPE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbRelationTypeWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbRelationTypeWorkspaceContext => context.getEntityType?.() === 'relation-type'
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { UmbPartialViewsRepository } from '../repository/partial-views.repositor
|
||||
import { PartialViewDetails } from '../config.js';
|
||||
import { createObservablePart, UmbBooleanState, UmbDeepState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { UpdatePartialViewRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
@@ -10,7 +10,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
export class UmbPartialViewWorkspaceContext extends UmbWorkspaceContext<
|
||||
UmbPartialViewsRepository,
|
||||
PartialViewDetails
|
||||
> implements UmbEntityWorkspaceContextInterface {
|
||||
> implements UmbSaveableWorkspaceContextInterface {
|
||||
getEntityId(): string | undefined {
|
||||
return this.getData()?.path;
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export class UmbPartialViewWorkspaceContext extends UmbWorkspaceContext<
|
||||
|
||||
|
||||
|
||||
export const UMB_PARTIAL_VIEW_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbPartialViewWorkspaceContext>(
|
||||
export const UMB_PARTIAL_VIEW_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbPartialViewWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbPartialViewWorkspaceContext => context.getEntityType?.() === 'partial-view'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbStylesheetRepository } from '../repository/stylesheet.repository.js';
|
||||
import { StylesheetDetails } from '../index.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbArrayState, UmbBooleanState, UmbObjectState, createObservablePart } from '@umbraco-cms/backoffice/observable-api';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
@@ -9,7 +9,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export type RichTextRuleModelSortable = RichTextRuleModel & { sortOrder?: number };
|
||||
|
||||
export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStylesheetRepository, StylesheetDetails> implements UmbEntityWorkspaceContextInterface {
|
||||
export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStylesheetRepository, StylesheetDetails> implements UmbSaveableWorkspaceContextInterface {
|
||||
#data = new UmbObjectState<StylesheetDetails | undefined>(undefined);
|
||||
#rules = new UmbArrayState<RichTextRuleModelSortable>([], (rule) => rule.name);
|
||||
data = this.#data.asObservable();
|
||||
@@ -166,7 +166,7 @@ export class UmbStylesheetWorkspaceContext extends UmbWorkspaceContext<UmbStyles
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_STYLESHEET_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbStylesheetWorkspaceContext>(
|
||||
export const UMB_STYLESHEET_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbStylesheetWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbStylesheetWorkspaceContext => context.getEntityType?.() === 'stylesheet'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbTemplateRepository } from '../repository/template.repository.js';
|
||||
import { loadCodeEditor } from '@umbraco-cms/backoffice/code-editor';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import {
|
||||
createObservablePart,
|
||||
UmbBooleanState,
|
||||
@@ -11,7 +11,7 @@ import type { TemplateItemResponseModel, TemplateResponseModel } from '@umbraco-
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext<UmbTemplateRepository, TemplateResponseModel> implements UmbEntityWorkspaceContextInterface {
|
||||
export class UmbTemplateWorkspaceContext extends UmbWorkspaceContext<UmbTemplateRepository, TemplateResponseModel> implements UmbSaveableWorkspaceContextInterface {
|
||||
#data = new UmbDeepState<TemplateResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
#masterTemplate = new UmbObjectState<TemplateItemResponseModel | null>(null);
|
||||
@@ -170,7 +170,7 @@ ${currentContent}`;
|
||||
|
||||
|
||||
|
||||
export const UMB_TEMPLATE_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbTemplateWorkspaceContext>(
|
||||
export const UMB_TEMPLATE_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbTemplateWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbTemplateWorkspaceContext => context.getEntityType?.() === 'template'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbUserGroupRepository } from '../repository/user-group.repository.js';
|
||||
import { UmbUserRepository } from '../../users/repository/user.repository.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import type { UserGroupResponseModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbArrayState, UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
@@ -8,7 +8,7 @@ import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
|
||||
|
||||
export class UmbUserGroupWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbUserGroupRepository, UserGroupResponseModel>
|
||||
implements UmbEntityWorkspaceContextInterface<UserGroupResponseModel | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<UserGroupResponseModel | undefined>
|
||||
{
|
||||
#data = new UmbObjectState<UserGroupResponseModel | undefined>(undefined);
|
||||
data = this.#data.asObservable();
|
||||
@@ -55,9 +55,11 @@ export class UmbUserGroupWorkspaceContext
|
||||
getEntityId(): string | undefined {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
getEntityType(): string {
|
||||
throw new Error('Method not implemented.');
|
||||
return 'user-group';
|
||||
}
|
||||
|
||||
getData(): UserGroupResponseModel | undefined {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@@ -105,7 +107,7 @@ export class UmbUserGroupWorkspaceContext
|
||||
}
|
||||
|
||||
|
||||
export const UMB_USER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbUserGroupWorkspaceContext>(
|
||||
export const UMB_USER_GROUP_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbUserGroupWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbUserGroupWorkspaceContext => context.getEntityType?.() === 'user-group'
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { UmbUserRepository } from '../repository/user.repository.js';
|
||||
import { type UmbUserDetail } from '../index.js';
|
||||
import { UmbEntityWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import { UmbSaveableWorkspaceContextInterface, UmbWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
|
||||
import type { UmbControllerHostElement } from '@umbraco-cms/backoffice/controller-api';
|
||||
import type { UpdateUserRequestModel } from '@umbraco-cms/backoffice/backend-api';
|
||||
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
|
||||
@@ -10,7 +10,7 @@ import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs';
|
||||
|
||||
export class UmbUserWorkspaceContext
|
||||
extends UmbWorkspaceContext<UmbUserRepository, UmbUserDetail>
|
||||
implements UmbEntityWorkspaceContextInterface<UmbUserDetail | undefined>
|
||||
implements UmbSaveableWorkspaceContextInterface<UmbUserDetail | undefined>
|
||||
{
|
||||
#authContext?: typeof UMB_AUTH.TYPE;
|
||||
|
||||
@@ -82,7 +82,7 @@ export class UmbUserWorkspaceContext
|
||||
}
|
||||
}
|
||||
|
||||
export const UMB_USER_WORKSPACE_CONTEXT = new UmbContextToken<UmbEntityWorkspaceContextInterface, UmbUserWorkspaceContext>(
|
||||
export const UMB_USER_WORKSPACE_CONTEXT = new UmbContextToken<UmbSaveableWorkspaceContextInterface, UmbUserWorkspaceContext>(
|
||||
'UmbWorkspaceContext',
|
||||
(context): context is UmbUserWorkspaceContext => context.getEntityType?.() === 'user'
|
||||
);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
|
||||
<Meta
|
||||
title="Guides/Extending the Backoffice/Dataset Context"
|
||||
parameters={{ previewTabs: { canvas: { hidden: true } } }}
|
||||
/>
|
||||
|
||||
# Variant Context
|
||||
|
||||
The Variant Context is a context that holds the data for a set of properties.
|
||||
Property Editors UIs require the Variant Context to be present to work. This enables Property Editor UIs to have a generic relation with its ownership.
|
||||
|
||||
The Variant context holds a name and a set of properties. What makes a property can vary but we require an alias and a value.
|
||||
|
||||
## Variant Context concerning Property Editors and Workspaces.
|
||||
|
||||
A Variant Context is the connection point between a Property Editor and a Workspace.
|
||||
|
||||
The hierarchy is as follows:
|
||||
- Workspace Context
|
||||
- Variant Context
|
||||
- Property Editor UIs
|
||||
|
||||
A variant context covers a set of properties, in some cases a workspace then needs to have multiple variants. An example of such is Document Workspace. Each variant has its own set of properties and a name.
|
||||
|
||||
## Setup a Variant Context
|
||||
|
||||
It would be good to have examples for developers to see how to set up a Variant Context, in code. (This might need to be a tutorial demonstrating implementing a simple workspace with a variant with Property Editor UIs)
|
||||
@@ -8,12 +8,14 @@ import { Meta } from '@storybook/addon-docs';
|
||||
# Workspace Context
|
||||
|
||||
A Workspace context is a container for the data of a workspace. It is a wrapper around the data of the entity that the workspace is working on. It is also responsible for loading and saving the data to the server.
|
||||
TODO: extend the description of a workspace
|
||||
TODO: Extend the description of a workspace
|
||||
|
||||
(rough notes)
|
||||
|
||||
- A workspace context knows about its entity type (e.g. content, media, member, etc.) and holds its unique string (ex: key).
|
||||
- Most workspaces contexts holds a draft state of its entities data. It is a copy of the entity data that can be modified at runtime and send to the server to be saved.
|
||||
- A workspace context knows about its entity type (e.g. content, media, member, etc.) and holds its unique string (e.g.: key).
|
||||
- Most workspaces contexts hold a draft state of its entity data. It is a copy of the entity data that can be modified at runtime and sent to the server to be saved.
|
||||
|
||||
If a workspace wants to utilize Property Editor UIs, then it must provide a variant context for the property editors. The variant-context is the generic interface between workspace and property editors. See variant contexts for more info.
|
||||
|
||||
TODO: More points and examples:
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ export const plugins: PluginOption[] = [
|
||||
src: 'public-assets/App_Plugins/*.js',
|
||||
dest: 'App_Plugins',
|
||||
},
|
||||
{
|
||||
src: 'public-assets/App_Plugins/custom-bundle-package/*.js',
|
||||
dest: 'App_Plugins/custom-bundle-package',
|
||||
},
|
||||
{
|
||||
src: 'src/assets/*.svg',
|
||||
dest: 'umbraco/backoffice/assets',
|
||||
|
||||
Reference in New Issue
Block a user