diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts index d042027c0668..42b8769acf0f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/content/workspace/content-detail-workspace-base.ts @@ -42,6 +42,7 @@ import type { UmbModalToken } from '@umbraco-cms/backoffice/modal'; import { UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; import { + UmbEntityUpdatedEvent, UmbRequestReloadChildrenOfEntityEvent, UmbRequestReloadStructureForEntityEvent, } from '@umbraco-cms/backoffice/entity-action'; @@ -709,13 +710,21 @@ export abstract class UmbContentDetailWorkspaceContextBase< ); this._data.setCurrent(newCurrentData); + const unique = this.getUnique()!; + const entityType = this.getEntityType(); + const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); - const event = new UmbRequestReloadStructureForEntityEvent({ - entityType: this.getEntityType(), - unique: this.getUnique()!, + const structureEvent = new UmbRequestReloadStructureForEntityEvent({ unique, entityType }); + eventContext.dispatchEvent(structureEvent); + + const updatedEvent = new UmbEntityUpdatedEvent({ + unique, + entityType, + eventUnique: this._workspaceEventUnique, }); - eventContext.dispatchEvent(event); + eventContext.dispatchEvent(updatedEvent); + this._closeModal(); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts index e6567e5a7c8f..ff91281d8999 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-action.event.ts @@ -2,7 +2,9 @@ import { UmbControllerEvent } from '@umbraco-cms/backoffice/controller-api'; import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; // eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface UmbEntityActionEventArgs extends UmbEntityModel {} +export interface UmbEntityActionEventArgs extends UmbEntityModel { + eventUnique?: string; +} export class UmbEntityActionEvent< ArgsType extends UmbEntityActionEventArgs = UmbEntityActionEventArgs, @@ -21,4 +23,8 @@ export class UmbEntityActionEvent< getUnique(): string | null { return this._args.unique; } + + getEventUnique(): string | undefined { + return this._args.eventUnique; + } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-updated.event.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-updated.event.ts new file mode 100644 index 000000000000..19bfc62daab4 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/entity-updated.event.ts @@ -0,0 +1,10 @@ +import type { UmbEntityActionEventArgs } from './entity-action.event.js'; +import { UmbEntityActionEvent } from './entity-action.event.js'; + +export class UmbEntityUpdatedEvent extends UmbEntityActionEvent { + static readonly TYPE = 'entity-updated'; + + constructor(args: UmbEntityActionEventArgs) { + super(UmbEntityUpdatedEvent.TYPE, args); + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts index 4347644d1f7f..37d12fa9f0da 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/entity-action/index.ts @@ -5,6 +5,7 @@ export * from './constants.js'; export * from './entity-action-base.js'; export * from './entity-action-list.element.js'; export * from './entity-action.event.js'; +export * from './entity-updated.event.js'; export type * from './types.js'; export { UmbRequestReloadStructureForEntityEvent } from './request-reload-structure-for-entity.event.js'; diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts index 3992d118efce..d54166a95189 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-items.manager.ts @@ -4,6 +4,8 @@ import { UmbArrayState } from '@umbraco-cms/backoffice/observable-api'; import { type ManifestRepository, umbExtensionsRegistry } from '@umbraco-cms/backoffice/extension-registry'; import { UmbExtensionApiInitializer } from '@umbraco-cms/backoffice/extension-api'; import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; +import { UmbEntityUpdatedEvent } from '@umbraco-cms/backoffice/entity-action'; const ObserveRepositoryAlias = Symbol(); @@ -14,6 +16,7 @@ export class UmbRepositoryItemsManager exte #init: Promise; #currentRequest?: Promise; + #eventContext?: typeof UMB_ACTION_EVENT_CONTEXT.TYPE; // the init promise is used externally for recognizing when the manager is ready. public get init() { @@ -70,6 +73,20 @@ export class UmbRepositoryItemsManager exte }, null, ); + + this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (context) => { + this.#eventContext = context; + + this.#eventContext.removeEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); + + this.#eventContext.addEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); + }); } getUniques(): Array { @@ -122,6 +139,25 @@ export class UmbRepositoryItemsManager exte } } + async #reloadItem(unique: string): Promise { + await this.#init; + if (!this.repository) throw new Error('Repository is not initialized'); + + const { data } = await this.repository.requestItems([unique]); + + if (data) { + const items = this.getItems(); + const item = items.find((item) => this.#getUnique(item) === unique); + + if (item) { + const index = items.indexOf(item); + const newItems = [...items]; + newItems[index] = data[0]; + this.#items.setValue(this.#sortByUniques(newItems)); + } + } + } + #sortByUniques(data: Array): Array { const uniques = this.getUniques(); return [...data].sort((a, b) => { @@ -130,4 +166,25 @@ export class UmbRepositoryItemsManager exte return aIndex - bIndex; }); } + + #onEntityUpdatedEvent = (event: UmbEntityUpdatedEvent) => { + const eventUnique = event.getUnique(); + + const items = this.getItems(); + if (items.length === 0) return; + + // Ignore events if the entity is not in the list of items. + const item = items.find((item) => this.#getUnique(item) === eventUnique); + if (!item) return; + + this.#reloadItem(item.unique); + }; + + override destroy(): void { + this.#eventContext?.removeEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); + super.destroy(); + } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts index 574f0e6faf28..07e3c570f9df 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/entity-detail/entity-detail-workspace-base.ts @@ -7,6 +7,7 @@ import { UmbEntityContext, type UmbEntityModel, type UmbEntityUnique } from '@um import { UMB_DISCARD_CHANGES_MODAL, UMB_MODAL_MANAGER_CONTEXT } from '@umbraco-cms/backoffice/modal'; import { UmbObjectState } from '@umbraco-cms/backoffice/observable-api'; import { + UmbEntityUpdatedEvent, UmbRequestReloadChildrenOfEntityEvent, UmbRequestReloadStructureForEntityEvent, } from '@umbraco-cms/backoffice/entity-action'; @@ -15,6 +16,7 @@ import { umbExtensionsRegistry, type ManifestRepository } from '@umbraco-cms/bac import type { UmbDetailRepository } from '@umbraco-cms/backoffice/repository'; import { UmbStateManager } from '@umbraco-cms/backoffice/utils'; import { UmbValidationContext } from '@umbraco-cms/backoffice/validation'; +import { UmbId } from '@umbraco-cms/backoffice/id'; const LOADING_STATE_UNIQUE = 'umbLoadingEntityDetail'; @@ -45,6 +47,8 @@ export abstract class UmbEntityDetailWorkspaceContextBase< protected _getDataPromise?: Promise; protected _detailRepository?: DetailRepositoryType; + #eventContext?: typeof UMB_ACTION_EVENT_CONTEXT.TYPE; + #parent = new UmbObjectState<{ entityType: string; unique: UmbEntityUnique } | undefined>(undefined); public readonly parentUnique = this.#parent.asObservablePart((parent) => (parent ? parent.unique : undefined)); public readonly parentEntityType = this.#parent.asObservablePart((parent) => @@ -85,6 +89,19 @@ export abstract class UmbEntityDetailWorkspaceContextBase< window.addEventListener('willchangestate', this.#onWillNavigate); this.#observeRepository(args.detailRepositoryAlias); this.addValidationContext(this.validationContext); + + this.consumeContext(UMB_ACTION_EVENT_CONTEXT, (context) => { + this.#eventContext = context; + + this.#eventContext.removeEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); + this.#eventContext.addEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); + }); } /** @@ -307,13 +324,21 @@ export abstract class UmbEntityDetailWorkspaceContextBase< this._data.setPersisted(data); this._data.setCurrent(data); - const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); - const event = new UmbRequestReloadStructureForEntityEvent({ - unique: this.getUnique()!, - entityType: this.getEntityType(), + const unique = this.getUnique()!; + const entityType = this.getEntityType(); + + const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + const event = new UmbRequestReloadStructureForEntityEvent({ unique, entityType }); + + eventContext.dispatchEvent(event); + + const updatedEvent = new UmbEntityUpdatedEvent({ + unique, + entityType, + eventUnique: this._workspaceEventUnique, }); - actionEventContext.dispatchEvent(event); + eventContext.dispatchEvent(updatedEvent); } #allowNavigateAway = false; @@ -396,8 +421,30 @@ export abstract class UmbEntityDetailWorkspaceContextBase< } } + // Discriminator to identify events from this workspace context + protected readonly _workspaceEventUnique = UmbId.new(); + + #onEntityUpdatedEvent = (event: UmbEntityUpdatedEvent) => { + const eventEntityUnique = event.getUnique(); + const eventEntityType = event.getEntityType(); + const eventDiscriminator = event.getEventUnique(); + + // Ignore events for other entities + if (eventEntityType !== this.getEntityType()) return; + if (eventEntityUnique !== this.getUnique()) return; + + // Ignore events from this workspace so we don't reload the data twice. Ex saving this workspace + if (eventDiscriminator === this._workspaceEventUnique) return; + + this.reload(); + }; + public override destroy(): void { window.removeEventListener('willchangestate', this.#onWillNavigate); + this.#eventContext?.removeEventListener( + UmbEntityUpdatedEvent.TYPE, + this.#onEntityUpdatedEvent as unknown as EventListener, + ); this._detailRepository?.destroy(); this.#entityContext.destroy(); super.destroy(); diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/manifests.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/manifests.ts index 83800af9fac6..2f736381e681 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/manifests.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/entity-action/manifests.ts @@ -1,9 +1,4 @@ -import { - UMB_USER_PERMISSION_DOCUMENT_ROLLBACK, - UMB_DOCUMENT_ENTITY_TYPE, - UMB_DOCUMENT_WORKSPACE_ALIAS, -} from '../../constants.js'; -import { UMB_WORKSPACE_CONDITION_ALIAS } from '@umbraco-cms/backoffice/workspace'; +import { UMB_USER_PERMISSION_DOCUMENT_ROLLBACK, UMB_DOCUMENT_ENTITY_TYPE } from '../../constants.js'; import { UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS } from '@umbraco-cms/backoffice/recycle-bin'; export const manifests: Array = [ @@ -12,7 +7,7 @@ export const manifests: Array = [ kind: 'default', alias: 'Umb.EntityAction.Document.Rollback', name: 'Rollback Document Entity Action', - weight: 500, + weight: 450, api: () => import('./rollback.action.js'), forEntityTypes: [UMB_DOCUMENT_ENTITY_TYPE], meta: { @@ -27,12 +22,6 @@ export const manifests: Array = [ { alias: UMB_ENTITY_IS_NOT_TRASHED_CONDITION_ALIAS, }, - /* Currently the rollback is tightly coupled to the workspace contexts so we only allow it to show up - In the document workspace. */ - { - alias: UMB_WORKSPACE_CONDITION_ALIAS, - match: UMB_DOCUMENT_WORKSPACE_ALIAS, - }, ], }, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts index c8949086cc1c..e41ad2d0539d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/rollback/modal/rollback-modal.element.ts @@ -1,5 +1,7 @@ -import { UMB_DOCUMENT_WORKSPACE_CONTEXT, UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN } from '../../constants.js'; +import { UMB_DOCUMENT_ENTITY_TYPE } from '../../constants.js'; import { UmbRollbackRepository } from '../repository/rollback.repository.js'; +import { UmbDocumentDetailRepository } from '../../repository/index.js'; +import type { UmbDocumentDetailModel } from '../../types.js'; import type { UmbRollbackModalData, UmbRollbackModalValue } from './types.js'; import { diffWords, type Change } from '@umbraco-cms/backoffice/external/diff'; import { css, customElement, html, nothing, repeat, state, unsafeHTML } from '@umbraco-cms/backoffice/external/lit'; @@ -8,8 +10,13 @@ import { UmbTextStyles } from '@umbraco-cms/backoffice/style'; import { UmbUserItemRepository } from '@umbraco-cms/backoffice/user'; import { UMB_PROPERTY_DATASET_CONTEXT } from '@umbraco-cms/backoffice/property'; import type { UUISelectEvent } from '@umbraco-cms/backoffice/external/uui'; +import { UMB_APP_LANGUAGE_CONTEXT, UmbLanguageItemRepository } from '@umbraco-cms/backoffice/language'; +import { UMB_ENTITY_CONTEXT } from '@umbraco-cms/backoffice/entity'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import '../../modals/shared/document-variant-language-picker.element.js'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; +import { UmbEntityUpdatedEvent, UmbRequestReloadStructureForEntityEvent } from '@umbraco-cms/backoffice/entity-action'; type DocumentVersion = { id: string; @@ -22,10 +29,10 @@ type DocumentVersion = { @customElement('umb-rollback-modal') export class UmbRollbackModalElement extends UmbModalBaseElement { @state() - versions: DocumentVersion[] = []; + _versions: DocumentVersion[] = []; @state() - currentVersion?: { + _selectedVersion?: { date: string; name: string; user: string; @@ -37,17 +44,19 @@ export class UmbRollbackModalElement extends UmbModalBaseElement = []; - #propertyDatasetContext?: typeof UMB_PROPERTY_DATASET_CONTEXT.TYPE; + #rollbackRepository = new UmbRollbackRepository(this); + #userItemRepository = new UmbUserItemRepository(this); #localizeDateOptions: Intl.DateTimeFormatOptions = { day: 'numeric', @@ -56,37 +65,76 @@ export class UmbRollbackModalElement extends UmbModalBaseElement { - this.#propertyDatasetContext = instance; - this.currentCulture = instance.getVariantId().culture ?? undefined; - this.#requestVersions(); + this.#currentDatasetCulture = instance.getVariantId().culture ?? undefined; + this.#selectCulture(); }); - this.consumeContext(UMB_DOCUMENT_WORKSPACE_CONTEXT, (instance) => { - this.#workspaceContext = instance; + this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (instance) => { + this.#currentAppCulture = instance.getAppCulture(); + this.#selectCulture(); + }); + + this.consumeContext(UMB_ENTITY_CONTEXT, async (instance) => { + if (instance.getEntityType() !== UMB_DOCUMENT_ENTITY_TYPE) { + throw new Error(`Entity type is not ${UMB_DOCUMENT_ENTITY_TYPE}`); + } + + const unique = instance?.getUnique(); + + if (!unique) { + throw new Error('Document unique is not set'); + } + + const { data } = await new UmbDocumentDetailRepository(this).requestByUnique(unique); + if (!data) return; + + this.#currentDocument = data; + const itemVariants = this.#currentDocument?.variants ?? []; + + this._isInvariant = itemVariants.length === 1 && new UmbVariantId(itemVariants[0].culture).isInvariant(); + this.#selectCulture(); - this.observe(instance.variantOptions, (options) => { - this.availableVariants = options.map((option) => { + const cultures = itemVariants.map((x) => x.culture).filter((x) => x !== null) as string[]; + const { data: languageItems } = await new UmbLanguageItemRepository(this).requestItems(cultures); + + if (languageItems) { + this._availableVariants = languageItems.map((language) => { return { - name: option.language.name, - value: option.language.unique, - selected: option.language.unique === this.currentCulture, + name: language.name, + value: language.unique, + selected: language.unique === this._selectedCulture, }; }); - }); + } else { + this._availableVariants = []; + } + + this.#requestVersions(); }); } - async #requestVersions() { - if (!this.#propertyDatasetContext) return; + #selectCulture() { + const contextCulture = this.#currentDatasetCulture ?? this.#currentAppCulture ?? null; + this._selectedCulture = this._isInvariant ? null : contextCulture; + } - const documentId = this.#propertyDatasetContext.getUnique(); - if (!documentId) return; + async #requestVersions() { + if (!this.#currentDocument?.unique) { + throw new Error('Document unique is not set'); + } - const { data } = await this.#rollbackRepository.requestVersionsByDocumentId(documentId, this.currentCulture); + const { data } = await this.#rollbackRepository.requestVersionsByDocumentId( + this.#currentDocument?.unique, + this._selectedCulture ?? undefined, + ); if (!data) return; const tempItems: DocumentVersion[] = []; @@ -108,28 +156,38 @@ export class UmbRollbackModalElement extends UmbModalBaseElement item.isCurrentlyPublishedVersion)?.id; if (id) { - this.#setCurrentVersion(id); + this.#selectVersion(id); } } - async #setCurrentVersion(id: string) { - const version = this.versions.find((item) => item.id === id); - if (!version) return; + async #selectVersion(id: string) { + const version = this._versions.find((item) => item.id === id); + + if (!version) { + this._selectedVersion = undefined; + this._diffs = []; + return; + } const { data } = await this.#rollbackRepository.requestVersionById(id); - if (!data) return; - this.currentVersion = { + if (!data) { + this._selectedVersion = undefined; + this._diffs = []; + return; + } + + this._selectedVersion = { date: version.date, user: version.user, - name: data.variants.find((x) => x.culture === this.currentCulture)?.name || data.variants[0].name, + name: data.variants.find((x) => x.culture === this._selectedCulture)?.name || data.variants[0].name, id: data.id, properties: data.values - .filter((x) => x.culture === this.currentCulture || !x.culture) // When invariant, culture is undefined or null. + .filter((x) => x.culture === this._selectedCulture || !x.culture) // When invariant, culture is undefined or null. .map((value: any) => { return { alias: value.alias, @@ -137,20 +195,35 @@ export class UmbRollbackModalElement extends UmbModalBaseElement 1 ? this.currentCulture : undefined; - this.#rollbackRepository.rollback(id, culture); + const id = this._selectedVersion.id; + const culture = this._selectedCulture ?? undefined; - const docUnique = this.#workspaceContext?.getUnique() ?? ''; - // TODO Use the load method on the context instead of location.href, when it works. - // this.#workspaceContext?.load(docUnique); - location.href = UMB_EDIT_DOCUMENT_WORKSPACE_PATH_PATTERN.generateAbsolute({ unique: docUnique }); - this.modalContext?.reject(); + const { error } = await this.#rollbackRepository.rollback(id, culture); + if (error) return; + + const unique = this.#currentDocument?.unique; + const entityType = this.#currentDocument?.entityType; + + if (!unique || !entityType) { + throw new Error('Document unique or entity type is not set'); + } + + const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + + const reloadStructureEvent = new UmbRequestReloadStructureForEntityEvent({ unique, entityType }); + actionEventContext.dispatchEvent(reloadStructureEvent); + + const entityUpdatedEvent = new UmbEntityUpdatedEvent({ unique, entityType }); + actionEventContext.dispatchEvent(entityUpdatedEvent); + + this.modalContext?.submit(); } #onCancel() { @@ -158,7 +231,7 @@ export class UmbRollbackModalElement extends UmbModalBaseElement item.id === id); + const version = this._versions.find((item) => item.id === id); if (!version) return; version.preventCleanup = preventCleanup; @@ -176,125 +249,147 @@ export class UmbRollbackModalElement extends UmbModalBaseElement - ${this.localize.term('general_language')} - - + `; } #renderVersions() { - return html` ${this.#renderCultureSelect()} - ${repeat( - this.versions, - (item) => item.id, - (item) => { - return html` -
this.#onVersionClicked(item.id)} - @keydown=${() => {}} - class="rollback-item ${this.currentVersion?.id === item.id ? 'active' : ''}"> -
-

- -

-

${item.user}

-

${item.isCurrentlyPublishedVersion ? this.localize.term('rollback_currentPublishedVersion') : ''}

+ if (!this._versions.length) { + return html`No versions available`; + } + + return html` + ${repeat( + this._versions, + (item) => item.id, + (item) => { + return html` +
this.#onVersionClicked(item.id)} + @keydown=${() => {}} + class="rollback-item ${this._selectedVersion?.id === item.id ? 'active' : ''}"> +
+

+ +

+

${item.user}

+

${item.isCurrentlyPublishedVersion ? this.localize.term('rollback_currentPublishedVersion') : ''}

+
+ this.#onPreventCleanup(event, item.id, !item.preventCleanup)} + label=${item.preventCleanup + ? this.localize.term('contentTypeEditor_historyCleanupEnableCleanup') + : this.localize.term('contentTypeEditor_historyCleanupPreventCleanup')}>
- this.#onPreventCleanup(event, item.id, !item.preventCleanup)} - label=${item.preventCleanup - ? this.localize.term('contentTypeEditor_historyCleanupEnableCleanup') - : this.localize.term('contentTypeEditor_historyCleanupPreventCleanup')}> -
- `; - }, - )}`; + `; + }, + )}`; } - #renderCurrentVersion() { - if (!this.currentVersion) return; + async #setDiffs() { + if (!this._selectedVersion) return; - let draftValues = - (this.#workspaceContext?.getData()?.values as Array<{ alias: string; culture: string; value: any }>) ?? []; + const currentPropertyValues = this.#currentDocument?.values.filter( + (x) => x.culture === this._selectedCulture || !x.culture, + ); // When invariant, culture is undefined or null. - draftValues = draftValues.filter((x) => x.culture === this.currentCulture || !x.culture); // When invariant, culture is undefined or null. + if (!currentPropertyValues) { + throw new Error('Current property values are not set'); + } + + const currentName = this.#currentDocument?.variants.find((x) => x.culture === this._selectedCulture)?.name; + + if (!currentName) { + throw new Error('Current name is not set'); + } const diffs: Array<{ alias: string; diff: Change[] }> = []; - const nameDiff = diffWords(this.#workspaceContext?.getName() ?? '', this.currentVersion.name); + const nameDiff = diffWords(currentName, this._selectedVersion.name); diffs.push({ alias: 'name', diff: nameDiff }); - this.currentVersion.properties.forEach((item) => { - const draftValue = draftValues.find((x) => x.alias === item.alias); + this._selectedVersion.properties.forEach((item) => { + const draftValue = currentPropertyValues.find((x) => x.alias === item.alias); if (!draftValue) return; - const draftValueString = trimQuotes(JSON.stringify(draftValue.value)); - const versionValueString = trimQuotes(JSON.stringify(item.value)); + const draftValueString = this.#trimQuotes(JSON.stringify(draftValue.value)); + const versionValueString = this.#trimQuotes(JSON.stringify(item.value)); const diff = diffWords(draftValueString, versionValueString); diffs.push({ alias: item.alias, diff }); }); - /** - * - * @param str - */ - function trimQuotes(str: string): string { - return str.replace(/^['"]|['"]$/g, ''); - } + this._diffs = [...diffs]; + } + + #renderSelectedVersion() { + if (!this._selectedVersion) + return html` + No selected version + `; return html` - ${unsafeHTML(this.localize.term('rollback_diffHelp'))} - - - - - - ${this.localize.term('general_alias')} - ${this.localize.term('general_value')} - - ${repeat( - diffs, - (item) => item.alias, - (item) => { - const diff = diffs.find((x) => x?.alias === item.alias); - return html` - - ${item.alias} - - ${diff - ? diff.diff.map((part) => - part.added - ? html`${part.value}` - : part.removed - ? html`${part.value}` - : part.value, - ) - : nothing} - - - `; - }, - )} - + + ${unsafeHTML(this.localize.term('rollback_diffHelp'))} + + + + + + ${this.localize.term('general_alias')} + ${this.localize.term('general_value')} + + ${repeat( + this._diffs, + (item) => item.alias, + (item) => { + const diff = this._diffs.find((x) => x?.alias === item.alias); + return html` + + ${item.alias} + + ${diff + ? diff.diff.map((part) => + part.added + ? html`${part.value}` + : part.removed + ? html`${part.value}` + : part.value, + ) + : nothing} + + + `; + }, + )} + + `; } get currentVersionHeader() { return ( - this.localize.date(this.currentVersion?.date ?? new Date(), this.#localizeDateOptions) + + this.localize.date(this._selectedVersion?.date ?? new Date(), this.#localizeDateOptions) + ' - ' + - this.currentVersion?.user + this._selectedVersion?.user ); } @@ -302,10 +397,17 @@ export class UmbRollbackModalElement extends UmbModalBaseElement
- -
${this.#renderVersions()}
-
- ${this.#renderCurrentVersion()} +
+ ${this._availableVariants.length + ? html` + + ${this.#renderCultureSelect()} + + ` + : nothing} + ${this.#renderVersions()} +
+ ${this.#renderSelectedVersion()}
+ label=${this.localize.term('actions_rollback')} + ?disabled=${!this._selectedVersion}> `; @@ -329,14 +432,15 @@ export class UmbRollbackModalElement extends UmbModalBaseElement