diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/pick-document-variant-modal.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/pick-document-variant-modal.controller.ts index c953322f64..696263afd4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/pick-document-variant-modal.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/pick-document-variant-modal.controller.ts @@ -30,19 +30,6 @@ export class UmbPickDocumentVariantModalController extends UmbBaseController { // TODO: What do to when there is no options? } - // TODO: Maybe move this to modal [NL] - if (selected.length === 0) { - // TODO: Make it possible to use consume context without callback. [NL] - const ctrl = this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (appLanguageContext) => {}); - const context = await ctrl.asPromise(); - const appCulture = context.getAppCulture(); - // If the app language is one of the options, select it by default: - if (appCulture && modalData.options.some((o) => o.language.unique === appCulture)) { - selected.push(new UmbVariantId(appCulture, null)); - } - ctrl.destroy(); - } - const modalContext = modalManagerContext.open(UMB_DOCUMENT_LANGUAGE_PICKER_MODAL, { data: modalData, // We need to turn the selected variant ids into strings for them to be serializable to the value state, in other words the value of a modal cannot hold class instances: diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/variant-picker/document-variant-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/variant-picker/document-variant-picker-modal.element.ts index 7d60157b54..51cc60c9e6 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/variant-picker/document-variant-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/variant-picker/document-variant-picker-modal.element.ts @@ -27,11 +27,26 @@ export class UmbDocumentVariantPickerModalElement extends UmbModalBaseElement< connectedCallback(): void { super.connectedCallback(); - this.#selectionManager.setSelectable(true); - this.#selectionManager.setMultiple(true); + this.#setInitialSelection(); + } - // Make sure all mandatory variants are selected when not in unpublish mode - // TODO: Currently only supports culture variants, not segment variants, but as well our Selection Manager also only supports a single string value pr. selection... [NL] + async #setInitialSelection() { + const selected = this.value?.selection ?? []; + + if (selected.length === 0) { + // TODO: Make it possible to use consume context without callback. [NL] + const ctrl = this.consumeContext(UMB_APP_LANGUAGE_CONTEXT, (appLanguageContext) => {}); + const context = await ctrl.asPromise(); + const appCulture = context.getAppCulture(); + // If the app language is one of the options, select it by default: + if (appCulture && modalData.options.some((o) => o.language.unique === appCulture)) { + selected.push(new UmbVariantId(appCulture, null)); + } + ctrl.destroy(); + } + + this.#selectionManager.setMultiple(true); + this.#selectionManager.setSelectable(true); this.#selectionManager.setSelection(this.value?.selection ?? []); if (this.data?.type !== 'unpublish') { diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts index 1537f70be0..78c8a90322 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/workspace/document-workspace.context.ts @@ -5,12 +5,9 @@ import { UmbDocumentDetailRepository } from '../repository/index.js'; import type { UmbDocumentDetailModel, UmbDocumentVariantModel, UmbDocumentVariantOptionModel } from '../types.js'; import { umbPickDocumentVariantModal, type UmbDocumentVariantPickerModalType } from '../modals/index.js'; import { UmbDocumentPublishingRepository } from '../repository/publishing/index.js'; +import { UmbUnpublishDocumentEntityAction } from '../entity-actions/unpublish.action.js'; import { UMB_DOCUMENT_WORKSPACE_ALIAS } from './manifests.js'; -import { - type UmbObjectWithVariantProperties, - UmbVariantId, - variantPropertiesObjectToString, -} from '@umbraco-cms/backoffice/variant'; +import { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import { UmbContentTypePropertyStructureManager } from '@umbraco-cms/backoffice/content-type'; import { UmbEditableWorkspaceContextBase, @@ -21,6 +18,7 @@ import { import { appendToFrozenArray, combineObservables, + naiveObjectComparison, partialUpdateFrozenArray, UmbArrayState, UmbObjectState, @@ -28,7 +26,6 @@ import { import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; import { UmbLanguageCollectionRepository, type UmbLanguageDetailModel } from '@umbraco-cms/backoffice/language'; import { firstValueFrom } from '@umbraco-cms/backoffice/external/rxjs'; -import { UmbUnpublishDocumentEntityAction } from '../entity-actions/unpublish.action.js'; type EntityType = UmbDocumentDetailModel; export class UmbDocumentWorkspaceContext @@ -212,11 +209,45 @@ export class UmbDocumentWorkspaceContext } } + #calculateChangedVariants() { + const persisted = this.#persistedData.getValue(); + if (!persisted) throw new Error('Persisted data is missing'); + const current = this.#currentData.getValue(); + if (!persisted) throw new Error('Current data is missing'); + + const changedVariants = current?.variants.map((variant) => { + const persistedVariant = persisted.variants.find((x) => UmbVariantId.Create(variant).compare(x)); + return { + culture: variant.culture, + segment: variant.segment, + equal: persistedVariant ? naiveObjectComparison(variant, persistedVariant) : false, + }; + }); + + const changedProperties = current?.values.map((value) => { + const persistedValues = persisted.values.find((x) => UmbVariantId.Create(value).compare(x)); + return { + culture: value.culture, + segment: value.segment, + equal: persistedValues ? naiveObjectComparison(value, persistedValues) : false, + }; + }); + + // calculate the variantIds of those who either have a change in properties or in variants: + return ( + changedVariants + ?.concat(changedProperties ?? []) + .filter((x) => x.equal === false) + .map((x) => new UmbVariantId(x.culture, x.segment)) ?? [] + ); + } + async #pickVariantsForAction(type: UmbDocumentVariantPickerModalType): Promise { const activeVariants = this.splitView.getActiveVariants(); // TODO: Picked variants should include the ones that has been changed (but not jet saved) this requires some more awareness about the state of runtime data. [NL] - const selected = activeVariants.map((activeVariant) => UmbVariantId.Create(activeVariant)); + const activeVariantIds = activeVariants.map((activeVariant) => UmbVariantId.Create(activeVariant)); + const selected = activeVariantIds.concat(this.#calculateChangedVariants()); const options = await firstValueFrom(this.variantOptions); // If there is only one variant, we don't need to open the modal.