Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE } from '../entity.js';
import type { UmbDocumentBlueprintPropertyDataContext } from './document-blueprint-property-dataset-context.js';
import type { UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';

export const IsDocumentBlueprintPropertyDatasetContext = (
context: UmbPropertyDatasetContext,
): context is UmbDocumentBlueprintPropertyDataContext => context.getEntityType() === UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE;

export const UMB_DOCUMENT_BLUEPRINT_PROPERTY_DATASET_CONTEXT = new UmbContextToken<
UmbPropertyDatasetContext,
UmbDocumentBlueprintPropertyDataContext
>('UmbVariantContext', undefined, IsDocumentBlueprintPropertyDatasetContext);
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import type { UmbDocumentBlueprintWorkspaceContext } from '../workspace/index.js';
import type { UmbNameablePropertyDatasetContext, UmbPropertyDatasetContext } from '@umbraco-cms/backoffice/property';
import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { type Observable, map } from '@umbraco-cms/backoffice/external/rxjs';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbVariantModel } from '@umbraco-cms/backoffice/variant';
import { UmbVariantId } from '@umbraco-cms/backoffice/variant';
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';

// TODO: This code can be split into a UmbContentTypePropertyDatasetContext, leaving just the publishing state and methods to this class.
export class UmbDocumentBlueprintPropertyDataContext
extends UmbContextBase<UmbPropertyDatasetContext>
implements UmbPropertyDatasetContext, UmbNameablePropertyDatasetContext
{
#workspace: UmbDocumentBlueprintWorkspaceContext;
#variantId: UmbVariantId;
public getVariantId() {
return this.#variantId;
}

#currentVariant = new UmbObjectState<UmbVariantModel | 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.

getEntityType(): string {
return this.#workspace.getEntityType();
}
getUnique(): string | undefined {
return this.#workspace.getUnique();
}
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: UmbDocumentBlueprintWorkspaceContext, variantId?: UmbVariantId) {
// The controller alias, is a very generic name cause we want only one of these for this controller host.

super(host, UMB_PROPERTY_DATASET_CONTEXT);
this.#workspace = workspace;
this.#variantId = variantId ?? UmbVariantId.CreateInvariant();

this.observe(
this.#workspace.variantById(this.#variantId),
async (variantInfo) => {
if (!variantInfo) return;
this.#currentVariant.setValue(variantInfo);
},
'_observeActiveVariant',
);
}

#createPropertyVariantId(property: UmbPropertyTypeModel) {
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 this method, 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,
): Promise<Observable<ReturnType | undefined> | undefined> {
await this.#workspace.isLoaded();
const structure = await this.#workspace.structure.getPropertyStructureByAlias(propertyAlias);
if (structure) {
return this.#workspace.propertyValueByAlias<ReturnType>(propertyAlias, this.#createPropertyVariantId(structure));
}
return;
}

// 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,
): Promise<Observable<ReturnType | undefined> | undefined> {
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS } from './manifests.js';
import { html, customElement, css } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';

@customElement('umb-document-blueprint-root-workspace')
export class UmbDocumentBlueprintRootWorkspaceElement extends UmbLitElement {
render() {
return html`<umb-workspace-editor alias="Umb.Workspace.DocumentBlueprint" headline="Document Blueprints">
return html`<umb-workspace-editor alias=${UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS} headline="Document Blueprints">
<div id="wrapper">
<uui-box>
<h2>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS } from './manifests.js';
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT } from './document-blueprint-workspace.context-token.js';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import { css, html, nothing, customElement, state, repeat } from '@umbraco-cms/backoffice/external/lit';
Expand All @@ -14,6 +15,7 @@ export class UmbDocumentBlueprintWorkspaceSplitViewElement extends UmbLitElement

constructor() {
super();
console.log('split view');

// TODO: Refactor: use a split view workspace context token:
this.consumeContext(UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT, (context) => {
Expand Down Expand Up @@ -42,14 +44,14 @@ export class UmbDocumentBlueprintWorkspaceSplitViewElement extends UmbLitElement
view.index + '_' + (view.culture ?? '') + '_' + (view.segment ?? '') + '_' + this._variants!.length,
(view) => html`
<umb-workspace-split-view
alias="Umb.Workspace.DocumentBlueprint"
alias=${UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS}
.splitViewIndex=${view.index}
.displayNavigation=${view.index === this._variants!.length - 1}></umb-workspace-split-view>
`,
)}
</div>

<umb-workspace-footer alias="Umb.Workspace.DocumentBlueprint"></umb-workspace-footer>`
<umb-workspace-footer alias=${UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS}></umb-workspace-footer>`
: nothing;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { UmbDocumentBlueprintPropertyDataContext } from '../property-dataset-context/document-blueprint-property-dataset-context.js';
import { UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE } from '../entity.js';
import { UmbDocumentBlueprintDetailRepository } from '../repository/index.js';
import type {
UmbDocumentBlueprintDetailModel,
UmbDocumentBlueprintVariantModel,
UmbDocumentBlueprintVariantOptionModel,
} from '../types.js';
import { UmbDocumentPropertyDataContext } from '../../documents/property-dataset-context/document-property-dataset-context.js';
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS } from './manifests.js';
import {
appendToFrozenArray,
mergeObservables,
Expand All @@ -28,7 +29,6 @@ import { UMB_INVARIANT_CULTURE, UmbVariantId } from '@umbraco-cms/backoffice/var
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language';
import type { UmbRoutableWorkspaceContext } from '@umbraco-cms/backoffice/workspace';
import { UmbDocumentWorkspaceContext } from '@umbraco-cms/backoffice/document';

type EntityType = UmbDocumentBlueprintDetailModel;

Expand All @@ -47,12 +47,16 @@ export class UmbDocumentBlueprintWorkspaceContext
#persistedData = new UmbObjectState<EntityType | undefined>(undefined);

#currentData = new UmbObjectState<EntityType | undefined>(undefined);

// TODo: Optimize this so it uses either a App Language Context? [NL]
#getDataPromise?: Promise<any>;
// TODO: Optimize this so it uses either a App Language Context? [NL]
#languageRepository = new UmbLanguageCollectionRepository(this);
#languages = new UmbArrayState<UmbLanguageDetailModel>([], (x) => x.unique);
public readonly languages = this.#languages.asObservable();

public isLoaded() {
return this.#getDataPromise;
}

readonly unique = this.#currentData.asObservablePart((data) => data?.unique);
readonly contentTypeUnique = this.#currentData.asObservablePart((data) => data?.documentType.unique);

Expand Down Expand Up @@ -105,7 +109,7 @@ export class UmbDocumentBlueprintWorkspaceContext
);

constructor(host: UmbControllerHost) {
super(host, 'Umb.Workspace.DocumentBlueprint');
super(host, UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS);

this.observe(this.contentTypeUnique, (unique) => this.structure.loadType(unique));
this.observe(this.varies, (varies) => (this.#varies = varies));
Expand Down Expand Up @@ -159,7 +163,7 @@ export class UmbDocumentBlueprintWorkspaceContext

async load(unique: string) {
this.resetState();

this.#getDataPromise = this.repository.requestByUnique(unique);
const { data, asObservable } = await this.repository.requestByUnique(unique);

if (data) {
Expand Down Expand Up @@ -429,10 +433,14 @@ export class UmbDocumentBlueprintWorkspaceContext
}
*/

public createPropertyDatasetContext(host: UmbControllerHost, variantId: UmbVariantId) {
/*public createPropertyDatasetContext(host: UmbControllerHost, variantId: UmbVariantId) {
// TODO: [LK] Temporary workaround/hack to get the workspace to load.
const docCxt = new UmbDocumentWorkspaceContext(host);
return new UmbDocumentPropertyDataContext(host, docCxt, variantId);
}*/

public createPropertyDatasetContext(host: UmbControllerHost, variantId: UmbVariantId) {
return new UmbDocumentBlueprintPropertyDataContext(host, this, variantId);
}

public destroy(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './document-blueprint-workspace.context-token.js';
export * from './document-blueprint-workspace.context.js';
29 changes: 27 additions & 2 deletions src/packages/documents/document-blueprints/workspace/manifests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE } from '../entity.js';
import { UmbSaveWorkspaceAction } from '@umbraco-cms/backoffice/workspace';
import type { ManifestWorkspace, ManifestWorkspaceActions } from '@umbraco-cms/backoffice/extension-registry';
import type {
ManifestWorkspace,
ManifestWorkspaceActions,
ManifestWorkspaceView,
} from '@umbraco-cms/backoffice/extension-registry';

export const UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS = 'Umb.Workspace.DocumentBlueprint';

Expand All @@ -15,6 +19,27 @@ const workspace: ManifestWorkspace = {
},
};

const workspaceViews: Array<ManifestWorkspaceView> = [
{
type: 'workspaceView',
alias: 'Umb.WorkspaceView.DocumentBlueprint.Edit',
name: 'Document Blueprint Workspace Edit View',
element: () => import('./views/edit/document-blueprint-workspace-view-edit.element.js'),
weight: 200,
meta: {
label: '#general_content',
pathname: 'content',
icon: 'document',
},
conditions: [
{
alias: 'Umb.Condition.WorkspaceAlias',
match: workspace.alias,
},
],
},
];

const workspaceActions: Array<ManifestWorkspaceActions> = [
{
type: 'workspaceAction',
Expand All @@ -37,4 +62,4 @@ const workspaceActions: Array<ManifestWorkspaceActions> = [
},
];

export const manifests = [workspace, ...workspaceActions];
export const manifests = [workspace, ...workspaceViews, ...workspaceActions];
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT } from '../../document-blueprint-workspace.context-token.js';
import { css, html, customElement, property, state, repeat } from '@umbraco-cms/backoffice/external/lit';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
import type { UmbPropertyTypeModel } from '@umbraco-cms/backoffice/content-type';
import { UmbContentTypePropertyStructureHelper } from '@umbraco-cms/backoffice/content-type';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbDocumentTypeDetailModel } from '@umbraco-cms/backoffice/document-type';

@customElement('umb-document-blueprint-workspace-view-edit-properties')
export class UmbDocumentBlueprintWorkspaceViewEditPropertiesElement extends UmbLitElement {
@property({ type: String, attribute: 'container-id', reflect: false })
public get containerId(): string | null | undefined {
return this.#propertyStructureHelper.getContainerId();
}
public set containerId(value: string | null | undefined) {
this.#propertyStructureHelper.setContainerId(value);
}

#propertyStructureHelper = new UmbContentTypePropertyStructureHelper<UmbDocumentTypeDetailModel>(this);

@state()
_propertyStructure?: Array<UmbPropertyTypeModel>;

constructor() {
super();

this.consumeContext(UMB_DOCUMENT_BLUEPRINT_WORKSPACE_CONTEXT, (workspaceContext) => {
this.#propertyStructureHelper.setStructureManager(workspaceContext.structure);
});
this.observe(
this.#propertyStructureHelper.propertyStructure,
(propertyStructure) => {
this._propertyStructure = propertyStructure;
},
null,
);
}

render() {
return this._propertyStructure
? repeat(
this._propertyStructure,
(property) => property.alias,
(property) =>
html`<umb-property-type-based-property
class="property"
.property=${property}></umb-property-type-based-property> `,
)
: '';
}

static styles = [
UmbTextStyles,
css`
.property {
border-bottom: 1px solid var(--uui-color-divider);
}
.property:last-child {
border-bottom: 0;
}
`,
];
}

export default UmbDocumentBlueprintWorkspaceViewEditPropertiesElement;

declare global {
interface HTMLElementTagNameMap {
'umb-document-blueprint-workspace-view-edit-properties': UmbDocumentBlueprintWorkspaceViewEditPropertiesElement;
}
}
Loading