align code across content workspaces

This commit is contained in:
Niels Lyngsø
2024-10-01 10:02:06 +02:00
parent 8d46ef709a
commit 77ae965dae
12 changed files with 183 additions and 77 deletions

View File

@@ -11,6 +11,7 @@ import {
UmbSubmittableWorkspaceContextBase,
UmbInvariantWorkspacePropertyDatasetContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import { UmbObjectState, appendToFrozenArray } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -70,7 +71,7 @@ export class UmbBlockTypeWorkspaceContext<BlockTypeData extends UmbBlockTypeWith
protected override resetState() {
super.resetState();
this.#data.setValue(undefined);
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
}
createPropertyDatasetContext(host: UmbControllerHost): UmbPropertyDatasetContext {

View File

@@ -6,6 +6,7 @@ import {
type UmbRoutableWorkspaceContext,
UmbWorkspaceIsNewRedirectController,
type ManifestWorkspace,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import {
UmbBooleanState,
@@ -205,7 +206,7 @@ export class UmbBlockWorkspaceContext<LayoutDataType extends UmbBlockLayoutBaseM
this.#initialSettings = undefined;
this.content.reset();
this.settings.reset();
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
}
async load(unique: string) {

View File

@@ -10,6 +10,7 @@ import {
UmbSubmittableWorkspaceContextBase,
UmbInvariantWorkspacePropertyDatasetContext,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -87,7 +88,7 @@ export class UmbPropertyTypeWorkspaceContext<PropertyTypeData extends UmbPropert
protected override resetState() {
super.resetState();
this.#data.setValue(undefined);
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
this.removeUmbControllerByAlias('observePropertyTypeData');
}

View File

@@ -4,6 +4,8 @@ import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
import type { UmbRouterSlotElement } from '@umbraco-cms/backoffice/router';
import { ensurePathEndsWithSlash, umbUrlPatternToString } from '@umbraco-cms/backoffice/utils';
export const UmbWorkspaceIsNewRedirectControllerAlias = Symbol('IsNewRedirectControllerAlias');
/**
* Observe the workspace context to see if the entity is new or not.
* If that changes redirect to the edit url.
@@ -19,7 +21,7 @@ export class UmbWorkspaceIsNewRedirectController extends UmbControllerBase {
workspaceContext: UmbSubmittableWorkspaceContextBase<unknown>,
router: UmbRouterSlotElement,
) {
super(host, 'isNewRedirectController');
super(host, UmbWorkspaceIsNewRedirectControllerAlias);
// Navigate to edit route when language is created:
this.observe(workspaceContext.isNew, (isNew) => {
@@ -37,5 +39,7 @@ export class UmbWorkspaceIsNewRedirectController extends UmbControllerBase {
}
}
});
// TODO: If workspace route changes cause of other reasons then this controller should be destroyed.
}
}

View File

@@ -5,3 +5,8 @@ export const UMB_DOCUMENT_BLUEPRINT_FOLDER_ENTITY_TYPE = 'document-blueprint-fol
export type UmbDocumentBlueprintRootEntityType = typeof UMB_DOCUMENT_BLUEPRINT_ROOT_ENTITY_TYPE;
export type UmbDocumentBlueprintEntityType = typeof UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE;
export type UmbDocumentBlueprintFolderEntityType = typeof UMB_DOCUMENT_BLUEPRINT_FOLDER_ENTITY_TYPE;
export type UmbDocumentBlueprintEntityTypeUnion =
| UmbDocumentBlueprintRootEntityType
| UmbDocumentBlueprintEntityType
| UmbDocumentBlueprintFolderEntityType;

View File

@@ -0,0 +1,21 @@
import { UMB_DOCUMENTS_SECTION_PATHNAME } from '../section/paths.js';
import { UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE, type UmbDocumentBlueprintEntityTypeUnion } from './entity.js';
import type { UmbEntityUnique } from '@umbraco-cms/backoffice/entity';
import { UmbPathPattern } from '@umbraco-cms/backoffice/router';
import { UMB_WORKSPACE_PATH_PATTERN } from '@umbraco-cms/backoffice/workspace';
export const UMB_DOCUMENT_BLUEPRINT_WORKSPACE_PATH = UMB_WORKSPACE_PATH_PATTERN.generateAbsolute({
sectionName: UMB_DOCUMENTS_SECTION_PATHNAME,
entityType: UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE,
});
export const UMB_CREATE_DOCUMENT_BLUEPRINT_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{
parentEntityType: UmbDocumentBlueprintEntityTypeUnion;
parentUnique?: UmbEntityUnique;
documentTypeUnique: string;
}>('create/parent/:parentEntityType/:parentUnique/:documentTypeUnique', UMB_DOCUMENT_BLUEPRINT_WORKSPACE_PATH);
export const UMB_EDIT_BLUEPRINT_DOCUMENT_WORKSPACE_PATH_PATTERN = new UmbPathPattern<{ unique: string }>(
'edit/:unique',
UMB_DOCUMENT_BLUEPRINT_WORKSPACE_PATH,
);

View File

@@ -0,0 +1,16 @@
import type { UmbDocumentBlueprintVariantOptionModel } from './types.js';
type VariantType = UmbDocumentBlueprintVariantOptionModel;
export const sortVariants = (a: VariantType, b: VariantType) => {
const compareDefault = (a: VariantType, b: VariantType) =>
(a.language?.isDefault ? -1 : 1) - (b.language?.isDefault ? -1 : 1);
// Make sure mandatory variants goes on top.
const compareMandatory = (a: VariantType, b: VariantType) =>
(a.language?.isMandatory ? -1 : 1) - (b.language?.isMandatory ? -1 : 1);
const compareName = (a: VariantType, b: VariantType) => a.variant?.name.localeCompare(b.variant?.name || '') || 99;
return compareDefault(a, b) || compareMandatory(a, b) || compareName(a, b);
};

View File

@@ -7,6 +7,8 @@ import type {
UmbDocumentBlueprintVariantModel,
UmbDocumentBlueprintVariantOptionModel,
} from '../types.js';
import { sortVariants } from '../utils.js';
import { UMB_CREATE_DOCUMENT_BLUEPRINT_WORKSPACE_PATH_PATTERN } from '../paths.js';
import { UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS } from './manifests.js';
import {
appendToFrozenArray,
@@ -17,6 +19,7 @@ import {
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceIsNewRedirectControllerAlias,
UmbWorkspaceSplitViewManager,
} from '@umbraco-cms/backoffice/workspace';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
@@ -35,8 +38,15 @@ import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
import type { UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language';
import { UmbContentWorkspaceDataManager, type UmbContentWorkspaceContext } from '@umbraco-cms/backoffice/content';
import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils';
import { UMB_DOCUMENT_DETAIL_MODEL_VARIANT_SCAFFOLD } from '@umbraco-cms/backoffice/document';
import {
UMB_DOCUMENT_COLLECTION_ALIAS,
UMB_DOCUMENT_DETAIL_MODEL_VARIANT_SCAFFOLD,
UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN,
} from '@umbraco-cms/backoffice/document';
import { UmbDataTypeItemRepositoryManager } from '@umbraco-cms/backoffice/data-type';
import { Observable, map } from '@umbraco-cms/backoffice/external/rxjs';
import { UmbEntityContext, type UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import { UMB_SETTINGS_SECTION_PATH } from '@umbraco-cms/backoffice/settings';
type EntityModel = UmbDocumentBlueprintDetailModel;
@@ -119,27 +129,46 @@ export class UmbDocumentBlueprintWorkspaceContext
}
return [];
},
);
).pipe(map((results) => results.sort(sortVariants)));
// TODO: this should be set up for all entity workspace contexts in a base class
#entityContext = new UmbEntityContext(this);
constructor(host: UmbControllerHost) {
super(host, UMB_DOCUMENT_BLUEPRINT_WORKSPACE_ALIAS);
this.observe(this.contentTypeUnique, (unique) => this.structure.loadType(unique));
this.observe(this.variesByCulture, (varies) => {
this.#data.setVariesByCulture(varies);
this.#variesByCulture = varies;
});
this.observe(this.variesBySegment, (varies) => {
this.#data.setVariesBySegment(varies);
this.#variesBySegment = varies;
});
this.observe(this.varies, (varies) => (this.#varies = varies));
this.observe(this.structure.contentTypeDataTypeUniques, (dataTypeUniques: Array<string>) => {
this.#dataTypeItemManager.setUniques(dataTypeUniques);
});
this.observe(this.contentTypeUnique, (unique) => this.structure.loadType(unique), null);
this.observe(
this.varies,
(varies) => {
this.#data.setVaries(varies);
this.#varies = varies;
},
null,
);
this.observe(
this.variesByCulture,
(varies) => {
this.#data.setVariesByCulture(varies);
this.#variesByCulture = varies;
},
null,
);
this.observe(
this.variesBySegment,
(varies) => {
this.#data.setVariesBySegment(varies);
this.#variesBySegment = varies;
},
null,
);
this.observe(
this.structure.contentTypeDataTypeUniques,
(dataTypeUniques: Array<string>) => {
this.#dataTypeItemManager.setUniques(dataTypeUniques);
},
null,
);
this.observe(this.#dataTypeItemManager.items, (dataTypes) => {
// Make a map of the data type unique and editorAlias:
this.#dataTypeSchemaAliasMap = new Map(
@@ -148,14 +177,15 @@ export class UmbDocumentBlueprintWorkspaceContext
}),
);
});
this.loadLanguages();
this.routes.setRoutes([
{
path: 'create/parent/:entityType/:parentUnique/:documentTypeUnique',
path: UMB_CREATE_DOCUMENT_BLUEPRINT_WORKSPACE_PATH_PATTERN.toString(),
component: () => import('./document-blueprint-workspace-editor.element.js'),
setup: async (_component, info) => {
const parentEntityType = info.match.params.entityType;
const parentEntityType = info.match.params.parentEntityType;
const parentUnique = info.match.params.parentUnique === 'null' ? null : info.match.params.parentUnique;
const documentTypeUnique = info.match.params.documentTypeUnique;
this.create({ entityType: parentEntityType, unique: parentUnique }, documentTypeUnique);
@@ -168,10 +198,10 @@ export class UmbDocumentBlueprintWorkspaceContext
},
},
{
path: 'edit/:unique',
path: UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN.toString(),
component: () => import('./document-blueprint-workspace-editor.element.js'),
setup: (_component, info) => {
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
const unique = info.match.params.unique;
this.load(unique);
},
@@ -181,8 +211,7 @@ export class UmbDocumentBlueprintWorkspaceContext
override resetState() {
super.resetState();
this.#data.setPersisted(undefined);
this.#data.setCurrent(undefined);
this.#data.clear();
}
async loadLanguages() {
@@ -194,42 +223,50 @@ export class UmbDocumentBlueprintWorkspaceContext
async load(unique: string) {
this.resetState();
this.#getDataPromise = this.repository.requestByUnique(unique);
const { data, asObservable } = await this.repository.requestByUnique(unique);
type GetDataType = Awaited<ReturnType<UmbDocumentBlueprintDetailRepository['requestByUnique']>>;
const { data, asObservable } = (await this.#getDataPromise) as GetDataType;
if (data) {
this.#entityContext.setEntityType(UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE);
this.#entityContext.setUnique(unique);
this.setIsNew(false);
this.#data.setPersisted(data);
this.#data.setCurrent(data);
}
if (asObservable) {
this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'UmbDocumentBlueprintStoreObserver');
}
this.observe(asObservable(), (entity) => this.#onStoreChange(entity), 'UmbDocumentBlueprintStoreObserver');
}
#onStoreChange(entity: EntityModel | undefined) {
if (!entity) {
//TODO: This solution is alright for now. But reconsider when we introduce signal-r
history.pushState(null, '', 'section/document-blueprint');
history.pushState(null, '', UMB_SETTINGS_SECTION_PATH);
}
}
async create(parent: { entityType: string; unique: string | null }, documentTypeUnique: string) {
async create(parent: UmbEntityModel, documentTypeUnique: string) {
this.resetState();
this.#parent.setValue(parent);
const { data } = await this.repository.createScaffold({
this.#getDataPromise = this.repository.createScaffold({
documentType: { unique: documentTypeUnique, collection: null },
});
const { data } = await this.#getDataPromise;
if (!data) return undefined;
this.#entityContext.setEntityType(UMB_DOCUMENT_BLUEPRINT_ENTITY_TYPE);
this.#entityContext.setUnique(data.unique);
this.setIsNew(true);
this.#data.setPersisted(undefined);
this.#data.setCurrent(data);
return data;
}
getCollectionAlias() {
return UMB_DOCUMENT_COLLECTION_ALIAS;
}
getData() {
return this.#data.getCurrent();
}
@@ -294,7 +331,10 @@ export class UmbDocumentBlueprintWorkspaceContext
* @returns {Promise<Observable<ReturnType | undefined> | undefined>}
* @description Get an Observable for the value of this property.
*/
async propertyValueByAlias<PropertyValueType = unknown>(propertyAlias: string, variantId?: UmbVariantId) {
async propertyValueByAlias<PropertyValueType = unknown>(
propertyAlias: string,
variantId?: UmbVariantId,
): Promise<Observable<PropertyValueType | undefined> | undefined> {
return this.#data.createObservablePartOfCurrent(
(data) =>
data?.values?.find((x) => x?.alias === propertyAlias && (variantId ? variantId.compare(x as any) : true))

View File

@@ -18,6 +18,7 @@ import {
import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import { UmbTemplateDetailRepository } from '@umbraco-cms/backoffice/template';
import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action';
@@ -132,7 +133,7 @@ export class UmbDocumentTypeWorkspaceContext
path: UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN.toString(),
component: UmbDocumentTypeWorkspaceEditorElement,
setup: (_component, info) => {
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
const unique = info.match.params.unique;
this.load(unique);
},

View File

@@ -27,7 +27,7 @@ import { UMB_DOCUMENTS_SECTION_PATH } from '../../section/paths.js';
import { UmbDocumentPreviewRepository } from '../repository/preview/index.js';
import { sortVariants } from '../utils.js';
import { UMB_DOCUMENT_DETAIL_MODEL_VARIANT_SCAFFOLD, UMB_DOCUMENT_WORKSPACE_ALIAS } from './constants.js';
import { UmbEntityContext } from '@umbraco-cms/backoffice/entity';
import { UmbEntityContext, type UmbEntityModel } from '@umbraco-cms/backoffice/entity';
import { UMB_INVARIANT_CULTURE, UmbVariantId } from '@umbraco-cms/backoffice/variant';
import { UmbContentTypeStructureManager } from '@umbraco-cms/backoffice/content-type';
import {
@@ -35,6 +35,7 @@ import {
UmbSubmittableWorkspaceContextBase,
UmbWorkspaceIsNewRedirectController,
UmbWorkspaceSplitViewManager,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import {
appendToFrozenArray,
@@ -72,6 +73,7 @@ import type { UmbDocumentTypeDetailModel } from '@umbraco-cms/backoffice/documen
import { UmbIsTrashedEntityContext } from '@umbraco-cms/backoffice/recycle-bin';
import { UmbReadOnlyVariantStateManager } from '@umbraco-cms/backoffice/utils';
import { UmbDataTypeItemRepositoryManager } from '@umbraco-cms/backoffice/data-type';
import { UMB_DOCUMENT_COLLECTION_ALIAS } from '../collection/index.js';
type EntityModel = UmbDocumentDetailModel;
type EntityTypeModel = UmbDocumentTypeDetailModel;
@@ -183,34 +185,51 @@ export class UmbDocumentWorkspaceContext
new UmbVariantValuesValidationPathTranslator(this);
new UmbVariantsValidationPathTranslator(this);
this.observe(this.contentTypeUnique, (unique) => this.structure.loadType(unique));
this.observe(this.varies, (varies) => {
this.#data.setVaries(varies);
});
this.observe(this.variesByCulture, (varies) => {
this.#data.setVariesByCulture(varies);
this.#variesByCulture = varies;
});
this.observe(this.variesBySegment, (varies) => {
this.#data.setVariesBySegment(varies);
this.#variesBySegment = varies;
});
this.observe(this.varies, (varies) => {
this.#varies = varies;
});
this.observe(this.contentTypeUnique, (unique) => this.structure.loadType(unique), null);
this.observe(
this.varies,
(varies) => {
this.#data.setVaries(varies);
this.observe(this.structure.contentTypeDataTypeUniques, (dataTypeUniques: Array<string>) => {
this.#dataTypeItemManager.setUniques(dataTypeUniques);
});
this.observe(this.#dataTypeItemManager.items, (dataTypes) => {
// Make a map of the data type unique and editorAlias:
this.#dataTypeSchemaAliasMap = new Map(
dataTypes.map((dataType) => {
return [dataType.unique, dataType.propertyEditorSchemaAlias];
}),
);
});
this.#varies = varies;
},
null,
);
this.observe(
this.variesByCulture,
(varies) => {
this.#data.setVariesByCulture(varies);
this.#variesByCulture = varies;
},
null,
);
this.observe(
this.variesBySegment,
(varies) => {
this.#data.setVariesBySegment(varies);
this.#variesBySegment = varies;
},
null,
);
this.observe(
this.structure.contentTypeDataTypeUniques,
(dataTypeUniques: Array<string>) => {
this.#dataTypeItemManager.setUniques(dataTypeUniques);
},
null,
);
this.observe(
this.#dataTypeItemManager.items,
(dataTypes) => {
// Make a map of the data type unique and editorAlias:
this.#dataTypeSchemaAliasMap = new Map(
dataTypes.map((dataType) => {
return [dataType.unique, dataType.propertyEditorSchemaAlias];
}),
);
},
null,
);
this.loadLanguages();
@@ -253,6 +272,7 @@ export class UmbDocumentWorkspaceContext
path: UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN.toString(),
component: () => import('./document-workspace-editor.element.js'),
setup: (_component, info) => {
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
const unique = info.match.params.unique;
this.load(unique);
},
@@ -262,8 +282,7 @@ export class UmbDocumentWorkspaceContext
override resetState() {
super.resetState();
this.#data.setPersisted(undefined);
this.#data.setCurrent(undefined);
this.#data.clear();
}
async loadLanguages() {
@@ -297,11 +316,7 @@ export class UmbDocumentWorkspaceContext
}
}
async create(
parent: { entityType: string; unique: string | null },
documentTypeUnique: string,
blueprintUnique?: string,
) {
async create(parent: UmbEntityModel, documentTypeUnique: string, blueprintUnique?: string) {
this.resetState();
this.#parent.setValue(parent);
@@ -336,7 +351,7 @@ export class UmbDocumentWorkspaceContext
}
getCollectionAlias() {
return 'Umb.Collection.Document';
return UMB_DOCUMENT_COLLECTION_ALIAS;
}
getData() {
@@ -384,7 +399,6 @@ export class UmbDocumentWorkspaceContext
}
setName(name: string, variantId?: UmbVariantId) {
// TODO: We should move this type of logic to the act of saving [NL]
this.#data.updateVariantData(variantId ?? UmbVariantId.CreateInvariant(), { name });
}
@@ -438,7 +452,7 @@ export class UmbDocumentWorkspaceContext
* @returns The value or undefined if not set or found.
*/
getPropertyValue<ReturnType = unknown>(alias: string, variantId?: UmbVariantId) {
const currentData = this.getData();
const currentData = this.#data.getCurrent();
if (currentData) {
const newDataSet = currentData.values?.find(
(x) => x.alias === alias && (variantId ? variantId.compare(x) : true),

View File

@@ -8,6 +8,7 @@ import {
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
UmbEntityDetailWorkspaceContextBase,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -44,7 +45,7 @@ export class UmbLanguageWorkspaceContext
path: 'edit/:unique',
component: UmbLanguageWorkspaceEditorElement,
setup: (_component, info) => {
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
this.load(info.match.params.unique);
},
},

View File

@@ -8,6 +8,7 @@ import {
UmbWorkspaceIsNewRedirectController,
type UmbRoutableWorkspaceContext,
UmbEntityDetailWorkspaceContextBase,
UmbWorkspaceIsNewRedirectControllerAlias,
} from '@umbraco-cms/backoffice/workspace';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';
@@ -40,7 +41,7 @@ export class UmbWebhookWorkspaceContext
path: 'edit/:unique',
component: UmbWebhookWorkspaceEditorElement,
setup: (_component, info) => {
this.removeUmbControllerByAlias('isNewRedirectController');
this.removeUmbControllerByAlias(UmbWorkspaceIsNewRedirectControllerAlias);
this.load(info.match.params.unique);
},
},