From a5f155d62e4e88a13c5fc8de93c11d4a187cc680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:00:17 +0100 Subject: [PATCH 1/8] Sort at last by language name --- .../workspace-split-view-variant-selector.element.ts | 7 +++++++ .../src/packages/documents/documents/utils.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts index 3b684d937ecf..1dc70c493241 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts @@ -61,6 +61,13 @@ export class UmbWorkspaceSplitViewVariantSelectorElement< @state() private _labelDefault = ''; + /** + * Method to sort variants in the selector. + * Should be overwritten by actual implementation. + * @param {VariantOptionModelType} a - First variant option to compare + * @param {VariantOptionModelType} b - Second variant option to compare + * @returns {number} - Sorting value + */ // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _variantSorter = (a: VariantOptionModelType, b: VariantOptionModelType) => { return 0; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts index 531bca043e55..b40e3a1dab39 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts @@ -34,7 +34,7 @@ export const sortVariants = (a: VariantType, b: VariantType) => { const compareState = (a: VariantType, b: VariantType) => getVariantStateOrderValue(a.variant) - getVariantStateOrderValue(b.variant); - const compareName = (a: VariantType, b: VariantType) => a.variant?.name.localeCompare(b.variant?.name || '') || 99; + const compareName = (a: VariantType, b: VariantType) => a.language?.name.localeCompare(b.language?.name || '') || 999; return compareDefault(a, b) || compareMandatory(a, b) || compareState(a, b) || compareName(a, b); }; From 6f51e1dd5c356d2bb3acf07f208d79d02e671ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:05:37 +0100 Subject: [PATCH 2/8] ensure document language picker is sorted as variant selector --- .../shared/document-variant-language-picker.element.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts index 43f0f0c23d7a..8f3ba7515128 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts @@ -1,4 +1,5 @@ import { UmbDocumentVariantState, type UmbDocumentVariantOptionModel } from '../../types.js'; +import { sortVariants } from '../../utils.js'; import type { UUIBooleanInputElement } from '@umbraco-cms/backoffice/external/uui'; import { css, @@ -19,7 +20,13 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { #selectionManager!: UmbSelectionManager; @property({ type: Array, attribute: false }) - variantLanguageOptions: Array = []; + public get variantLanguageOptions(): Array { + return this.#variantLanguageOptions; + } + public set variantLanguageOptions(value: Array) { + this.#variantLanguageOptions = value.sort(sortVariants); + } + #variantLanguageOptions: Array = []; @property({ attribute: false }) set selectionManager(value: UmbSelectionManager) { From 16681f87cc4d6702c3281c19c2fdae5ddb50af19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:19:00 +0100 Subject: [PATCH 3/8] Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../modals/shared/document-variant-language-picker.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts index 8f3ba7515128..26c79125b873 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/modals/shared/document-variant-language-picker.element.ts @@ -24,7 +24,7 @@ export class UmbDocumentVariantLanguagePickerElement extends UmbLitElement { return this.#variantLanguageOptions; } public set variantLanguageOptions(value: Array) { - this.#variantLanguageOptions = value.sort(sortVariants); + this.#variantLanguageOptions = [...value].sort(sortVariants); } #variantLanguageOptions: Array = []; From 9283a5139d8806b0da9566e846c071751e141a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:19:10 +0100 Subject: [PATCH 4/8] Update src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../workspace-split-view-variant-selector.element.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts index 1dc70c493241..b6716c34ee7e 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/workspace/components/workspace-split-view/workspace-split-view-variant-selector.element.ts @@ -66,7 +66,7 @@ export class UmbWorkspaceSplitViewVariantSelectorElement< * Should be overwritten by actual implementation. * @param {VariantOptionModelType} a - First variant option to compare * @param {VariantOptionModelType} b - Second variant option to compare - * @returns {number} - Sorting value + * @returns {number} - Sorting value */ // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _variantSorter = (a: VariantOptionModelType, b: VariantOptionModelType) => { From 055b9eb46c0203ff5522f990154446a16a370173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:21:53 +0100 Subject: [PATCH 5/8] Update src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../src/packages/documents/documents/utils.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts index b40e3a1dab39..cb59b0982e98 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts @@ -34,8 +34,18 @@ export const sortVariants = (a: VariantType, b: VariantType) => { const compareState = (a: VariantType, b: VariantType) => getVariantStateOrderValue(a.variant) - getVariantStateOrderValue(b.variant); - const compareName = (a: VariantType, b: VariantType) => a.language?.name.localeCompare(b.language?.name || '') || 999; - + const compareName = (a: VariantType, b: VariantType) => { + const nameA = a.language?.name; + const nameB = b.language?.name; + + // If both names are missing, consider them equal. + if (!nameA && !nameB) return 0; + // If only one name is missing, sort the defined name first. + if (!nameA) return 1; + if (!nameB) return -1; + + return nameA.localeCompare(nameB); + }; return compareDefault(a, b) || compareMandatory(a, b) || compareState(a, b) || compareName(a, b); }; From 2c41adb1ce42b569e02a0ac07aceeb1aed175cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:24:47 +0100 Subject: [PATCH 6/8] refactor to avoid inline methods --- .../src/packages/documents/documents/utils.ts | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts index cb59b0982e98..89db3ea6b085 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts @@ -21,31 +21,38 @@ const getVariantStateOrderValue = (variant?: UmbDocumentVariantOptionModel['vari return variantStatesOrder[variant.state] || fallbackOrder; }; -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, unless they are published, cause then they already goes to the top and then we want to mix them with other published variants. - const compareMandatory = (a: VariantType, b: VariantType) => - a.variant?.state === DocumentVariantStateModel.PUBLISHED_PENDING_CHANGES || +// eslint-disable-next-line jsdoc/require-jsdoc +function compareDefault(a: VariantType, b: VariantType) { + return (a.language?.isDefault ? -1 : 1) - (b.language?.isDefault ? -1 : 1); +} +// Make sure mandatory variants goes on top, unless they are published, cause then they already goes to the top and then we want to mix them with other published variants. +// eslint-disable-next-line jsdoc/require-jsdoc +function compareMandatory(a: VariantType, b: VariantType) { + return a.variant?.state === DocumentVariantStateModel.PUBLISHED_PENDING_CHANGES || a.variant?.state === DocumentVariantStateModel.PUBLISHED - ? 0 - : (a.language?.isMandatory ? -1 : 1) - (b.language?.isMandatory ? -1 : 1); - const compareState = (a: VariantType, b: VariantType) => - getVariantStateOrderValue(a.variant) - getVariantStateOrderValue(b.variant); - - const compareName = (a: VariantType, b: VariantType) => { - const nameA = a.language?.name; - const nameB = b.language?.name; - - // If both names are missing, consider them equal. - if (!nameA && !nameB) return 0; - // If only one name is missing, sort the defined name first. - if (!nameA) return 1; - if (!nameB) return -1; - - return nameA.localeCompare(nameB); - }; + ? 0 + : (a.language?.isMandatory ? -1 : 1) - (b.language?.isMandatory ? -1 : 1); +} + +// eslint-disable-next-line jsdoc/require-jsdoc +function compareState(a: VariantType, b: VariantType) { + return getVariantStateOrderValue(a.variant) - getVariantStateOrderValue(b.variant); +} + +// eslint-disable-next-line jsdoc/require-jsdoc +function compareName(a: VariantType, b: VariantType) { + const nameA = a.language?.name; + const nameB = b.language?.name; + + // If both names are missing, consider them equal. + if (!nameA && !nameB) return 0; + // If only one name is missing, sort the defined name first. + if (!nameA) return 1; + if (!nameB) return -1; + + return nameA.localeCompare(nameB); +} +export const sortVariants = (a: VariantType, b: VariantType) => { return compareDefault(a, b) || compareMandatory(a, b) || compareState(a, b) || compareName(a, b); }; From 9da95077abe7a2f76abf1e55823432d61c72f490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:45:37 +0100 Subject: [PATCH 7/8] transform into a function --- src/Umbraco.Web.UI.Client/.claude/settings.local.json | 9 +++++++++ .../src/packages/documents/documents/utils.ts | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/.claude/settings.local.json diff --git a/src/Umbraco.Web.UI.Client/.claude/settings.local.json b/src/Umbraco.Web.UI.Client/.claude/settings.local.json new file mode 100644 index 000000000000..1e5411896b64 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(npm run lint:*)", + "Bash(npx eslint:*)", + "Bash(npm test:*)" + ] + } +} diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts index 89db3ea6b085..1c937e0b5c4f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/utils.ts @@ -52,9 +52,15 @@ function compareName(a: VariantType, b: VariantType) { return nameA.localeCompare(nameB); } -export const sortVariants = (a: VariantType, b: VariantType) => { +/** + * Sorts document variants based on multiple criteria: + * @param {VariantType} a - First variant to compare + * @param {VariantType} b - Second variant to compare + * @returns {number} - Sorting value + */ +export function sortVariants(a: VariantType, b: VariantType) { return compareDefault(a, b) || compareMandatory(a, b) || compareState(a, b) || compareName(a, b); -}; +} export const TimeOptions: Intl.DateTimeFormatOptions = { year: 'numeric', From cb59900cf6dc1c74d174f6f5eca5f563fe323654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 16 Jan 2026 17:46:13 +0100 Subject: [PATCH 8/8] revert config file commit --- src/Umbraco.Web.UI.Client/.claude/settings.local.json | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/.claude/settings.local.json diff --git a/src/Umbraco.Web.UI.Client/.claude/settings.local.json b/src/Umbraco.Web.UI.Client/.claude/settings.local.json deleted file mode 100644 index 1e5411896b64..000000000000 --- a/src/Umbraco.Web.UI.Client/.claude/settings.local.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "permissions": { - "allow": [ - "Bash(npm run lint:*)", - "Bash(npx eslint:*)", - "Bash(npm test:*)" - ] - } -}