@anzusystems/common-admin 1.47.0-beta.dev-1789897769 → 1.47.0-beta.dev-1790102667
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AFormRemoteAutocomplete-DIYc08Pe.mjs → AFormRemoteAutocomplete-BIW7Twfr.mjs} +2528 -1696
- package/dist/AFormRemoteAutocomplete-BIW7Twfr.mjs.map +1 -0
- package/dist/common-admin.css +1 -1
- package/dist/common-admin.d.ts +930 -475
- package/dist/common-admin.js +12067 -10445
- package/dist/common-admin.js.map +1 -1
- package/dist/{esm-Dov5R7kE.mjs → esm-Dvz_E-iW.mjs} +3106 -3085
- package/dist/esm-Dvz_E-iW.mjs.map +1 -0
- package/dist/labs.d.ts +2566 -36
- package/dist/labs.js +4948 -1342
- package/dist/labs.js.map +1 -1
- package/dist/{webfontloader-Db3zCeVG.mjs → webfontloader-BVmLxgC5.mjs} +2 -2
- package/dist/{webfontloader-Db3zCeVG.mjs.map → webfontloader-BVmLxgC5.mjs.map} +1 -1
- package/package.json +7 -7
- package/src/eslint/plugin.mjs +128 -33
- package/dist/AFormRemoteAutocomplete-DIYc08Pe.mjs.map +0 -1
- package/dist/esm-Dov5R7kE.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AFormRemoteAutocomplete-DIYc08Pe.mjs","names":["$slots","ot","X","h","Z","tt","l","et","nt","H","$attrs","$attrs","$attrs","$emit","$emit","$slots","$slots"],"sources":["../src/components/ARow.vue","../src/components/ARow.vue","../src/components/ACardLoader.vue","../src/components/ACardLoader.vue","../src/components/ACard.vue","../src/components/ACard.vue","../src/utils/common.ts","../src/utils/string.ts","../src/components/injectionKeys.ts","../src/components/AAnzuUserAvatar.vue","../src/components/AAnzuUserAvatar.vue","../src/components/collab/components/ACollabLockedByUser.vue","../src/components/collab/components/ACollabLockedByUser.vue","../src/components/collab/composables/collabEventBus.ts","../src/components/collab/types/Collab.ts","../src/components/collab/composables/commonAdminCollabOptions.ts","../src/components/collab/composables/collabState.ts","../src/components/collab/composables/collabCurrentUserId.ts","../src/components/collab/composables/collabField.ts","../src/components/form/AFormTextField.vue","../src/components/form/AFormTextField.vue","../src/components/ADatatableConfigButton.vue","../src/components/ADatatableConfigButton.vue","../src/plugins/i18n.ts","../src/composables/system/pagination.ts","../src/composables/system/datatableColumns.ts","../src/components/ADialogToolbar.vue","../src/components/ADialogToolbar.vue","../node_modules/@kyvg/vue3-notification/dist/index.es.js","../src/model/error/AnzuError.ts","../src/model/error/AnzuFatalError.ts","../src/composables/statusCodes.ts","../src/model/error/AnzuApiForbiddenError.ts","../src/model/error/AnzuApiValidationError.ts","../src/model/error/AnzuApiResponseCodeError.ts","../src/model/error/AnzuApiForbiddenOperationError.ts","../src/model/error/AnzuApiDependencyExistsError.ts","../src/model/error/AnzuApiTimeoutError.ts","../src/model/error/AnzuApiAxiosError.ts","../src/model/error/AnzuApiCancelledError.ts","../src/composables/system/alerts.ts","../node_modules/dayjs/dayjs.min.js","../node_modules/dayjs/plugin/utc.js","../node_modules/dayjs/plugin/customParseFormat.js","../src/utils/datetime.ts","../src/utils/event.ts","../src/components/buttons/filter/AFilterSubmitButton.vue","../src/components/buttons/filter/AFilterSubmitButton.vue","../src/components/buttons/filter/AFilterResetButton.vue","../src/components/buttons/filter/AFilterResetButton.vue","../src/services/api/apiHelper.ts","../src/utils/response.ts","../src/labs/api/apiErrors.ts","../src/labs/api/request.ts","../src/labs/api/useApiRequest.ts","../src/components/datetime/ADatetime.vue","../src/components/datetime/ADatetime.vue","../src/validators/vuelidate/common/useValidateBetween.ts","../src/validators/vuelidate/common/useValidateEmail.ts","../src/validators/vuelidate/common/useValidateMaxLength.ts","../src/validators/vuelidate/common/useValidateMaxValue.ts","../src/validators/vuelidate/common/useValidateMinLength.ts","../src/validators/vuelidate/common/useValidateMinValue.ts","../src/validators/vuelidate/common/useValidateNumeric.ts","../src/validators/vuelidate/common/useValidateRequired.ts","../src/validators/vuelidate/common/useValidateRequiredIf.ts","../src/validators/vuelidate/common/useValidateSlug.ts","../src/validators/vuelidate/common/useValidateStringArrayItemLength.ts","../src/validators/vuelidate/common/useValidateUrl.ts","../src/validators/vuelidate/common/useValidateCompareDates.ts","../src/validators/vuelidate/useValidate.ts","../src/components/datetime/TimePicker.vue","../src/components/datetime/TimePicker.vue","../src/utils/datetimePickerValue.ts","../src/components/datetime/ADatetimePicker.vue","../src/components/datetime/ADatetimePicker.vue","../src/components/form/AFormDatetimePicker.vue","../src/components/form/AFormDatetimePicker.vue","../src/components/form/AFormSwitch.vue","../src/components/form/AFormSwitch.vue","../src/components/AChipNoLink.vue","../src/components/AChipNoLink.vue","../src/model/valueObject/LogLevel.ts","../src/components/log/ALogLevelChip.vue","../src/components/log/ALogLevelChip.vue","../src/utils/number.ts","../src/components/ACopyText.vue","../src/components/ACopyText.vue","../src/composables/system/datatablePageStore.ts","../src/labs/filters/filterInjectionKeys.ts","../src/labs/filters/filterFactory.ts","../src/labs/filters/filterTimeIntervalTools.ts","../src/labs/api/useApiQueryBuilder.ts","../src/labs/api/listBody.ts","../src/labs/api/useApiFetchList.ts","../src/labs/filters/pagination.ts","../src/labs/api/useApiFetchByIds.ts","../src/labs/filters/AFilterBooleanSelect.vue","../src/labs/filters/AFilterBooleanSelect.vue","../src/labs/filters/AFilterString.vue","../src/labs/filters/AFilterString.vue","../src/labs/filters/AFilterRemoteAutocomplete.vue","../src/labs/filters/AFilterRemoteAutocomplete.vue","../src/utils/enum.ts","../src/labs/filters/AFilterRemoteAutocompleteWithMinimal.vue","../src/labs/filters/AFilterRemoteAutocompleteWithMinimal.vue","../src/labs/filters/AFilterValueObjectOptionsSelect.vue","../src/labs/filters/AFilterValueObjectOptionsSelect.vue","../src/labs/filters/AFilterTimeInterval.vue","../src/labs/filters/AFilterTimeInterval.vue","../src/components/datatable/datatable.ts","../src/labs/filters/AFilterEmpty.vue","../src/labs/filters/AFilterEmpty.vue","../src/labs/filters/AFilterDatetimePicker.vue","../src/labs/filters/AFilterDatetimePicker.vue","../src/labs/filters/AFilterInteger.vue","../src/labs/filters/AFilterInteger.vue","../src/labs/filters/FilterDetailItem.vue","../src/labs/filters/FilterDetailItem.vue","../src/labs/filters/UserAdminConfigFilter.ts","../src/types/UserAdminConfig.ts","../src/labs/filters/bookmarksStore.ts","../src/labs/filters/userAdminConfig.ts","../src/labs/filters/FilterBookmarks.vue","../src/labs/filters/FilterBookmarks.vue","../src/labs/listEditor/composables/useContainerWidth.ts","../src/labs/listEditor/composables/useIsTouchDevice.ts","../src/labs/listEditor/composables/useKeyboardNav.ts","../node_modules/sortablejs/modular/sortable.esm.js","../node_modules/@vueuse/integrations/dist/useSortable.js","../src/labs/listEditor/utils/positions.ts","../src/labs/listEditor/utils/tempId.ts","../src/labs/listEditor/composables/useListEditorController.ts","../src/labs/listEditor/composables/useNestedListEditor.ts","../src/labs/listEditor/composables/useNestedListEditorController.ts","../src/labs/listEditor/composables/useListEditorStateScope.ts","../src/labs/listEditor/composables/resolveCompactText.ts","../src/labs/unsavedGuard/useUnsavedSection.ts","../src/labs/listEditor/composables/useDeleteDialog.ts","../src/labs/listEditor/composables/useInlineEditing.ts","../src/labs/listEditor/utils/revealInvalidRows.ts","../src/labs/listEditor/composables/useListEditorScopeValidity.ts","../src/labs/listEditor/composables/useReorderMode.ts","../src/labs/listEditor/internal/LeDeleteDialog.vue","../src/labs/listEditor/internal/LeDeleteDialog.vue","../src/labs/listEditor/internal/LeMoveToPositionDialog.vue","../src/labs/listEditor/internal/LeMoveToPositionDialog.vue","../src/labs/listEditor/internal/LeEmptyState.vue","../src/labs/listEditor/internal/LeEmptyState.vue","../src/labs/listEditor/internal/LeStatus.vue","../src/labs/listEditor/internal/LeStatus.vue","../src/labs/listEditor/internal/LeUnsavedLabel.vue","../src/labs/listEditor/internal/LeUnsavedLabel.vue","../src/labs/listEditor/internal/LeDragHandle.vue","../src/labs/listEditor/internal/LeDragHandle.vue","../src/labs/listEditor/internal/constants.ts","../src/labs/listEditor/ASortableListEditor.vue","../src/labs/listEditor/ASortableListEditor.vue","../src/model/factory/UserAdminConfigFactory.ts","../src/labs/unsavedGuard/AUnsavedConfirmDialog.vue","../src/labs/unsavedGuard/AUnsavedConfirmDialog.vue","../src/labs/unsavedGuard/useUnsavedChangesGuard.ts","../src/labs/filters/FilterBookmarkDialog.vue","../src/labs/filters/FilterBookmarkDialog.vue","../src/components/buttons/filter/AFilterBookmarkButton.vue","../src/components/buttons/filter/AFilterBookmarkButton.vue","../src/labs/subjectSelect/AFilterWrapperSubjectSelect.vue","../src/labs/subjectSelect/AFilterWrapperSubjectSelect.vue","../src/labs/form/AFormRemoteAutocompleteWithCached.vue","../src/labs/form/AFormRemoteAutocompleteWithCached.vue","../src/labs/filters/AFilterAdvancedButton.vue","../src/labs/filters/AFilterAdvancedButton.vue","../src/labs/filters/FiltersSelected.vue","../src/labs/filters/FiltersSelected.vue","../src/labs/filters/AFilterWrapper.vue","../src/labs/filters/AFilterWrapper.vue","../src/labs/form/AFormRemoteAutocomplete.vue","../src/labs/form/AFormRemoteAutocomplete.vue"],"sourcesContent":["<script lang=\"ts\" setup>\n// #region docs-props\nwithDefaults(\n defineProps<{\n title?: string\n value?: string | number | undefined | null\n dataCy?: string | undefined\n titleClass?: string | undefined\n }>(),\n {\n title: '',\n value: '',\n dataCy: undefined,\n titleClass: 'font-weight-bold text-label-large',\n }\n)\n// #endregion docs-props\n</script>\n\n<template>\n <VRow :data-cy=\"dataCy\">\n <VCol>\n <h4\n v-if=\"title.length\"\n :class=\"titleClass\"\n >\n {{ title }}\n </h4>\n <slot>\n <span class=\"text-high-emphasis\">{{ value }}</span>\n </slot>\n </VCol>\n </VRow>\n</template>\n","<script lang=\"ts\" setup>\n// #region docs-props\nwithDefaults(\n defineProps<{\n title?: string\n value?: string | number | undefined | null\n dataCy?: string | undefined\n titleClass?: string | undefined\n }>(),\n {\n title: '',\n value: '',\n dataCy: undefined,\n titleClass: 'font-weight-bold text-label-large',\n }\n)\n// #endregion docs-props\n</script>\n\n<template>\n <VRow :data-cy=\"dataCy\">\n <VCol>\n <h4\n v-if=\"title.length\"\n :class=\"titleClass\"\n >\n {{ title }}\n </h4>\n <slot>\n <span class=\"text-high-emphasis\">{{ value }}</span>\n </slot>\n </VCol>\n </VRow>\n</template>\n","<script lang=\"ts\" setup>\n// #region docs-props\nwithDefaults(\n defineProps<{\n loading?: boolean\n }>(),\n {\n loading: undefined,\n }\n)\n// #endregion docs-props\n</script>\n\n<template>\n <div\n v-show=\"loading\"\n class=\"a-card-loader\"\n />\n</template>\n\n<style lang=\"scss\">\n// todo dark mode\n.a-card-loader {\n position: absolute;\n inset: 0;\n background-color: rgb(0 0 0 / 10%);\n z-index: 5;\n}\n</style>\n","<script lang=\"ts\" setup>\n// #region docs-props\nwithDefaults(\n defineProps<{\n loading?: boolean\n }>(),\n {\n loading: undefined,\n }\n)\n// #endregion docs-props\n</script>\n\n<template>\n <div\n v-show=\"loading\"\n class=\"a-card-loader\"\n />\n</template>\n\n<style lang=\"scss\">\n// todo dark mode\n.a-card-loader {\n position: absolute;\n inset: 0;\n background-color: rgb(0 0 0 / 10%);\n z-index: 5;\n}\n</style>\n","<script lang=\"ts\" setup>\nimport ACardLoader from '@/components/ACardLoader.vue'\nimport { computed } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n loading?: boolean\n title?: string\n blockInput?: boolean\n }>(),\n {\n loading: undefined,\n title: undefined,\n blockInput: false,\n }\n)\n\nconst loadingComputed = computed(() => {\n return props.loading ? 'primary' : false\n})\n</script>\n\n<template>\n <!-- Opt-in: the loader already blocks the mouse, and `inert` also drops focus without restoring\n it — a cost on cards whose filter sits under it. `|| undefined` because DOM without an\n `inert` property would take the attribute, and `inert=\"false\"` still reads as inert. -->\n <VCard\n :title=\"title\"\n variant=\"flat\"\n :loading=\"loadingComputed\"\n :inert=\"(loading && blockInput) || undefined\"\n >\n <ACardLoader :loading=\"loading\" />\n <slot />\n </VCard>\n</template>\n","<script lang=\"ts\" setup>\nimport ACardLoader from '@/components/ACardLoader.vue'\nimport { computed } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n loading?: boolean\n title?: string\n blockInput?: boolean\n }>(),\n {\n loading: undefined,\n title: undefined,\n blockInput: false,\n }\n)\n\nconst loadingComputed = computed(() => {\n return props.loading ? 'primary' : false\n})\n</script>\n\n<template>\n <!-- Opt-in: the loader already blocks the mouse, and `inert` also drops focus without restoring\n it — a cost on cards whose filter sits under it. `|| undefined` because DOM without an\n `inert` property would take the attribute, and `inert=\"false\"` still reads as inert. -->\n <VCard\n :title=\"title\"\n variant=\"flat\"\n :loading=\"loadingComputed\"\n :inert=\"(loading && blockInput) || undefined\"\n >\n <ACardLoader :loading=\"loading\" />\n <slot />\n </VCard>\n</template>\n","import type { DocId } from '@/types/common'\nimport { isProxy, isRef, toRaw, unref } from 'vue'\n\nexport const isUndefined = (value: unknown): value is undefined => {\n return typeof value === 'undefined'\n}\n\nexport const isDefined = <T>(value: T | undefined): value is T => {\n return !isUndefined(value)\n}\n\nexport const isNull = (value: unknown): value is null => {\n return value === null\n}\n\nexport const isNumber = (value: unknown): value is number => {\n return typeof value === 'number'\n}\n\nexport const isString = (value: unknown): value is string => {\n return typeof value === 'string'\n}\n\n/**\n * @template T Type used for request payload, by default same as Response type\n * @template R Response type override, optional\n */\nexport const isArray = <T = unknown>(value: unknown): value is Array<T> => {\n return Array.isArray(value)\n}\n\nexport const isFunction = <T extends (...args: any[]) => any>(value: unknown): value is T => {\n return typeof value === 'function'\n}\n\nexport const isBoolean = (value: unknown): value is boolean => {\n return typeof value === 'boolean'\n}\n\nexport const isDocId = (value: unknown): value is DocId => {\n return isString(value) && /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(value)\n}\n\nexport const isInt = (value: any): value is number => {\n const x = parseFloat(value)\n\n return !isNaN(value) && (x | 0) === x\n}\n\nexport const isObject = (value: unknown): value is object => {\n return typeof value === 'object' && !isArray(value) && !isNull(value)\n}\n\nexport const isEmptyObject = <T>(value: T): value is T => {\n if (isObject(value)) {\n return Object.keys(value).length === 0\n }\n return false\n}\n\nexport const isEmptyArray = (value: unknown): value is [] => {\n return isArray(value) && value.length === 0\n}\n\nexport const isEmpty = (value: unknown): boolean => {\n return (\n isNull(value) || isUndefined(value) || value === '' || value === 0 || isEmptyArray(value) || isEmptyObject(value)\n )\n}\n/**\n * Use only for objects with some primitives like:\n * number, string, boolean, null. Not supported: function, undefined, symbol, ...\n */\nexport const cloneDeep = <T>(object: T) => {\n if (typeof structuredClone === 'function') {\n try {\n if (isProxy(object)) {\n return structuredClone(toRaw(object)) as T\n }\n if (isRef(object)) {\n return structuredClone(unref(object)) as T\n }\n return structuredClone(object) as T\n } catch (error) {\n return JSON.parse(JSON.stringify(object)) as T\n }\n }\n return JSON.parse(JSON.stringify(object)) as T\n}\n","import type { UrlParams } from '@/services/api/apiHelper'\nimport { isNull, isUndefined } from '@/utils/common'\n\nexport const stringToInt = (value: any, fallbackValue = 0): number => {\n let check = fallbackValue\n try {\n check = Number.parseInt(value, 10)\n } catch {\n return fallbackValue\n }\n\n if (Number.isNaN(check)) {\n return fallbackValue\n }\n\n return check\n}\n\nexport const stringToFloat = (value: any, fallbackValue = 0): number => {\n let check = fallbackValue\n try {\n check = Number.parseFloat(value)\n } catch {\n return fallbackValue\n }\n\n if (Number.isNaN(check)) {\n return fallbackValue\n }\n\n return check\n}\n\nexport const stringToNumber = (value: string, fallbackValue?: number): number | null => {\n const trimmedValue = value.trim()\n if (trimmedValue === '') {\n return fallbackValue !== undefined ? fallbackValue : null\n }\n const numericValue = Number(trimmedValue)\n if (!Number.isNaN(numericValue) && Number.isFinite(numericValue)) {\n return numericValue\n }\n\n return fallbackValue !== undefined ? fallbackValue : null\n}\n\nexport const stringToBooleanExact = (value: string): boolean | null => {\n const trimmedValue = value.trim()\n if (trimmedValue === 'true') return true\n if (trimmedValue === 'false') return false\n return null\n}\n\nexport const stringSplitOnFirstOccurrence = (value: string, delimiter = '') => {\n const index = value.indexOf(delimiter)\n\n return {\n start: value.slice(0, index),\n end: value.slice(index + delimiter.length),\n }\n}\n\nexport const stringToSlug = (value: string) => {\n return value\n .toString()\n .toLowerCase()\n .trim()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/&/g, '-')\n .replace(/[^\\w-]+/g, '')\n .replace(/--+/g, '-')\n .replace(/^-+/, '')\n .replace(/-+$/, '')\n}\n\ntype Kebab<T extends string, A extends string = ''> = T extends `${infer F}${infer R}`\n ? Kebab<R, `${A}${F extends Lowercase<F> ? '' : '-'}${Lowercase<F>}`>\n : A\n\nexport const stringToKebabCase = <T extends string>(value: T): Kebab<T> =>\n value.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase() as Kebab<T>\n\nexport const stringTrimLength = (value: string, maxLength = 80): string => {\n if (value.length > maxLength) {\n return value.substring(1, maxLength) + '...'\n }\n\n return value\n}\n\n/**\n * Converts colon parameters to real values from params.\n *\n * @param template url containing colon parameters, example: '/:id/edit'\n * @param params object containing real values to be replaced, example: { id:5 }\n */\nexport const stringUrlTemplateReplace = (template: string, params: UrlParams) => {\n if (template.indexOf(':') === -1) return template\n const newParts: string[] = []\n const [path, queryString] = template.split('?')\n const parts = path.split('/')\n parts.forEach((part, index) => {\n newParts[index] = part\n if (!part.startsWith(':')) return\n const key = part.substring(1)\n if (!isUndefined(params[key])) newParts[index] = params[part.substring(1)] + ''\n })\n\n return newParts.join('/') + (queryString ? `?${queryString}` : '')\n}\n\n/**\n * Converts colon parameters to real values from params. Same as above but it additionally supports vue router regexp.\n *\n * @param template url containing colon parameters, example: '/:id(\\\\d+)/edit'\n * @param params object containing real values to be replaced, example: { id:5 }\n */\nexport const stringUrlTemplateReplaceVueRouter = (template: string, params: UrlParams) => {\n if (template.indexOf(':') === -1) return template\n const newParts: string[] = []\n const parts = template.split('/')\n parts.forEach((part: string, index: number) => {\n newParts[index] = part\n if (!part.startsWith(':')) return\n newParts[index] = part.substring(1)\n const regex = /^:([a-zA-Z0-9_-]+).*/\n const match = part.match(regex)\n if (isNull(match) || !match[1]) return\n if (!isUndefined(params[match[1]])) newParts[index] = params[match[1]] + ''\n })\n return newParts.join('/')\n}\n\n/**\n * Slot names with dots are not valid, Vue takes dots as modifiers, so we must replace dots with dash.\n */\nexport const stringNormalizeForSlotName = (name: string) => name.replace('.', '-')\n\nexport const stringIsValidEmail = (email: string): boolean => {\n const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,63}$/\n return emailRegex.test(email)\n}\n","import type { InjectionKey } from 'vue'\nimport type { LanguageCode } from '@/composables/languageSettings'\n\nexport const SystemScopeSymbol: InjectionKey<string | undefined> = Symbol.for('anzu:SystemScope')\nexport const SubjectScopeSymbol: InjectionKey<string | undefined> = Symbol.for('anzu:SubjectScope')\nexport const AvailableLanguagesSymbol: InjectionKey<LanguageCode[] | undefined> = Symbol.for('anzu:AvailableLanguages')\nexport const DefaultLanguageSymbol: InjectionKey<LanguageCode | undefined> = Symbol.for('anzu:DefaultLanguage')\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport type { AnzuUserMinimal } from '@/types/AnzuUser'\n\nconst props = withDefaults(\n defineProps<{\n user?: AnzuUserMinimal | undefined | null\n size?: number\n containerClass?: string\n tooltip?: string | undefined\n }>(),\n {\n user: undefined,\n size: 36,\n containerClass: '',\n tooltip: undefined,\n }\n)\n\nconst color = computed(() => {\n if (props.user?.avatar.color && props.user.avatar.color.length === 7) {\n return props.user.avatar.color\n }\n return '#3f6ad8'\n})\n\nconst fontSize = computed(() => {\n return props.size * 0.5 + 'px'\n})\n\nconst text = computed(() => {\n if (!props.user) return ''\n if (props.user.avatar.text.length > 0) return props.user.avatar.text\n const firstNameLastName = props.user.person.firstName.charAt(0) + props.user.person.lastName.charAt(0)\n if (firstNameLastName.length > 0) return firstNameLastName\n return props.user.email.slice(0, 2)\n})\n</script>\n\n<template>\n <VAvatar\n :color=\"color\"\n class=\"text-uppercase\"\n :class=\"containerClass\"\n :size=\"size\"\n >\n <div\n class=\"d-inline-flex text-white font-weight-light\"\n :style=\"{ fontSize: fontSize }\"\n >\n {{ text }}\n </div>\n <VTooltip\n v-if=\"tooltip\"\n activator=\"parent\"\n >\n {{ tooltip }}\n </VTooltip>\n </VAvatar>\n <div />\n</template>\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport type { AnzuUserMinimal } from '@/types/AnzuUser'\n\nconst props = withDefaults(\n defineProps<{\n user?: AnzuUserMinimal | undefined | null\n size?: number\n containerClass?: string\n tooltip?: string | undefined\n }>(),\n {\n user: undefined,\n size: 36,\n containerClass: '',\n tooltip: undefined,\n }\n)\n\nconst color = computed(() => {\n if (props.user?.avatar.color && props.user.avatar.color.length === 7) {\n return props.user.avatar.color\n }\n return '#3f6ad8'\n})\n\nconst fontSize = computed(() => {\n return props.size * 0.5 + 'px'\n})\n\nconst text = computed(() => {\n if (!props.user) return ''\n if (props.user.avatar.text.length > 0) return props.user.avatar.text\n const firstNameLastName = props.user.person.firstName.charAt(0) + props.user.person.lastName.charAt(0)\n if (firstNameLastName.length > 0) return firstNameLastName\n return props.user.email.slice(0, 2)\n})\n</script>\n\n<template>\n <VAvatar\n :color=\"color\"\n class=\"text-uppercase\"\n :class=\"containerClass\"\n :size=\"size\"\n >\n <div\n class=\"d-inline-flex text-white font-weight-light\"\n :style=\"{ fontSize: fontSize }\"\n >\n {{ text }}\n </div>\n <VTooltip\n v-if=\"tooltip\"\n activator=\"parent\"\n >\n {{ tooltip }}\n </VTooltip>\n </VAvatar>\n <div />\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, type Ref, shallowRef, unref, watch } from 'vue'\nimport AAnzuUserAvatar from '@/components/AAnzuUserAvatar.vue'\nimport { isNull, isNumber, isUndefined } from '@/utils/common'\nimport type { CollabCachedUsersMap } from '@/components/collab/composables/collabHelpers'\nimport type { IntegerId } from '@/types/common'\nimport type { AnzuUserMinimal } from '@/types/AnzuUser'\nimport { useI18n } from 'vue-i18n'\n\nconst props = withDefaults(\n defineProps<{\n id: null | undefined | IntegerId\n users: CollabCachedUsersMap | Ref<CollabCachedUsersMap>\n isModerator?: boolean\n }>(),\n {\n isModerator: false,\n }\n)\n\nconst cached = shallowRef<undefined | AnzuUserMinimal>(undefined)\nconst loaded = shallowRef<boolean>(false)\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst cachedUsers = unref(props.users)\nconst { t } = useI18n()\n\nconst item = computed(() => {\n if (isNumber(props.id) && props.id > 0) {\n return cachedUsers.get(props.id)\n }\n return undefined\n})\n\nconst tooltip = computed(() => {\n let prefix = ''\n if (props.isModerator) {\n prefix = t('common.collab.moderator') + ': '\n }\n if (item.value) {\n return item.value.person.fullName.length\n ? prefix + item.value.person.fullName\n : prefix + item.value.email.split('@')[0]\n }\n return undefined\n})\n\nwatch(\n item,\n async (newValue) => {\n if (loaded.value) return\n if (isUndefined(newValue) || !newValue._loaded) return\n cached.value = newValue\n loaded.value = true\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <div class=\"d-inline-flex\">\n <span v-if=\"isNull(id) || isUndefined(id)\" />\n <template v-else-if=\"loaded\">\n <VBadge\n v-if=\"isModerator\"\n location=\"top right\"\n color=\"white\"\n :width=\"12\"\n :min-width=\"12\"\n :height=\"14\"\n :offset-x=\"-5\"\n :offset-y=\"-5\"\n >\n <template #badge>\n <VIcon\n color=\"grey-darken-2\"\n :size=\"14\"\n icon=\"mdi-crown\"\n />\n </template>\n <AAnzuUserAvatar\n :user=\"cached ?? undefined\"\n :size=\"20\"\n :tooltip=\"tooltip\"\n />\n </VBadge>\n <AAnzuUserAvatar\n v-else\n :user=\"cached ?? undefined\"\n :size=\"20\"\n :tooltip=\"tooltip\"\n />\n </template>\n <VProgressCircular\n v-else\n :size=\"12\"\n :width=\"2\"\n indeterminate\n class=\"ml-auto mr-auto\"\n />\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, type Ref, shallowRef, unref, watch } from 'vue'\nimport AAnzuUserAvatar from '@/components/AAnzuUserAvatar.vue'\nimport { isNull, isNumber, isUndefined } from '@/utils/common'\nimport type { CollabCachedUsersMap } from '@/components/collab/composables/collabHelpers'\nimport type { IntegerId } from '@/types/common'\nimport type { AnzuUserMinimal } from '@/types/AnzuUser'\nimport { useI18n } from 'vue-i18n'\n\nconst props = withDefaults(\n defineProps<{\n id: null | undefined | IntegerId\n users: CollabCachedUsersMap | Ref<CollabCachedUsersMap>\n isModerator?: boolean\n }>(),\n {\n isModerator: false,\n }\n)\n\nconst cached = shallowRef<undefined | AnzuUserMinimal>(undefined)\nconst loaded = shallowRef<boolean>(false)\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst cachedUsers = unref(props.users)\nconst { t } = useI18n()\n\nconst item = computed(() => {\n if (isNumber(props.id) && props.id > 0) {\n return cachedUsers.get(props.id)\n }\n return undefined\n})\n\nconst tooltip = computed(() => {\n let prefix = ''\n if (props.isModerator) {\n prefix = t('common.collab.moderator') + ': '\n }\n if (item.value) {\n return item.value.person.fullName.length\n ? prefix + item.value.person.fullName\n : prefix + item.value.email.split('@')[0]\n }\n return undefined\n})\n\nwatch(\n item,\n async (newValue) => {\n if (loaded.value) return\n if (isUndefined(newValue) || !newValue._loaded) return\n cached.value = newValue\n loaded.value = true\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <div class=\"d-inline-flex\">\n <span v-if=\"isNull(id) || isUndefined(id)\" />\n <template v-else-if=\"loaded\">\n <VBadge\n v-if=\"isModerator\"\n location=\"top right\"\n color=\"white\"\n :width=\"12\"\n :min-width=\"12\"\n :height=\"14\"\n :offset-x=\"-5\"\n :offset-y=\"-5\"\n >\n <template #badge>\n <VIcon\n color=\"grey-darken-2\"\n :size=\"14\"\n icon=\"mdi-crown\"\n />\n </template>\n <AAnzuUserAvatar\n :user=\"cached ?? undefined\"\n :size=\"20\"\n :tooltip=\"tooltip\"\n />\n </VBadge>\n <AAnzuUserAvatar\n v-else\n :user=\"cached ?? undefined\"\n :size=\"20\"\n :tooltip=\"tooltip\"\n />\n </template>\n <VProgressCircular\n v-else\n :size=\"12\"\n :width=\"2\"\n indeterminate\n class=\"ml-auto mr-auto\"\n />\n </div>\n</template>\n","import type { EventBusKey } from '@vueuse/core'\nimport { useEventBus } from '@vueuse/core'\nimport type { CollabFieldDataEnvelope, CollabRoom, CollabRoomPlainData } from '@/components/collab/types/Collab'\n\nexport interface CollabRoomDataChangedEvent {\n room: CollabRoom\n field: string\n}\n\nexport interface CollabJoinRequestEvent {\n room: CollabRoom\n userId: number\n timestamp: number\n}\n\nexport interface CollabApprovedJoinRequestEvent {\n room: CollabRoom\n}\n\nexport interface CollabRejectedJoinRequestEvent {\n room: CollabRoom\n}\n\nexport interface CollabStartingEvent {\n room: CollabRoom\n startedCallback: (data: CollabRoomPlainData) => void\n}\n\nexport interface CollabGatheringBufferDataEvent {\n room: CollabRoom\n}\n\nexport interface CollabRequestToTakeModerationEvent {\n room: CollabRoom\n userId: number\n timestamp: number\n}\n\nexport interface CollabApprovedRequestToTakeModerationEvent {\n room: CollabRoom\n}\n\nexport interface CollabRejectedRequestToTakeModerationEvent {\n room: CollabRoom\n}\n\nexport interface CollabKickedFromRoomEvent {\n room: CollabRoom\n}\n\nexport interface CollabPurgeRoomEvent {\n room: CollabRoom\n}\n\nexport const collabRoomDataChangedEventBusKey: EventBusKey<CollabRoomDataChangedEvent> =\n Symbol('anzu:collabRoomDataChanged')\n\nexport const collabReconnectEventBusKey: EventBusKey<'reconnect'> = Symbol('anzu:collabReconnect')\n\nexport const collabStartingEventBusKey: EventBusKey<CollabStartingEvent> = Symbol('anzu:collabStarting')\n\nexport const collabGatheringBufferDataEventBusKey: EventBusKey<CollabGatheringBufferDataEvent> = Symbol(\n 'anzu:collabGatheringBufferData'\n)\n\nexport const collabApprovedJoinRequestEventBusKey: EventBusKey<CollabApprovedJoinRequestEvent> = Symbol(\n 'anzu:collabApprovedJoinRequest'\n)\n\nexport const collabRejectedJoinRequestEventBusKey: EventBusKey<CollabRejectedJoinRequestEvent> = Symbol(\n 'anzu:collabRejectedJoinRequest'\n)\n\nexport const collabJoinRequestEventBusKey: EventBusKey<CollabJoinRequestEvent> = Symbol('anzu:collabJoinRequest')\n\nexport const collabApprovedRequestToTakeModerationEventBusKey: EventBusKey<CollabApprovedRequestToTakeModerationEvent> =\n Symbol('anzu:collabApprovedRequestToTakeModeration')\n\nexport const collabRejectedRequestToTakeModerationEventBusKey: EventBusKey<CollabRejectedRequestToTakeModerationEvent> =\n Symbol('anzu:collabRejectedRequestToTakeModeration')\n\nexport const collabRequestToTakeModerationEventBusKey: EventBusKey<CollabRequestToTakeModerationEvent> = Symbol(\n 'anzu:collabRequestToTakeModeration'\n)\n\nexport const collabKickedFromRoomEventBusKey: EventBusKey<CollabKickedFromRoomEvent> =\n Symbol('anzu:collabKickedFromRoom')\n\nexport const collabPurgeRoomEventBusKey: EventBusKey<CollabPurgeRoomEvent> = Symbol('anzu:collabPurgeRoom')\n\nexport function useCollabRoomDataChangeEventBus() {\n return useEventBus<CollabRoomDataChangedEvent, CollabFieldDataEnvelope>(collabRoomDataChangedEventBusKey)\n}\n\nexport function useCollabReconnectEventBus() {\n return useEventBus(collabReconnectEventBusKey)\n}\n\nexport function useCollabStartingEventBus() {\n return useEventBus<CollabStartingEvent, { startedCallback: (data: CollabRoomPlainData) => void }>(\n collabStartingEventBusKey\n )\n}\n\nexport function useCollabGatheringBufferDataEventBus() {\n return useEventBus<CollabGatheringBufferDataEvent>(collabGatheringBufferDataEventBusKey)\n}\n\nexport function useCollabApprovedJoinRequestEventBus() {\n return useEventBus<CollabApprovedJoinRequestEvent>(collabApprovedJoinRequestEventBusKey)\n}\n\nexport function useCollabRejectedJoinRequestEventBus() {\n return useEventBus<CollabRejectedJoinRequestEvent>(collabRejectedJoinRequestEventBusKey)\n}\n\nexport function useCollabJoinRequestEventBus() {\n return useEventBus<CollabJoinRequestEvent>(collabJoinRequestEventBusKey)\n}\n\nexport function useCollabApprovedRequestToTakeModerationEventBus() {\n return useEventBus<CollabApprovedRequestToTakeModerationEvent>(collabApprovedRequestToTakeModerationEventBusKey)\n}\n\nexport function useCollabRejectedRequestToTakeModerationEventBus() {\n return useEventBus<CollabRejectedRequestToTakeModerationEvent>(collabRejectedRequestToTakeModerationEventBusKey)\n}\n\nexport function useCollabRequestToTakeModerationEventBus() {\n return useEventBus<CollabRequestToTakeModerationEvent>(collabRequestToTakeModerationEventBusKey)\n}\n\nexport function useCollabKickedFromRoomEventBus() {\n return useEventBus<CollabKickedFromRoomEvent>(collabKickedFromRoomEventBusKey)\n}\n\nexport function useCollabPurgeRoomEventBus() {\n return useEventBus<CollabPurgeRoomEvent>(collabPurgeRoomEventBusKey)\n}\n\nexport const CollabFieldLockType = {\n Acquire: 'acquire',\n Release: 'release',\n} as const\nexport type CollabFieldLockTypeType = (typeof CollabFieldLockType)[keyof typeof CollabFieldLockType]\n\nexport const CollabFieldLockStatus = {\n Success: 'success',\n Failure: 'failure',\n} as const\nexport type CollabFieldLockStatusType = (typeof CollabFieldLockStatus)[keyof typeof CollabFieldLockStatus]\n\nexport interface CollabFieldLockStatusPayload {\n type: CollabFieldLockTypeType\n status: CollabFieldLockStatusType\n}\n\nexport const createFieldLockStatusPayload = (\n type: CollabFieldLockTypeType,\n status: CollabFieldLockStatusType\n): CollabFieldLockStatusPayload => ({\n type,\n status,\n})\n\nexport interface CollabFieldLockStatusEvent {\n room: CollabRoom\n field: string\n}\n\nexport const collabFieldLockStatusEventBusKey: EventBusKey<CollabFieldLockStatusEvent> =\n Symbol('anzu:collabFieldLockStatus')\n\nexport function useCollabFieldLockStatusEventBus() {\n return useEventBus<CollabFieldLockStatusEvent, CollabFieldLockStatusPayload>(collabFieldLockStatusEventBusKey)\n}\n","import type { RouteParams } from 'vue-router'\nimport type { CollabCachedUsersMap } from '@/components/collab/composables/collabHelpers'\n\nexport type CollabUserId = number\nexport type CollabUserIdNullable = number | null\n\nexport type CollabRoom = string\n\nexport type CollabComponentConfig =\n | undefined\n | {\n room: CollabRoom\n field: CollabFieldName\n cachedUsers: CollabCachedUsersMap\n }\n\nexport const CollabStatus = {\n Inactive: 'inactive',\n Active: 'active',\n} as const\nexport type CollabStatusType = (typeof CollabStatus)[keyof typeof CollabStatus]\n\nexport interface CollabRoomInfo {\n name: CollabRoom\n moderator: CollabUserIdNullable\n users: CollabUserId[]\n status: CollabStatusType\n options: CollabRoomOptions\n}\n\nexport interface CollabRoomsInfo extends Record<CollabRoom, CollabRoomInfo> {}\n\nexport interface CollabFieldDataEnvelope {\n type: 'scalar' | 'json'\n user: CollabUserId\n value: CollabFieldData\n}\n\nexport type CollabFieldData = unknown\nexport type CollabFieldName = string\nexport type CollabFieldLock = CollabUserIdNullable\n\nexport interface CollabRoomLocks extends Record<CollabFieldName, CollabFieldLock> {}\n\nexport interface CollabRoomData extends Record<CollabFieldName, CollabFieldDataEnvelope> {}\n\nexport interface CollabRoomPlainData extends Record<CollabFieldName, CollabFieldData> {}\n\nexport const CollabAccessRoomStatus = {\n Ok: 'ok',\n Occupied: 'occupied',\n Failed: 'failed',\n} as const\nexport type CollabAccessRoomStatusType = (typeof CollabAccessRoomStatus)[keyof typeof CollabAccessRoomStatus]\n\nexport interface CollabRoomInfoCallback {\n room: CollabRoomInfo\n}\n\ninterface CollabAccessRoomCallback {\n status: CollabAccessRoomStatusType\n}\n\nexport interface CollabSuccessAccessRoomCallback extends CollabAccessRoomCallback, CollabRoomInfoCallback {\n status: typeof CollabAccessRoomStatus.Ok\n}\n\nexport interface CollabOccupiedAccessRoomCallback extends CollabAccessRoomCallback, CollabRoomInfoCallback {\n status: typeof CollabAccessRoomStatus.Occupied\n}\n\nexport interface CollabFailedAccessRoomCallback extends CollabAccessRoomCallback {\n status: typeof CollabAccessRoomStatus.Failed\n reason: string\n}\n\nexport type CollabAccessRoomCallbackTypes =\n | CollabSuccessAccessRoomCallback\n | CollabOccupiedAccessRoomCallback\n | CollabFailedAccessRoomCallback\n\nexport function isCollabSuccessAccessRoomCallback(\n callback: CollabAccessRoomCallbackTypes\n): callback is CollabSuccessAccessRoomCallback {\n return callback.status === CollabAccessRoomStatus.Ok\n}\n\nexport function isCollabOccupiedAccessRoomCallback(\n callback: CollabAccessRoomCallbackTypes\n): callback is CollabSuccessAccessRoomCallback {\n return callback.status === CollabAccessRoomStatus.Occupied\n}\n\nexport const CollabChangeRoomLockStatus = {\n Ok: 'ok',\n Failed: 'failed',\n} as const\nexport type CollabChangeRoomLockStatusType =\n (typeof CollabChangeRoomLockStatus)[keyof typeof CollabChangeRoomLockStatus]\n\nexport interface CollabRoomLocksInfoCallback {\n locks: CollabRoomLocks | undefined | null\n}\n\ninterface CollabChangeRoomLocksInfoCallback {\n status: CollabChangeRoomLockStatusType\n}\n\nexport interface CollabSuccessChangeRoomLockCallback\n extends CollabChangeRoomLocksInfoCallback, CollabRoomLocksInfoCallback {\n status: typeof CollabChangeRoomLockStatus.Ok\n locks: CollabRoomLocks | undefined | null\n}\n\nexport interface CollabFailedChangeRoomLockCallback extends CollabChangeRoomLocksInfoCallback {\n status: typeof CollabChangeRoomLockStatus.Failed\n reason: string\n}\n\nexport type CollabChangeRoomLockCallbackTypes = CollabSuccessChangeRoomLockCallback | CollabFailedChangeRoomLockCallback\n\nexport function isCollabSuccessChangeRoomLockCallback(\n callback: CollabChangeRoomLockCallbackTypes\n): callback is CollabSuccessChangeRoomLockCallback {\n return callback.status === CollabChangeRoomLockStatus.Ok\n}\n\nexport function isCollabFailedChangeRoomLockCallback(\n callback: CollabChangeRoomLockCallbackTypes\n): callback is CollabFailedChangeRoomLockCallback {\n return callback.status === CollabChangeRoomLockStatus.Failed\n}\n\nexport interface CollabFieldLockOptions {\n forceFailure?: boolean\n}\n\nexport const CollabRoomJoinStrategy = {\n Free: 'free',\n Moderated: 'moderated',\n} as const\nexport type CollabRoomJoinStrategyType = (typeof CollabRoomJoinStrategy)[keyof typeof CollabRoomJoinStrategy]\n\nexport interface CollabRoomOptions {\n joinStrategy?: CollabRoomJoinStrategyType\n allowedSameUser?: boolean\n editors?: CollabFieldName[]\n}\n\nexport const CollabRequestToTakeModerationStatus = {\n Ok: 'ok',\n AlreadyRequested: 'alreadyRequested',\n Failed: 'failed',\n} as const\nexport type CollabRequestToTakeModerationStatusType =\n (typeof CollabRequestToTakeModerationStatus)[keyof typeof CollabRequestToTakeModerationStatus]\n\nexport interface CollabRequestToTakeModerationStatusCallback {\n status: CollabRequestToTakeModerationStatusType\n}\n\nexport const CollabRequestToJoinStatus = {\n Ok: 'ok',\n AlreadyRequested: 'alreadyRequested',\n Failed: 'failed',\n} as const\nexport type CollabRequestToJoinStatusType = (typeof CollabRequestToJoinStatus)[keyof typeof CollabRequestToJoinStatus]\n\nexport interface CollabRequestToJoinStatusCallback {\n status: CollabRequestToJoinStatusType\n}\n\nexport interface CollabClientToServerEvents {\n subscribeCollabRoomInfo: (room: CollabRoom, callback: (data: CollabRoomInfoCallback) => void) => void\n unsubscribeCollabRoomInfo: (room: CollabRoom, callback: (data: CollabRoomInfoCallback) => void) => void\n joinCollabRoom: (\n room: CollabRoom,\n options: CollabRoomOptions,\n callback: (data: CollabAccessRoomCallbackTypes) => void\n ) => void\n leaveCollabRoom: (room: CollabRoom, callback: (data: CollabAccessRoomCallbackTypes) => void) => void\n acquireFieldLock: (\n room: CollabRoom,\n field: CollabFieldName,\n options: CollabFieldLockOptions,\n callback: (data: CollabChangeRoomLockCallbackTypes) => void\n ) => void\n releaseFieldLock: (\n room: CollabRoom,\n field: CollabFieldName,\n changedData: unknown,\n options: CollabFieldLockOptions,\n callback: (data: CollabChangeRoomLockCallbackTypes) => void\n ) => void\n changeFieldData: (\n room: CollabRoom,\n field: CollabFieldName,\n changedData: unknown,\n callback: (data: CollabChangeRoomLockCallbackTypes) => void\n ) => void\n requestToJoin: (\n room: CollabRoom,\n timestamp: number,\n callback: (data: CollabRequestToJoinStatusCallback) => void\n ) => void\n approveRequestToJoin: (room: CollabRoom, userId: CollabUserId) => void\n rejectRequestToJoin: (room: CollabRoom, userId: CollabUserId) => void\n enteredCollabRoom: (room: CollabRoom) => void\n requestToTakeModeration: (\n room: CollabRoom,\n timestamp: number,\n callback: (data: CollabRequestToTakeModerationStatusCallback) => void\n ) => void\n approveRequestToTakeModeration: (room: CollabRoom) => void\n rejectRequestToTakeModeration: (room: CollabRoom) => void\n kickUserFromRoom: (room: CollabRoom, userId: CollabUserId) => void\n purgeRoom: (room: CollabRoom) => void\n transferModeration: (room: CollabRoom, userId: CollabUserId) => void\n fetchRoomsInfo: (rooms: CollabRoom[], callback: (data: CollabRoomsInfo) => void) => void\n}\n\nexport interface CollabServerToClientEvents {\n collabRoomChanged: (room: CollabRoomInfo) => void\n collabRoomLocksChanged: (room: CollabRoom, locks: CollabRoomLocks) => void\n collabRoomDataChanged: (room: CollabRoom, data: CollabRoomData) => void\n requestToJoin: (room: CollabRoom, user: CollabUserId, timestamp: number) => void\n approvedRequestToJoin: (room: CollabRoom) => void\n rejectedRequestToJoin: (room: CollabRoom) => void\n startCollab: (room: CollabRoom, callback: (data: CollabRoomPlainData) => void) => void\n requestToTakeModeration: (room: CollabRoom, user: CollabUserId, timestamp: number) => void\n transferredModeration: (room: CollabRoom) => void\n approvedRequestToTakeModeration: (room: CollabRoom) => void\n rejectedRequestToTakeModeration: (room: CollabRoom) => void\n kickedFromRoom: (room: CollabRoom) => void\n}\n\nexport interface CollabConfig extends CollabRoomOptions {\n room: CollabRoom\n joinStrategy: CollabRoomJoinStrategyType\n occupiedOrKickedRedirectToRoute: string\n editors: CollabFieldName[]\n}\nexport type CollabRouteMeta = (params: RouteParams) => CollabConfig\n\nexport interface CollabDelayedRequest {\n userId: CollabUserId\n timestamp: number\n}\n","import { ref } from 'vue'\nimport type { CommonAdminCollabOptions } from '@/AnzuSystemsCommonAdmin'\nimport { isUndefined } from '@/utils/common'\n\nconst collabOptions = ref<CommonAdminCollabOptions>({\n enabled: false,\n socketUrl: '',\n beforeReconnect: () => new Promise((resolve) => resolve()),\n})\n\nexport function initCommonAdminCollabOptions(data: CommonAdminCollabOptions | undefined) {\n if (isUndefined(data)) return\n collabOptions.value = data\n}\n\nexport function useCommonAdminCollabOptions() {\n if (isUndefined(collabOptions.value)) {\n throw new Error(\"Composable can't be used without properly configured common admin.\")\n }\n\n return {\n collabOptions,\n }\n}\n","import type { Socket } from 'socket.io-client'\nimport type {\n CollabClientToServerEvents,\n CollabFieldData,\n CollabFieldLock,\n CollabFieldName,\n CollabRoom,\n CollabRoomInfo,\n CollabRoomPlainData,\n CollabServerToClientEvents,\n} from '@/components/collab/types/Collab'\nimport { computed, reactive, ref, type Ref, toRaw } from 'vue'\nimport { useCollabGatheringBufferDataEventBus } from '@/components/collab/composables/collabEventBus'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\n\nconst collabConnected = ref(true)\nconst collabSocket: Ref<Socket<CollabServerToClientEvents, CollabClientToServerEvents> | undefined> = ref()\nconst collabRoomInfoState = reactive(new Map<CollabRoom, CollabRoomInfo>())\n// Plain, not reactive: bookkeeping for the map above, nothing renders from it.\nlet collabRoomInfoWriteCounter = 0\nconst collabRoomInfoWriteSeq = new Map<CollabRoom, number>()\nconst collabFieldLocksState = reactive(new Map<CollabRoom, Map<CollabFieldName, CollabFieldLock>>())\nconst collabFieldDataBufferState = reactive(new Map<CollabRoom, Map<CollabFieldName, CollabFieldData>>())\n\nexport function useCollabState() {\n const { collabOptions } = useCommonAdminCollabOptions()\n\n const collabReconnecting = computed(() => collabOptions.value.enabled && !collabConnected.value)\n\n const gatherBufferData = (room: CollabRoom): CollabRoomPlainData => {\n const collabGatheringBufferDataEventBus = useCollabGatheringBufferDataEventBus()\n collabGatheringBufferDataEventBus.emit({ room })\n let dataBuffer: CollabRoomPlainData = {}\n const dataBufferMap = collabFieldDataBufferState.get(room)\n if (dataBufferMap) {\n dataBuffer = toRaw(Object.fromEntries(dataBufferMap.entries()))\n collabFieldDataBufferState.delete(room)\n }\n return dataBuffer\n }\n\n /**\n * Call before emitting anything whose acknowledgement writes `collabRoomInfoState`, and let the\n * returned predicate decide whether that write still applies.\n *\n * The server serialises join and leave per room only for the lifetime of its lease, so a leave that\n * outruns it can acknowledge after a following join and mark a room inactive while the client is in\n * it — after which the client goes quiet with nothing visible to show for it.\n */\n const claimRoomInfoWrite = (room: CollabRoom) => {\n /* Global and never restarting, so a number is never handed out twice. Claims outlive a\n * reconnect on purpose — see the `connect` handler in `collabInit.ts`. */\n const seq = ++collabRoomInfoWriteCounter\n collabRoomInfoWriteSeq.set(room, seq)\n\n return () => collabRoomInfoWriteSeq.get(room) === seq\n }\n\n return {\n collabReconnecting,\n collabConnected,\n collabSocket,\n collabRoomInfoState,\n claimRoomInfoWrite,\n collabFieldLocksState,\n collabFieldDataBufferState,\n gatherBufferData,\n }\n}\n","import { ref } from 'vue'\nimport type { IntegerIdNullable } from '@/types/common'\n\nconst currentUserId = ref<IntegerIdNullable>(null)\n\nexport function useCollabCurrentUserId() {\n function setCollabUserCurrentId(value: IntegerIdNullable) {\n currentUserId.value = value\n }\n\n return {\n setCollabUserCurrentId,\n currentUserId,\n }\n}\n","import {\n type CollabChangeRoomLockCallbackTypes,\n type CollabFieldData,\n type CollabFieldDataEnvelope,\n type CollabFieldLockOptions,\n type CollabFieldName,\n type CollabRoom,\n CollabStatus,\n isCollabFailedChangeRoomLockCallback,\n isCollabSuccessChangeRoomLockCallback,\n} from '@/components/collab/types/Collab'\nimport { computed, ref } from 'vue'\nimport {\n CollabFieldLockStatus,\n type CollabFieldLockStatusEvent,\n type CollabFieldLockStatusPayload,\n CollabFieldLockType,\n type CollabGatheringBufferDataEvent,\n type CollabRoomDataChangedEvent,\n createFieldLockStatusPayload,\n useCollabFieldLockStatusEventBus,\n useCollabGatheringBufferDataEventBus,\n useCollabRoomDataChangeEventBus,\n} from '@/components/collab/composables/collabEventBus'\nimport { type Fn, tryOnBeforeUnmount } from '@vueuse/core'\nimport { useCollabState } from '@/components/collab/composables/collabState'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\nimport { useCollabCurrentUserId } from '@/components/collab/composables/collabCurrentUserId'\n\nexport function useCollabField(room: CollabRoom, field: CollabFieldName, disableAutoUnsubscribe = false) {\n const { collabOptions } = useCommonAdminCollabOptions()\n const { currentUserId } = useCollabCurrentUserId()\n const { collabSocket, collabFieldLocksState, collabFieldDataBufferState, collabRoomInfoState } = useCollabState()\n\n const changeEventBus = useCollabRoomDataChangeEventBus()\n const unsubscribeCollabFieldDataChangeListener = ref<undefined | Fn>()\n const fieldChangeCallback = ref<undefined | ((payload: CollabFieldDataEnvelope) => void)>()\n\n const fieldLockStatusEventBus = useCollabFieldLockStatusEventBus()\n const unsubscribeCollabFieldLockStatusListener = ref<undefined | Fn>()\n const fieldLockStatusCallback = ref<undefined | ((payload: CollabFieldLockStatusPayload) => void)>()\n\n const collabGatheringBufferDataEventBus = useCollabGatheringBufferDataEventBus()\n const unsubscribeCollabGatheringBufferData = ref<undefined | Fn>()\n const collabGatheringBufferDataCallback = ref<undefined | Fn>()\n\n const fieldChangeEventBusListener = (event: CollabRoomDataChangedEvent, payload?: CollabFieldDataEnvelope) => {\n if (\n event.room !== room ||\n event.field !== field ||\n isUndefined(payload) ||\n isUndefined(fieldChangeCallback.value)\n ) {\n return\n }\n fieldChangeCallback.value(payload)\n }\n\n const fieldLockStatusEventBusListener = (\n event: CollabFieldLockStatusEvent,\n payload?: CollabFieldLockStatusPayload\n ) => {\n if (\n event.room !== room ||\n event.field !== field ||\n isUndefined(payload) ||\n isUndefined(fieldLockStatusCallback.value)\n ) {\n return\n }\n fieldLockStatusCallback.value(payload)\n }\n\n const collabGatheringBufferDataEventBusListener = (event: CollabGatheringBufferDataEvent) => {\n if (event.room === room && isDefined(collabGatheringBufferDataCallback.value)) {\n collabGatheringBufferDataCallback.value()\n }\n }\n\n const addCollabFieldDataChangeListener = (callback: (data: CollabFieldDataEnvelope) => void) => {\n fieldChangeCallback.value = callback\n unsubscribeCollabFieldDataChangeListener.value = changeEventBus.on(fieldChangeEventBusListener)\n }\n const addCollabFieldLockStatusListener = (callback: (data: CollabFieldLockStatusPayload) => void) => {\n fieldLockStatusCallback.value = callback\n unsubscribeCollabFieldLockStatusListener.value = fieldLockStatusEventBus.on(fieldLockStatusEventBusListener)\n }\n\n const addCollabGatheringBufferDataListener = (callback: () => void) => {\n collabGatheringBufferDataCallback.value = callback\n unsubscribeCollabGatheringBufferData.value = collabGatheringBufferDataEventBus.on(\n collabGatheringBufferDataEventBusListener\n )\n }\n\n tryOnBeforeUnmount(() => {\n if (disableAutoUnsubscribe) return\n if (isDefined(unsubscribeCollabFieldDataChangeListener.value)) {\n unsubscribeCollabFieldDataChangeListener.value()\n }\n if (isDefined(unsubscribeCollabFieldLockStatusListener.value)) {\n unsubscribeCollabFieldLockStatusListener.value()\n }\n if (isDefined(unsubscribeCollabGatheringBufferData.value)) {\n unsubscribeCollabGatheringBufferData.value()\n }\n })\n\n const lockedByUser = computed(() => {\n const roomLockData = collabFieldLocksState.get(room)\n if (roomLockData) {\n const lock = roomLockData.get(field)\n if (lock && currentUserId.value !== lock) {\n return lock\n }\n }\n return null\n })\n\n const acquireCollabFieldLock = (options: Partial<CollabFieldLockOptions> = {}) => {\n if (!collabOptions.value.enabled || isUndefined(collabSocket.value)) return\n const roomInfo = collabRoomInfoState.get(room)\n if (roomInfo && roomInfo.status === CollabStatus.Inactive) return\n collabSocket.value\n ?.timeout(1000)\n .emit('acquireFieldLock', room, field, options, (error, response: CollabChangeRoomLockCallbackTypes) => {\n const statusEvent: CollabFieldLockStatusEvent = { field, room }\n if (error || isCollabFailedChangeRoomLockCallback(response)) {\n return void fieldLockStatusEventBus.emit(\n statusEvent,\n createFieldLockStatusPayload(CollabFieldLockType.Acquire, CollabFieldLockStatus.Failure)\n )\n }\n if (isCollabSuccessChangeRoomLockCallback(response)) {\n if (!collabFieldLocksState.has(room)) {\n collabFieldLocksState.set(room, new Map())\n }\n const locks = new Map(response.locks ? Object.entries(response.locks) : [])\n for (const [field, lock] of locks.entries()) {\n collabFieldLocksState.get(room)?.set(field, lock)\n }\n\n return void fieldLockStatusEventBus.emit(\n statusEvent,\n createFieldLockStatusPayload(CollabFieldLockType.Acquire, CollabFieldLockStatus.Success)\n )\n }\n })\n }\n\n const releaseCollabFieldLock = (data: CollabFieldData, options: Partial<CollabFieldLockOptions> = {}) => {\n if (!collabOptions.value.enabled || isUndefined(collabSocket.value)) return\n const roomInfo = collabRoomInfoState.get(room)\n if (roomInfo && roomInfo.status === CollabStatus.Inactive) {\n if (!collabFieldDataBufferState.has(room)) {\n collabFieldDataBufferState.set(room, new Map())\n }\n collabFieldDataBufferState.get(room)?.set(field, data)\n return\n }\n collabSocket.value\n ?.timeout(1000)\n .emit('releaseFieldLock', room, field, data, options, (error, response: CollabChangeRoomLockCallbackTypes) => {\n const statusEvent: CollabFieldLockStatusEvent = { field, room }\n if (error || isCollabFailedChangeRoomLockCallback(response)) {\n return void fieldLockStatusEventBus.emit(\n statusEvent,\n createFieldLockStatusPayload(CollabFieldLockType.Release, CollabFieldLockStatus.Failure)\n )\n }\n if (isCollabSuccessChangeRoomLockCallback(response)) {\n if (!collabFieldLocksState.has(room)) {\n collabFieldLocksState.set(room, new Map())\n }\n if (response.locks) {\n for (const field of Object.keys(response.locks)) {\n collabFieldLocksState.get(room)?.delete(field)\n }\n }\n\n return void fieldLockStatusEventBus.emit(\n statusEvent,\n createFieldLockStatusPayload(CollabFieldLockType.Release, CollabFieldLockStatus.Success)\n )\n }\n })\n }\n\n const changeCollabFieldData = (data: CollabFieldData) => {\n if (!collabOptions.value.enabled || isUndefined(collabSocket.value)) return\n const roomInfo = collabRoomInfoState.get(room)\n if (roomInfo && roomInfo.status === CollabStatus.Inactive) return\n collabSocket.value.emit('changeFieldData', room, field, data, () => {\n return\n })\n }\n\n return {\n addCollabFieldDataChangeListener,\n addCollabFieldLockStatusListener,\n addCollabGatheringBufferDataListener,\n acquireCollabFieldLock,\n releaseCollabFieldLock,\n changeCollabFieldData,\n lockedByUser,\n collabFieldDataBufferState,\n unsubscribeCollabFieldDataChangeListener,\n unsubscribeCollabFieldLockStatusListener,\n unsubscribeCollabGatheringBufferData,\n }\n}\n","<script lang=\"ts\" setup>\nimport { computed, inject, ref, watch } from 'vue'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport type { VuetifyIconValue } from '@/types/Vuetify'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { useI18n } from 'vue-i18n'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport {\n CollabFieldLockStatus,\n type CollabFieldLockStatusPayload,\n CollabFieldLockType,\n} from '@/components/collab/composables/collabEventBus'\nimport type { CollabComponentConfig, CollabFieldData, CollabFieldLockOptions } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport type { IntegerIdNullable } from '@/types/common'\nimport type { VTextField } from 'vuetify/components/VTextField'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string | number | null | undefined\n label?: string\n errorMessage?: string\n required?: boolean\n v?: any\n prependIcon?: VuetifyIconValue\n appendIcon?: VuetifyIconValue\n dataCy?: string\n hideLabel?: boolean\n type?: string\n step?: number\n maxlength?: number | undefined\n collab?: CollabComponentConfig\n disabled?: boolean\n placeholder?: undefined | string\n persistentPlaceholder?: boolean\n help?: string | undefined\n }>(),\n {\n label: undefined,\n errorMessage: undefined,\n required: undefined,\n v: null,\n prependIcon: undefined,\n appendIcon: undefined,\n dataCy: undefined,\n hideLabel: false,\n type: 'text',\n step: undefined,\n maxlength: undefined,\n collab: undefined,\n disabled: undefined,\n placeholder: undefined,\n persistentPlaceholder: false,\n help: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: string | number | null | undefined): void\n (e: 'click:append', data: string | number | null | undefined): void\n (e: 'blur', data: string | number | null | undefined): void\n (e: 'focus', data: string | number | null | undefined): void\n}>()\n\nconst textFieldRef = ref<InstanceType<typeof VTextField> | null>(null)\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n\nconst releaseFieldLock = ref((_data: CollabFieldData, _options?: Partial<CollabFieldLockOptions>) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst acquireFieldLock = ref((options?: Partial<CollabFieldLockOptions>) => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const {\n releaseCollabFieldLock,\n acquireCollabFieldLock,\n addCollabFieldLockStatusListener,\n addCollabGatheringBufferDataListener,\n lockedByUser,\n } = useCollabField(props.collab.room, props.collab.field)\n releaseFieldLock.value = releaseCollabFieldLock\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n addCollabFieldLockStatusListener((data: CollabFieldLockStatusPayload) => {\n if (data.status === CollabFieldLockStatus.Failure && data.type === CollabFieldLockType.Acquire) {\n textFieldRef.value?.blur()\n }\n })\n addCollabGatheringBufferDataListener(() => {\n textFieldRef.value?.blur()\n })\n}\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onUpdate = (newValue: string) => {\n emit('update:modelValue', newValue)\n}\nconst onBlur = () => {\n emit('blur', props.modelValue)\n props.v?.$touch()\n releaseFieldLock.value(props.modelValue)\n}\n\nconst onFocus = () => {\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return [props.v.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n if (props.v?.required && props.v?.required.$params.type === 'required') return true\n return false\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nconst focus = () => {\n textFieldRef.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n</script>\n\n<template>\n <VTextField\n ref=\"textFieldRef\"\n :prepend-icon=\"prependIcon\"\n :data-cy=\"dataCy\"\n :error-messages=\"errorMessageComputed\"\n :model-value=\"modelValue\"\n :required=\"requiredComputed\"\n :type=\"type\"\n :step=\"step\"\n :append-icon=\"appendIcon\"\n :maxlength=\"maxlength\"\n :disabled=\"disabledComputed\"\n :placeholder=\"placeholder\"\n :persistent-placeholder=\"persistentPlaceholder\"\n trim\n autocomplete=\"off\"\n @click:append=\"(event: any) => emit('click:append', event)\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @update:model-value=\"onUpdate($event)\"\n >\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ labelComputed\n }}<span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append-inner\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n <template\n v-if=\"$slots.prepend\"\n #prepend\n >\n <slot name=\"prepend\" />\n </template>\n <template\n v-if=\"help\"\n #append\n >\n <VIcon\n v-tooltip=\"help\"\n icon=\"mdi-help-circle-outline\"\n />\n </template>\n </VTextField>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject, ref, watch } from 'vue'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport type { VuetifyIconValue } from '@/types/Vuetify'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { useI18n } from 'vue-i18n'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport {\n CollabFieldLockStatus,\n type CollabFieldLockStatusPayload,\n CollabFieldLockType,\n} from '@/components/collab/composables/collabEventBus'\nimport type { CollabComponentConfig, CollabFieldData, CollabFieldLockOptions } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport type { IntegerIdNullable } from '@/types/common'\nimport type { VTextField } from 'vuetify/components/VTextField'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string | number | null | undefined\n label?: string\n errorMessage?: string\n required?: boolean\n v?: any\n prependIcon?: VuetifyIconValue\n appendIcon?: VuetifyIconValue\n dataCy?: string\n hideLabel?: boolean\n type?: string\n step?: number\n maxlength?: number | undefined\n collab?: CollabComponentConfig\n disabled?: boolean\n placeholder?: undefined | string\n persistentPlaceholder?: boolean\n help?: string | undefined\n }>(),\n {\n label: undefined,\n errorMessage: undefined,\n required: undefined,\n v: null,\n prependIcon: undefined,\n appendIcon: undefined,\n dataCy: undefined,\n hideLabel: false,\n type: 'text',\n step: undefined,\n maxlength: undefined,\n collab: undefined,\n disabled: undefined,\n placeholder: undefined,\n persistentPlaceholder: false,\n help: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: string | number | null | undefined): void\n (e: 'click:append', data: string | number | null | undefined): void\n (e: 'blur', data: string | number | null | undefined): void\n (e: 'focus', data: string | number | null | undefined): void\n}>()\n\nconst textFieldRef = ref<InstanceType<typeof VTextField> | null>(null)\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n\nconst releaseFieldLock = ref((_data: CollabFieldData, _options?: Partial<CollabFieldLockOptions>) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst acquireFieldLock = ref((options?: Partial<CollabFieldLockOptions>) => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const {\n releaseCollabFieldLock,\n acquireCollabFieldLock,\n addCollabFieldLockStatusListener,\n addCollabGatheringBufferDataListener,\n lockedByUser,\n } = useCollabField(props.collab.room, props.collab.field)\n releaseFieldLock.value = releaseCollabFieldLock\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n addCollabFieldLockStatusListener((data: CollabFieldLockStatusPayload) => {\n if (data.status === CollabFieldLockStatus.Failure && data.type === CollabFieldLockType.Acquire) {\n textFieldRef.value?.blur()\n }\n })\n addCollabGatheringBufferDataListener(() => {\n textFieldRef.value?.blur()\n })\n}\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onUpdate = (newValue: string) => {\n emit('update:modelValue', newValue)\n}\nconst onBlur = () => {\n emit('blur', props.modelValue)\n props.v?.$touch()\n releaseFieldLock.value(props.modelValue)\n}\n\nconst onFocus = () => {\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return [props.v.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n if (props.v?.required && props.v?.required.$params.type === 'required') return true\n return false\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nconst focus = () => {\n textFieldRef.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n</script>\n\n<template>\n <VTextField\n ref=\"textFieldRef\"\n :prepend-icon=\"prependIcon\"\n :data-cy=\"dataCy\"\n :error-messages=\"errorMessageComputed\"\n :model-value=\"modelValue\"\n :required=\"requiredComputed\"\n :type=\"type\"\n :step=\"step\"\n :append-icon=\"appendIcon\"\n :maxlength=\"maxlength\"\n :disabled=\"disabledComputed\"\n :placeholder=\"placeholder\"\n :persistent-placeholder=\"persistentPlaceholder\"\n trim\n autocomplete=\"off\"\n @click:append=\"(event: any) => emit('click:append', event)\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @update:model-value=\"onUpdate($event)\"\n >\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ labelComputed\n }}<span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append-inner\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n <template\n v-if=\"$slots.prepend\"\n #prepend\n >\n <slot name=\"prepend\" />\n </template>\n <template\n v-if=\"help\"\n #append\n >\n <VIcon\n v-tooltip=\"help\"\n icon=\"mdi-help-circle-outline\"\n />\n </template>\n </VTextField>\n</template>\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport type { ColumnInternalValues } from '@/composables/system/datatableColumns'\nimport { cloneDeep } from '@/utils/common'\n\nconst props = withDefaults(\n defineProps<{\n columnsAll: ColumnInternalValues[]\n columnsHidden: Array<string>\n buttonT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n buttonT: 'common.system.datatable.config',\n buttonClass: 'ml-1',\n dataCy: 'table-settings',\n }\n)\nconst emit = defineEmits<{\n (e: 'update:columnsHidden', data: Array<string>): void\n}>()\n\nconst { t } = useI18n()\n\nconst isVisible = (key: string) => {\n return !props.columnsHidden.includes(key)\n}\n\nconst toggleVisibility = (key: string) => {\n const cloned = cloneDeep(props.columnsHidden)\n const index = cloned.indexOf(key)\n if (index > -1) {\n cloned.splice(index, 1)\n emit('update:columnsHidden', cloned)\n return\n }\n cloned.push(key)\n emit('update:columnsHidden', cloned)\n}\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis\"\n icon\n size=\"x-small\"\n variant=\"text\"\n >\n <VIcon icon=\"mdi-cog\" />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(buttonT) }}\n </VTooltip>\n <VMenu\n :min-width=\"260\"\n activator=\"parent\"\n >\n <VCard>\n <VList density=\"compact\">\n <VListItem>\n <VListItemTitle>\n <strong>{{ t('common.system.datatable.displayCols') }}</strong>\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-for=\"column in columnsAll\"\n :key=\"column.key\"\n @click.stop=\"toggleVisibility(column.key)\"\n >\n <VListItemTitle>\n <VIcon\n v-if=\"isVisible(column.key)\"\n class=\"mr-2\"\n icon=\"mdi-checkbox-marked\"\n />\n <VIcon\n v-else\n class=\"mr-2\"\n icon=\"mdi-checkbox-blank-outline\"\n />\n {{ column.title }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VCard>\n </VMenu>\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport type { ColumnInternalValues } from '@/composables/system/datatableColumns'\nimport { cloneDeep } from '@/utils/common'\n\nconst props = withDefaults(\n defineProps<{\n columnsAll: ColumnInternalValues[]\n columnsHidden: Array<string>\n buttonT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n buttonT: 'common.system.datatable.config',\n buttonClass: 'ml-1',\n dataCy: 'table-settings',\n }\n)\nconst emit = defineEmits<{\n (e: 'update:columnsHidden', data: Array<string>): void\n}>()\n\nconst { t } = useI18n()\n\nconst isVisible = (key: string) => {\n return !props.columnsHidden.includes(key)\n}\n\nconst toggleVisibility = (key: string) => {\n const cloned = cloneDeep(props.columnsHidden)\n const index = cloned.indexOf(key)\n if (index > -1) {\n cloned.splice(index, 1)\n emit('update:columnsHidden', cloned)\n return\n }\n cloned.push(key)\n emit('update:columnsHidden', cloned)\n}\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis\"\n icon\n size=\"x-small\"\n variant=\"text\"\n >\n <VIcon icon=\"mdi-cog\" />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(buttonT) }}\n </VTooltip>\n <VMenu\n :min-width=\"260\"\n activator=\"parent\"\n >\n <VCard>\n <VList density=\"compact\">\n <VListItem>\n <VListItemTitle>\n <strong>{{ t('common.system.datatable.displayCols') }}</strong>\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-for=\"column in columnsAll\"\n :key=\"column.key\"\n @click.stop=\"toggleVisibility(column.key)\"\n >\n <VListItemTitle>\n <VIcon\n v-if=\"isVisible(column.key)\"\n class=\"mr-2\"\n icon=\"mdi-checkbox-marked\"\n />\n <VIcon\n v-else\n class=\"mr-2\"\n icon=\"mdi-checkbox-blank-outline\"\n />\n {{ column.title }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VCard>\n </VMenu>\n </VBtn>\n</template>\n","import type { Locale, Path } from 'vue-i18n'\nimport { createI18n } from 'vue-i18n'\nimport type en from '@/locales/en'\n\nexport type MessageSchema = typeof en\n\nconst REQUIRED_LOCALES = ['en', 'sk']\n\n/**\n * Custom Slovak Pluralization Rule.\n *\n * Automatically detects the format of the translation string based on the number\n * of pipe-separated choices (`choicesLength`) and returns the correct index.\n *\n * Case A: 4 choices (Extended format with explicit 0 support)\n * Structure: \"0 items | 1 item | 2-4 items | 5+ items\"\n * - 0 -> Index 0\n * - 1 -> Index 1\n * - 2-4 -> Index 2\n * - 5+ -> Index 3\n *\n * Case B: 3 choices (Starndard Slovak format)\n * Structure: \"1 item | 2-4 items | 5+ items\"\n * - 1 -> Index 0\n * - 2-4 -> Index 1\n * - 5+ -> Index 2 (Includes 0)\n *\n * Case C: 2 choices or fewer (Fallback)\n * - 1 -> Index 0\n * - Other-> Index 1\n */\nexport const slovakPluralizationRule = (choice: number, choicesLength: number) => {\n if (choicesLength === 4) {\n if (choice === 0) return 0\n if (choice === 1) return 1\n if (choice >= 2 && choice <= 4) return 2\n return 3\n }\n if (choicesLength === 3) {\n if (choice === 1) return 0\n if (choice >= 2 && choice <= 4) return 1\n return 2\n }\n return choice === 1 ? 0 : 1\n}\n\nexport const i18n = createI18n<[MessageSchema], string, false>({\n globalInjection: false,\n legacy: false,\n locale: REQUIRED_LOCALES[0],\n fallbackLocale: false,\n pluralRules: {\n sk: slovakPluralizationRule,\n // Czech shares the Slovak plural categories (one / 2-4 / other), and without\n // a rule the default would pick zero|one|other: \"1 nepotvrzené změny\".\n cs: slovakPluralizationRule,\n },\n missing: (locale: Locale, key: Path) => {\n if (REQUIRED_LOCALES.includes(locale) && !key.startsWith('system.subject.')) {\n console.warn(`Missing ${locale} translation: ${key}`)\n }\n },\n})\n","import { computed, reactive } from 'vue'\nimport type { Pagination } from '@/types/Pagination'\n\nexport function usePagination(sortBy: string | null = 'id', sortDescending: boolean = true) {\n return reactive<Pagination>({\n sortBy: sortBy,\n descending: sortDescending,\n page: 1,\n rowsPerPage: 25,\n rowsNumber: 0,\n hasNextPage: null,\n currentViewCount: 0,\n totalCount: 0,\n })\n}\n\n/**\n * @deprecated No labs replacement exists. Until one does, inline the predicate: see\n * `admin-blog` `NoteDatatable.vue`, which computes it from a labs `Ref<Pagination>` in three lines.\n */\nexport function usePaginationAutoHide(pagination: Pagination) {\n const showPagination = computed(() => {\n if (pagination.page === 1 && pagination.currentViewCount < pagination.rowsPerPage) return false\n return true\n })\n\n return {\n showPagination,\n }\n}\n","import { computed, onMounted, type Ref, watch } from 'vue'\nimport { i18n } from '@/plugins/i18n'\nimport type { Pagination } from '@/types/Pagination'\nimport { usePagination } from '@/composables/system/pagination'\nimport { isArray, isObject, isUndefined } from '@/utils/common'\n\nexport const DATETIME_AUTO_LABEL_TRACKING = ['createdAt', 'modifiedAt']\n\nexport const SORT_BY_SCORE = '_score'\nexport const SORT_BY_ID = 'id'\nexport const SORT_BY_SCORE_DATE = 'score_date'\nexport const SORT_BY_SCORE_BEST = 'score_best'\nexport const SortOrder = {\n Asc: 'asc',\n Desc: 'desc',\n} as const\nexport type SortOrderType = (typeof SortOrder)[keyof typeof SortOrder]\n\nexport type DatatableSortBy =\n | {\n key: string\n order: SortOrderType\n }\n | null\n | undefined\n\nexport type DatatableOrderingOption = {\n id: number\n titleT: string\n sortBy?: DatatableSortBy\n customData?: any\n}\n\nexport type DatatableOrderingOptions = Array<DatatableOrderingOption>\n\nexport type ColumnConfig = {\n key: string\n title?: string\n sortable?: boolean\n fixed?: boolean\n maxWidth?: number\n}\n\nexport type ColumnInternalValues = {\n key: string\n title?: string\n sortable: boolean\n fixed: boolean\n}\n\nexport type StoredData = {\n hidden?: string[]\n}\n\nconst defaultColumn: ColumnInternalValues = {\n key: '',\n title: undefined,\n sortable: false,\n fixed: false,\n}\n\nexport function createDatatableColumnsConfig(\n config: ColumnConfig[],\n columnsHidden: Ref<Array<string>>,\n system: string | undefined = undefined,\n subject: string | undefined = undefined,\n disableActions: boolean = false,\n customInitialPagination: Pagination | undefined = undefined,\n customI18n: undefined | any = undefined,\n showExpand: undefined | boolean = undefined,\n storeId: string | undefined = undefined\n) {\n const localI18n = customI18n ?? i18n\n const { t } = localI18n.global || localI18n\n const pagination: Pagination = usePagination()\n if (customInitialPagination) {\n for (const prop of Object.keys(pagination)) {\n if (prop in customInitialPagination) {\n // @ts-ignore\n pagination[prop] = customInitialPagination[prop]\n }\n }\n }\n\n const columnsAll = config.map((item) => {\n const obj = { ...defaultColumn, ...item }\n if (!isUndefined(obj.title)) {\n // do not modify\n } else if (isUndefined(obj.title) && DATETIME_AUTO_LABEL_TRACKING.includes(obj.key)) {\n obj.title = t('common.model.tracking.' + obj.key)\n } else if (isUndefined(obj.title) && system && subject) {\n obj.title = t(system + '.' + subject + '.model.' + obj.key)\n } else {\n obj.title = ''\n }\n return obj\n })\n\n const columnsVisible = computed(() => {\n const columns: any = []\n if (showExpand) columns.push({ key: 'data-table-expand', sortable: false })\n columnsAll.forEach((column) => {\n if (!columnsHidden.value.includes(column.key)) {\n columns.push(column)\n }\n })\n if (!disableActions) columns.push({ key: 'actions', sortable: false, fixed: true })\n return columns\n })\n\n const updateSortBy = (sortBy: { key: string; order: SortOrderType } | undefined | null) => {\n if (!sortBy) {\n pagination.sortBy = null\n return\n }\n pagination.sortBy = sortBy.key\n pagination.descending = sortBy.order === SortOrder.Desc ? true : false\n }\n\n const loadStoredColumns = () => {\n if (!storeId || !localStorage) return\n const stored = localStorage.getItem(storeId)\n if (!stored) return\n const storedData = JSON.parse(stored) as StoredData\n if (!isObject(storedData)) return\n if (!isArray(storedData.hidden)) return\n columnsHidden.value = storedData.hidden as string[]\n }\n\n const storeColumns = (columns: string[]) => {\n if (!storeId || !localStorage) return\n localStorage.setItem(storeId, JSON.stringify({ hidden: columns }))\n }\n\n onMounted(() => {\n loadStoredColumns()\n })\n\n watch(columnsHidden, (newValue) => {\n storeColumns(newValue)\n })\n\n return {\n columnsAll,\n columnsVisible,\n columnsHidden,\n updateSortBy,\n pagination,\n }\n}\n","<script setup lang=\"ts\">\nconst emit = defineEmits<{\n (e: 'onCancel'): void\n}>()\n\nconst onCancel = () => {\n emit('onCancel')\n}\n</script>\n\n<template>\n <VToolbar\n density=\"compact\"\n color=\"transparent\"\n >\n <VToolbarTitle class=\"flex-fill\">\n <slot />\n </VToolbarTitle>\n <VSpacer />\n <VBtn\n class=\"ml-2\"\n icon=\"mdi-close\"\n size=\"small\"\n variant=\"text\"\n data-cy=\"button-close\"\n @click.stop=\"onCancel\"\n />\n </VToolbar>\n</template>\n","<script setup lang=\"ts\">\nconst emit = defineEmits<{\n (e: 'onCancel'): void\n}>()\n\nconst onCancel = () => {\n emit('onCancel')\n}\n</script>\n\n<template>\n <VToolbar\n density=\"compact\"\n color=\"transparent\"\n >\n <VToolbarTitle class=\"flex-fill\">\n <slot />\n </VToolbarTitle>\n <VSpacer />\n <VBtn\n class=\"ml-2\"\n icon=\"mdi-close\"\n size=\"small\"\n variant=\"text\"\n data-cy=\"button-close\"\n @click.stop=\"onCancel\"\n />\n </VToolbar>\n</template>\n","(function(){\"use strict\";var o;try{if(typeof document<\"u\"){var e=document.createElement(\"style\");e.nonce=(o=document.head.querySelector(\"meta[property=csp-nonce]\"))==null?void 0:o.content,e.appendChild(document.createTextNode(\".vue-notification-group{display:block;position:fixed;z-index:5000}.vue-notification-wrapper{display:block;overflow:hidden;width:100%;margin:0;padding:0}.notification-title{font-weight:600}.vue-notification-template{display:block;box-sizing:border-box;background:#fff;text-align:left}.vue-notification{display:block;box-sizing:border-box;text-align:left;font-size:12px;padding:10px;margin:0 5px 5px;color:#fff;background:#44a4fc;border-left:5px solid #187FE7}.vue-notification.warn{background:#ffb648;border-left-color:#f48a06}.vue-notification.error{background:#e54d42;border-left-color:#b82e24}.vue-notification.success{background:#68cd86;border-left-color:#42a85f}.vn-fade-enter-active,.vn-fade-leave-active,.vn-fade-move{transition:all .5s}.vn-fade-enter-from,.vn-fade-leave-to{opacity:0}\")),document.head.appendChild(e)}}catch(n){console.error(\"vite-plugin-css-injected-by-js\",n)}})();\nimport { defineComponent as Q, ref as X, computed as h, onMounted as Z, onUnmounted as tt, createVNode as l, TransitionGroup as et, mergeProps as nt, Fragment as H, isVNode as ot } from \"vue\";\nconst B = /* @__PURE__ */ new Map();\nfunction it(t) {\n return { all: t = t || /* @__PURE__ */ new Map(), on: function(o, i) {\n var a = t.get(o);\n a ? a.push(i) : t.set(o, [i]);\n }, off: function(o, i) {\n var a = t.get(o);\n a && (i ? a.splice(a.indexOf(i) >>> 0, 1) : t.set(o, []));\n }, emit: function(o, i) {\n var a = t.get(o);\n a && a.slice().map(function(r) {\n r(i);\n }), (a = t.get(\"*\")) && a.slice().map(function(r) {\n r(o, i);\n });\n } };\n}\nconst y = it(), T = \"[-+]?[0-9]*.?[0-9]+\", R = [\n {\n name: \"px\",\n regexp: new RegExp(`^${T}px$`)\n },\n {\n name: \"%\",\n regexp: new RegExp(`^${T}%$`)\n },\n /**\n * Fallback option\n * If no suffix specified, assigning \"px\"\n */\n {\n name: \"px\",\n regexp: new RegExp(`^${T}$`)\n }\n], at = (t) => {\n if (t === \"auto\")\n return {\n type: t,\n value: 0\n };\n for (let o = 0; o < R.length; o++) {\n const i = R[o];\n if (i.regexp.test(t))\n return {\n type: i.name,\n value: parseFloat(t)\n };\n }\n return {\n type: \"\",\n value: t\n };\n}, st = (t) => {\n switch (typeof t) {\n case \"number\":\n return { type: \"px\", value: t };\n case \"string\":\n return at(t);\n default:\n return { type: \"\", value: t };\n }\n}, j = {\n x: /* @__PURE__ */ new Set([\"left\", \"center\", \"right\"]),\n y: /* @__PURE__ */ new Set([\"top\", \"bottom\"])\n}, rt = /* @__PURE__ */ ((t) => () => t++)(0), lt = (t) => typeof t != \"string\" ? [] : t.split(/\\s+/gi).filter(Boolean), ct = (t) => {\n typeof t == \"string\" && (t = lt(t));\n let o = null, i = null;\n return t.forEach((a) => {\n j.y.has(a) && (i = a), j.x.has(a) && (o = a);\n }), { x: o, y: i };\n}, b = {\n position: [\"top\", \"right\"],\n cssAnimation: \"vn-fade\",\n velocityAnimation: {\n enter: (t) => ({\n height: [t.clientHeight, 0],\n opacity: [1, 0]\n }),\n leave: {\n height: 0,\n opacity: [0, 1]\n }\n }\n}, ut = (t, o) => {\n let i, a, r = o;\n const m = () => {\n a = Date.now(), i = setTimeout(t, r);\n }, g = () => {\n clearTimeout(i), r -= Date.now() - a;\n };\n return m(), {\n start: m,\n stop: g\n };\n};\nfunction ft(t) {\n return typeof t == \"function\" || Object.prototype.toString.call(t) === \"[object Object]\" && !ot(t);\n}\nconst v = {\n IDLE: 0,\n DESTROYED: 2\n}, dt = /* @__PURE__ */ Q({\n // eslint-disable-next-line vue/multi-word-component-names\n name: \"notifications\",\n props: {\n group: {\n type: String,\n default: \"\"\n },\n /** \n * Width of notification holder, can be `%`, `px` string or number.\n * @example '100%', '200px', 200 \n * */\n width: {\n type: [Number, String],\n default: 300\n },\n reverse: {\n type: Boolean,\n default: !1\n },\n position: {\n type: [String, Array],\n default: () => b.position\n },\n classes: {\n type: [String, Array],\n default: \"vue-notification\"\n },\n animationType: {\n type: String,\n default: \"css\",\n validator(t) {\n return t === \"css\" || t === \"velocity\";\n }\n },\n animation: {\n type: Object,\n default() {\n return b.velocityAnimation;\n }\n },\n animationName: {\n type: String,\n default: b.cssAnimation\n },\n speed: {\n type: Number,\n default: 300\n },\n /** Time (in ms) to keep the notification on screen (if **negative** - notification will stay **forever** or until clicked) */\n duration: {\n type: Number,\n default: 3e3\n },\n delay: {\n type: Number,\n default: 0\n },\n max: {\n type: Number,\n default: 1 / 0\n },\n ignoreDuplicates: {\n type: Boolean,\n default: !1\n },\n closeOnClick: {\n type: Boolean,\n default: !0\n },\n pauseOnHover: {\n type: Boolean,\n default: !1\n },\n /** Use [v-html](https://vuejs.org/api/built-in-directives.html#v-html) to set `title` and `text` */\n dangerouslySetInnerHtml: {\n type: Boolean,\n default: !1\n }\n },\n emits: {\n /* eslint-disable @typescript-eslint/no-unused-vars */\n click: (t) => !0,\n destroy: (t) => !0,\n start: (t) => !0\n /* eslint-enable @typescript-eslint/no-unused-vars */\n },\n slots: Object,\n setup: (t, {\n emit: o,\n slots: i,\n expose: a\n }) => {\n const r = X([]), m = B.get(\"velocity\"), g = h(() => t.animationType === \"velocity\"), c = h(() => r.value.filter((e) => e.state !== v.DESTROYED)), D = h(() => st(t.width)), S = h(() => {\n const {\n x: e,\n y: n\n } = ct(t.position), s = D.value.value, u = D.value.type, p = {\n width: s + u\n };\n return n && (p[n] = \"0px\"), e && (e === \"center\" ? p.left = `calc(50% - ${+s / 2}${u})` : p[e] = \"0px\"), p;\n }), L = h(() => g.value ? {\n onEnter: G,\n onLeave: W,\n onAfterLeave: A\n } : {}), k = (e) => {\n o(\"click\", e), t.closeOnClick && d(e);\n }, C = (e) => {\n var n;\n t.pauseOnHover && ((n = e.timer) == null || n.stop());\n }, P = (e) => {\n var n;\n t.pauseOnHover && ((n = e.timer) == null || n.start());\n }, N = (e = {}) => {\n if (e.group || (e.group = \"\"), e.data || (e.data = {}), t.group !== e.group)\n return;\n if (e.clean || e.clear) {\n F();\n return;\n }\n const n = typeof e.duration == \"number\" ? e.duration : t.duration, s = typeof e.speed == \"number\" ? e.speed : t.speed, u = typeof e.ignoreDuplicates == \"boolean\" ? e.ignoreDuplicates : t.ignoreDuplicates, {\n title: p,\n text: U,\n type: q,\n data: z,\n id: J\n } = e, f = {\n id: J || rt(),\n title: p,\n text: U,\n type: q,\n state: v.IDLE,\n speed: s,\n length: n + 2 * s,\n data: z,\n duplicates: 0\n };\n n >= 0 && (f.timer = ut(() => d(f), f.length));\n const I = \"bottom\" in S.value, K = t.reverse ? !I : I;\n let x = -1;\n const $ = c.value.find((M) => M.title === e.title && M.text === e.text);\n if (u && $) {\n $.duplicates++;\n return;\n }\n K ? (r.value.push(f), o(\"start\", f), c.value.length > t.max && (x = 0)) : (r.value.unshift(f), o(\"start\", f), c.value.length > t.max && (x = c.value.length - 1)), x !== -1 && d(c.value[x]);\n }, O = (e) => {\n _(e);\n }, Y = (e) => [\"vue-notification-template\", t.classes, e.type || \"\"], V = (e) => g.value ? void 0 : {\n transition: `all ${e.speed}ms`\n }, d = (e) => {\n var n;\n (n = e.timer) == null || n.stop(), e.state = v.DESTROYED, A(), o(\"destroy\", e);\n }, _ = (e) => {\n const n = r.value.find((s) => s.id === e);\n n && d(n);\n }, F = () => {\n c.value.forEach(d);\n }, w = (e, n) => {\n var u;\n const s = (u = t.animation) == null ? void 0 : u[e];\n return typeof s == \"function\" ? s(n) : s;\n }, G = (e, n) => {\n const s = w(\"enter\", e);\n m(e, s, {\n duration: t.speed,\n complete: n\n });\n }, W = (e, n) => {\n const s = w(\"leave\", e);\n m(e, s, {\n duration: t.speed,\n complete: n\n });\n };\n function A() {\n r.value = r.value.filter((e) => e.state !== v.DESTROYED);\n }\n return Z(() => {\n y.on(\"add\", N), y.on(\"close\", O);\n }), tt(() => {\n y.off(\"add\", N), y.off(\"close\", O);\n }), () => {\n let e;\n return l(\"div\", {\n class: \"vue-notification-group\",\n style: S.value\n }, [l(et, nt(L.value, {\n tag: \"div\",\n css: !g.value,\n name: t.animationName\n }), ft(e = c.value.map((n) => l(\"div\", {\n key: n.id,\n class: \"vue-notification-wrapper\",\n style: V(n),\n \"data-id\": n.id,\n onMouseenter: () => C(n),\n onMouseleave: () => P(n)\n }, [i.body ? i.body({\n item: n,\n class: [t.classes, n.type],\n close: () => d(n)\n }) : l(\"div\", {\n class: Y(n),\n onClick: () => k(n)\n }, [t.dangerouslySetInnerHtml ? l(H, null, [n.title ? l(\"div\", {\n class: \"notification-title\",\n innerHTML: n.title\n }, null) : null, l(\"div\", {\n class: \"notification-content\",\n innerHTML: n.text\n }, null)]) : l(H, null, [n.title ? l(\"div\", {\n class: \"notification-title\"\n }, [n.title]) : null, l(\"div\", {\n class: \"notification-content\"\n }, [n.text])])])]))) ? e : {\n default: () => [e]\n })]);\n };\n }\n}), E = (t) => {\n typeof t == \"string\" && (t = { title: \"\", text: t }), typeof t == \"object\" && y.emit(\"add\", t);\n};\nE.close = (t) => {\n y.emit(\"close\", t);\n};\nconst gt = () => ({ notify: E }), pt = \"Notifications\";\nfunction yt(t, o = {}) {\n Object.entries(o).forEach((a) => B.set(...a));\n const i = o.name || \"notify\";\n t.config.globalProperties[\"$\" + i] = E, t.component(o.componentName || pt, dt);\n}\nconst ht = {\n install: yt\n};\nexport {\n dt as Notifications,\n ht as default,\n E as notify,\n gt as useNotification\n};\n","export const isAnzuError = (error: unknown): error is AnzuError => {\n return error instanceof AnzuError\n}\n\n/**\n * The base every Anzu error extends.\n *\n * It exists so the api helpers can ask \"has this already been mapped?\" without testing the error's\n * name: a string prefix answers true for anyone else's class called `Anzu…`, and answers false the\n * moment a class forgets to set `name`. One `instanceof` says exactly what is meant.\n */\nexport class AnzuError extends Error {\n constructor(message: string, cause: unknown = undefined) {\n super(message)\n this.name = 'AnzuError'\n this.cause = cause\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nexport const isAnzuFatalError = (error: any): error is AnzuFatalError => {\n return error instanceof AnzuFatalError\n}\n\nexport class AnzuFatalError extends AnzuError {\n constructor(cause?: Error, message = '') {\n // Empty message renders as \"No error message\" in Sentry.\n const resolvedMessage = message || 'Unexpected error'\n super(resolvedMessage)\n this.name = 'AnzuFatalError'\n this.cause = cause\n this.message = resolvedMessage\n }\n}\n","export const HTTP_STATUS_OK = 200\nexport const HTTP_STATUS_CREATED = 201\nexport const HTTP_STATUS_ACCEPTED = 202\nexport const HTTP_STATUS_NO_CONTENT = 204\nexport const HTTP_STATUS_BAD_REQUEST = 400\nexport const HTTP_STATUS_UNAUTHORIZED = 401\nexport const HTTP_STATUS_FORBIDDEN = 403\nexport const HTTP_STATUS_NOT_FOUND = 404\nexport const HTTP_STATUS_UNPROCESSABLE_ENTITY = 422\n\nexport const HTTP_STATUS_VALID_ALL = [HTTP_STATUS_OK, HTTP_STATUS_CREATED, HTTP_STATUS_ACCEPTED, HTTP_STATUS_NO_CONTENT]\n","import { AnzuError } from '@/model/error/AnzuError'\nimport axios, { type AxiosError } from 'axios'\nimport { HTTP_STATUS_FORBIDDEN } from '@/composables/statusCodes'\n\nexport const axiosErrorResponseIsForbidden = (error: Error): error is AxiosError => {\n return axios.isAxiosError(error) && error.response?.status === HTTP_STATUS_FORBIDDEN\n}\n\nexport const isAnzuApiForbiddenError = (error: any): error is AnzuApiForbiddenError => {\n return error instanceof AnzuApiForbiddenError\n}\n\nexport class AnzuApiForbiddenError extends AnzuError {\n constructor(cause?: Error, message = '') {\n super(message)\n this.name = 'AnzuApiForbiddenError'\n this.cause = cause\n this.message = message\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nimport axios, { type AxiosError } from 'axios'\nimport { HTTP_STATUS_UNPROCESSABLE_ENTITY } from '@/composables/statusCodes'\n\ninterface ValidationResponseDataFields {\n [key: string]: string[]\n}\n\nexport interface AnzuApiValidationResponseData {\n contextId: string\n error: string\n fields: ValidationResponseDataFields\n}\n\nexport interface ValidationError {\n field: string\n errors: string[]\n}\n\nconst ERROR_VALIDATION = 'validation_failed'\n\nexport const axiosErrorResponseHasValidationData = (error: Error) => {\n return (\n axios.isAxiosError(error) &&\n error.response?.status === HTTP_STATUS_UNPROCESSABLE_ENTITY &&\n error.response.data?.error === ERROR_VALIDATION &&\n error.response.data?.fields\n )\n}\n\nexport const isAnzuApiValidationError = (error: any): error is AnzuApiValidationError => {\n return error instanceof AnzuApiValidationError\n}\n\n/**\n * Check if AnzuApiValidationError error contain a specific error for a specific field\n *\n * @param error\n * @param errorName - Name of the error to check for (e.g., 'error_field_not_unique')\n * @param fieldName - Name of the field to check (e.g., 'cms.userAdminConfig.model.systemResource')\n */\n\nexport const hasAnzuApiValidationErrorSpecific = (\n error: AnzuApiValidationError,\n errorName: string,\n fieldName: string\n) => {\n return error.fields.some((field) => field.field === fieldName && field.errors.includes(errorName))\n}\n\nfunction resolveResponseData(axiosError: AxiosError, system: string, entity: string) {\n const data = axiosError.response?.data as AnzuApiValidationResponseData\n const items = [] as ValidationError[]\n for (const [key, values] of Object.entries(data.fields)) {\n items.push({\n field: system + '.' + entity + '.model.' + key,\n errors: values,\n })\n }\n return items\n}\n\nexport class AnzuApiValidationError extends AnzuError {\n fields: ValidationError[]\n\n constructor(axiosError: AxiosError, system: string, entity: string, cause?: Error, message = '') {\n const fields = resolveResponseData(axiosError, system, entity)\n // Kept low-cardinality on purpose; field details would break Sentry grouping.\n const resolvedMessage = message || `Validation failed for ${system}.${entity} (${fields.length} fields)`\n super(resolvedMessage)\n this.name = 'AnzuApiValidationError'\n this.cause = cause\n this.message = resolvedMessage\n this.fields = fields\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nexport const isAnzuApiResponseCodeError = (error: any): error is AnzuApiResponseCodeError => {\n return error instanceof AnzuApiResponseCodeError\n}\n\nexport class AnzuApiResponseCodeError extends AnzuError {\n code: number\n\n constructor(code: number, cause?: Error, message?: string) {\n // Empty message renders as \"No error message\" in Sentry.\n const resolvedMessage = message || `API responded with unexpected status code ${code}`\n super(resolvedMessage)\n this.name = 'AnzuApiResponseCodeError'\n this.cause = cause\n this.code = code\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nimport axios, { type AxiosError } from 'axios'\nimport { HTTP_STATUS_UNPROCESSABLE_ENTITY } from '@/composables/statusCodes'\n\ninterface ForbiddenOperationResponseData {\n contextId: string\n error: string\n detail: string\n}\n\nconst ERROR_FORBIDDEN_OPERATION = 'forbidden_operation_error'\n\nexport const axiosErrorResponseHasForbiddenOperationData = (error: Error) => {\n return (\n axios.isAxiosError(error) &&\n error.response?.status === HTTP_STATUS_UNPROCESSABLE_ENTITY &&\n error.response.data?.error === ERROR_FORBIDDEN_OPERATION &&\n error.response.data?.detail\n )\n}\n\nexport const isAnzuApiForbiddenOperationError = (error: any): error is AnzuApiForbiddenOperationError => {\n return error instanceof AnzuApiForbiddenOperationError\n}\n\nfunction resolveResponseData(axiosError: AxiosError) {\n const data = axiosError.response?.data as ForbiddenOperationResponseData\n return data.detail\n}\n\nexport class AnzuApiForbiddenOperationError extends AnzuError {\n detail: string\n\n constructor(axiosError: AxiosError, cause?: Error, message = '') {\n super(message)\n this.name = 'AnzuApiForbiddenOperationError'\n this.cause = cause\n this.message = message\n this.detail = resolveResponseData(axiosError)\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nimport axios, { type AxiosError } from 'axios'\nimport { HTTP_STATUS_UNPROCESSABLE_ENTITY } from '@/composables/statusCodes'\n\nexport interface AnzuApiDependencyExistsResponseData {\n contextId: string\n error: string\n dependencies: string[]\n}\n\nconst ERROR_VALIDATION = 'dependency_exists_error'\n\nexport const axiosErrorResponseHasDependencyExistsData = (error: Error) => {\n return (\n axios.isAxiosError(error) &&\n error.response?.status === HTTP_STATUS_UNPROCESSABLE_ENTITY &&\n error.response.data?.error === ERROR_VALIDATION &&\n error.response.data?.dependencies\n )\n}\n\nexport const isAnzuApiDependencyExistsError = (error: any): error is AnzuApiDependencyExistsError => {\n return error instanceof AnzuApiDependencyExistsError\n}\n\nfunction resolveResponseData(axiosError: AxiosError) {\n const data = axiosError.response?.data as AnzuApiDependencyExistsResponseData\n\n return data.dependencies\n}\n\nexport class AnzuApiDependencyExistsError extends AnzuError {\n dependencies: string[]\n\n constructor(axiosError: AxiosError, system: string, entity: string, cause?: Error, message = '') {\n super(message)\n this.name = 'AnzuApiDependencyExistsError'\n this.cause = cause\n this.message = message\n this.dependencies = resolveResponseData(axiosError)\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nimport axios from 'axios'\n\nexport const isAnzuApiTimeoutError = (error: any): error is AnzuApiTimeoutError => {\n return error instanceof AnzuApiTimeoutError\n}\n\nexport const axiosErrorIsTimeout = (error: Error) => {\n return (\n axios.isAxiosError(error) &&\n (error.code === 'ECONNABORTED' ||\n error.message.includes('timeout') ||\n (error.cause instanceof Error && error.cause.message.includes('timeout')))\n )\n}\n\n/**\n * Custom error class for timeout error\n */\nexport class AnzuApiTimeoutError extends AnzuError {\n constructor(cause: Error | undefined = undefined) {\n super('API request timed out')\n this.name = 'AnzuApiTimeoutError'\n this.cause = cause\n }\n}\n","import { AnzuError } from '@/model/error/AnzuError'\nimport type { AxiosError } from 'axios'\n\nexport const isAnzuApiAxiosError = (error: unknown): error is AnzuApiAxiosError => {\n return error instanceof AnzuApiAxiosError\n}\n\n/**\n * Custom error class for Axios-related errors\n */\nexport class AnzuApiAxiosError extends AnzuError {\n declare cause: AxiosError<any, any>\n\n constructor(cause: AxiosError<any, any>) {\n super('API request failed')\n this.name = 'AnzuApiAxiosError'\n this.cause = cause\n }\n}\n","import axios from 'axios'\nimport { AnzuError } from '@/model/error/AnzuError'\n\nexport const isAnzuApiCancelledError = (error: unknown): error is AnzuApiCancelledError => {\n return error instanceof AnzuApiCancelledError\n}\n\n/**\n * A request the caller stopped, told apart from a request that failed.\n *\n * Axios reports it as a `CanceledError` -- an axios error carrying `code: 'ERR_CANCELED'`, not the\n * `DOMException` an `AbortController`-shaped check would look for, which is why such a check never\n * fires.\n */\nexport const axiosErrorIsCancelled = (error: unknown) =>\n // Both, because they answer for different things. `isCancel` reads an internal marker axios puts\n // on the error it constructs; the code check catches a cancellation that arrived as a plain\n // object -- rebuilt across a boundary, or handed over by a test.\n axios.isCancel(error) || (axios.isAxiosError(error) && error.code === 'ERR_CANCELED')\n\n/**\n * A stopped request is an ordinary outcome -- another keystroke in an autocomplete, a route change\n * while a list is loading -- so it needs a class of its own. Reported as a transport failure it\n * would raise an error at the user for something the user did.\n */\nexport class AnzuApiCancelledError extends AnzuError {\n constructor(cause: unknown = undefined) {\n super('API request was cancelled', cause)\n this.name = 'AnzuApiCancelledError'\n }\n}\n","import { notify } from '@kyvg/vue3-notification'\nimport { i18n } from '@/plugins/i18n'\nimport { isAnzuFatalError } from '@/model/error/AnzuFatalError'\nimport { isAnzuApiForbiddenError } from '@/model/error/AnzuApiForbiddenError'\nimport { isAnzuApiValidationError, type ValidationError } from '@/model/error/AnzuApiValidationError'\nimport { isAnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { isAnzuApiForbiddenOperationError } from '@/model/error/AnzuApiForbiddenOperationError'\nimport { isAnzuApiDependencyExistsError } from '@/model/error/AnzuApiDependencyExistsError'\nimport { isAnzuApiTimeoutError } from '@/model/error/AnzuApiTimeoutError'\nimport { isAnzuApiAxiosError } from '@/model/error/AnzuApiAxiosError'\nimport { isAnzuApiCancelledError } from '@/model/error/AnzuApiCancelledError'\n\nconst DEFAULT_DURATION_SECONDS = 3\n\nexport const NEW_LINE_MARK = '\\n'\n\nexport type RecordWasType = 'created' | 'deleted' | 'updated' | 'published' | 'unpublished' | 'enabled' | 'disabled'\n\nexport function useAlerts() {\n const showSuccess = (message: string, duration = DEFAULT_DURATION_SECONDS) => {\n notify({\n group: 'alerts',\n text: message,\n duration: duration * 1000,\n type: 'success',\n })\n }\n\n const showSuccessT = (translation: string, duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n showSuccess(t(translation), duration)\n }\n\n const showError = (message: string, duration = DEFAULT_DURATION_SECONDS) => {\n notify({\n group: 'alerts',\n text: message,\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showErrorT = (translation: string, duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n showError(t(translation), duration)\n }\n\n const showInfo = (message: string, duration = DEFAULT_DURATION_SECONDS) => {\n notify({\n group: 'alerts',\n text: message,\n duration: duration * 1000,\n type: 'info',\n })\n }\n\n const showInfoT = (translation: string, duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n showInfo(t(translation), duration)\n }\n\n const showWarning = (message: string, duration = DEFAULT_DURATION_SECONDS) => {\n notify({\n group: 'alerts',\n text: message,\n duration: duration * 1000,\n type: 'warning',\n })\n }\n\n const showWarningT = (translation: string, duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n showWarning(t(translation), duration)\n }\n\n const showValidationError = (duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n notify({\n group: 'alerts',\n text: t('common.alert.fixValidationErrors'),\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showRecordWas = (variant: RecordWasType, duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n notify({\n group: 'alerts',\n text: t('common.alert.recordWas.' + variant),\n duration: duration * 1000,\n type: 'success',\n })\n }\n\n const showApiValidationError = (errors: ValidationError[], duration = -1, fieldIsTranslated = false) => {\n const { t, te } = i18n.global\n const texts = [t('common.alert.fixApiValidationErrors')]\n\n for (let i = 0; i < errors.length; i++) {\n let fieldText = ''\n if (fieldIsTranslated) {\n fieldText += errors[i].field\n } else if (te(errors[i].field)) {\n fieldText += t(errors[i].field)\n } else if (errors[i].field.includes('[')) {\n fieldText += resolveListErrors(errors[i].field)\n } else {\n fieldText += errors[i].field.split('.').at(-1)\n }\n const errorsTexts = new Set<string>()\n for (let j = 0; j < errors[i].errors.length; j++) {\n if (te('error.apiValidation.' + errors[i].errors[j])) {\n errorsTexts.add(t('error.apiValidation.' + errors[i].errors[j]))\n continue\n }\n errorsTexts.add(t('error.apiValidation.noTranslation'))\n }\n if (fieldText.length > 0) {\n texts.push(fieldText + ': ' + Array.from(errorsTexts).join(', '))\n }\n }\n notify({\n group: 'alerts',\n text: texts.join(NEW_LINE_MARK),\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showApiForbiddenOperationError = (detail: string, duration = -1) => {\n const { t, te } = i18n.global\n let text = t('error.apiForbiddenOperation.noTranslation')\n if (te('error.apiForbiddenOperation.' + detail)) {\n text = t('error.apiForbiddenOperation.' + detail)\n }\n notify({\n group: 'alerts',\n text: text,\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showUnknownError = (duration = -1) => {\n const { t } = i18n.global\n notify({\n group: 'alerts',\n text: t('common.alert.unknownError'),\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showForbiddenError = (duration = DEFAULT_DURATION_SECONDS) => {\n const { t } = i18n.global\n notify({\n group: 'alerts',\n text: t('common.alert.forbiddenError'),\n duration: duration * 1000,\n type: 'error',\n })\n }\n\n const showErrorsDefault = (error: any, duration = -1) => {\n // A stopped request is not a failure to report: something newer asked for it to stop, or the\n // view it belonged to is gone. It returns `true` -- handled, nothing to show -- because the\n // callers that fall back on `if (!showErrorsDefault(e)) showUnknownError()` would otherwise toast\n // \"unknown error\" every time a user typed one more character into an autocomplete.\n if (isAnzuApiCancelledError(error)) return true\n if (isAnzuApiForbiddenError(error)) {\n showForbiddenError(duration)\n return true\n }\n if (isAnzuApiValidationError(error)) {\n showApiValidationError(error.fields, duration)\n return true\n }\n if (isAnzuApiDependencyExistsError(error)) {\n showErrorT('error.apiDependencyExists.message', duration)\n return true\n }\n if (isAnzuApiForbiddenOperationError(error)) {\n showApiForbiddenOperationError(error.detail, duration)\n return true\n }\n if (isAnzuApiTimeoutError(error)) {\n showErrorT('error.apiTimedOut.message', duration)\n return true\n }\n if (isAnzuApiAxiosError(error)) {\n showUnknownError(duration)\n return true\n }\n if (isAnzuFatalError(error)) {\n showUnknownError(duration)\n return true\n }\n if (isAnzuApiResponseCodeError(error)) {\n showUnknownError(duration)\n return true\n }\n return false\n }\n\n const resolveListErrors = (error: string) => {\n const { t } = i18n.global\n const parsedField = error.split('[')\n const firstField = parsedField[0].trim()\n const parsedSecond = parsedField[1].split(']')\n const indexNumber = parsedSecond[0]\n const secondField: string = parsedSecond[1] ?? ''\n\n return t(firstField) + '[' + indexNumber + ']: ' + t(firstField.slice(0, -1) + secondField)\n }\n\n return {\n showSuccess,\n showSuccessT,\n showError,\n showErrorT,\n showInfo,\n showInfoT,\n showWarning,\n showWarningT,\n showValidationError,\n showRecordWas,\n showApiValidationError,\n showApiForbiddenOperationError,\n showUnknownError,\n showForbiddenError,\n showErrorsDefault,\n }\n}\n","!function(t,e){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=e():\"function\"==typeof define&&define.amd?define(e):(t=\"undefined\"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){\"use strict\";var t=1e3,e=6e4,n=36e5,r=\"millisecond\",i=\"second\",s=\"minute\",u=\"hour\",a=\"day\",o=\"week\",c=\"month\",f=\"quarter\",h=\"year\",d=\"date\",l=\"Invalid Date\",$=/^(\\d{4})[-/]?(\\d{1,2})?[-/]?(\\d{0,2})[Tt\\s]*(\\d{1,2})?:?(\\d{1,2})?:?(\\d{1,2})?[.:]?(\\d+)?$/,y=/\\[([^\\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ordinal:function(t){var e=[\"th\",\"st\",\"nd\",\"rd\"],n=t%100;return\"[\"+t+(e[(n-20)%10]||e[n]||e[0])+\"]\"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:\"\"+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?\"+\":\"-\")+m(r,2,\"0\")+\":\"+m(i,2,\"0\")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return+(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||\"\").toLowerCase().replace(/s$/,\"\")},u:function(t){return void 0===t}},g=\"en\",D={};D[g]=M;var p=\"$isDayjsObject\",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if(\"string\"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split(\"-\");if(!i&&u.length>1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n=\"object\"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if(\"string\"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||\"0\").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate(\"s\"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v=\"set\"+(this.$u?\"UTC\":\"\");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+\"Hours\",0);case u:return $(v+\"Minutes\",1);case s:return $(v+\"Seconds\",2);case i:return $(v+\"Milliseconds\",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=b.p(t),f=\"set\"+(this.$u?\"UTC\":\"\"),l=(n={},n[a]=f+\"Date\",n[d]=f+\"Date\",n[c]=f+\"Month\",n[h]=f+\"FullYear\",n[u]=f+\"Hours\",n[s]=f+\"Minutes\",n[i]=f+\"Seconds\",n[r]=f+\"Milliseconds\",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||\"YYYY-MM-DDTHH:mm:ssZ\",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,\"0\")},$=f||function(t,e,n){var r=t<12?\"AM\":\"PM\";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case\"YY\":return String(e.$y).slice(-2);case\"YYYY\":return b.s(e.$y,4,\"0\");case\"M\":return a+1;case\"MM\":return b.s(a+1,2,\"0\");case\"MMM\":return h(n.monthsShort,a,c,3);case\"MMMM\":return h(c,a);case\"D\":return e.$D;case\"DD\":return b.s(e.$D,2,\"0\");case\"d\":return String(e.$W);case\"dd\":return h(n.weekdaysMin,e.$W,o,2);case\"ddd\":return h(n.weekdaysShort,e.$W,o,3);case\"dddd\":return o[e.$W];case\"H\":return String(s);case\"HH\":return b.s(s,2,\"0\");case\"h\":return d(1);case\"hh\":return d(2);case\"a\":return $(s,u,!0);case\"A\":return $(s,u,!1);case\"m\":return String(u);case\"mm\":return b.s(u,2,\"0\");case\"s\":return String(e.$s);case\"ss\":return b.s(e.$s,2,\"0\");case\"SSS\":return b.s(e.$ms,3,\"0\");case\"Z\":return i}return null}(t)||i.replace(\":\",\"\")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),Y=_.prototype;return O.prototype=Y,[[\"$ms\",r],[\"$s\",i],[\"$m\",s],[\"$H\",u],[\"$W\",a],[\"$M\",c],[\"$y\",h],[\"$D\",d]].forEach((function(t){Y[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=!0),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O}));","!function(t,i){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=i():\"function\"==typeof define&&define.amd?define(i):(t=\"undefined\"!=typeof globalThis?globalThis:t||self).dayjs_plugin_utc=i()}(this,(function(){\"use strict\";var t=\"minute\",i=/[+-]\\d\\d(?::?\\d\\d)?/g,e=/([+-]|\\d\\d)/g;return function(s,f,n){var u=f.prototype;n.utc=function(t){var i={date:t,utc:!0,args:arguments};return new f(i)},u.utc=function(i){var e=n(this.toDate(),{locale:this.$L,utc:!0});return i?e.add(this.utcOffset(),t):e},u.local=function(){return n(this.toDate(),{locale:this.$L,utc:!1})};var r=u.parse;u.parse=function(t){t.utc&&(this.$u=!0),this.$utils().u(t.$offset)||(this.$offset=t.$offset),r.call(this,t)};var o=u.init;u.init=function(){if(this.$u){var t=this.$d;this.$y=t.getUTCFullYear(),this.$M=t.getUTCMonth(),this.$D=t.getUTCDate(),this.$W=t.getUTCDay(),this.$H=t.getUTCHours(),this.$m=t.getUTCMinutes(),this.$s=t.getUTCSeconds(),this.$ms=t.getUTCMilliseconds()}else o.call(this)};var a=u.utcOffset;u.utcOffset=function(s,f){var n=this.$utils().u;if(n(s))return this.$u?0:n(this.$offset)?a.call(this):this.$offset;if(\"string\"==typeof s&&(s=function(t){void 0===t&&(t=\"\");var s=t.match(i);if(!s)return null;var f=(\"\"+s[0]).match(e)||[\"-\",0,0],n=f[0],u=60*+f[1]+ +f[2];return 0===u?0:\"+\"===n?u:-u}(s),null===s))return this;var u=Math.abs(s)<=16?60*s:s;if(0===u)return this.utc(f);var r=this.clone();if(f)return r.$offset=u,r.$u=!1,r;var o=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();return(r=this.local().add(u+o,t)).$offset=u,r.$x.$localOffset=o,r};var h=u.format;u.format=function(t){var i=t||(this.$u?\"YYYY-MM-DDTHH:mm:ss[Z]\":\"\");return h.call(this,i)},u.valueOf=function(){var t=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*t},u.isUTC=function(){return!!this.$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var l=u.toDate;u.toDate=function(t){return\"s\"===t&&this.$offset?n(this.format(\"YYYY-MM-DD HH:mm:ss:SSS\")).toDate():l.call(this)};var c=u.diff;u.diff=function(t,i,e){if(t&&this.$u===t.$u)return c.call(this,t,i,e);var s=this.local(),f=n(t).local();return c.call(s,f,i,e)}}}));","!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_plugin_customParseFormat=t()}(this,(function(){\"use strict\";var e={LTS:\"h:mm:ss A\",LT:\"h:mm A\",L:\"MM/DD/YYYY\",LL:\"MMMM D, YYYY\",LLL:\"MMMM D, YYYY h:mm A\",LLLL:\"dddd, MMMM D, YYYY h:mm A\"},t=/(\\[[^[]*\\])|([-_:/.,()\\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,n=/\\d/,r=/\\d\\d/,i=/\\d\\d?/,o=/\\d*[^-_:/,()\\s\\d]+/,s={},a=function(e){return(e=+e)+(e>68?1900:2e3)};var f=function(e){return function(t){this[e]=+t}},h=[/[+-]\\d\\d:?(\\d\\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if(\"Z\"===e)return 0;var t=e.match(/([+-]|\\d\\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:\"+\"===t[0]?-n:n}(e)}],u=function(e){var t=s[e];return t&&(t.indexOf?t:t.s.concat(t.f))},d=function(e,t){var n,r=s.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?\"pm\":\"PM\");return n},c={A:[o,function(e){this.afternoon=d(e,!1)}],a:[o,function(e){this.afternoon=d(e,!0)}],Q:[n,function(e){this.month=3*(e-1)+1}],S:[n,function(e){this.milliseconds=100*+e}],SS:[r,function(e){this.milliseconds=10*+e}],SSS:[/\\d{3}/,function(e){this.milliseconds=+e}],s:[i,f(\"seconds\")],ss:[i,f(\"seconds\")],m:[i,f(\"minutes\")],mm:[i,f(\"minutes\")],H:[i,f(\"hours\")],h:[i,f(\"hours\")],HH:[i,f(\"hours\")],hh:[i,f(\"hours\")],D:[i,f(\"day\")],DD:[r,f(\"day\")],Do:[o,function(e){var t=s.ordinal,n=e.match(/\\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\\[|\\]/g,\"\")===e&&(this.day=r)}],w:[i,f(\"week\")],ww:[r,f(\"week\")],M:[i,f(\"month\")],MM:[r,f(\"month\")],MMM:[o,function(e){var t=u(\"months\"),n=(u(\"monthsShort\")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[o,function(e){var t=u(\"months\").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\\d+/,f(\"year\")],YY:[r,function(e){this.year=a(e)}],YYYY:[/\\d{4}/,f(\"year\")],Z:h,ZZ:h};function l(n){var r,i;r=n,i=s&&s.formats;for(var o=(n=r.replace(/(\\[[^\\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\\[[^\\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),a=o.length,f=0;f<a;f+=1){var h=o[f],u=c[h],d=u&&u[0],l=u&&u[1];o[f]=l?{regex:d,parser:l}:h.replace(/^\\[|\\]$/g,\"\")}return function(e){for(var t={},n=0,r=0;n<a;n+=1){var i=o[n];if(\"string\"==typeof i)r+=i.length;else{var s=i.regex,f=i.parser,h=e.slice(r),u=s.exec(h)[0];f.call(t,u),e=e.replace(u,\"\")}}return function(e){var t=e.afternoon;if(void 0!==t){var n=e.hours;t?n<12&&(e.hours+=12):12===n&&(e.hours=0),delete e.afternoon}}(t),t}}return function(e,t,n){n.p.customParseFormat=!0,e&&e.parseTwoDigitYear&&(a=e.parseTwoDigitYear);var r=t.prototype,i=r.parse;r.parse=function(e){var t=e.date,r=e.utc,o=e.args;this.$u=r;var a=o[1];if(\"string\"==typeof a){var f=!0===o[2],h=!0===o[3],u=f||h,d=o[2];h&&(d=o[2]),s=this.$locale(),!f&&d&&(s=n.Ls[d]),this.$d=function(e,t,n,r){try{if([\"x\",\"X\"].indexOf(t)>-1)return new Date((\"X\"===t?1e3:1)*e);var i=l(t)(e),o=i.year,s=i.month,a=i.day,f=i.hours,h=i.minutes,u=i.seconds,d=i.milliseconds,c=i.zone,m=i.week,M=new Date,Y=a||(o||s?1:M.getDate()),p=o||M.getFullYear(),v=0;o&&!s||(v=s>0?s-1:M.getMonth());var D,w=f||0,g=h||0,y=u||0,L=d||0;return c?new Date(Date.UTC(p,v,Y,w,g,y,L+60*c.offset*1e3)):n?new Date(Date.UTC(p,v,Y,w,g,y,L)):(D=new Date(p,v,Y,w,g,y,L),m&&(D=r(D).week(m).toDate()),D)}catch(e){return new Date(\"\")}}(t,a,r,n),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(a)&&(this.$d=new Date(\"\")),s={}}else if(a instanceof Array)for(var c=a.length,m=1;m<=c;m+=1){o[1]=a[m-1];var M=n.apply(this,o);if(M.isValid()){this.$d=M.$d,this.$L=M.$L,this.init();break}m===c&&(this.$d=new Date(\"\"))}else i.call(this,e)}}}));","import type { OpUnitType, QUnitType } from 'dayjs'\nimport dayjs from 'dayjs'\nimport utc from 'dayjs/plugin/utc'\nimport customParseFormat from 'dayjs/plugin/customParseFormat'\nimport { isNull, isUndefined } from '@/utils/common'\nimport { stringToInt } from '@/utils/string'\nimport type { DateUTC, DatetimeUTC, DatetimeUTCNullable } from '@/types/common'\n\ndayjs.extend(utc)\ndayjs.extend(customParseFormat)\n\nexport const SUFFIX = '.000000Z'\nconst FORMAT = 'YYYY-MM-DDTHH:mm:ss'\n\nexport const DATETIME_MIN = '1970-01-01T00:00:00.000000Z'\nexport const DATETIME_MAX = '2100-01-01T00:00:00.000000Z'\n\nexport const dateNow = (): Date => {\n return dayjs().utc().toDate()\n}\n\nexport const dateTimeToDate = (isoDate: DatetimeUTC | DatetimeUTCNullable | string): Date => {\n return dayjs(isoDate).toDate()\n}\nexport const timestampCurrent = (): number => {\n return stringToInt(dayjs().utc().unix())\n}\n\nexport const dateTimeNow = (ignoreFractionalSeconds = true, ignoreSeconds = false): string => {\n if (ignoreFractionalSeconds && !ignoreSeconds) return dayjs().utc().format('YYYY-MM-DDTHH:mm:ss') + SUFFIX\n if (ignoreFractionalSeconds && ignoreSeconds) return dayjs().utc().format('YYYY-MM-DDTHH:mm:00') + SUFFIX\n if (!ignoreFractionalSeconds && ignoreSeconds) return dayjs().utc().format('YYYY-MM-DDTHH:mm:00.SSSSSS') + 'Z'\n return dayjs().utc().format('YYYY-MM-DDTHH:mm:ss.SSSSSS') + 'Z'\n}\n\nexport const dateTimeStartOfDay = (days = 0) => {\n if (days === 0) {\n return dayjs().startOf('day').utc().format(FORMAT) + SUFFIX\n }\n return dayjs().add(days, 'days').startOf('day').utc().format(FORMAT) + SUFFIX\n}\n\nexport const dateTimeEndOfDay = (days = 0) => {\n if (days === 0) {\n return dayjs().endOf('day').utc().format(FORMAT) + SUFFIX\n }\n return dayjs().add(days, 'days').endOf('day').utc().format(FORMAT) + SUFFIX\n}\n\nexport const dateModifyMinutes = (minutes = 0, date: null | Date = null): Date => {\n if (date === null) date = new Date()\n if (minutes === 0) return date\n if (minutes > 0) return dayjs(date).add(minutes, 'minutes').toDate()\n if (minutes < 0) return dayjs(date).subtract(Math.abs(minutes), 'minutes').toDate()\n return date\n}\n\n/** Today as a calendar day: UTC midnight of the local date, the shape a `type: 'date'` picker emits. */\nexport const dateUtcToday = (): DateUTC => {\n const now = new Date()\n return dayjs.utc(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())).format(FORMAT) + SUFFIX\n}\n\nexport const dateToUtc = (date: dayjs.ConfigType, suffix = SUFFIX) => {\n return dayjs(date).utc().format('YYYY-MM-DDTHH:mm:ss') + suffix\n}\n\nexport const yearNow = () => {\n return dayjs().utc().format('YYYY')\n}\n\nexport const dateTimePretty = (\n isoDate: DatetimeUTC | DatetimeUTCNullable | string | null,\n edgeDateValue = '',\n showSeconds = false\n): string => {\n if (isoDate === DATETIME_MAX || isoDate === DATETIME_MIN || isoDate === '' || isNull(isoDate) || isUndefined(isoDate))\n return edgeDateValue\n return dayjs(isoDate).format(showSeconds ? 'DD.MM.YYYY HH:mm:ss' : 'DD.MM.YYYY HH:mm')\n}\n\nexport const dateTimeFriendly = (\n isoDate: DatetimeUTC | DatetimeUTCNullable | string | null,\n edgeDateValue = '',\n showSeconds = false\n) => {\n if (\n isoDate === DATETIME_MAX ||\n isoDate === DATETIME_MIN ||\n isoDate === '' ||\n isNull(isoDate) ||\n isUndefined(isoDate)\n ) {\n return edgeDateValue\n }\n let displayYear = true\n let displayDayMonth = true\n const date = dayjs(isoDate)\n const now = dayjs()\n if (now.format('YYYY') === date.format('YYYY')) {\n displayYear = false\n }\n if (now.format('YYYY-MM-DD') === date.format('YYYY-MM-DD')) {\n displayDayMonth = false\n }\n if (!displayYear && !displayDayMonth) return dayjs(date).format(showSeconds ? 'H:mm:ss' : 'H:mm')\n if (!displayYear) return dayjs(date).format(showSeconds ? 'D.M. H:mm:ss' : 'D.M. H:mm')\n return dayjs(date).format(showSeconds ? 'D.M.YYYY H:mm:ss' : 'D.M.YYYY H:mm')\n}\n\nexport const datePretty = (isoDate: DatetimeUTC | DatetimeUTCNullable | string | null, edgeDateValue = ''): string => {\n if (isoDate === DATETIME_MAX || isoDate === DATETIME_MIN || isoDate === '' || isNull(isoDate) || isUndefined(isoDate))\n return edgeDateValue\n return dayjs(isoDate).format('DD.MM.YYYY')\n}\n\n/** Counterpart of `datePretty` for calendar-day values: reads the day the API stores, in any timezone. */\nexport const dateUtcPretty = (\n isoDate: DatetimeUTC | DatetimeUTCNullable | string | null,\n edgeDateValue = ''\n): string => {\n if (isoDate === DATETIME_MAX || isoDate === DATETIME_MIN || isoDate === '' || isNull(isoDate) || isUndefined(isoDate))\n return edgeDateValue\n return dayjs.utc(isoDate).format('DD.MM.YYYY')\n}\n\nexport const timePretty = (isoDate: DatetimeUTC | DatetimeUTCNullable | string | null, edgeDateValue = ''): string => {\n if (isoDate === DATETIME_MAX || isoDate === DATETIME_MIN || isoDate === '' || isNull(isoDate) || isUndefined(isoDate))\n return edgeDateValue\n return dayjs(isoDate).format('HH:mm')\n}\n\nexport const dateDiff = (date1: Date, date2: Date, unit: QUnitType | OpUnitType = 'ms') => {\n const date1dayjs = dayjs(date1)\n const date2dayjs = dayjs(date2)\n return date1dayjs.diff(date2dayjs, unit)\n}\n\nexport const isDatetimeUTC = (value: unknown): value is DatetimeUTC => {\n return typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{3,6})?Z$/.test(value)\n}\n\ntype MonthIntervalUTC = { from: DatetimeUTC; until: DatetimeUTC }\ntype MonthIntervalDate = { from: Date; until: Date }\ntype GetMonthIntervalFn = {\n (nowDate: Date, returnType: 'utc', monthOffset?: number, expandToCurrentMonth?: boolean): MonthIntervalUTC\n (nowDate: Date, returnType: 'date', monthOffset?: number, expandToCurrentMonth?: boolean): MonthIntervalDate\n}\nconst _getMonthInterval = (\n nowDate: Date,\n returnType: 'date' | 'utc',\n monthOffset: number = 0,\n expandToCurrentMonth: boolean = false\n): MonthIntervalUTC | MonthIntervalDate => {\n const from = new Date(nowDate)\n from.setMonth(from.getMonth() + monthOffset)\n from.setDate(1)\n from.setHours(0, 0, 0, 0)\n const until = new Date(nowDate)\n if (expandToCurrentMonth) {\n until.setMonth(until.getMonth() + 1, 0)\n } else {\n until.setMonth(until.getMonth() + monthOffset + 1, 0)\n }\n until.setHours(23, 59, 59, 999)\n if (returnType === 'utc') {\n return {\n from: dateToUtc(from),\n until: dateToUtc(until),\n }\n }\n return { from, until }\n}\nexport const getMonthInterval = _getMonthInterval as GetMonthIntervalFn\n","export const eventClickBlur = (event?: Event): void => {\n if (event?.currentTarget instanceof HTMLElement) {\n event.currentTarget.blur()\n }\n}\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport { eventClickBlur } from '@/utils/event'\n\nwithDefaults(\n defineProps<{\n buttonT?: string\n buttonClass?: string\n dataCy?: string\n touched?: boolean\n }>(),\n {\n buttonT: 'common.button.submitFilter',\n buttonClass: '',\n dataCy: 'filter-submit',\n touched: true,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'submit'): void\n}>()\n\nconst { t } = useI18n()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n emit('submit')\n}\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n color=\"primary\"\n type=\"submit\"\n :variant=\"touched ? 'flat' : 'text'\"\n @click=\"onClick\"\n >\n {{ t(buttonT) }}\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport { eventClickBlur } from '@/utils/event'\n\nwithDefaults(\n defineProps<{\n buttonT?: string\n buttonClass?: string\n dataCy?: string\n touched?: boolean\n }>(),\n {\n buttonT: 'common.button.submitFilter',\n buttonClass: '',\n dataCy: 'filter-submit',\n touched: true,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'submit'): void\n}>()\n\nconst { t } = useI18n()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n emit('submit')\n}\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n color=\"primary\"\n type=\"submit\"\n :variant=\"touched ? 'flat' : 'text'\"\n @click=\"onClick\"\n >\n {{ t(buttonT) }}\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\n\nwithDefaults(\n defineProps<{\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n tooltipT: 'common.button.resetFilter',\n buttonClass: 'ml-2',\n dataCy: 'filter-reset',\n }\n)\nconst emit = defineEmits<{\n (e: 'reset'): void\n}>()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n emit('reset')\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis px-2\"\n min-width=\"36px\"\n variant=\"flat\"\n @click.stop=\"onClick\"\n >\n <VIcon\n color=\"grey-darken-1\"\n icon=\"mdi-filter-remove-outline\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\n\nwithDefaults(\n defineProps<{\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n tooltipT: 'common.button.resetFilter',\n buttonClass: 'ml-2',\n dataCy: 'filter-reset',\n }\n)\nconst emit = defineEmits<{\n (e: 'reset'): void\n}>()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n emit('reset')\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis px-2\"\n min-width=\"36px\"\n variant=\"flat\"\n @click.stop=\"onClick\"\n >\n <VIcon\n color=\"grey-darken-1\"\n icon=\"mdi-filter-remove-outline\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n</template>\n","import { stringUrlTemplateReplace } from '@/utils/string'\nimport { isEmptyObject } from '@/utils/common'\n\nexport type UrlParams = {\n [key: string]: number | string\n}\n\nexport const replaceUrlParameters = (urlTemplate: string, urlParams: UrlParams, overrideUrlTemplate = '') => {\n if (isEmptyObject(urlParams)) return urlTemplate\n return stringUrlTemplateReplace(overrideUrlTemplate === '' ? urlTemplate : overrideUrlTemplate, urlParams)\n}\n","import { HTTP_STATUS_VALID_ALL } from '@/composables/statusCodes'\n\nexport const isValidHTTPStatus = (statusCode: number) => {\n return HTTP_STATUS_VALID_ALL.includes(statusCode)\n}\n","import axios, { type AxiosError } from 'axios'\nimport { AnzuApiAxiosError } from '@/model/error/AnzuApiAxiosError'\nimport { AnzuApiCancelledError, axiosErrorIsCancelled } from '@/model/error/AnzuApiCancelledError'\nimport {\n AnzuApiDependencyExistsError,\n axiosErrorResponseHasDependencyExistsData,\n} from '@/model/error/AnzuApiDependencyExistsError'\nimport { AnzuApiForbiddenError, axiosErrorResponseIsForbidden } from '@/model/error/AnzuApiForbiddenError'\nimport {\n AnzuApiForbiddenOperationError,\n axiosErrorResponseHasForbiddenOperationData,\n} from '@/model/error/AnzuApiForbiddenOperationError'\nimport { AnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { AnzuApiTimeoutError, axiosErrorIsTimeout } from '@/model/error/AnzuApiTimeoutError'\nimport { AnzuApiValidationError, axiosErrorResponseHasValidationData } from '@/model/error/AnzuApiValidationError'\nimport { AnzuError, isAnzuError } from '@/model/error/AnzuError'\nimport { AnzuFatalError } from '@/model/error/AnzuFatalError'\nimport { HTTP_STATUS_FORBIDDEN, HTTP_STATUS_UNAUTHORIZED } from '@/composables/statusCodes'\n\nexport type ApiErrorContext = {\n system: string\n entity: string\n /** The url actually requested, parameters substituted and query included -- not the template. */\n url?: string\n /**\n * The status the backend answered with, when it answered at all. Absent for a transport failure,\n * where there is no response.\n *\n * It is here so an application can decide what is worth writing down without the call sites having\n * to: a 404 that a caller probes for, for instance. Those used to be silenced per call, which made\n * whether a failure was recorded depend on which call made it. The switch is the application's now,\n * and this is what it needs to use it.\n *\n * Two statuses are not the application's to decide, and the library keeps them: 401 and 403. They\n * are not an endpoint failing its contract, they are the session -- nobody is logged in, or this\n * user may not -- and every admin in the fleet already branches on them and acts. Everything else\n * reaches the logger and is filtered here, on this field.\n */\n status?: number\n}\n\nexport type ApiErrorLogger = (error: Error, context: ApiErrorContext) => void\n\n/** What reporting does until an application says otherwise; exported so a test can put it back. */\nexport const defaultApiErrorLogger: ApiErrorLogger = (error, context) => {\n console.error('Api error: ' + (context.url ?? ''), error)\n}\n\nlet logger: ApiErrorLogger | null = defaultApiErrorLogger\n\n/**\n * Replaces the logger the api helpers report unexpected failures through, or turns reporting off\n * with `null`.\n *\n * It is one switch for the whole family rather than a flag on each instance, which is what it\n * replaces: whether a failure was written down used to depend on which helper made the call and how\n * that instance happened to be constructed.\n *\n * An application that wants these where it can see them passes its own:\n * `setApiErrorLogger((e, ctx) => Sentry.captureException(e, { extra: ctx }))`.\n */\nexport const setApiErrorLogger = (fn: ApiErrorLogger | null): void => {\n logger = fn\n}\n\n// Only the failures nobody planned for. A validation or forbidden answer is the backend saying\n// something the caller asked about and will show; writing those down as well would be noise that\n// teaches people to ignore the log.\nconst LOGGED = [AnzuApiAxiosError, AnzuFatalError, AnzuApiResponseCodeError]\n\n/**\n * Reports an error once, after it has been mapped, and hands it back so the caller can throw it.\n *\n * After, not during: an error the helper raised itself -- a body that never arrived, a status it\n * refuses -- is already an `Anzu*` class by the time it reaches the mapping, so a logger placed\n * inside the mapping would never see the two cases it exists for.\n */\n/** The status the backend answered with, read off whichever class carries it. */\nconst answeredStatus = (error: unknown): number | undefined => {\n if (error instanceof AnzuApiResponseCodeError) return error.code\n if (error instanceof AnzuApiAxiosError) return error.cause.response?.status\n\n return undefined\n}\n\nexport const report = <E>(error: E, context: ApiErrorContext): E => {\n const status = answeredStatus(error)\n // Neither of these is an unplanned failure. A 401 is \"nobody is logged in\", which every admin\n // branches on before sending the user to the login page -- writing it down would mean an \"Api\n // error\" for every unauthenticated start of the app. A 403 is \"this user may not\", which the\n // caller shows. Both are the session rather than an endpoint breaking its contract.\n //\n // By status rather than by class, because the class only keeps it quiet on one of the two paths: a\n // rejected 403 becomes `AnzuApiForbiddenError`, which is outside `LOGGED`, while one that arrives\n // fulfilled -- as `options.validateStatus` allows -- becomes an `AnzuApiResponseCodeError`, which\n // is inside it. Left to the class, the policy would hold or not depending on how the caller\n // configured axios.\n //\n // It is the one thing the `status` field above does not leave to the application, and deliberately:\n // an app that wanted its own unauthenticated starts in the log would be asking for noise it cannot\n // act on, while an app that wants 404 or 409 filtered has the field to do it with.\n if (status === HTTP_STATUS_UNAUTHORIZED || status === HTTP_STATUS_FORBIDDEN) return error\n\n if (logger !== null && LOGGED.some((cls) => error instanceof cls)) {\n try {\n // Filled in here rather than by the caller: the status belongs to the failure, and only the\n // mapped error knows it -- the helper that built the context has not looked at the error yet.\n logger(error as unknown as Error, { ...context, status })\n } catch {\n // A logger that throws must not replace the failure the caller is waiting for.\n }\n }\n\n return error\n}\n\n/**\n * Turns whatever axios rejected with into one of the Anzu error classes.\n *\n * There used to be a copy of this inside each helper. The order of the checks is what decides which\n * class a failure becomes, so four copies were four chances for the same failure to arrive under\n * different names depending on which helper made the call.\n */\nexport const mapApiError = (err: unknown, context: ApiErrorContext): AnzuError => {\n const { system, entity } = context\n // The predicates below are typed against `Error` / `AxiosError` and each begins by checking what\n // it was handed, so narrowing here only satisfies their signatures.\n const error = err as Error\n const axiosError = err as AxiosError\n\n // Already mapped -- including the errors a helper raised about its own contract. Wrapping it again\n // would bury the class the caller branches on.\n if (isAnzuError(err)) return err\n\n // Before everything else, because it is not a failure: the caller stopped this request.\n if (axiosErrorIsCancelled(err)) return new AnzuApiCancelledError(error)\n\n // The rendered url, not `config.url`: that one is relative, carries no params, and would become\n // this error's `message` -- the only url in the family that never went through `requestedUrl`.\n if (axiosErrorResponseIsForbidden(axiosError)) return new AnzuApiForbiddenError(axiosError, context.url)\n\n if (axiosErrorResponseHasValidationData(axiosError)) {\n return new AnzuApiValidationError(axiosError, system, entity, error)\n }\n\n if (axiosErrorResponseHasDependencyExistsData(axiosError)) {\n return new AnzuApiDependencyExistsError(axiosError, system, entity, error)\n }\n\n if (axiosErrorResponseHasForbiddenOperationData(axiosError)) {\n return new AnzuApiForbiddenOperationError(axiosError, error)\n }\n\n if (axiosErrorIsTimeout(error)) return new AnzuApiTimeoutError(error)\n\n if (axios.isAxiosError(err)) return new AnzuApiAxiosError(axiosError)\n\n return new AnzuFatalError(error)\n}\n","import type { AxiosClientFn } from '@/labs/api/client'\nimport axios, { type AxiosInstance, type AxiosRequestConfig } from 'axios'\nimport { isNull, isString, isUndefined } from '@/utils/common'\nimport { ref, type Ref } from 'vue'\n\n/**\n * Whether the response carries a body at all.\n *\n * `''` is not an empty document, it is what axios hands back when no bytes arrived: its adapter\n * returns `responseText`, and `transformResponse` only attempts `JSON.parse` when the string is\n * truthy, so a 204 and a body-less 200 both arrive as `''`. `0` and `false` do parse and are real\n * values -- reading them as absent is the bug this replaces.\n *\n * `null` is treated as absent too. It is distinguishable from `''` at runtime, but nothing can carry\n * it in the type: the response type excludes `null` so that a command site cannot declare itself as\n * returning one.\n */\nexport const hasBody = (res: { data: unknown }): boolean =>\n !isUndefined(res.data) && !isNull(res.data) && res.data !== ''\n\n/**\n * Strips what the helper decides from whatever the caller passed as `options`.\n *\n * The type says these cannot be set, but a type says nothing at runtime: `data` in particular\n * survived the spread whenever no body was passed, so a caller could put a body on a GET through\n * the back door and skip the serialisation with it.\n */\nconst HELPER_OWNED = ['method', 'url', 'data', 'signal'] as const\n\nexport const ownedByHelper = <T extends object>(options: T): Omit<T, (typeof HELPER_OWNED)[number]> => {\n const rest = { ...options } as Record<string, unknown>\n for (const key of HELPER_OWNED) delete rest[key]\n\n return rest as Omit<T, (typeof HELPER_OWNED)[number]>\n}\n\n/**\n * Renders a config axios kept, and nothing else. It has no `baseURL` and no `params` of its own, so\n * what comes out is what the config carries.\n *\n * Built on first use rather than at module load: importing this library should not create an axios\n * instance. A consumer that mocks axios and counts `create` calls would otherwise see one it never\n * made -- which is exactly how this was found, in a fleet test asserting that its own client is\n * built once.\n */\nlet rendererInstance: AxiosInstance | undefined\nconst renderer = (): AxiosInstance => (rendererInstance ??= axios.create())\n\n/**\n * The url as axios will actually request it: the client's `baseURL` and default `params`, the\n * request's own `params`, and whatever `paramsSerializer` renders them.\n *\n * Built by axios itself rather than approximated: a url recorded before the call is not the one\n * that went out, and an approximation renders arrays, nested objects and dates differently from the\n * wire -- which is worse than no url, because it looks findable and is not. It is handed the same\n * config the request was given, minus what this helper owns, for the same reason: a call carrying\n * its own `paramsSerializer` or `baseURL` is asking for a url that the defaults do not produce.\n *\n * `undefined` in, `undefined` out: a call that failed before it had a url has none to report, and\n * asking axios for one would answer with the client's root -- a url that was never requested and\n * that reads like an endpoint. An empty string is different: that is a call whose url really is the\n * client root, and it gets rendered.\n *\n * Rendered from the config axios actually used whenever there is one: the one it keeps on its own\n * error, or the one it keeps on the response it did return, which covers the failures the helper\n * raises itself after reading that response. Both are the request as it went out -- merged, and past\n * any request interceptor that rewrote the url or the params -- while anything rebuilt here is a\n * reconstruction, and by the time a failure is described the factory may hand back a different\n * instance or its defaults may have moved on.\n *\n * A config that axios kept is rendered through an instance with no defaults of its own, for that\n * same reason: `getUri` merges the instance's defaults *under* the config it is given, so rendering\n * it through the caller's client would let a default added since the request appear in a url that\n * never carried it. The rebuild is the one case that does want those defaults -- there is no record\n * of the request to read them from -- so it goes through the client.\n *\n * Never throws. It runs on every failure path, inside the catch, so an exception here would replace\n * the error the caller is waiting for with one about building a diagnostic string -- and a client\n * without `getUri` (a hand-built stub, a mock) must not turn a mapped failure into a `TypeError`.\n */\nexport const requestedUrl = (\n client: AxiosClientFn,\n url: string | undefined,\n options: AxiosRequestConfig = {},\n failure?: unknown,\n dispatched?: AxiosRequestConfig\n): string | undefined => {\n if (isUndefined(url)) return undefined\n\n try {\n const sent = (axios.isAxiosError(failure) ? failure.config : undefined) ?? dispatched\n const built: unknown = isUndefined(sent)\n ? client().getUri({ ...ownedByHelper(options), url })\n : renderer().getUri(sent)\n\n // A stub can answer with anything. The declared type says string, so it has to be one.\n return isString(built) ? built : url\n } catch {\n return url\n }\n}\n\nexport type Abortable = {\n /** Runs one call with a signal of its own, registered so `abort()` can reach it. */\n run: <T>(fn: (signal: AbortSignal, generation: number) => Promise<T>, external?: AbortSignal) => Promise<T>\n /** Stops every call this instance still has in flight. */\n abort: () => void\n /** The generation a call starts in; a stale one must not write to state the caller can see. */\n generation: () => number\n /** Whether this instance has anything in flight. */\n loading: Ref<boolean>\n}\n\nexport type AbortableOptions = {\n /**\n * Each call supersedes the one before it. The abort happens before the new call registers, so\n * \"the latest wins\" holds by construction rather than by how the two calls happen to interleave.\n */\n cancelPrevious?: boolean\n}\n\nexport const createAbortable = (options: AbortableOptions = {}): Abortable => {\n const { cancelPrevious = false } = options\n const controllers = new Set<AbortController>()\n let generation = 0\n\n /**\n * True while this instance has a request in flight.\n *\n * It is derived from the set rather than counted, which is what makes it safe to turn\n * `cancelPrevious` on. The pattern everywhere in the fleet is a `loading` ref the caller clears in\n * a `finally`, and under `cancelPrevious` that `finally` belongs to the call that was just\n * superseded -- so the spinner goes out while the call the user is waiting for is still running.\n * Here the superseded call's controller leaves the set at the same moment the new one joins it, so\n * the value never dips between the two.\n */\n const loading = ref(false)\n const syncLoading = () => {\n loading.value = controllers.size > 0\n }\n\n const abortAll = () => {\n controllers.forEach((controller) => controller.abort())\n controllers.clear()\n }\n\n const run = async <T>(\n fn: (signal: AbortSignal, generation: number) => Promise<T>,\n external?: AbortSignal\n ): Promise<T> => {\n // Before the new controller is registered, or the abort would take the new call with it.\n if (cancelPrevious) abortAll()\n\n generation += 1\n const controller = new AbortController()\n controllers.add(controller)\n syncLoading()\n\n // The external signal is relayed rather than passed through: `abort()` has to keep working, and\n // it can only reach a controller this set owns.\n const relay = () => controller.abort()\n if (external) {\n if (external.aborted) controller.abort()\n else external.addEventListener('abort', relay, { once: true })\n }\n\n try {\n return await fn(controller.signal, generation)\n } catch (err: unknown) {\n // A call can have more than one request under its signal -- the batch sends a page set at\n // once -- and when one of them fails the rest are work nobody is waiting for any more. Stop\n // them here, while the controller is still reachable: the `finally` below drops it from the\n // set, and after that a later `abort()` has nothing to abort them with.\n controller.abort()\n throw err\n } finally {\n external?.removeEventListener('abort', relay)\n controllers.delete(controller)\n syncLoading()\n }\n }\n\n return {\n run,\n abort: () => {\n // Bumped so a call already on its way back cannot write to the caller's state afterwards.\n generation += 1\n abortAll()\n syncLoading()\n },\n generation: () => generation,\n loading,\n }\n}\n","import { AnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { AnzuFatalError } from '@/model/error/AnzuFatalError'\nimport { replaceUrlParameters, type UrlParams } from '@/services/api/apiHelper'\nimport { isDefined, isNull, isUndefined } from '@/utils/common'\nimport { isValidHTTPStatus } from '@/utils/response'\nimport type { AxiosRequestConfig, Method } from 'axios'\nimport { HTTP_STATUS_NO_CONTENT } from '@/composables/statusCodes'\nimport type { Ref } from 'vue'\nimport type { AxiosClientFn } from '@/labs/api/client'\nimport { mapApiError, report } from '@/labs/api/apiErrors'\nimport { type Abortable, createAbortable, hasBody, ownedByHelper, requestedUrl } from '@/labs/api/request'\n\nexport type ExecuteRequestParams<B> = {\n urlTemplate?: string\n urlParams?: UrlParams\n body?: B\n /** Stops this one call, leaving the instance's other calls alone. */\n signal?: AbortSignal\n}\n\nexport type UseApiRequestParams = {\n client: AxiosClientFn\n method: Method\n system: string\n entity: string\n urlTemplate?: string\n urlParams?: UrlParams\n /** Anything axios takes except what this helper decides: the method, the url, the body and the signal. */\n options?: Omit<AxiosRequestConfig, 'method' | 'url' | 'data' | 'signal'>\n /** Each call supersedes the one before it -- the autocomplete shape. */\n cancelPrevious?: boolean\n}\n\nexport type UseApiRequestReturnType<R, B> = {\n execute: (params?: ExecuteRequestParams<B>) => Promise<R>\n abort: () => void\n /**\n * True while this instance has a request in flight, false once the last one settles.\n *\n * It is here so a caller does not have to keep its own: the hand-rolled version is a ref cleared\n * in a `finally`, and that `finally` belongs to whichever call ended -- including one that\n * `cancelPrevious` just superseded, which turns the spinner off while the call the user is waiting\n * for is still running. This one never dips between a superseded call and the one that replaced it.\n */\n loading: Ref<boolean>\n}\n\n// The url is only ever used to say which request the message is about, and a helper that failed\n// before it had one still has to be able to say something. Handed over as a function because\n// building it costs a render and the successful reading of a response does not need it.\ntype Interpret<R> = (res: { status: number; data: unknown }, url: () => string | undefined) => R\n\nconst createRequest = <R, B>(params: UseApiRequestParams, interpret: Interpret<R>): UseApiRequestReturnType<R, B> => {\n const { client, method, system, entity, urlTemplate, urlParams, options = {}, cancelPrevious = false } = params\n const abortable: Abortable = createAbortable({ cancelPrevious })\n\n const execute = async (executeParams: ExecuteRequestParams<B> = {}): Promise<R> => {\n const { urlTemplate: templateOverride, urlParams: paramsOverride, body, signal } = executeParams\n\n const template = isDefined(templateOverride) ? templateOverride : urlTemplate\n const resolvedParams = isDefined(paramsOverride) ? paramsOverride : urlParams\n // Assigned inside `run`, at the moment there is a url to ask for; undefined until then, which is\n // what a failure before dispatch honestly reports. An empty string is a different answer: that\n // is a call whose url really is the client root, and it gets rendered as one.\n let url: string | undefined\n // The config axios used, kept for the failures this helper raises after reading the response:\n // they are not axios errors and carry no config of their own, and rebuilding one describes the\n // request as the client would send it now rather than as it was sent.\n let dispatched: AxiosRequestConfig | undefined\n\n try {\n const res = await abortable.run((abortSignal) => {\n // Inside `run`, and inside the try with it: `run` opens the generation and, with\n // `cancelPrevious`, stops the call before this one, so a call that throws on its way to the\n // wire still supersedes its predecessor instead of leaving it current. And a caller that\n // forgot the template gets the same error class as every other failure rather than a bare\n // `Error` nothing in the fleet is written to catch.\n if (isUndefined(template)) throw new AnzuFatalError(undefined, 'Url template is undefined')\n const requestUrl =\n template !== '' && isDefined(resolvedParams) ? replaceUrlParameters(template, resolvedParams) : template\n\n const axiosConfig: AxiosRequestConfig = { method, url: requestUrl }\n // `null` omits the body, as it always has -- a caller that means to send JSON `null` wraps it.\n if (!isNull(body) && !isUndefined(body)) axiosConfig.data = JSON.stringify(body)\n\n // `options` first, then what this helper owns: a caller cannot reach in and set the method,\n // the url, the body or the signal through it. The type says so too; this is for javascript\n // callers and for anything typed loosely enough to slip past it.\n const config = { ...ownedByHelper(options), ...axiosConfig, signal: abortSignal }\n const instance = client()\n\n // Recorded last, when nothing between here and the call can throw any more. A body that will\n // not serialise, or a client factory that fails, is a request that never happened, and the\n // report has to be able to say so rather than name a url nobody asked for.\n url = requestUrl\n\n return instance.request(config)\n }, signal)\n\n dispatched = res.config\n if (!isValidHTTPStatus(res.status)) throw new AnzuApiResponseCodeError(res.status)\n\n // The url the report will name, so a message and the context beside it cannot disagree about\n // which request failed when an interceptor rewrote it on the way out.\n return interpret(res, () => requestedUrl(client, url, options, undefined, dispatched))\n } catch (err: unknown) {\n // Built once and handed to both, the way the batch does it: half the work on the failure path,\n // and one place that could go wrong instead of two.\n const context = { system, entity, url: requestedUrl(client, url, options, err, dispatched) }\n\n throw report(mapApiError(err, context), context)\n }\n }\n\n return { execute, abort: abortable.abort, loading: abortable.loading }\n}\n\n/**\n * A request to an endpoint that always answers with a body.\n *\n * A response without one is the endpoint breaking its own contract, not an empty answer, so it fails\n * like any other error rather than handing back a value the declared type does not admit. An\n * endpoint that answers nothing is `useApiCommand`; one that may answer either is `optionalBody`.\n *\n * `R` excludes `null`, `undefined` and `void` on purpose: those are ways of saying \"no body\", and a\n * caller saying that has chosen the wrong helper. It is also what makes the migration visible --\n * every `useApiRequest<void, …>` in the fleet stops compiling and names itself.\n */\nexport function useApiRequest<R extends NonNullable<unknown>, B = never>(\n params: UseApiRequestParams & { optionalBody?: false }\n): UseApiRequestReturnType<R, B>\n/**\n * The same, for an endpoint where a body is optional and its absence is a legitimate answer. The\n * caller narrows, which is the point -- use it only where the endpoint really is documented that way.\n */\nexport function useApiRequest<R extends NonNullable<unknown>, B = never>(\n params: UseApiRequestParams & { optionalBody: true }\n): UseApiRequestReturnType<R | undefined, B>\nexport function useApiRequest<R extends NonNullable<unknown>, B = never>(\n params: UseApiRequestParams & { optionalBody?: boolean }\n): UseApiRequestReturnType<R | undefined, B> {\n const optionalBody = params.optionalBody === true\n\n return createRequest<R | undefined, B>(params, (res, url) => {\n // 204 is decided by status alone, before the body is looked at: it carries none by definition,\n // so anything that arrived with one is not something to hand on. A 202 may legitimately carry a\n // body, which is why it is not in here and falls through to `hasBody` like any other success.\n if (res.status === HTTP_STATUS_NO_CONTENT) {\n if (optionalBody) return undefined\n\n throw new AnzuApiResponseCodeError(res.status)\n }\n\n if (hasBody(res)) return res.data as R\n if (optionalBody) return undefined\n\n throw new AnzuApiResponseCodeError(res.status, undefined, 'Expected a response body, url: ' + url())\n })\n}\n\n/**\n * A request that asks the backend to do something and reads nothing back -- a delete, or a call that\n * only starts work and answers 202. Any successful status resolves; a body, if one arrives, is\n * ignored rather than typed.\n */\nexport const useApiCommand = <B = never>(params: UseApiRequestParams): UseApiRequestReturnType<void, B> =>\n createRequest<void, B>(params, () => undefined)\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport { dateTimePretty } from '@/utils/datetime'\nimport type { DatetimeUTCNullable } from '@/types/common'\n\nconst props = withDefaults(\n defineProps<{\n dateTime: DatetimeUTCNullable\n edgeDateValue?: string\n }>(),\n {\n edgeDateValue: 'n/a',\n }\n)\n\nconst pretty = computed(() => {\n return dateTimePretty(props.dateTime, props.edgeDateValue)\n})\n</script>\n\n<template>\n {{ pretty }}\n</template>\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport { dateTimePretty } from '@/utils/datetime'\nimport type { DatetimeUTCNullable } from '@/types/common'\n\nconst props = withDefaults(\n defineProps<{\n dateTime: DatetimeUTCNullable\n edgeDateValue?: string\n }>(),\n {\n edgeDateValue: 'n/a',\n }\n)\n\nconst pretty = computed(() => {\n return dateTimePretty(props.dateTime, props.edgeDateValue)\n})\n</script>\n\n<template>\n {{ pretty }}\n</template>\n","import { between, createI18nMessage } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateBetween() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(between, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.between',\n })\n}\n","import { createI18nMessage, email } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateEmail() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(email, {\n messagePath: () => 'error.jsValidation.email',\n })\n}\n","import { createI18nMessage, maxLength } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateMaxLength() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(maxLength, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.maxLength',\n })\n}\n","import { createI18nMessage, maxValue } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateMaxValue() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(maxValue, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.maxValue',\n })\n}\n","import { createI18nMessage, minLength } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateMinLength() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(minLength, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.minLength',\n })\n}\n","import { createI18nMessage, minValue } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateMinValue() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(minValue, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.minValue',\n })\n}\n","import { createI18nMessage, numeric } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateNumeric() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(numeric, {\n messagePath: () => 'error.jsValidation.numeric',\n })\n}\n","import { createI18nMessage, required } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateRequired() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(required, {\n messagePath: () => 'error.jsValidation.required',\n })\n}\n","import { createI18nMessage, requiredIf } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateRequiredIf() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(requiredIf, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.required',\n })\n}\n","import { createI18nMessage, helpers } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateSlug() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(helpers.regex(/^[a-z\\-0-9]+$/), {\n messagePath: () => 'error.jsValidation.slug',\n })\n}\n","import { createI18nMessage, helpers } from '@vuelidate/validators'\nimport { unref } from 'vue'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateStringArrayItemLength() {\n const withI18nMessage = createI18nMessage({ t })\n\n const stringArrayItemLengthValidator = (min: number, max: number) => {\n return (value: string[]) =>\n !helpers.req(value) || value.every((item) => item.length >= unref(min) && item.length <= unref(max))\n }\n const stringArrayItemLengthHelper = (min: number, max: number) => {\n return {\n $validator: stringArrayItemLengthValidator(min, max),\n // $message not required when using i18n\n // $message: (input: { $params: Record<string, any> }) => {\n // const { $params } = input\n // return `Item length in list must have between ${$params.min} and ${$params.max} characters.`\n // },\n $params: {\n min,\n max,\n type: 'stringArrayItemLength',\n },\n }\n }\n\n return withI18nMessage(stringArrayItemLengthHelper, {\n withArguments: true,\n messagePath: () => 'error.jsValidation.stringArrayItemLength',\n })\n}\n","import { createI18nMessage, url } from '@vuelidate/validators'\nimport { i18n } from '@/plugins/i18n'\n\nconst { t } = i18n.global\n\nexport function useValidateUrl() {\n const withI18nMessage = createI18nMessage({ t })\n\n return withI18nMessage(url, {\n messagePath: () => 'error.jsValidation.url',\n })\n}\n","import { createI18nMessage } from '@vuelidate/validators'\nimport { type ComputedRef, type Ref, type ShallowRef, unref, type WritableComputedRef } from 'vue'\nimport { i18n } from '@/plugins/i18n'\nimport type { DatetimeUTCNullable } from '@/types/common'\n\nconst { t } = i18n.global\n\ntype OtherDateType =\n | Ref<DatetimeUTCNullable>\n | ComputedRef<DatetimeUTCNullable>\n | ShallowRef<DatetimeUTCNullable>\n | WritableComputedRef<DatetimeUTCNullable>\n\nexport function useValidateCompareDates() {\n const withI18nMessage = createI18nMessage({ t })\n\n const datesCompareValidator = (\n otherDate: OtherDateType,\n otherDateName: string,\n variant: 'laterThan' | 'onOrAfter' | 'earlierThan' | 'onOrBefore'\n ) => {\n return (value: DatetimeUTCNullable) => {\n const unrefOtherDate = unref(otherDate)\n\n if (value === null && unrefOtherDate === null) {\n return true\n }\n\n if (value === null || unrefOtherDate === null) {\n return true\n }\n\n const dateValue = new Date(value)\n const dateOther = new Date(unrefOtherDate)\n\n switch (variant) {\n case 'laterThan':\n return dateValue > dateOther\n case 'onOrAfter':\n return dateValue >= dateOther\n case 'earlierThan':\n return dateValue < dateOther\n case 'onOrBefore':\n return dateValue <= dateOther\n default:\n return false\n }\n }\n }\n\n const datesCompareHelper = (\n otherDate: OtherDateType,\n otherDateName: string,\n variant: 'laterThan' | 'onOrAfter' | 'earlierThan' | 'onOrBefore'\n ) => {\n return {\n $validator: datesCompareValidator(otherDate, otherDateName, variant),\n $params: {\n otherDateName: unref(otherDateName),\n variant,\n type: 'validateDate',\n },\n }\n }\n\n return withI18nMessage(datesCompareHelper, {\n withArguments: true,\n messagePath: (params) => `error.jsValidation.datesCompare.${params.$params.variant}`,\n })\n}\n","import { useValidateBetween } from '@/validators/vuelidate/common/useValidateBetween'\nimport { useValidateEmail } from '@/validators/vuelidate/common/useValidateEmail'\nimport { useValidateMaxLength } from '@/validators/vuelidate/common/useValidateMaxLength'\nimport { useValidateMaxValue } from '@/validators/vuelidate/common/useValidateMaxValue'\nimport { useValidateMinLength } from '@/validators/vuelidate/common/useValidateMinLength'\nimport { useValidateMinValue } from '@/validators/vuelidate/common/useValidateMinValue'\nimport { useValidateNumeric } from '@/validators/vuelidate/common/useValidateNumeric'\nimport { useValidateRequired } from '@/validators/vuelidate/common/useValidateRequired'\nimport { useValidateRequiredIf } from '@/validators/vuelidate/common/useValidateRequiredIf'\nimport { useValidateSlug } from '@/validators/vuelidate/common/useValidateSlug'\nimport { useValidateStringArrayItemLength } from '@/validators/vuelidate/common/useValidateStringArrayItemLength'\nimport { useValidateUrl } from '@/validators/vuelidate/common/useValidateUrl'\nimport { useValidateCompareDates } from '@/validators/vuelidate/common/useValidateCompareDates'\n\nexport function useValidate() {\n return {\n required: useValidateRequired(),\n requiredIf: useValidateRequiredIf(),\n minLength: useValidateMinLength(),\n maxLength: useValidateMaxLength(),\n minValue: useValidateMinValue(),\n maxValue: useValidateMaxValue(),\n between: useValidateBetween(),\n email: useValidateEmail(),\n numeric: useValidateNumeric(),\n slug: useValidateSlug(),\n url: useValidateUrl(),\n stringArrayItemLength: useValidateStringArrayItemLength(),\n datesCompare: useValidateCompareDates(),\n }\n}\n","<script setup lang=\"ts\">\nimport { nextTick, ref, useTemplateRef, watch, computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nconst emit = defineEmits<{\n (e: 'onEnterKeyup'): void\n (e: 'focusConfirm'): void\n}>()\n\nconst modelValue = defineModel<null | { hours: number; minutes: number }>('modelValue', {\n required: true,\n})\n\nconst hours = ref<string | undefined>(\n // eslint-disable-next-line vue/no-ref-object-reactivity-loss\n modelValue.value ? String(modelValue.value.hours).padStart(2, '0') : '12'\n)\nconst minutes = ref<string | undefined>(\n // eslint-disable-next-line vue/no-ref-object-reactivity-loss\n modelValue.value ? String(modelValue.value.minutes).padStart(2, '0') : '00'\n)\n\nconst hoursRefInput = useTemplateRef<HTMLInputElement>('hoursRefInput')\nconst minutesRefInput = useTemplateRef<HTMLInputElement>('minutesRefInput')\n\nconst hoursComputed = computed({\n get: () => hours.value,\n set: (value: string | number) => {\n let cleanValue = String(value).replace(/[^0-9]/g, '')\n\n if (cleanValue && parseInt(cleanValue) > 23) {\n hours.value = '23'\n nextTick(() => minutesRefInput.value?.focus())\n return\n }\n\n if (cleanValue.length > 2) {\n cleanValue = cleanValue.slice(0, 2)\n }\n\n hours.value = cleanValue\n\n if (cleanValue.length === 2) {\n nextTick(() => minutesRefInput.value?.focus())\n }\n },\n})\n\nconst minutesComputed = computed({\n get: () => minutes.value,\n set: (value: string | number) => {\n let cleanValue = String(value).replace(/[^0-9]/g, '')\n\n if (cleanValue && parseInt(cleanValue) > 59) {\n minutes.value = '59'\n emit('focusConfirm')\n return\n }\n\n if (cleanValue.length > 2) {\n cleanValue = cleanValue.slice(0, 2)\n }\n\n minutes.value = cleanValue\n\n if (cleanValue.length === 2) {\n emit('focusConfirm')\n }\n },\n})\n\nconst selectContent = async (event: FocusEvent) => {\n const target = event.target as HTMLInputElement | null\n await nextTick()\n target?.select()\n}\n\nconst onBlurHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n hours.value = parsedHours >= 0 && parsedHours <= 23 ? String(parsedHours).padStart(2, '0') : '00'\n}\n\nconst onBlurMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n minutes.value = parsedMinutes >= 0 && parsedMinutes <= 59 ? String(parsedMinutes).padStart(2, '0') : '00'\n}\n\nconst onEnterHoursKeyup = () => {\n onBlurHours()\n emit('onEnterKeyup')\n}\n\nconst onEnterMinutesKeyup = () => {\n onBlurMinutes()\n emit('onEnterKeyup')\n}\n\nconst increaseHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n const newHours = isNaN(parsedHours) ? 1 : (parsedHours + 1) % 24\n hours.value = String(newHours).padStart(2, '0')\n}\n\nconst decreaseHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n const newHours = isNaN(parsedHours) ? 23 : (parsedHours - 1 + 24) % 24\n hours.value = String(newHours).padStart(2, '0')\n}\n\nconst increaseMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n const parsedHours = parseInt(hours.value || '0')\n\n if (isNaN(parsedMinutes)) {\n minutes.value = '01'\n return\n }\n\n if (parsedMinutes === 59) {\n minutes.value = '00'\n const newHours = isNaN(parsedHours) ? 1 : (parsedHours + 1) % 24\n hours.value = String(newHours).padStart(2, '0')\n } else {\n const newMinutes = parsedMinutes + 1\n minutes.value = String(newMinutes).padStart(2, '0')\n }\n}\n\nconst decreaseMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n const parsedHours = parseInt(hours.value || '0')\n\n if (isNaN(parsedMinutes)) {\n minutes.value = '59'\n return\n }\n\n if (parsedMinutes === 0) {\n minutes.value = '59'\n const newHours = isNaN(parsedHours) ? 23 : (parsedHours - 1 + 24) % 24\n hours.value = String(newHours).padStart(2, '0')\n } else {\n const newMinutes = parsedMinutes - 1\n minutes.value = String(newMinutes).padStart(2, '0')\n }\n}\n\nconst focusHour = () => {\n hoursRefInput.value?.focus()\n}\n\nwatch([hours, minutes], ([newHours, newMinutes], [oldHours, oldMinutes]) => {\n if (newHours === oldHours && newMinutes === oldMinutes) return\n const hoursInt = parseInt(newHours ?? (modelValue.value ? modelValue.value.hours.toString() : '12'))\n const minutesInt = parseInt(newMinutes ?? (modelValue.value ? modelValue.value.minutes.toString() : '0'))\n if (hoursInt >= 0 && hoursInt <= 23 && minutesInt >= 0 && minutesInt <= 59) {\n modelValue.value = { hours: hoursInt, minutes: minutesInt }\n }\n})\n\ndefineExpose({\n focusHour,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-datetime-picker-time\">\n <div class=\"a-datetime-picker-time__item a-datetime-picker-time__item\">\n <input\n ref=\"hoursRefInput\"\n v-model=\"hoursComputed\"\n class=\"a-datetime-picker-time__input a-datetime-picker-time__input--hours\"\n type=\"text\"\n :aria-label=\"t('$vuetify.timePicker.hour')\"\n tabindex=\"1\"\n min=\"0\"\n max=\"23\"\n @focus=\"selectContent\"\n @blur=\"onBlurHours\"\n @keyup.enter=\"onEnterHoursKeyup\"\n />\n <div class=\"a-datetime-picker-time__arrows\">\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-up\"\n @click=\"increaseHours\"\n >\n <VIcon icon=\"mdi-chevron-up\" />\n </VBtn>\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-down\"\n @click=\"decreaseHours\"\n >\n <VIcon icon=\"mdi-chevron-down\" />\n </VBtn>\n </div>\n </div>\n <span class=\"a-datetime-picker-time__separator\">:</span>\n <div class=\"a-datetime-picker-time__item\">\n <input\n ref=\"minutesRefInput\"\n v-model=\"minutesComputed\"\n class=\"a-datetime-picker-time__input a-datetime-picker-time__input--minutes\"\n type=\"text\"\n :aria-label=\"t('$vuetify.timePicker.minute')\"\n tabindex=\"2\"\n min=\"0\"\n max=\"59\"\n @focus=\"selectContent\"\n @blur=\"onBlurMinutes\"\n @keyup.enter=\"onEnterMinutesKeyup\"\n />\n <div class=\"a-datetime-picker-time__arrows\">\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-up\"\n @click=\"increaseMinutes\"\n >\n <VIcon icon=\"mdi-chevron-up\" />\n </VBtn>\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-down\"\n @click=\"decreaseMinutes\"\n >\n <VIcon icon=\"mdi-chevron-down\" />\n </VBtn>\n </div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\" scoped>\n$hover-bg-color: rgb(0 0 0 / 5%);\n\n.a-datetime-picker-time {\n display: flex;\n\n &__item {\n flex-grow: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 40px;\n\n &:hover {\n background-color: $hover-bg-color;\n }\n }\n\n &__separator {\n font-weight: bold;\n font-size: 1.2rem;\n text-align: center;\n font-family: Roboto, sans-serif;\n min-height: 40px;\n padding: 0 5px;\n display: flex;\n align-items: center;\n }\n\n &__arrows {\n display: flex;\n flex-direction: column;\n opacity: 0;\n\n .v-btn {\n padding: 0 !important;\n min-width: 28px !important;\n width: 28px !important;\n height: 28px !important;\n }\n\n .a-datetime-picker-time__item:hover &,\n .a-datetime-picker-time__input:focus + &,\n &:focus-within {\n opacity: 1;\n }\n }\n\n &__input {\n width: 100%;\n max-width: 128px;\n height: 100%;\n display: inline-block;\n background: transparent;\n /* stylelint-disable-next-line */\n -webkit-box-shadow: none;\n box-shadow: none;\n border: 0;\n border-radius: 0;\n text-align: center;\n margin: 0;\n padding: 0;\n line-height: inherit;\n font-size: 1rem;\n position: relative;\n /* stylelint-disable-next-line */\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n /* stylelint-disable-next-line */\n -webkit-appearance: textfield;\n /* stylelint-disable-next-line */\n -moz-appearance: textfield;\n appearance: textfield;\n outline: none;\n\n &--hours {\n font-weight: bold;\n }\n }\n\n &__input::-webkit-inner-spin-button,\n &__input::-webkit-outer-spin-button {\n /* stylelint-disable-next-line */\n -webkit-appearance: none;\n margin: 0;\n }\n}\n</style>\n","<script setup lang=\"ts\">\nimport { nextTick, ref, useTemplateRef, watch, computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nconst emit = defineEmits<{\n (e: 'onEnterKeyup'): void\n (e: 'focusConfirm'): void\n}>()\n\nconst modelValue = defineModel<null | { hours: number; minutes: number }>('modelValue', {\n required: true,\n})\n\nconst hours = ref<string | undefined>(\n // eslint-disable-next-line vue/no-ref-object-reactivity-loss\n modelValue.value ? String(modelValue.value.hours).padStart(2, '0') : '12'\n)\nconst minutes = ref<string | undefined>(\n // eslint-disable-next-line vue/no-ref-object-reactivity-loss\n modelValue.value ? String(modelValue.value.minutes).padStart(2, '0') : '00'\n)\n\nconst hoursRefInput = useTemplateRef<HTMLInputElement>('hoursRefInput')\nconst minutesRefInput = useTemplateRef<HTMLInputElement>('minutesRefInput')\n\nconst hoursComputed = computed({\n get: () => hours.value,\n set: (value: string | number) => {\n let cleanValue = String(value).replace(/[^0-9]/g, '')\n\n if (cleanValue && parseInt(cleanValue) > 23) {\n hours.value = '23'\n nextTick(() => minutesRefInput.value?.focus())\n return\n }\n\n if (cleanValue.length > 2) {\n cleanValue = cleanValue.slice(0, 2)\n }\n\n hours.value = cleanValue\n\n if (cleanValue.length === 2) {\n nextTick(() => minutesRefInput.value?.focus())\n }\n },\n})\n\nconst minutesComputed = computed({\n get: () => minutes.value,\n set: (value: string | number) => {\n let cleanValue = String(value).replace(/[^0-9]/g, '')\n\n if (cleanValue && parseInt(cleanValue) > 59) {\n minutes.value = '59'\n emit('focusConfirm')\n return\n }\n\n if (cleanValue.length > 2) {\n cleanValue = cleanValue.slice(0, 2)\n }\n\n minutes.value = cleanValue\n\n if (cleanValue.length === 2) {\n emit('focusConfirm')\n }\n },\n})\n\nconst selectContent = async (event: FocusEvent) => {\n const target = event.target as HTMLInputElement | null\n await nextTick()\n target?.select()\n}\n\nconst onBlurHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n hours.value = parsedHours >= 0 && parsedHours <= 23 ? String(parsedHours).padStart(2, '0') : '00'\n}\n\nconst onBlurMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n minutes.value = parsedMinutes >= 0 && parsedMinutes <= 59 ? String(parsedMinutes).padStart(2, '0') : '00'\n}\n\nconst onEnterHoursKeyup = () => {\n onBlurHours()\n emit('onEnterKeyup')\n}\n\nconst onEnterMinutesKeyup = () => {\n onBlurMinutes()\n emit('onEnterKeyup')\n}\n\nconst increaseHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n const newHours = isNaN(parsedHours) ? 1 : (parsedHours + 1) % 24\n hours.value = String(newHours).padStart(2, '0')\n}\n\nconst decreaseHours = () => {\n const parsedHours = parseInt(hours.value || '0')\n const newHours = isNaN(parsedHours) ? 23 : (parsedHours - 1 + 24) % 24\n hours.value = String(newHours).padStart(2, '0')\n}\n\nconst increaseMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n const parsedHours = parseInt(hours.value || '0')\n\n if (isNaN(parsedMinutes)) {\n minutes.value = '01'\n return\n }\n\n if (parsedMinutes === 59) {\n minutes.value = '00'\n const newHours = isNaN(parsedHours) ? 1 : (parsedHours + 1) % 24\n hours.value = String(newHours).padStart(2, '0')\n } else {\n const newMinutes = parsedMinutes + 1\n minutes.value = String(newMinutes).padStart(2, '0')\n }\n}\n\nconst decreaseMinutes = () => {\n const parsedMinutes = parseInt(minutes.value || '0')\n const parsedHours = parseInt(hours.value || '0')\n\n if (isNaN(parsedMinutes)) {\n minutes.value = '59'\n return\n }\n\n if (parsedMinutes === 0) {\n minutes.value = '59'\n const newHours = isNaN(parsedHours) ? 23 : (parsedHours - 1 + 24) % 24\n hours.value = String(newHours).padStart(2, '0')\n } else {\n const newMinutes = parsedMinutes - 1\n minutes.value = String(newMinutes).padStart(2, '0')\n }\n}\n\nconst focusHour = () => {\n hoursRefInput.value?.focus()\n}\n\nwatch([hours, minutes], ([newHours, newMinutes], [oldHours, oldMinutes]) => {\n if (newHours === oldHours && newMinutes === oldMinutes) return\n const hoursInt = parseInt(newHours ?? (modelValue.value ? modelValue.value.hours.toString() : '12'))\n const minutesInt = parseInt(newMinutes ?? (modelValue.value ? modelValue.value.minutes.toString() : '0'))\n if (hoursInt >= 0 && hoursInt <= 23 && minutesInt >= 0 && minutesInt <= 59) {\n modelValue.value = { hours: hoursInt, minutes: minutesInt }\n }\n})\n\ndefineExpose({\n focusHour,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-datetime-picker-time\">\n <div class=\"a-datetime-picker-time__item a-datetime-picker-time__item\">\n <input\n ref=\"hoursRefInput\"\n v-model=\"hoursComputed\"\n class=\"a-datetime-picker-time__input a-datetime-picker-time__input--hours\"\n type=\"text\"\n :aria-label=\"t('$vuetify.timePicker.hour')\"\n tabindex=\"1\"\n min=\"0\"\n max=\"23\"\n @focus=\"selectContent\"\n @blur=\"onBlurHours\"\n @keyup.enter=\"onEnterHoursKeyup\"\n />\n <div class=\"a-datetime-picker-time__arrows\">\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-up\"\n @click=\"increaseHours\"\n >\n <VIcon icon=\"mdi-chevron-up\" />\n </VBtn>\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-down\"\n @click=\"decreaseHours\"\n >\n <VIcon icon=\"mdi-chevron-down\" />\n </VBtn>\n </div>\n </div>\n <span class=\"a-datetime-picker-time__separator\">:</span>\n <div class=\"a-datetime-picker-time__item\">\n <input\n ref=\"minutesRefInput\"\n v-model=\"minutesComputed\"\n class=\"a-datetime-picker-time__input a-datetime-picker-time__input--minutes\"\n type=\"text\"\n :aria-label=\"t('$vuetify.timePicker.minute')\"\n tabindex=\"2\"\n min=\"0\"\n max=\"59\"\n @focus=\"selectContent\"\n @blur=\"onBlurMinutes\"\n @keyup.enter=\"onEnterMinutesKeyup\"\n />\n <div class=\"a-datetime-picker-time__arrows\">\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-up\"\n @click=\"increaseMinutes\"\n >\n <VIcon icon=\"mdi-chevron-up\" />\n </VBtn>\n <VBtn\n tabindex=\"-1\"\n variant=\"text\"\n class=\"a-datetime-picker-time__arrow-down\"\n @click=\"decreaseMinutes\"\n >\n <VIcon icon=\"mdi-chevron-down\" />\n </VBtn>\n </div>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\" scoped>\n$hover-bg-color: rgb(0 0 0 / 5%);\n\n.a-datetime-picker-time {\n display: flex;\n\n &__item {\n flex-grow: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 40px;\n\n &:hover {\n background-color: $hover-bg-color;\n }\n }\n\n &__separator {\n font-weight: bold;\n font-size: 1.2rem;\n text-align: center;\n font-family: Roboto, sans-serif;\n min-height: 40px;\n padding: 0 5px;\n display: flex;\n align-items: center;\n }\n\n &__arrows {\n display: flex;\n flex-direction: column;\n opacity: 0;\n\n .v-btn {\n padding: 0 !important;\n min-width: 28px !important;\n width: 28px !important;\n height: 28px !important;\n }\n\n .a-datetime-picker-time__item:hover &,\n .a-datetime-picker-time__input:focus + &,\n &:focus-within {\n opacity: 1;\n }\n }\n\n &__input {\n width: 100%;\n max-width: 128px;\n height: 100%;\n display: inline-block;\n background: transparent;\n /* stylelint-disable-next-line */\n -webkit-box-shadow: none;\n box-shadow: none;\n border: 0;\n border-radius: 0;\n text-align: center;\n margin: 0;\n padding: 0;\n line-height: inherit;\n font-size: 1rem;\n position: relative;\n /* stylelint-disable-next-line */\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n /* stylelint-disable-next-line */\n -webkit-appearance: textfield;\n /* stylelint-disable-next-line */\n -moz-appearance: textfield;\n appearance: textfield;\n outline: none;\n\n &--hours {\n font-weight: bold;\n }\n }\n\n &__input::-webkit-inner-spin-button,\n &__input::-webkit-outer-spin-button {\n /* stylelint-disable-next-line */\n -webkit-appearance: none;\n margin: 0;\n }\n}\n</style>\n","import dayjs from 'dayjs'\nimport utc from 'dayjs/plugin/utc'\nimport customParseFormat from 'dayjs/plugin/customParseFormat'\nimport { isNull, isUndefined } from '@/utils/common'\nimport { SUFFIX } from '@/utils/datetime'\nimport type { DatetimeUTC } from '@/types/common'\n\ndayjs.extend(utc)\ndayjs.extend(customParseFormat)\n\n/**\n * Value arithmetic of ADatetimePicker, kept out of the component so both modes can be tested\n * without a DOM.\n *\n * `datetime` values are instants: parsed as such, shown in local time, serialized through `.utc()`.\n * `date` values are calendar days pinned to UTC midnight (`YYYY-MM-DDT00:00:00.000000Z`) and must\n * never cross a timezone: every internal object stays in UTC mode, so `.year()/.month()/.date()`\n * and `.format()` read the same day the API stores.\n */\nexport type DatetimePickerType = 'datetime' | 'date'\n\nconst MODEL_FORMAT = 'YYYY-MM-DDTHH:mm:ss.SSSSSSZ'\nconst SERIALIZE_FORMAT = 'YYYY-MM-DDTHH:mm:ss'\nconst DATE_TEXT_FORMAT = 'DD.MM.YYYY'\nconst DATETIME_TEXT_FORMATS = ['DD.MM.YYYY HH:mm', DATE_TEXT_FORMAT]\n\nexport const placeholderFor = (type: DatetimePickerType) => (type === 'date' ? 'dd.mm.yyyy' : 'dd.mm.yyyy hh:mm')\n\nexport const displayFormatFor = (type: DatetimePickerType) => (type === 'date' ? DATE_TEXT_FORMAT : 'DD.MM.YYYY HH:mm')\n\nexport const parseModel = (\n value: DatetimeUTC | null | undefined,\n type: DatetimePickerType,\n lastMinuteMoment = false\n): dayjs.Dayjs | null => {\n // `dayjs.utc(undefined)` is now, not Invalid.\n if (isNull(value) || isUndefined(value) || value.length === 0) return null\n if (type === 'date') {\n const parsed = dayjs.utc(value)\n return parsed.isValid() ? parsed : null\n }\n // The canonical shape carries six fraction digits, but `isDatetimeUTC` also accepts three and an\n // API can answer with none; returning null for those would blank the field and save the blank.\n const parsed = dayjs(value, MODEL_FORMAT)\n const instant = parsed.isValid() ? parsed : dayjs(value)\n if (!instant.isValid()) return null\n return lastMinuteMoment ? instant.millisecond(999) : instant.millisecond(0)\n}\n\nexport const parseTyped = (text: string, type: DatetimePickerType, keepSeconds = 0): dayjs.Dayjs | null => {\n if (type === 'date') {\n // The format has to stay a string. `dayjs.utc(text, [format])` takes the array branch of\n // customParseFormat, which calls the plain factory and drops UTC, so a typed day comes back\n // shifted by the local offset - the original bug. `dayjs(text, [format]).utc()` shifts it too.\n const parsed = dayjs.utc(text, DATE_TEXT_FORMAT)\n return parsed.isValid() ? parsed : null\n }\n const parsed = dayjs(text, DATETIME_TEXT_FORMATS)\n return parsed.isValid() ? parsed.second(keepSeconds) : null\n}\n\nexport const serialize = (internal: dayjs.Dayjs, type: DatetimePickerType): DatetimeUTC => {\n if (type === 'date') return internal.format('YYYY-MM-DD') + 'T00:00:00' + SUFFIX\n return internal.utc().format(SERIALIZE_FORMAT) + SUFFIX\n}\n\nexport const formatDisplay = (internal: dayjs.Dayjs, type: DatetimePickerType) =>\n internal.format(displayFormatFor(type))\n\n/** VDatePicker works with local `Date`s, so a date-mode day travels as its local namesake. */\nexport const toCalendarDate = (internal: dayjs.Dayjs, type: DatetimePickerType): Date =>\n type === 'date' ? new Date(internal.year(), internal.month(), internal.date()) : internal.toDate()\n\nexport const applyCalendarDate = (internal: dayjs.Dayjs, picked: Date, type: DatetimePickerType): dayjs.Dayjs => {\n if (type === 'date') {\n return dayjs.utc(Date.UTC(picked.getFullYear(), picked.getMonth(), picked.getDate()))\n }\n // Year and month first: setting the day of an adjacent month onto a shorter month overflows\n // (8 Feb + day 31 lands on 3 Mar, which the following month set then carries into January).\n return internal.set('year', picked.getFullYear()).set('month', picked.getMonth()).set('date', picked.getDate())\n}\n\n/** Today's calendar day, taken from the local clock - the UTC day is yesterday or tomorrow for a part of it. */\nexport const todayValue = (type: DatetimePickerType, lastMinuteMoment = false): dayjs.Dayjs => {\n if (type === 'date') {\n const now = new Date()\n return dayjs.utc(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()))\n }\n return lastMinuteMoment ? dayjs().second(59).millisecond(999) : dayjs().second(0).millisecond(0)\n}\n\n/** Base for a picker interaction that starts with no value at all. */\nexport const emptyBaseValue = (type: DatetimePickerType, lastMinuteMoment = false): dayjs.Dayjs => {\n if (type === 'date') return todayValue(type)\n return lastMinuteMoment\n ? dayjs().hour(0).minute(0).second(59).millisecond(999)\n : dayjs().hour(0).minute(0).second(0).millisecond(0)\n}\n\n/** By second, as `lastMinuteMoment` holds ms at 999; by day where the time carries no meaning. */\nexport const isSameValue = (value: dayjs.Dayjs, other: dayjs.Dayjs | null, type: DatetimePickerType): boolean =>\n isNull(other) ? false : value.isSame(other, type === 'date' ? 'day' : 'second')\n","<script lang=\"ts\" setup>\nimport type { DatetimeUTC } from '@/types/common'\nimport { computed, nextTick, ref, toRaw, useTemplateRef, watch } from 'vue'\nimport { isDefined, isNull, isUndefined } from '@/utils/common'\nimport useVuelidate, { type ErrorObject } from '@vuelidate/core'\nimport { useValidate } from '@/validators/vuelidate/useValidate'\nimport TimePicker from '@/components/datetime/TimePicker.vue'\nimport type { Dayjs } from 'dayjs'\nimport {\n applyCalendarDate,\n type DatetimePickerType,\n emptyBaseValue,\n formatDisplay,\n isSameValue,\n parseModel,\n parseTyped,\n placeholderFor,\n serialize,\n toCalendarDate,\n todayValue,\n} from '@/utils/datetimePickerValue'\nimport { useI18n } from 'vue-i18n'\nimport type { VTextField } from 'vuetify/components/VTextField'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: DatetimeUTC | null | undefined\n type?: DatetimePickerType\n label?: string\n hideLabel?: boolean\n clearable?: boolean\n disabled?: boolean\n hideDetails?: boolean\n required?: boolean\n hideSetToNow?: boolean\n placeholder?: string\n dataCy?: string\n defaultValue?: DatetimeUTC | null | undefined\n errorMessages?: string[]\n lastMinuteMoment?: boolean\n }>(),\n {\n type: 'datetime',\n label: '',\n hideLabel: false,\n clearable: false,\n disabled: false,\n hideDetails: false,\n required: false,\n hideSetToNow: false,\n placeholder: '',\n dataCy: '',\n defaultValue: null,\n errorMessages: undefined,\n lastMinuteMoment: false,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'blur'): void\n (e: 'focus'): void\n (e: 'update:modelValue', data: DatetimeUTC | null | undefined): void\n (e: 'onOpen'): void\n (e: 'onClose'): void\n (e: 'afterClear'): void\n}>()\n\nconst pickerOpened = ref(false)\nconst pickerKey = ref(0)\nconst timeKey = ref(0)\nconst timePickerInstance = useTemplateRef<InstanceType<typeof TimePicker>>('timePickerInstance')\nconst inputInstance = useTemplateRef<InstanceType<typeof VTextField>>('inputInstance')\nconst confirmRefButton = useTemplateRef<HTMLButtonElement>('confirmRefButton')\nconst textFieldValue = ref('')\n\nconst datePickerValue = ref<null | Date>(null)\nconst timePickerValue = ref<null | { hours: number; minutes: number }>(null)\nconst datetimeInternal = ref<null | Dayjs>(null)\n\nconst { t } = useI18n()\n\nconst placeholderComputed = computed(() => {\n return props.placeholder.length ? props.placeholder : placeholderFor(props.type)\n})\n\nconst { requiredIf } = useValidate()\nconst rules = computed(() => {\n return {\n textFieldValue: {\n required: requiredIf(props.required),\n },\n }\n})\nconst v$ = useVuelidate(rules, { textFieldValue })\n\nconst tryEmitNewValue = (newValue: DatetimeUTC | null | undefined) => {\n if (newValue === props.modelValue) return\n emit('update:modelValue', newValue)\n}\n\nconst updateDateAndTimePickerOnlyWhenChanged = (newValue: Dayjs | null) => {\n if (isNull(newValue)) return\n if (\n props.type !== 'date' &&\n (isNull(timePickerValue.value) ||\n newValue.hour() !== timePickerValue.value.hours ||\n newValue.minute() !== timePickerValue.value.minutes)\n ) {\n timePickerValue.value = { hours: newValue.hour(), minutes: newValue.minute() }\n }\n if (\n isNull(datePickerValue.value) ||\n newValue.year() !== datePickerValue.value.getFullYear() ||\n newValue.month() !== datePickerValue.value.getMonth() ||\n newValue.date() !== datePickerValue.value.getDate()\n ) {\n datePickerValue.value = toCalendarDate(newValue, props.type)\n }\n}\n\nwatch(\n () => props.modelValue,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n datetimeInternal.value = parseModel(newValue, props.type, props.lastMinuteMoment)\n },\n { immediate: true }\n)\n\nconst watchDatePicker = (newValue: null | Date, internal: Dayjs) => {\n if (isNull(newValue)) return internal\n return applyCalendarDate(internal, newValue, props.type)\n}\n\nconst watchTimePicker = (newValue: null | { hours: number; minutes: number }, internal: Dayjs) => {\n if (isNull(newValue) || props.type === 'date') return internal\n return internal.set('hour', newValue.hours).set('minute', newValue.minutes)\n}\n\nwatch([timePickerValue, datePickerValue], ([newTimePickerValue, newDatePickerValue]) => {\n let newDate: Dayjs | null = null\n\n if (!isNull(datetimeInternal.value)) {\n newDate = datetimeInternal.value\n } else {\n newDate =\n parseModel(props.modelValue, props.type, props.lastMinuteMoment) ??\n emptyBaseValue(props.type, props.lastMinuteMoment)\n }\n\n newDate = watchTimePicker(newTimePickerValue, newDate!)\n newDate = watchDatePicker(newDatePickerValue, newDate!)\n if (newDate.isSame(toRaw(datetimeInternal.value))) return\n datetimeInternal.value = newDate\n})\n\nwatch(\n datetimeInternal,\n (newValue) => {\n if (isNull(newValue)) {\n textFieldValue.value = ''\n tryEmitNewValue(null)\n return\n }\n const newUtcValue = serialize(newValue, props.type)\n textFieldValue.value = formatDisplay(newValue, props.type)\n updateDateAndTimePickerOnlyWhenChanged(newValue)\n tryEmitNewValue(newUtcValue)\n },\n { immediate: true }\n)\n\nwatch(pickerOpened, (newValue) => {\n if (newValue) {\n onTextFieldBlur()\n if (isNull(datetimeInternal.value) && (isNull(props.defaultValue) || isUndefined(props.defaultValue))) {\n datetimeInternal.value = todayValue(props.type, props.lastMinuteMoment)\n }\n emit('onOpen')\n return\n }\n emit('onClose')\n})\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessages)) return props.errorMessages\n if (v$.value.textFieldValue.$errors.length)\n return [v$.value.textFieldValue.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst onTextFieldBlur = () => {\n const filtered = textFieldValue.value.replace(/[^\\s\\d.:]/g, '').trim()\n if (filtered.length === 0 && !props.required) {\n datetimeInternal.value = parseModel(props.defaultValue, props.type, props.lastMinuteMoment)\n emit('blur')\n return\n }\n // keep seconds from original model\n const seconds = parseModel(props.modelValue, props.type, props.lastMinuteMoment)?.second() ?? 0\n const reparsed = parseTyped(filtered, props.type, seconds)\n if (!isNull(reparsed)) {\n // A day click blurs this field before the picker emits, so re-assigning an unchanged datetime\n // would push the stale date back into it.\n if (isSameValue(reparsed, toRaw(datetimeInternal.value), props.type)) {\n textFieldValue.value = formatDisplay(reparsed, props.type)\n } else {\n datetimeInternal.value = reparsed\n }\n v$.value.textFieldValue.$touch()\n emit('blur')\n return\n }\n if (!isNull(datetimeInternal.value)) {\n textFieldValue.value = formatDisplay(datetimeInternal.value, props.type)\n }\n v$.value.textFieldValue.$touch()\n emit('blur')\n}\n\nconst onClear = () => {\n if (isNull(props.defaultValue) || isUndefined(props.defaultValue)) {\n datetimeInternal.value = null\n datePickerValue.value = null\n timePickerValue.value = null\n emit('afterClear')\n return\n }\n datetimeInternal.value = parseModel(props.defaultValue, props.type, props.lastMinuteMoment)\n emit('afterClear')\n}\n\nconst close = () => {\n pickerOpened.value = false\n inputInstance.value?.focus()\n inputInstance.value?.blur()\n emit('onClose')\n emit('blur')\n}\n\nconst onTextFieldFocus = () => {\n emit('focus')\n}\n\nconst onTimePickerEnterKeyup = () => {\n pickerOpened.value = false\n}\n\nconst onFocusConfirm = () => {\n confirmRefButton.value?.focus()\n}\n\nconst onDatePickerUpdate = () => {\n if (props.type === 'date') {\n // The value travels through pre-flush watchers, so closing now would emit blur and release the\n // collab lock with the previous value still in the model.\n nextTick(close)\n return\n }\n timePickerInstance.value?.focusHour()\n}\n\nconst now = () => {\n datetimeInternal.value = todayValue(props.type, props.lastMinuteMoment)\n nextTick(() => {\n // Vuetify navigates the calendar to a new value on its own, but skips an unchanged day, so a\n // value that is already today would leave the user on whatever month they paged to.\n pickerKey.value++\n timeKey.value++\n })\n}\n</script>\n\n<template>\n <VTextField\n ref=\"inputInstance\"\n v-model=\"textFieldValue\"\n :error-messages=\"errorMessageComputed\"\n :persistent-placeholder=\"true\"\n :placeholder=\"placeholderComputed\"\n class=\"a-datetime-picker\"\n :hide-details=\"hideDetails ? true : 'auto'\"\n :data-cy=\"dataCy.length ? dataCy : undefined\"\n :disabled=\"disabled\"\n autocomplete=\"off\"\n @blur=\"onTextFieldBlur\"\n @focus=\"onTextFieldFocus\"\n @keyup.enter=\"onTextFieldBlur\"\n >\n <template #append-inner>\n <VIcon\n v-if=\"clearable && defaultValue !== modelValue\"\n class=\"a-datetime-picker__clearable-icon\"\n icon=\"mdi-close-circle\"\n @click.stop=\"onClear\"\n />\n <VMenu\n v-if=\"!disabled\"\n location=\"bottom end\"\n origin=\"top end\"\n :close-on-content-click=\"false\"\n :model-value=\"pickerOpened\"\n @update:model-value=\"(value: boolean) => (pickerOpened = value)\"\n >\n <template #activator=\"{ props: menuProps }\">\n <VIcon\n class=\"a-datetime-picker__calendar-icon\"\n icon=\"mdi-calendar\"\n size=\"small\"\n v-bind=\"menuProps\"\n />\n </template>\n\n <VCard v-if=\"pickerOpened\">\n <VBtn\n v-tooltip=\"t('common.button.close')\"\n icon\n variant=\"text\"\n :width=\"36\"\n :height=\"36\"\n class=\"position-absolute top-0 right-0\"\n @click.stop=\"close\"\n >\n <VIcon\n icon=\"mdi-close\"\n color=\"white\"\n />\n </VBtn>\n <VDatePicker\n :key=\"pickerKey\"\n v-model=\"datePickerValue\"\n class=\"a-datetime-picker-calendar\"\n color=\"primary\"\n show-adjacent-months\n v-bind=\"$attrs\"\n @update:model-value=\"onDatePickerUpdate\"\n />\n <TimePicker\n v-if=\"type !== 'date'\"\n ref=\"timePickerInstance\"\n :key=\"timeKey\"\n v-model=\"timePickerValue\"\n @on-enter-keyup=\"onTimePickerEnterKeyup\"\n @focus-confirm=\"onFocusConfirm\"\n />\n <div class=\"d-flex\">\n <button\n v-if=\"!hideSetToNow\"\n type=\"button\"\n class=\"a-datetime-picker__bottom-button\"\n tabindex=\"8\"\n @click=\"now\"\n >\n {{ type === 'date' ? t('common.time.today') : t('common.time.now') }}\n </button>\n <button\n ref=\"confirmRefButton\"\n type=\"button\"\n class=\"a-datetime-picker__bottom-button\"\n tabindex=\"7\"\n @click.stop=\"close\"\n >\n {{ t('common.button.confirm') }}\n </button>\n </div>\n </VCard>\n </VMenu>\n\n <div class=\"ml-1\">\n <slot name=\"append-inner\" />\n </div>\n </template>\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ label\n }}<span\n v-if=\"required\"\n class=\"required\"\n />\n </template>\n </VTextField>\n</template>\n\n<style lang=\"scss\" scoped>\n.a-datetime-picker {\n :deep(.v-field__append-inner .v-icon) {\n cursor: pointer;\n }\n\n &__calendar-icon {\n margin-top: 2px;\n opacity: 0.6 !important;\n }\n\n &__clearable-icon {\n opacity: 0 !important;\n }\n\n &:hover {\n .a-datetime-picker__clearable-icon {\n opacity: 0.6 !important;\n }\n }\n\n &__bottom-button {\n width: 100%;\n text-align: center;\n font-size: 0.86rem;\n font-family: Roboto, sans-serif;\n font-weight: bold;\n line-height: 1.8;\n padding: 6px 0;\n\n &:hover {\n background-color: rgb(0 0 0 / 5%);\n }\n }\n}\n\n.a-datetime-picker-calendar {\n :deep(.v-picker-title) {\n display: none;\n }\n\n :deep(.v-date-picker-header) {\n padding-top: 12px;\n }\n\n :deep(.v-date-picker-month) {\n padding-bottom: 2px;\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport type { DatetimeUTC } from '@/types/common'\nimport { computed, nextTick, ref, toRaw, useTemplateRef, watch } from 'vue'\nimport { isDefined, isNull, isUndefined } from '@/utils/common'\nimport useVuelidate, { type ErrorObject } from '@vuelidate/core'\nimport { useValidate } from '@/validators/vuelidate/useValidate'\nimport TimePicker from '@/components/datetime/TimePicker.vue'\nimport type { Dayjs } from 'dayjs'\nimport {\n applyCalendarDate,\n type DatetimePickerType,\n emptyBaseValue,\n formatDisplay,\n isSameValue,\n parseModel,\n parseTyped,\n placeholderFor,\n serialize,\n toCalendarDate,\n todayValue,\n} from '@/utils/datetimePickerValue'\nimport { useI18n } from 'vue-i18n'\nimport type { VTextField } from 'vuetify/components/VTextField'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: DatetimeUTC | null | undefined\n type?: DatetimePickerType\n label?: string\n hideLabel?: boolean\n clearable?: boolean\n disabled?: boolean\n hideDetails?: boolean\n required?: boolean\n hideSetToNow?: boolean\n placeholder?: string\n dataCy?: string\n defaultValue?: DatetimeUTC | null | undefined\n errorMessages?: string[]\n lastMinuteMoment?: boolean\n }>(),\n {\n type: 'datetime',\n label: '',\n hideLabel: false,\n clearable: false,\n disabled: false,\n hideDetails: false,\n required: false,\n hideSetToNow: false,\n placeholder: '',\n dataCy: '',\n defaultValue: null,\n errorMessages: undefined,\n lastMinuteMoment: false,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'blur'): void\n (e: 'focus'): void\n (e: 'update:modelValue', data: DatetimeUTC | null | undefined): void\n (e: 'onOpen'): void\n (e: 'onClose'): void\n (e: 'afterClear'): void\n}>()\n\nconst pickerOpened = ref(false)\nconst pickerKey = ref(0)\nconst timeKey = ref(0)\nconst timePickerInstance = useTemplateRef<InstanceType<typeof TimePicker>>('timePickerInstance')\nconst inputInstance = useTemplateRef<InstanceType<typeof VTextField>>('inputInstance')\nconst confirmRefButton = useTemplateRef<HTMLButtonElement>('confirmRefButton')\nconst textFieldValue = ref('')\n\nconst datePickerValue = ref<null | Date>(null)\nconst timePickerValue = ref<null | { hours: number; minutes: number }>(null)\nconst datetimeInternal = ref<null | Dayjs>(null)\n\nconst { t } = useI18n()\n\nconst placeholderComputed = computed(() => {\n return props.placeholder.length ? props.placeholder : placeholderFor(props.type)\n})\n\nconst { requiredIf } = useValidate()\nconst rules = computed(() => {\n return {\n textFieldValue: {\n required: requiredIf(props.required),\n },\n }\n})\nconst v$ = useVuelidate(rules, { textFieldValue })\n\nconst tryEmitNewValue = (newValue: DatetimeUTC | null | undefined) => {\n if (newValue === props.modelValue) return\n emit('update:modelValue', newValue)\n}\n\nconst updateDateAndTimePickerOnlyWhenChanged = (newValue: Dayjs | null) => {\n if (isNull(newValue)) return\n if (\n props.type !== 'date' &&\n (isNull(timePickerValue.value) ||\n newValue.hour() !== timePickerValue.value.hours ||\n newValue.minute() !== timePickerValue.value.minutes)\n ) {\n timePickerValue.value = { hours: newValue.hour(), minutes: newValue.minute() }\n }\n if (\n isNull(datePickerValue.value) ||\n newValue.year() !== datePickerValue.value.getFullYear() ||\n newValue.month() !== datePickerValue.value.getMonth() ||\n newValue.date() !== datePickerValue.value.getDate()\n ) {\n datePickerValue.value = toCalendarDate(newValue, props.type)\n }\n}\n\nwatch(\n () => props.modelValue,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n datetimeInternal.value = parseModel(newValue, props.type, props.lastMinuteMoment)\n },\n { immediate: true }\n)\n\nconst watchDatePicker = (newValue: null | Date, internal: Dayjs) => {\n if (isNull(newValue)) return internal\n return applyCalendarDate(internal, newValue, props.type)\n}\n\nconst watchTimePicker = (newValue: null | { hours: number; minutes: number }, internal: Dayjs) => {\n if (isNull(newValue) || props.type === 'date') return internal\n return internal.set('hour', newValue.hours).set('minute', newValue.minutes)\n}\n\nwatch([timePickerValue, datePickerValue], ([newTimePickerValue, newDatePickerValue]) => {\n let newDate: Dayjs | null = null\n\n if (!isNull(datetimeInternal.value)) {\n newDate = datetimeInternal.value\n } else {\n newDate =\n parseModel(props.modelValue, props.type, props.lastMinuteMoment) ??\n emptyBaseValue(props.type, props.lastMinuteMoment)\n }\n\n newDate = watchTimePicker(newTimePickerValue, newDate!)\n newDate = watchDatePicker(newDatePickerValue, newDate!)\n if (newDate.isSame(toRaw(datetimeInternal.value))) return\n datetimeInternal.value = newDate\n})\n\nwatch(\n datetimeInternal,\n (newValue) => {\n if (isNull(newValue)) {\n textFieldValue.value = ''\n tryEmitNewValue(null)\n return\n }\n const newUtcValue = serialize(newValue, props.type)\n textFieldValue.value = formatDisplay(newValue, props.type)\n updateDateAndTimePickerOnlyWhenChanged(newValue)\n tryEmitNewValue(newUtcValue)\n },\n { immediate: true }\n)\n\nwatch(pickerOpened, (newValue) => {\n if (newValue) {\n onTextFieldBlur()\n if (isNull(datetimeInternal.value) && (isNull(props.defaultValue) || isUndefined(props.defaultValue))) {\n datetimeInternal.value = todayValue(props.type, props.lastMinuteMoment)\n }\n emit('onOpen')\n return\n }\n emit('onClose')\n})\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessages)) return props.errorMessages\n if (v$.value.textFieldValue.$errors.length)\n return [v$.value.textFieldValue.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst onTextFieldBlur = () => {\n const filtered = textFieldValue.value.replace(/[^\\s\\d.:]/g, '').trim()\n if (filtered.length === 0 && !props.required) {\n datetimeInternal.value = parseModel(props.defaultValue, props.type, props.lastMinuteMoment)\n emit('blur')\n return\n }\n // keep seconds from original model\n const seconds = parseModel(props.modelValue, props.type, props.lastMinuteMoment)?.second() ?? 0\n const reparsed = parseTyped(filtered, props.type, seconds)\n if (!isNull(reparsed)) {\n // A day click blurs this field before the picker emits, so re-assigning an unchanged datetime\n // would push the stale date back into it.\n if (isSameValue(reparsed, toRaw(datetimeInternal.value), props.type)) {\n textFieldValue.value = formatDisplay(reparsed, props.type)\n } else {\n datetimeInternal.value = reparsed\n }\n v$.value.textFieldValue.$touch()\n emit('blur')\n return\n }\n if (!isNull(datetimeInternal.value)) {\n textFieldValue.value = formatDisplay(datetimeInternal.value, props.type)\n }\n v$.value.textFieldValue.$touch()\n emit('blur')\n}\n\nconst onClear = () => {\n if (isNull(props.defaultValue) || isUndefined(props.defaultValue)) {\n datetimeInternal.value = null\n datePickerValue.value = null\n timePickerValue.value = null\n emit('afterClear')\n return\n }\n datetimeInternal.value = parseModel(props.defaultValue, props.type, props.lastMinuteMoment)\n emit('afterClear')\n}\n\nconst close = () => {\n pickerOpened.value = false\n inputInstance.value?.focus()\n inputInstance.value?.blur()\n emit('onClose')\n emit('blur')\n}\n\nconst onTextFieldFocus = () => {\n emit('focus')\n}\n\nconst onTimePickerEnterKeyup = () => {\n pickerOpened.value = false\n}\n\nconst onFocusConfirm = () => {\n confirmRefButton.value?.focus()\n}\n\nconst onDatePickerUpdate = () => {\n if (props.type === 'date') {\n // The value travels through pre-flush watchers, so closing now would emit blur and release the\n // collab lock with the previous value still in the model.\n nextTick(close)\n return\n }\n timePickerInstance.value?.focusHour()\n}\n\nconst now = () => {\n datetimeInternal.value = todayValue(props.type, props.lastMinuteMoment)\n nextTick(() => {\n // Vuetify navigates the calendar to a new value on its own, but skips an unchanged day, so a\n // value that is already today would leave the user on whatever month they paged to.\n pickerKey.value++\n timeKey.value++\n })\n}\n</script>\n\n<template>\n <VTextField\n ref=\"inputInstance\"\n v-model=\"textFieldValue\"\n :error-messages=\"errorMessageComputed\"\n :persistent-placeholder=\"true\"\n :placeholder=\"placeholderComputed\"\n class=\"a-datetime-picker\"\n :hide-details=\"hideDetails ? true : 'auto'\"\n :data-cy=\"dataCy.length ? dataCy : undefined\"\n :disabled=\"disabled\"\n autocomplete=\"off\"\n @blur=\"onTextFieldBlur\"\n @focus=\"onTextFieldFocus\"\n @keyup.enter=\"onTextFieldBlur\"\n >\n <template #append-inner>\n <VIcon\n v-if=\"clearable && defaultValue !== modelValue\"\n class=\"a-datetime-picker__clearable-icon\"\n icon=\"mdi-close-circle\"\n @click.stop=\"onClear\"\n />\n <VMenu\n v-if=\"!disabled\"\n location=\"bottom end\"\n origin=\"top end\"\n :close-on-content-click=\"false\"\n :model-value=\"pickerOpened\"\n @update:model-value=\"(value: boolean) => (pickerOpened = value)\"\n >\n <template #activator=\"{ props: menuProps }\">\n <VIcon\n class=\"a-datetime-picker__calendar-icon\"\n icon=\"mdi-calendar\"\n size=\"small\"\n v-bind=\"menuProps\"\n />\n </template>\n\n <VCard v-if=\"pickerOpened\">\n <VBtn\n v-tooltip=\"t('common.button.close')\"\n icon\n variant=\"text\"\n :width=\"36\"\n :height=\"36\"\n class=\"position-absolute top-0 right-0\"\n @click.stop=\"close\"\n >\n <VIcon\n icon=\"mdi-close\"\n color=\"white\"\n />\n </VBtn>\n <VDatePicker\n :key=\"pickerKey\"\n v-model=\"datePickerValue\"\n class=\"a-datetime-picker-calendar\"\n color=\"primary\"\n show-adjacent-months\n v-bind=\"$attrs\"\n @update:model-value=\"onDatePickerUpdate\"\n />\n <TimePicker\n v-if=\"type !== 'date'\"\n ref=\"timePickerInstance\"\n :key=\"timeKey\"\n v-model=\"timePickerValue\"\n @on-enter-keyup=\"onTimePickerEnterKeyup\"\n @focus-confirm=\"onFocusConfirm\"\n />\n <div class=\"d-flex\">\n <button\n v-if=\"!hideSetToNow\"\n type=\"button\"\n class=\"a-datetime-picker__bottom-button\"\n tabindex=\"8\"\n @click=\"now\"\n >\n {{ type === 'date' ? t('common.time.today') : t('common.time.now') }}\n </button>\n <button\n ref=\"confirmRefButton\"\n type=\"button\"\n class=\"a-datetime-picker__bottom-button\"\n tabindex=\"7\"\n @click.stop=\"close\"\n >\n {{ t('common.button.confirm') }}\n </button>\n </div>\n </VCard>\n </VMenu>\n\n <div class=\"ml-1\">\n <slot name=\"append-inner\" />\n </div>\n </template>\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ label\n }}<span\n v-if=\"required\"\n class=\"required\"\n />\n </template>\n </VTextField>\n</template>\n\n<style lang=\"scss\" scoped>\n.a-datetime-picker {\n :deep(.v-field__append-inner .v-icon) {\n cursor: pointer;\n }\n\n &__calendar-icon {\n margin-top: 2px;\n opacity: 0.6 !important;\n }\n\n &__clearable-icon {\n opacity: 0 !important;\n }\n\n &:hover {\n .a-datetime-picker__clearable-icon {\n opacity: 0.6 !important;\n }\n }\n\n &__bottom-button {\n width: 100%;\n text-align: center;\n font-size: 0.86rem;\n font-family: Roboto, sans-serif;\n font-weight: bold;\n line-height: 1.8;\n padding: 6px 0;\n\n &:hover {\n background-color: rgb(0 0 0 / 5%);\n }\n }\n}\n\n.a-datetime-picker-calendar {\n :deep(.v-picker-title) {\n display: none;\n }\n\n :deep(.v-date-picker-header) {\n padding-top: 12px;\n }\n\n :deep(.v-date-picker-month) {\n padding-bottom: 2px;\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport { computed, inject, nextTick, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport type { DatetimeUTCNullable, IntegerIdNullable } from '@/types/common'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\nimport ADatetimePicker from '@/components/datetime/ADatetimePicker.vue'\nimport type { DatetimePickerType } from '@/utils/datetimePickerValue'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: DatetimeUTCNullable | undefined\n type?: DatetimePickerType\n label?: string\n errorMessage?: string\n required?: boolean\n v?: any\n dataCy?: string\n clearable?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean\n }>(),\n {\n type: 'datetime',\n label: undefined,\n errorMessage: undefined,\n required: undefined,\n v: null,\n dataCy: undefined,\n clearable: false,\n collab: undefined,\n disabled: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: DatetimeUTCNullable | undefined): void\n (e: 'click:append', data: string | number | null | undefined): void\n (e: 'blur', data: string | number | null | undefined): void\n (e: 'focus', data: string | number | null | undefined): void\n}>()\n\nconst modelValueComputed = computed({\n get() {\n return props.modelValue\n },\n set(newValue: DatetimeUTCNullable | undefined) {\n emit('update:modelValue', newValue)\n },\n})\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst changeFieldData = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, changeCollabFieldData, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n changeFieldData.value = changeCollabFieldData\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst isOpened = ref(false)\nconst isFocused = ref(false)\n\nconst onOpen = () => {\n isOpened.value = true\n acquireFieldLock.value()\n}\n\nconst onClose = () => {\n isOpened.value = false\n // The picker emits close before its watchers flush the picked value into the model.\n nextTick(() => {\n releaseFieldLock.value(props.modelValue)\n })\n}\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onBlur = () => {\n props.v?.$touch()\n // The picker commits a typed value in a watcher that runs after this event, so releasing the lock\n // here would hand the room the previous value - and clearing `isFocused` would skip the change.\n nextTick(() => {\n isFocused.value = false\n emit('blur', isUndefined(props.modelValue) ? null : props.modelValue)\n if (isOpened.value === false) releaseFieldLock.value(props.modelValue)\n })\n}\n\nconst onFocus = () => {\n isFocused.value = true\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return [props.v.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n if (props.v?.required && props.v?.required.$params.type === 'required') return true\n return false\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nwatch(modelValueComputed, (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (collabOptions.value.enabled && (isFocused.value || isOpened.value)) {\n changeFieldData.value(newValue)\n }\n})\n</script>\n\n<template>\n <ADatetimePicker\n v-model=\"modelValueComputed\"\n :type=\"type\"\n :data-cy=\"dataCy\"\n :error-messages=\"errorMessageComputed\"\n :required=\"requiredComputed\"\n :disabled=\"disabledComputed\"\n :label=\"labelComputed\"\n :clearable=\"clearable\"\n v-bind=\"$attrs\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @on-open=\"onOpen\"\n @on-close=\"onClose\"\n >\n <template #append-inner>\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n </ADatetimePicker>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject, nextTick, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport type { DatetimeUTCNullable, IntegerIdNullable } from '@/types/common'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\nimport ADatetimePicker from '@/components/datetime/ADatetimePicker.vue'\nimport type { DatetimePickerType } from '@/utils/datetimePickerValue'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: DatetimeUTCNullable | undefined\n type?: DatetimePickerType\n label?: string\n errorMessage?: string\n required?: boolean\n v?: any\n dataCy?: string\n clearable?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean\n }>(),\n {\n type: 'datetime',\n label: undefined,\n errorMessage: undefined,\n required: undefined,\n v: null,\n dataCy: undefined,\n clearable: false,\n collab: undefined,\n disabled: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: DatetimeUTCNullable | undefined): void\n (e: 'click:append', data: string | number | null | undefined): void\n (e: 'blur', data: string | number | null | undefined): void\n (e: 'focus', data: string | number | null | undefined): void\n}>()\n\nconst modelValueComputed = computed({\n get() {\n return props.modelValue\n },\n set(newValue: DatetimeUTCNullable | undefined) {\n emit('update:modelValue', newValue)\n },\n})\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst changeFieldData = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, changeCollabFieldData, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n changeFieldData.value = changeCollabFieldData\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst isOpened = ref(false)\nconst isFocused = ref(false)\n\nconst onOpen = () => {\n isOpened.value = true\n acquireFieldLock.value()\n}\n\nconst onClose = () => {\n isOpened.value = false\n // The picker emits close before its watchers flush the picked value into the model.\n nextTick(() => {\n releaseFieldLock.value(props.modelValue)\n })\n}\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onBlur = () => {\n props.v?.$touch()\n // The picker commits a typed value in a watcher that runs after this event, so releasing the lock\n // here would hand the room the previous value - and clearing `isFocused` would skip the change.\n nextTick(() => {\n isFocused.value = false\n emit('blur', isUndefined(props.modelValue) ? null : props.modelValue)\n if (isOpened.value === false) releaseFieldLock.value(props.modelValue)\n })\n}\n\nconst onFocus = () => {\n isFocused.value = true\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return [props.v.$errors.map((item: ErrorObject) => item.$message).join(' ')]\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n if (props.v?.required && props.v?.required.$params.type === 'required') return true\n return false\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nwatch(modelValueComputed, (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (collabOptions.value.enabled && (isFocused.value || isOpened.value)) {\n changeFieldData.value(newValue)\n }\n})\n</script>\n\n<template>\n <ADatetimePicker\n v-model=\"modelValueComputed\"\n :type=\"type\"\n :data-cy=\"dataCy\"\n :error-messages=\"errorMessageComputed\"\n :required=\"requiredComputed\"\n :disabled=\"disabledComputed\"\n :label=\"labelComputed\"\n :clearable=\"clearable\"\n v-bind=\"$attrs\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @on-open=\"onOpen\"\n @on-close=\"onClose\"\n >\n <template #append-inner>\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n </ADatetimePicker>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, ref, watch } from 'vue'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport { isDefined } from '@/utils/common'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport type { IntegerIdNullable } from '@/types/common'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n label?: string\n dataCy?: string\n hideLabel?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean\n }>(),\n {\n label: undefined,\n dataCy: undefined,\n hideLabel: false,\n collab: undefined,\n disabled: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: boolean): void\n (e: 'blur', data: boolean): void\n (e: 'focus', data: boolean): void\n}>()\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst onClick = () => {\n acquireFieldLock.value()\n setTimeout(() => {\n releaseFieldLock.value(props.modelValue)\n }, 500)\n}\n\nconst onUpdate = (newValue: boolean) => {\n emit('update:modelValue', newValue)\n}\nconst onBlur = () => {\n emit('blur', props.modelValue)\n releaseFieldLock.value(props.modelValue)\n}\n\nconst onFocus = () => {\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n</script>\n\n<template>\n <VSwitch\n :data-cy=\"dataCy\"\n :model-value=\"modelValue\"\n :disabled=\"disabledComputed\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @update:model-value=\"onUpdate($event as unknown as boolean)\"\n @click.stop=\"onClick\"\n >\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ label }}\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n </VSwitch>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, ref, watch } from 'vue'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport { isDefined } from '@/utils/common'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport type { IntegerIdNullable } from '@/types/common'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n label?: string\n dataCy?: string\n hideLabel?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean\n }>(),\n {\n label: undefined,\n dataCy: undefined,\n hideLabel: false,\n collab: undefined,\n disabled: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: boolean): void\n (e: 'blur', data: boolean): void\n (e: 'focus', data: boolean): void\n}>()\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst onClick = () => {\n acquireFieldLock.value()\n setTimeout(() => {\n releaseFieldLock.value(props.modelValue)\n }, 500)\n}\n\nconst onUpdate = (newValue: boolean) => {\n emit('update:modelValue', newValue)\n}\nconst onBlur = () => {\n emit('blur', props.modelValue)\n releaseFieldLock.value(props.modelValue)\n}\n\nconst onFocus = () => {\n emit('focus', props.modelValue)\n acquireFieldLock.value()\n}\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n</script>\n\n<template>\n <VSwitch\n :data-cy=\"dataCy\"\n :model-value=\"modelValue\"\n :disabled=\"disabledComputed\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @update:model-value=\"onUpdate($event as unknown as boolean)\"\n @click.stop=\"onClick\"\n >\n <template\n v-if=\"!hideLabel\"\n #label\n >\n {{ label }}\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n </VSwitch>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport { isUndefined } from '@/utils/common'\n\nconst props = withDefaults(\n defineProps<{\n color?: string | undefined\n size?: string\n dataCy?: string | undefined\n }>(),\n {\n color: undefined,\n size: 'small',\n dataCy: undefined,\n }\n)\n\nconst customColorClass = computed(() => {\n return isUndefined(props.color) ? 'a-chip-no-link--custom-color' : ''\n})\n</script>\n\n<template>\n <VChip\n :color=\"color as string\"\n :data-cy=\"dataCy\"\n class=\"a-chip-no-link\"\n :class=\"customColorClass\"\n label\n :size=\"size as string\"\n >\n <slot />\n </VChip>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport { isUndefined } from '@/utils/common'\n\nconst props = withDefaults(\n defineProps<{\n color?: string | undefined\n size?: string\n dataCy?: string | undefined\n }>(),\n {\n color: undefined,\n size: 'small',\n dataCy: undefined,\n }\n)\n\nconst customColorClass = computed(() => {\n return isUndefined(props.color) ? 'a-chip-no-link--custom-color' : ''\n})\n</script>\n\n<template>\n <VChip\n :color=\"color as string\"\n :data-cy=\"dataCy\"\n class=\"a-chip-no-link\"\n :class=\"customColorClass\"\n label\n :size=\"size as string\"\n >\n <slot />\n </VChip>\n</template>\n","import { ref } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\n\nexport const LogLevel = {\n Debug: 'DEBUG',\n Info: 'INFO',\n Notice: 'NOTICE',\n Warning: 'WARNING',\n Error: 'ERROR',\n Critical: 'CRITICAL',\n Alert: 'ALERT',\n Emergency: 'EMERGENCY',\n} as const\nexport type LogLevelType = (typeof LogLevel)[keyof typeof LogLevel]\nexport const LogLevelDefault = LogLevel.Info\n\nexport function useLogLevel() {\n const logLevelOptions = ref<ValueObjectOption<LogLevelType>[]>([\n {\n value: LogLevel.Debug,\n title: LogLevel.Debug,\n color: 'blue-grey lighten-5',\n },\n {\n value: LogLevel.Info,\n title: LogLevel.Info,\n color: 'blue-grey lighten-3',\n },\n {\n value: LogLevel.Notice,\n title: LogLevel.Notice,\n color: 'amber lighten-4',\n },\n {\n value: LogLevel.Warning,\n title: LogLevel.Warning,\n color: 'amber',\n },\n {\n value: LogLevel.Error,\n title: LogLevel.Error,\n color: 'red',\n },\n {\n value: LogLevel.Critical,\n title: LogLevel.Critical,\n color: 'red accent-4',\n },\n {\n value: LogLevel.Alert,\n title: LogLevel.Alert,\n color: 'pink',\n },\n {\n value: LogLevel.Emergency,\n title: LogLevel.Emergency,\n color: 'ping darken-4',\n },\n ])\n\n const getLogLevelOption = (value: LogLevelType) => {\n return logLevelOptions.value.find((item) => item.value === value)\n }\n\n return {\n logLevelOptions,\n getLogLevelOption,\n }\n}\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport AChipNoLink from '@/components/AChipNoLink.vue'\nimport { type LogLevelType, useLogLevel } from '@/model/valueObject/LogLevel'\n\nconst props = withDefaults(\n defineProps<{\n level: LogLevelType\n }>(),\n {}\n)\n\nconst { getLogLevelOption } = useLogLevel()\nconst levelOption = computed(() => {\n return getLogLevelOption(props.level)\n})\n</script>\n\n<template>\n <AChipNoLink\n v-if=\"levelOption\"\n :color=\"levelOption.color\"\n >\n {{ levelOption.title }}\n </AChipNoLink>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed } from 'vue'\nimport AChipNoLink from '@/components/AChipNoLink.vue'\nimport { type LogLevelType, useLogLevel } from '@/model/valueObject/LogLevel'\n\nconst props = withDefaults(\n defineProps<{\n level: LogLevelType\n }>(),\n {}\n)\n\nconst { getLogLevelOption } = useLogLevel()\nconst levelOption = computed(() => {\n return getLogLevelOption(props.level)\n})\n</script>\n\n<template>\n <AChipNoLink\n v-if=\"levelOption\"\n :color=\"levelOption.color\"\n >\n {{ levelOption.title }}\n </AChipNoLink>\n</template>\n","export const numberToString = (value: number): string => {\n return '' + value\n}\n","<script lang=\"ts\" setup>\nimport { useClipboard } from '@vueuse/core'\nimport { eventClickBlur } from '@/utils/event'\nimport { isNumber, isString } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { useAlerts } from '@/composables/system/alerts'\nimport { numberToString } from '@/utils/number'\nimport { withModifiers } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n value: number | string\n notifyT?: string\n tooltipT?: string\n dataCy?: string\n }>(),\n {\n notifyT: 'common.alert.textWasCopied',\n tooltipT: 'common.button.copy',\n dataCy: 'copy-text',\n }\n)\n\nconst { copy, isSupported } = useClipboard()\nconst { showSuccess } = useAlerts()\nconst { t } = useI18n()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n if (!isSupported) return\n if (isNumber(props.value)) {\n copy(numberToString(props.value)).then(() => {\n showSuccess(t(props.notifyT))\n })\n } else if (isString(props.value) && props.value.length) {\n copy(props.value).then(() => {\n showSuccess(t(props.notifyT))\n })\n }\n}\n</script>\n\n<template>\n <slot\n name=\"activator\"\n :props=\"{\n onClick: withModifiers((e) => onClick(e), ['stop']),\n disabled: !isSupported,\n }\"\n >\n <div\n :class=\"{ 'cursor-pointer': isSupported }\"\n :data-cy=\"dataCy\"\n class=\"d-inline-flex align-center anzu-copy-text\"\n @click.stop=\"onClick\"\n >\n <span>{{ value }}</span>\n <VIcon\n v-if=\"isSupported\"\n class=\"ml-1\"\n size=\"x-small\"\n icon=\"mdi-content-copy\"\n />\n <VTooltip\n v-if=\"tooltipT\"\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </div>\n </slot>\n</template>\n\n<style lang=\"scss\">\n.anzu-copy-text {\n .v-icon {\n opacity: 0;\n }\n\n &:hover {\n .v-icon {\n opacity: 1;\n }\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport { useClipboard } from '@vueuse/core'\nimport { eventClickBlur } from '@/utils/event'\nimport { isNumber, isString } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { useAlerts } from '@/composables/system/alerts'\nimport { numberToString } from '@/utils/number'\nimport { withModifiers } from 'vue'\n\nconst props = withDefaults(\n defineProps<{\n value: number | string\n notifyT?: string\n tooltipT?: string\n dataCy?: string\n }>(),\n {\n notifyT: 'common.alert.textWasCopied',\n tooltipT: 'common.button.copy',\n dataCy: 'copy-text',\n }\n)\n\nconst { copy, isSupported } = useClipboard()\nconst { showSuccess } = useAlerts()\nconst { t } = useI18n()\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n if (!isSupported) return\n if (isNumber(props.value)) {\n copy(numberToString(props.value)).then(() => {\n showSuccess(t(props.notifyT))\n })\n } else if (isString(props.value) && props.value.length) {\n copy(props.value).then(() => {\n showSuccess(t(props.notifyT))\n })\n }\n}\n</script>\n\n<template>\n <slot\n name=\"activator\"\n :props=\"{\n onClick: withModifiers((e) => onClick(e), ['stop']),\n disabled: !isSupported,\n }\"\n >\n <div\n :class=\"{ 'cursor-pointer': isSupported }\"\n :data-cy=\"dataCy\"\n class=\"d-inline-flex align-center anzu-copy-text\"\n @click.stop=\"onClick\"\n >\n <span>{{ value }}</span>\n <VIcon\n v-if=\"isSupported\"\n class=\"ml-1\"\n size=\"x-small\"\n icon=\"mdi-content-copy\"\n />\n <VTooltip\n v-if=\"tooltipT\"\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </div>\n </slot>\n</template>\n\n<style lang=\"scss\">\n.anzu-copy-text {\n .v-icon {\n opacity: 0;\n }\n\n &:hover {\n .v-icon {\n opacity: 1;\n }\n }\n}\n</style>\n","import { ref } from 'vue'\n\n// The page is remembered per table. A single global slot used to leak across entities: paging\n// list B to page 5, closing any detail and then opening list A reopened A on page 5, because\n// both the stored page and the preserve flag were shared. The flag stays global on purpose —\n// it means \"the next list I land on should restore its page\" — but the page itself is keyed.\nconst storedPages = ref<Record<string, number>>({})\nconst preservePage = ref<boolean>(false)\n\nconst UNSCOPED_KEY = '__unscoped'\n\nexport const datatablePageKey = (system?: unknown, subject?: unknown): string =>\n typeof system === 'string' && typeof subject === 'string' ? `${system}_${subject}` : UNSCOPED_KEY\n\nexport function useDatatablePageStore() {\n const setStoredPage = (key: string, page: number) => {\n storedPages.value[key] = page\n }\n\n const setPreservePage = () => {\n preservePage.value = true\n }\n\n const consumeStoredPage = (key: string): number | null => {\n if (!preservePage.value) return null\n preservePage.value = false\n return storedPages.value[key] ?? null\n }\n\n return {\n setStoredPage,\n setPreservePage,\n consumeStoredPage,\n }\n}\n","import type { InjectionKey, Ref } from 'vue'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport type { Pagination } from '@/labs/filters/pagination'\n\nexport const FilterDataKey: InjectionKey<FilterData> = Symbol.for('anzu:FilterDataKey')\nexport const FilterConfigKey: InjectionKey<FilterConfig> = Symbol.for('anzu:FilterConfigKey')\n\nexport const FilterInnerDataKey: InjectionKey<FilterData> = Symbol.for('anzu:FilterInnerDataKey')\nexport const FilterInnerConfigKey: InjectionKey<FilterConfig> = Symbol.for('anzu:FilterInnerConfigKey')\n\nexport const FilterSubmitResetCounterKey: InjectionKey<Ref<number>> = Symbol.for('anzu:FilterSubmitResetCounterKey')\nexport const FilterSelectedKey: InjectionKey<Ref<Map<string, ValueObjectOption<string | number>[]>>> =\n Symbol.for('anzu:FilterSelectedKey')\n\nexport const DatatablePaginationKey: InjectionKey<Ref<Pagination>> = Symbol.for('anzu:DatatablePaginationKey')\n\nexport const SubjectSelectCloseSidebarKey: InjectionKey<() => void> = Symbol.for('anzu:SubjectSelectCloseSidebarKey')\n\n// The key a datatable stores its remembered page under. Provided by `useFilterHelpers` so that\n// `ADatatablePagination` writes under the same key `loadStoredFilters` reads — several tables can\n// share one system/subject (cms has seven for `cms/article`), and they tell themselves apart by\n// overriding `storeFiltersLocalStorage`.\nexport const DatatablePageStoreKey: InjectionKey<string> = Symbol.for('anzu:DatatablePageStoreKey')\n","import { getCurrentInstance, provide, reactive, type Ref, toRaw } from 'vue'\nimport { datatablePageKey, useDatatablePageStore } from '@/composables/system/datatablePageStore'\nimport { DatatablePageStoreKey } from '@/labs/filters/filterInjectionKeys'\nimport {\n cloneDeep,\n isArray,\n isBoolean,\n isEmptyArray,\n isEmptyObject,\n isNull,\n isNumber,\n isObject,\n isString,\n isUndefined,\n} from '@/utils/common'\nimport type { AnyFn } from '@vueuse/core'\nimport type { Pagination } from '@/labs/filters/pagination'\nimport { type DatatableSortBy, SortOrder } from '@/composables/system/datatableColumns'\nimport { stringToBooleanExact, stringToNumber } from '@/utils/string'\nimport type { ValueObjectOption } from '@/types/ValueObject'\n\nexport type FilterStoreIdentifier = { system: string; subject: string }\n\nconst SORT_URL_PARAM = '_sort'\nconst END_FILTER_MARKER = '~'\n\n// `URLSearchParams` percent-encodes characters a URL fragment accepts verbatim, and vue-router\n// then runs `encodeURI` over the hash, which escapes the `%` a second time — `_sort=id%2Cdesc`\n// arrives as `id%252Cdesc` and the sort is silently lost. Handing these back keeps a built hash\n// stable through `router.push({ hash })`. `~` stays encoded because the end marker relies on it\n// never occurring inside a value; `&`, `=` carry the structure, `+` reads back as a space.\nconst RELAXED_IN_HASH: Record<string, string> = {\n '%2C': ',',\n '%3A': ':',\n '%2F': '/',\n '%40': '@',\n '%24': '$',\n '%21': '!',\n '%27': \"'\",\n '%28': '(',\n '%29': ')',\n '%3B': ';',\n '%3F': '?',\n}\nconst relaxHashEncoding = (value: string) =>\n value.replace(/%(2C|3A|2F|40|24|21|27|28|29|3B|3F)/g, (match) => RELAXED_IN_HASH[match])\n\n// `structuredClone` gives every array default a fresh identity, so `!==` is always true for them\n// and an array default would be written into the url on every submit.\nconst isSameFilterValue = (a: AllowedFilterValues, b: AllowedFilterValues): boolean => {\n if (isArray(a) && isArray(b)) {\n return a.length === b.length && a.every((item, index) => item === b[index])\n }\n return a === b\n}\n\nconst encodeFilterHash = (data: Record<string, AllowedFilterValues>, sortBy?: DatatableSortBy): string => {\n const params = new URLSearchParams()\n for (const key in data) {\n const value = data[key]\n if (isUndefined(value) || isNull(value)) continue\n if (isArray(value) && isEmptyArray(value)) continue\n if (isObject(value) && isEmptyObject(value)) continue\n if (isString(value) && value.length === 0) continue\n params.set(key, isArray(value) ? value.join(',') : String(value))\n }\n if (sortBy) {\n params.set(SORT_URL_PARAM, `${sortBy.key},${sortBy.order}`)\n }\n if (params.size === 0) return ''\n return relaxHashEncoding(params.toString()) + END_FILTER_MARKER\n}\n\n/**\n * Hash for a filter link, with values equal to their default left out.\n *\n * Pair it with `router.push({ name, hash })`, which needs the leading `#` — without it vue-router\n * glues the value onto the path instead. A hash still containing `%` (diacritics, `&`, `=`) does\n * not survive that trip; check with `isRouterSafeHash` and fall back to assigning\n * `window.location.hash` after navigating. Returns an empty string when nothing differs from\n * the defaults.\n */\nexport function buildFilterHash<F extends readonly MakeFilterOption<string>[]>(\n filterConfig: FilterConfig<F>,\n filters: Partial<Record<keyof FilterData<F> & string, AllowedFilterValues>>,\n sortBy?: DatatableSortBy\n): string {\n const data: Record<string, AllowedFilterValues> = {}\n for (const [key, value] of Object.entries(filters) as [string, AllowedFilterValues][]) {\n const field = filterConfig.fields[key as keyof FilterConfig<F>['fields']]\n if (isUndefined(field) || isSameFilterValue(value, field.default)) continue\n data[key] = value\n }\n const hash = encodeFilterHash(data, sortBy)\n return hash.length === 0 ? hash : '#' + hash\n}\n\n/** Whether `router.push({ hash })` would leave the hash intact — see `buildFilterHash`. */\nexport const isRouterSafeHash = (hash: string): boolean => !hash.includes('%')\n\nconst defaultRenderOptions: FilerRenderOptions = {\n skip: false,\n selected: true,\n xs: undefined,\n sm: undefined,\n md: undefined,\n lg: undefined,\n xl: undefined,\n}\n\nexport function createFilterStore<F extends readonly MakeFilterOption<string>[]>(filterFields: F): FilterData<F> {\n return reactive(\n filterFields.reduce((acc, field) => {\n return {\n ...acc,\n [field.name]: cloneDeep(field.default),\n }\n }, {} as FilterData<F>)\n ) as FilterData<F>\n}\n\nexport function createFilter<F extends readonly MakeFilterOption<string>[]>(\n filterFields: F,\n store: FilterData<F>,\n options?: Partial<GeneralFilterOptions>\n): {\n filterConfig: FilterConfig<F>\n filterData: FilterData<F>\n} {\n const config = filterFields.reduce(\n (acc, filter) => {\n const key = filter.name as keyof FilterData<F>\n const defaultValue = cloneDeep(filter.default)\n\n return {\n ...acc,\n [key]: {\n name: key as string,\n variant: resolveValue(filter.variant, 'eq'),\n type: resolveValue(filter.type, 'custom'),\n titleT:\n filter.titleT ??\n (options?.system && options?.subject && filter.name\n ? `${options.system}.${options.subject}.filter.${filter.name}`\n : undefined),\n apiName: resolveValue(filter.apiName, filter.name),\n clearable: resolveValue(filter.clearable, true),\n mandatory: resolveValue(filter.mandatory, false),\n multiple: isArray(defaultValue),\n advanced: resolveValue(filter.advanced, false),\n related: resolveValue(filter.related, undefined),\n exclude: resolveValue(filter.exclude, false),\n default: defaultValue,\n render: { ...defaultRenderOptions, ...resolveValue(filter.render, {}) },\n },\n }\n },\n {} as FilterConfig<F>['fields']\n )\n\n const defaultGlobalOptions: GeneralFilterOptions = {\n elastic: false,\n system: undefined,\n subject: undefined,\n simpleFilters: false,\n ...options,\n }\n\n if (defaultGlobalOptions.elastic) {\n defaultGlobalOptions.simpleFilters = true\n }\n\n const filterConfig = reactive({\n general: defaultGlobalOptions,\n touched: false,\n fields: config,\n }) as FilterConfig<F>\n\n return {\n filterConfig,\n filterData: store as FilterData<F>,\n }\n}\n\nfunction resolveValue<T>(value: T | undefined, fallback: T): T {\n return isUndefined(value) ? fallback : value\n}\n\nexport function useFilterClearHelpers<\n F extends readonly MakeFilterOption<string>[] = readonly MakeFilterOption<string>[],\n>() {\n const clearOne = (name: keyof FilterData<F>, filterData: FilterData<F>, filterConfig: FilterConfig<F>) => {\n if (!filterConfig.fields[name]?.clearable) return\n filterData[name] = cloneDeep(filterConfig.fields[name].default)\n }\n\n const clearAll = (filterData: FilterData<F>, filterConfig: FilterConfig<F>) => {\n for (const filterName in filterConfig.fields) {\n clearOne(filterName as keyof FilterData<F>, filterData, filterConfig)\n }\n }\n const clearOneFilterSelected = (\n name: string,\n optionValue: number | string,\n filterData: FilterData<F>,\n filterConfig: FilterConfig<F>,\n filterSelected: Ref<Map<string, ValueObjectOption<string | number>[]>>\n ) => {\n if (!isClearable(name, filterConfig)) return\n // update selected\n const config = filterConfig.fields[name as keyof FilterConfig<F>['fields']]\n const selectedFound = filterSelected.value.get(name)\n if (selectedFound && selectedFound.length === 1) {\n filterSelected.value.delete(name)\n } else if (selectedFound) {\n const foundIndex = selectedFound.findIndex((item) => item.value === optionValue)\n selectedFound.splice(foundIndex, 1)\n }\n // update data\n if (config.type === 'timeInterval' && config.related) {\n filterData[name as keyof FilterData<F>] = config.default\n filterData[config.related as keyof FilterData<F>] =\n filterConfig.fields[config.related as keyof FilterConfig<F>['fields']].default\n } else if (\n isArray(filterData[name as keyof FilterData<F>]) &&\n (filterData[name as keyof FilterData<F>] as any[]).length > 0\n ) {\n const foundIndex = (filterData[name as keyof FilterData<F>] as any[]).findIndex((item) => item === optionValue)\n const newArray = [...toRaw(filterData[name as keyof FilterData<F>] as any[])]\n newArray.splice(foundIndex, 1)\n filterData[name as keyof FilterData<F>] = newArray as AllowedFilterValues\n } else if (isString(filterData[name as keyof FilterData<F>]) || isNumber(filterData[name as keyof FilterData<F>])) {\n filterData[name as keyof FilterData<F>] = config.default\n } else if (isBoolean(filterData[name as keyof FilterData<F>])) {\n filterData[name as keyof FilterData<F>] = config.default\n }\n }\n\n const clearAllFilterSelected = (\n filterData: FilterData<F>,\n filterConfig: FilterConfig<F>,\n filterSelected: Ref<Map<string, ValueObjectOption<string | number>[]>>\n ) => {\n for (const key of filterSelected.value.keys()) {\n if (isClearable(key, filterConfig)) {\n filterSelected.value.delete(key)\n }\n }\n }\n\n const isClearable = (name: string, filterConfig: FilterConfig<F>) => {\n const config = filterConfig.fields[name as keyof FilterConfig<F>['fields']]\n return !(config.mandatory || !config.clearable)\n }\n\n return {\n clearOne,\n clearAll,\n clearOneFilterSelected,\n clearAllFilterSelected,\n isClearable,\n }\n}\n\ninterface FilterHelpersMoreOptions {\n storeFiltersLocalStorage: string | boolean // false to disable, string to override store key\n populateUrlParams: boolean\n}\n\nconst FilterHelpersMoreOptionsDefault = {\n storeFiltersLocalStorage: true,\n populateUrlParams: true,\n}\n\nexport function useFilterHelpers<F extends readonly MakeFilterOption<string>[] = readonly MakeFilterOption<string>[]>(\n filterData: FilterData<F>,\n filterConfig: FilterConfig<F>,\n moreOptions: Partial<FilterHelpersMoreOptions> = {}\n) {\n const options = { ...FilterHelpersMoreOptionsDefault, ...moreOptions }\n\n let storeKey: undefined | string = undefined\n if (isString(options.storeFiltersLocalStorage)) {\n storeKey = options.storeFiltersLocalStorage\n } else if (\n isBoolean(options.storeFiltersLocalStorage) &&\n true === options.storeFiltersLocalStorage &&\n isString(filterConfig.general.system) &&\n isString(filterConfig.general.subject)\n ) {\n storeKey = 'tableFilter_' + filterConfig.general.system + '_' + filterConfig.general.subject\n }\n\n // Independent of `storeFiltersLocalStorage` being on: the remembered page is keyed even when\n // filters are not persisted. A string override is what distinguishes tables sharing a subject.\n const pageStoreKey = isString(options.storeFiltersLocalStorage)\n ? options.storeFiltersLocalStorage\n : datatablePageKey(filterConfig.general.system, filterConfig.general.subject)\n // Called from a datatable's setup, so `ADatatablePagination` picks it up. Guarded because a\n // composable may legitimately be called outside setup, and Vue would warn.\n if (getCurrentInstance()) {\n provide(DatatablePageStoreKey, pageStoreKey)\n }\n\n const { clearAll } = useFilterClearHelpers<F>()\n\n const getFilterDataForStoring = (): Record<string, AllowedFilterValues> => {\n const data: Record<string, AllowedFilterValues> = {}\n for (const filterName in filterData) {\n try {\n const key = filterName as keyof FilterData<F>\n const value = filterData[key]\n if (\n !isUndefined(value) &&\n !isNull(value) &&\n !isEmptyArray(value) &&\n !isSameFilterValue(value, filterConfig.fields[key].default)\n ) {\n data[filterName] = value\n }\n } catch (e) {\n // Ignore errors\n }\n }\n return data\n }\n\n const serializeFilters = (\n data: Record<string, AllowedFilterValues>,\n pagination: Ref<Pagination>,\n includeSort: boolean\n ): string => {\n return encodeFilterHash(data, includeSort ? pagination.value.sortBy : undefined)\n }\n\n const deserializeFilters = (\n hash: string\n ): { filters: Record<string, AllowedFilterValues>; sortBy: DatatableSortBy } | null => {\n if (!hash) return null\n if (hash.startsWith('#')) hash = hash.substring(1)\n\n // URLSearchParams percent-encodes `~` in values, so the marker cannot occur inside our own\n // data — a hash without it is foreign or truncated, and null lets localStorage take over.\n const markerIndex = hash.indexOf(END_FILTER_MARKER)\n if (markerIndex === -1) return null\n hash = hash.slice(0, markerIndex)\n\n const params = new URLSearchParams(hash)\n const result: Record<string, AllowedFilterValues> = {}\n let sortBy: DatatableSortBy = null\n\n const sortParam = params.get(SORT_URL_PARAM)\n if (sortParam) {\n const [key, order] = sortParam.split(',')\n if (key && (order === SortOrder.Asc || order === SortOrder.Desc)) {\n sortBy = { key, order }\n }\n params.delete(SORT_URL_PARAM)\n }\n\n for (const [key, value] of params.entries()) {\n const fieldConfig = filterConfig.fields[key as keyof typeof filterConfig.fields]\n if (isUndefined(fieldConfig)) {\n console.error(`Filter config not found for ${key}`)\n continue\n }\n const isMultiple = fieldConfig.multiple ?? false\n\n if (isMultiple) {\n const items = value.split(',')\n\n const allNumeric = items.every((item) => !isNaN(Number(item)))\n\n result[key] = allNumeric ? items.map(Number) : items\n } else {\n result[key] = value\n }\n }\n\n // An empty result would still count as \"found\", shadowing localStorage.\n if (isEmptyObject(result) && isNull(sortBy)) return null\n\n return { filters: result, sortBy }\n }\n\n const updateLocationHash = (serialized: string) => {\n if (options.populateUrlParams === false) return\n window.location.hash = serialized\n }\n\n const resetLocationHash = () => {\n if (options.populateUrlParams === false) return\n window.location.hash = ''\n }\n\n const parseLocationHash = () => {\n if (options.populateUrlParams === false) return null\n return deserializeFilters(window.location.hash)\n }\n\n const storeFilterLocalStorage = (serialized: string) => {\n if (!storeKey || !localStorage) return\n localStorage.setItem(storeKey, serialized)\n }\n\n const loadFilterLocalStorage = () => {\n if (!storeKey || !localStorage) return null\n const stored = localStorage.getItem(storeKey)\n if (!stored || !isString(stored)) return null\n return deserializeFilters(stored)\n }\n\n const resetFilter = (pagination: Ref<Pagination>, callback?: AnyFn) => {\n pagination.value = { ...pagination.value, page: 1 }\n if (storeKey && localStorage) {\n localStorage.removeItem(storeKey)\n }\n resetLocationHash()\n filterConfig.touched = false\n if (callback) callback()\n }\n\n const submitFilter = (pagination: Ref<Pagination>, callback?: AnyFn) => {\n const data = getFilterDataForStoring()\n const serialized = serializeFilters(data, pagination, true)\n updateLocationHash(serialized)\n storeFilterLocalStorage(serialized)\n pagination.value = { ...pagination.value, page: 1 }\n filterConfig.touched = false\n if (callback) callback()\n }\n\n const loadStoredFilters = (pagination: Ref<Pagination>, callback?: AnyFn) => {\n const { consumeStoredPage } = useDatatablePageStore()\n let source: 'hash' | 'localStorage' = 'hash'\n let storedFromHash = parseLocationHash()\n if (isNull(storedFromHash)) {\n source = 'localStorage'\n storedFromHash = loadFilterLocalStorage()\n }\n if (isNull(storedFromHash) || (isEmptyObject(storedFromHash.filters) && isNull(storedFromHash.sortBy))) {\n const restoredPage = consumeStoredPage(pageStoreKey)\n if (restoredPage !== null) {\n pagination.value = { ...pagination.value, page: restoredPage }\n }\n if (callback) callback()\n return false\n }\n\n // A hash naming at least one field is authoritative: it arrives from a link, or from stepping\n // back to an older address, and in both cases it describes the whole view. Without this reset\n // the fields it does not mention keep whatever the module-level filter store still holds from\n // an earlier visit, so the same link lands differently depending on how the user got to it.\n // On a fresh page load the store is already at its defaults and this is a no-op. Local storage\n // keeps merging, because there the absent fields were left out as equal to their default.\n //\n // A hash carrying only `_sort` is excluded on purpose. Unknown keys are dropped before this\n // point, so such a hash also results from a link meant for a different table sharing the page\n // - it must not wipe this one's filter. Only `clearable` fields are reset, as everywhere else.\n const hashDescribesThisView = source === 'hash' && !isEmptyObject(storedFromHash.filters)\n if (hashDescribesThisView) {\n clearAll(filterData, filterConfig)\n }\n\n for (const filterName in filterData) {\n const key = filterName as keyof FilterData<F>\n let value = storedFromHash.filters[key]\n if (isUndefined(value)) continue\n if (isString(value)) {\n const tryConvertNumber = stringToNumber(value)\n if (!isNull(tryConvertNumber)) {\n value = tryConvertNumber\n } else {\n const tryConvertBoolean = stringToBooleanExact(value)\n if (!isNull(tryConvertBoolean)) {\n value = tryConvertBoolean\n }\n }\n }\n filterData[key] = value\n }\n if (source === 'localStorage' && storeKey && localStorage) {\n const stored = localStorage.getItem(storeKey)\n if (stored) {\n updateLocationHash(stored)\n }\n }\n // Drained either way: the flag means \"the next list I land on should restore its page\", so\n // leaving it set would hand the remembered page to whichever table comes after this one.\n const restoredPage = consumeStoredPage(pageStoreKey)\n pagination.value = {\n ...pagination.value,\n // A link need not carry the sort. Taking `null` from it would drop `order[...]` from the\n // query, and paging without ORDER BY can repeat or skip rows.\n sortBy: storedFromHash.sortBy ?? pagination.value.sortBy,\n // A hash replaces the view, so a link starts at the first page. A restored page still wins:\n // the flag behind it is only ever set by the close button, which means \"I am coming back to\n // this list\", and that address carries the list's own hash along with it.\n page: restoredPage ?? (source === 'hash' ? 1 : pagination.value.page),\n }\n if (hashDescribesThisView) {\n // Local storage mirrors the last applied state, so a link becomes the view the user returns\n // to. Re-serialized rather than stored verbatim, to drop values equal to their default.\n // A sort-only hash is not a link to this view, so it does not overwrite what is remembered.\n storeFilterLocalStorage(serializeFilters(getFilterDataForStoring(), pagination, true))\n }\n if (callback) callback()\n return true\n }\n\n return {\n loadStoredFilters,\n resetFilter,\n submitFilter,\n serializeFilters,\n deserializeFilters,\n }\n}\n\nexport type AllowedFilterValues = number | number[] | string | string[] | null | undefined | boolean\n\nexport interface GeneralFilterOptions {\n system?: string\n subject?: string\n elastic?: boolean\n simpleFilters?: boolean\n}\n\nexport interface FilerRenderOptions {\n skip: boolean\n // Whether the field is shown as a selected-filter chip (FiltersSelected). Default true.\n // Optional for backward compatibility (other admins may construct FilerRenderOptions).\n selected?: boolean\n xs: number | undefined\n sm: number | undefined\n md: number | undefined\n lg: number | undefined\n xl: number | undefined\n}\n\nexport type FilterVariant =\n | 'search'\n | 'lt'\n | 'in'\n | 'notIn'\n | 'endsWith'\n | 'startsWith'\n | 'memberOf'\n | 'neq'\n | 'gte'\n | 'gt'\n | 'eq'\n | 'lte'\n | 'custom'\n\nexport type FilterType = 'boolean' | 'datetime' | 'integer' | 'string' | 'custom' | 'timeInterval'\n\nexport interface MakeFilterOption<TName extends string = string> {\n name: TName\n default: AllowedFilterValues\n type?: FilterType\n variant?: FilterVariant\n titleT?: string\n apiName?: string\n clearable?: boolean\n mandatory?: boolean\n advanced?: boolean\n exclude?: boolean\n related?: string | undefined\n render?: Partial<FilerRenderOptions>\n}\n\nexport interface FilterField {\n name: string\n type: FilterType\n variant: FilterVariant\n titleT?: string\n default: AllowedFilterValues\n apiName: string\n clearable: boolean\n mandatory: boolean\n multiple: boolean\n advanced: boolean\n exclude: boolean\n related: string | undefined\n render: FilerRenderOptions\n}\n\nexport type FilterConfig<F extends readonly MakeFilterOption<string>[] = readonly MakeFilterOption<string>[]> = {\n general: GeneralFilterOptions\n touched: boolean\n fields: {\n [P in F[number]['name']]: FilterField\n }\n}\n\nexport type FilterData<F extends readonly MakeFilterOption<string>[] = readonly MakeFilterOption<string>[]> = {\n [P in F[number]['name']]: AllowedFilterValues\n}\n\nexport type FilterStore<T extends readonly { name: string }[]> = {\n [K in T[number]['name']]: AllowedFilterValues\n}\n","import { computed, type Ref } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { useValidate } from '@/validators/vuelidate/useValidate'\nimport useVuelidate from '@vuelidate/core'\nimport type { DatetimeUTCNullable } from '@/types/common'\n\n/** note: number value represents time interval in minutes, null represent unselected */\nexport type TimeIntervalToolsValue = number | TimeIntervalSpecialOptionsType | null\n\nexport const TimeIntervalSpecialOptions = {\n CurrentMonth: 'cm',\n LastMonth: 'lm',\n Last3Months: 'l3m',\n Custom: 'custom',\n} as const\n\nexport type TimeIntervalSpecialOptionsType =\n (typeof TimeIntervalSpecialOptions)[keyof typeof TimeIntervalSpecialOptions]\n\nexport function useTimeIntervalOptions(allowed: TimeIntervalToolsValue[] | undefined = undefined) {\n const { t } = useI18n()\n\n const timeIntervalOptions = computed<ValueObjectOption<TimeIntervalToolsValue>[]>(() => {\n const values = [\n {\n value: null,\n title: t('common.model.all'),\n },\n {\n value: 60,\n title: '1 hodina',\n },\n {\n value: 1_440,\n title: '1 deň',\n },\n {\n value: 10_080,\n title: '7 dní',\n },\n {\n value: 40_320,\n title: '28 dní',\n },\n {\n value: TimeIntervalSpecialOptions.CurrentMonth,\n title: 'Prebiehajúci mesiac',\n },\n {\n value: TimeIntervalSpecialOptions.LastMonth,\n title: 'Minulý mesiac',\n },\n {\n value: TimeIntervalSpecialOptions.Last3Months,\n title: 'Posledné 3 mesiace',\n },\n {\n value: TimeIntervalSpecialOptions.Custom,\n title: 'Vlastné',\n },\n ]\n if (isUndefined(allowed)) return values\n\n return values.filter((item) => allowed.includes(item.value) || isNull(item.value))\n })\n\n const getTimeIntervalOption = (value: TimeIntervalToolsValue) => {\n return timeIntervalOptions.value.find((item) => item.value === value)\n }\n\n return {\n timeIntervalOptions,\n getTimeIntervalOption,\n }\n}\n\nexport function useFilterTimeIntervalValidators(\n dialogData: Ref<{\n from: DatetimeUTCNullable\n until: DatetimeUTCNullable\n }>\n) {\n // const { t } = useI18n()\n const { datesCompare, required } = useValidate()\n\n const fromComputed = computed(() => {\n return dialogData.value.from\n })\n\n const untilComputed = computed(() => {\n return dialogData.value.until\n })\n\n const rules = {\n dialogData: {\n from: {\n required,\n datesCompare: datesCompare(untilComputed, 'Until', 'onOrBefore'),\n },\n until: {\n required,\n datesCompare: datesCompare(fromComputed, 'From', 'laterThan'),\n },\n },\n }\n\n const v$ = useVuelidate(rules, { dialogData }, { $scope: 'AFilterTimeIntervalScope' })\n\n return {\n v$,\n }\n}\n","import { ref } from 'vue'\nimport { isArray, isBoolean, isNull, isNumber, isString, isUndefined } from '@/utils/common'\nimport type { FilterVariant } from '@/types/Filter'\nimport type { AllowedFilterValues, FilterConfig, FilterData, FilterField } from '@/labs/filters/filterFactory'\nimport type { DatetimeUTCNullable } from '@/types/common'\nimport { TimeIntervalSpecialOptions, type TimeIntervalToolsValue } from '@/labs/filters/filterTimeIntervalTools'\nimport { dateModifyMinutes, dateTimeNow, dateTimeToDate, dateToUtc, getMonthInterval } from '@/utils/datetime'\nimport { SortOrder } from '@/composables/system/datatableColumns'\n\n/**\n * Docs: /doc/Admin-Cms-Doc/Filters.md\n */\nexport function useApiQueryBuilder() {\n const q = ref<string[]>([])\n\n const querySetLimit = (value: number): void => {\n queryAdd('limit', value)\n }\n\n const querySetOffset = (page: number, limit: number): void => {\n queryAdd('offset', Math.max(0, (page - 1) * limit))\n }\n\n const querySetOrder = (field: string | null, desc: boolean): void => {\n if (!isNull(field) && field.length > 0) queryAdd('order[' + field + ']', desc ? SortOrder.Desc : SortOrder.Asc)\n }\n\n const formatValue = (value: string | number | boolean): string | number => {\n if (isBoolean(value)) {\n return value ? '1' : '0'\n }\n return value\n }\n\n const queryAddFilter = (filterVariant: FilterVariant, field: string, value: string | number | boolean): void => {\n if (isString(value) && value.length === 0) return\n q.value.push('filter_' + filterVariant + '[' + field + ']=' + formatValue(value))\n }\n\n const resolveTimeIntervalFilter = (\n fromName: string,\n untilName: string,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>,\n mandatory: boolean,\n exclude: boolean\n ): null | {\n from: DatetimeUTCNullable\n until: DatetimeUTCNullable\n } => {\n let fromValue = filterData[fromName] as TimeIntervalToolsValue\n let untilValue = filterData[untilName] as DatetimeUTCNullable\n if (isNull(fromValue) && mandatory && !exclude) {\n fromValue = filterConfig.fields[fromName].default as TimeIntervalToolsValue\n }\n if (isNull(untilValue) && mandatory && !exclude) {\n untilValue = filterConfig.fields[fromName].default as DatetimeUTCNullable\n }\n if (isString(fromValue) && isString(untilValue)) {\n return {\n from: fromValue,\n until: untilValue,\n }\n }\n const now = dateTimeNow()\n const nowDate = dateTimeToDate(now)\n switch (fromValue) {\n case TimeIntervalSpecialOptions.CurrentMonth: {\n return getMonthInterval(nowDate, 'utc', 0, false)\n }\n case TimeIntervalSpecialOptions.LastMonth: {\n return getMonthInterval(nowDate, 'utc', -1, false)\n }\n case TimeIntervalSpecialOptions.Last3Months: {\n return getMonthInterval(nowDate, 'utc', -2, true)\n }\n default: {\n if (isNumber(fromValue)) {\n return {\n from: dateToUtc(dateModifyMinutes(fromValue * -1, nowDate)),\n until: now,\n }\n }\n }\n }\n return null\n }\n\n const getValue = (value: AllowedFilterValues, config: FilterField): string | number | boolean | null => {\n if (isNull(value)) {\n if (config.mandatory && !config.exclude && !isUndefined(config.default)) {\n return isArray(config.default) ? config.default.join(',') : config.default\n }\n return null\n }\n if (isString(value)) {\n if (value.length === 0) {\n if (config.mandatory && !config.exclude && !isUndefined(config.default) && !isNull(config.default)) {\n return encodeURIComponent(isArray(config.default) ? config.default.join(',') : config.default)\n }\n return null\n }\n return encodeURIComponent(value)\n }\n if (isArray(value)) {\n if (value.length === 0) {\n if (config.mandatory && !config.exclude && isArray(config.default)) {\n return config.default.map((item) => (isString(item) ? encodeURIComponent(item) : item)).join(',')\n }\n return null\n }\n return value.map((item) => (isString(item) ? encodeURIComponent(item) : item)).join(',')\n }\n if (isNumber(value) || isBoolean(value)) {\n return value\n }\n\n return null\n }\n\n const queryAdd = (key: string, value: any): void => {\n q.value.push(key + '=' + value)\n }\n\n const queryBuild = (): string => {\n return '?' + q.value.join('&')\n }\n\n const querySetFilters = (filterData: FilterData<any>, filterConfig: FilterConfig<any>): void => {\n const isSimpleFilters = filterConfig.general.simpleFilters\n for (const filterName in filterData) {\n const filterFieldValue = filterData[filterName] as AllowedFilterValues\n const filterFieldConfig = filterConfig.fields[filterName]\n if (isUndefined(filterFieldConfig) || filterFieldConfig.exclude) {\n continue\n }\n const name = filterFieldConfig.apiName || filterName\n if (filterFieldConfig.type === 'timeInterval' && !isUndefined(filterFieldConfig.related)) {\n const data = resolveTimeIntervalFilter(\n filterName,\n filterFieldConfig.related,\n filterData,\n filterConfig,\n filterFieldConfig.mandatory,\n filterFieldConfig.exclude\n )\n if (isNull(data)) {\n continue\n }\n const filterFieldConfigRelated = filterConfig.fields[filterFieldConfig.related]\n const nameRelated = filterFieldConfigRelated.apiName || filterFieldConfig.related\n if (isSimpleFilters) {\n queryAdd(name, data.from)\n queryAdd(nameRelated, data.until)\n continue\n }\n if (data.from) queryAddFilter('gte', name, data.from)\n if (data.until) {\n queryAddFilter('lte', nameRelated, data.until)\n }\n continue\n }\n const value = getValue(filterFieldValue, filterFieldConfig)\n if (isNull(value)) {\n continue\n }\n if (isSimpleFilters) {\n queryAdd(name, value)\n continue\n }\n queryAddFilter(filterFieldConfig.variant, name, value)\n }\n }\n\n return {\n resolveTimeIntervalFilter,\n querySetLimit,\n querySetOffset,\n querySetOrder,\n queryAddFilter,\n querySetFilters,\n queryAdd,\n queryBuild,\n q,\n }\n}\n","import { AnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { isBoolean, isNumber, isObject } from '@/utils/common'\nimport type { Pagination } from '@/labs/filters/pagination'\n\nexport type ListBody<T> = {\n items: T[]\n /**\n * Which kind of list answered, read from the response rather than inferred from `pagination`.\n *\n * They are two different things and conflating them cost a bug: `pagination` is what to write, and\n * for an infinite list that includes `totalCount: 0` to clear the counted mode's leftovers -- so a\n * reader using `totalCount` to recognise the mode sees a counted list of zero items.\n */\n mode: 'counted' | 'infinite' | 'unknown'\n /**\n * What the response said about the mode it is in, plus the other mode's field cleared: a counted\n * body carries `hasNextPage: null` and an infinite one `totalCount: 0`, so a value left over from\n * the previous query cannot go on describing this one. A missing or malformed field of the mode's\n * own kind is not written at all.\n */\n pagination: Partial<Pagination>\n /**\n * Whether `totalCount` is a bound rather than a count.\n *\n * The backend's counted envelope carries `bigTable`, and with it on -- which is the default -- the\n * count it sends is `offset + limit + 1`: a look-ahead that says \"there is at least one more page\",\n * not how many rows exist. It is corrected to the real total only when the page came back short,\n * which is to say only when there was nothing more to look ahead to.\n *\n * Page-by-page navigation does not care: the sentinel is exactly what it needs to enable Next.\n * Anything that treats the number as a total does -- dividing by a page size to learn how many\n * pages exist yields 2, whatever the real answer is.\n */\n countIsBound: boolean\n}\n\n/**\n * Reads a list response.\n *\n * The array is the only thing that decides whether this is a list at all. The existing shape guards\n * test for a metadata key and nothing else, so `{ totalCount: 1 }` passed as a list and the caller\n * got `undefined` typed as an array.\n *\n * Metadata only picks the mode, and is optional: a well-formed array is not worth discarding because\n * the count beside it is missing or of the wrong type.\n *\n * `hasNextPage` decides, and only its absence falls through to `totalCount`. It has to be that way\n * round, because the backend's infinite envelope carries BOTH: `ApiInfiniteResponseList` serialises\n * `hasNextPage`, `data` and `totalCount` (the last marked `@deprecated`, which is a docblock and\n * suppresses nothing), while the counted one carries `totalCount`, `data` and `bigTable` and never\n * `hasNextPage`. So the presence of `hasNextPage` is the only unambiguous signal, and reading\n * `totalCount` first would turn every infinite list in the fleet into a counted one -- with a total\n * that is not a total: with `bigTable` on, which is the default, the counted number is a look-ahead\n * sentinel, `offset + limit + 1`, and the infinite envelope reports that same sentinel unconditionally.\n */\nexport const readListBody = <T>(body: unknown, status: number, url: string | undefined): ListBody<T> => {\n if (!isObject(body) || !Array.isArray((body as { data?: unknown }).data)) {\n throw new AnzuApiResponseCodeError(status, undefined, 'Expected a list body, url: ' + url)\n }\n\n const { data, totalCount, hasNextPage, bigTable } = body as {\n data: T[]\n totalCount?: unknown\n hasNextPage?: unknown\n bigTable?: unknown\n }\n\n if (isBoolean(hasNextPage)) {\n return { items: data, mode: 'infinite', pagination: { hasNextPage, totalCount: 0 }, countIsBound: false }\n }\n\n if (isNumber(totalCount)) {\n // `null`, not `false`: the field is three-valued and the paginators read it that way. `isNull`\n // is what picks the mode -- `ADatatablePagination.vue:62,67,73` and both `ASubjectSelect.vue`\n // take a non-null value to mean an infinite list, so `false` here says \"infinite, and there is\n // no next page\": Next and Last go dead on every page and the total renders as the number of\n // rows on screen. `null` is the counted list saying the infinite mode's field does not apply.\n return {\n items: data,\n mode: 'counted',\n pagination: { totalCount, hasNextPage: null },\n countIsBound: bigTable === true,\n }\n }\n\n return { items: data, mode: 'unknown', pagination: {}, countIsBound: false }\n}\n","import { AnzuFatalError } from '@/model/error/AnzuFatalError'\nimport { AnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { replaceUrlParameters, type UrlParams } from '@/services/api/apiHelper'\nimport { isValidHTTPStatus } from '@/utils/response'\nimport type { AxiosRequestConfig } from 'axios'\nimport { useApiQueryBuilder } from '@/labs/api/useApiQueryBuilder'\nimport { HTTP_STATUS_NO_CONTENT } from '@/composables/statusCodes'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport type { Ref } from 'vue'\nimport { isDefined, isNull, isUndefined } from '@/utils/common'\nimport type { Pagination } from '@/labs/filters/pagination'\nimport { SortOrder } from '@/composables/system/datatableColumns'\nimport type { AxiosClientFn } from '@/labs/api/client'\nimport { mapApiError, report } from '@/labs/api/apiErrors'\nimport { createAbortable, hasBody, ownedByHelper, requestedUrl } from '@/labs/api/request'\nimport { readListBody } from '@/labs/api/listBody'\n\nexport type UseApiFetchListParams = {\n client: AxiosClientFn\n system: string\n entity: string\n urlTemplate?: string\n urlParams?: UrlParams\n /** Anything axios takes except what this helper decides: the method, the url, the body and the signal. */\n options?: Omit<AxiosRequestConfig, 'method' | 'url' | 'data' | 'signal'>\n cancelPrevious?: boolean\n}\n\nexport type FetchListParams = {\n urlTemplate?: string\n urlParams?: UrlParams\n forceElastic?: boolean\n /** Stops this one call, leaving the instance's other calls alone. */\n signal?: AbortSignal\n}\n\nexport const generateListQuery = (\n pagination: Ref<Pagination>,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>\n): string => {\n const { querySetLimit, querySetOffset, querySetOrder, queryBuild, querySetFilters } = useApiQueryBuilder()\n querySetLimit(pagination.value.rowsPerPage)\n querySetOffset(pagination.value.page, pagination.value.rowsPerPage)\n if (pagination.value.sortBy) {\n querySetOrder(pagination.value.sortBy.key, pagination.value.sortBy.order === SortOrder.Desc)\n }\n querySetFilters(filterData, filterConfig)\n return queryBuild()\n}\n\nexport const useApiFetchList = <T>(params: UseApiFetchListParams): UseApiFetchListReturnType<T> => {\n const { client, system, entity, urlTemplate, urlParams, options = {}, cancelPrevious = false } = params\n const abortable = createAbortable({ cancelPrevious })\n\n const execute = async (\n pagination: Ref<Pagination>,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>,\n fetchParams: FetchListParams = {}\n ): Promise<T[]> => {\n const { urlTemplate: urlTemplateOverride, urlParams: urlParamsOverride, forceElastic = false, signal } = fetchParams\n\n // Assigned inside `run`, once, at the moment there is a url to ask for. It stays undefined until\n // then, and that is what a failure before dispatch reports: the field says which url was\n // requested, and a call that never reached the wire requested none. Neither the client root nor\n // the path it was going to build is an answer to that question.\n let url: string | undefined\n // The config axios used, kept for the failures this helper raises after reading the response:\n // they carry no config of their own, and rebuilding one describes the request as the client\n // would send it now rather than as it was sent.\n let dispatched: AxiosRequestConfig | undefined\n\n // Handed over by `run`, not read before it: `run` is what opens a new generation, so a value\n // taken beforehand belongs to the previous call and would never match.\n let generation = 0\n let ownSignal: AbortSignal | undefined\n const writePagination = (next: Partial<Pagination>) => {\n // Two ways to stop being the call whose answer counts, and both have to be checked: a newer\n // call opened a generation, or this one was cancelled through a signal of its own. Aborting\n // does not stop a response already on its way, so either can still arrive and write.\n //\n // The generation belongs to the instance, not to this `pagination` ref, so one instance serves\n // one list. Two concurrent calls on a shared instance writing to different refs would leave\n // the older ref unwritten -- correct for the same list shown twice, wrong for two lists.\n if (abortable.generation() !== generation) return\n if (ownSignal?.aborted === true) return\n // The caller's own signal, read directly rather than through the relay `run` set up for it.\n // `run` drops that relay as soon as the response is in hand, and the write happens after --\n // so an abort landing in between leaves `ownSignal` untouched, and the call the caller just\n // stopped would go on to write the pagination. This is the only state the family writes\n // outside `run`, so it is the only place the gap exists.\n if (signal?.aborted === true) return\n pagination.value = { ...pagination.value, ...next }\n }\n\n try {\n const res = await abortable.run((abortSignal, currentGeneration) => {\n generation = currentGeneration\n ownSignal = abortSignal\n\n // The whole url is derived here, inside `run`, and that is the point of putting it here:\n // `run` is what opens a new generation and, with `cancelPrevious`, stops the call before\n // this one. Anything done ahead of it belongs to no generation yet, so a missing template or\n // a malformed filter config -- both of which throw while the url is being built -- would\n // leave the previous call current, and its answer, arriving afterwards, would write\n // pagination for a query the caller has already replaced. It also keeps all of it inside the\n // try, so the caller gets the same error class as for every other failure rather than a bare\n // `Error` nothing in the fleet is written to catch.\n const template = isDefined(urlTemplateOverride) ? urlTemplateOverride : urlTemplate\n if (isUndefined(template)) throw new AnzuFatalError(undefined, 'Url template is undefined')\n\n const resolvedParams = isDefined(urlParamsOverride) ? urlParamsOverride : urlParams\n const searchApi = filterConfig.general.elastic || forceElastic ? '/search' : ''\n const baseUrl =\n (isUndefined(resolvedParams) ? template : replaceUrlParameters(template, resolvedParams)) + searchApi\n const requestUrl = baseUrl + generateListQuery(pagination, filterData, filterConfig)\n const instance = client()\n\n // Recorded last, when nothing between here and the call can throw any more: a client factory\n // that fails is a request that never happened, and the report says so by naming no url.\n url = requestUrl\n\n return instance.get(requestUrl, { ...ownedByHelper(options), signal: abortSignal })\n }, signal)\n\n dispatched = res.config\n // The url the report will name, so a message and the context beside it cannot disagree about\n // which request failed when an interceptor rewrote it on the way out.\n const asSent = () => requestedUrl(client, url, options, undefined, dispatched)\n if (!isValidHTTPStatus(res.status)) throw new AnzuApiResponseCodeError(res.status)\n\n // 204 is an empty list, and the metadata has to say so -- left alone it keeps answering for\n // the previous query.\n if (res.status === HTTP_STATUS_NO_CONTENT) {\n // A 204 says the list is empty; it says nothing about which kind of list it is. So the mode\n // the pagination is already in decides which field gets cleared: a counted list keeps\n // `null`, and an infinite one keeps a boolean and gets `false` -- which is what it means,\n // \"there is nothing after this\". Writing `null` for both put an infinite list into counted\n // mode, where `ASubjectSelect` reads a next page as available and its autoload fires again\n // on the same 204, and `ADatatablePagination` offers Next and Last on an empty page.\n const stillCounted = isNull(pagination.value.hasNextPage)\n writePagination({ totalCount: 0, hasNextPage: stillCounted ? null : false, currentViewCount: 0 })\n return []\n }\n\n if (!hasBody(res)) {\n throw new AnzuApiResponseCodeError(res.status, undefined, 'Expected a response body, url: ' + asSent())\n }\n\n const list = readListBody<T>(res.data, res.status, asSent())\n // Only when the response said something about paging at all: a body that named no mode has\n // said nothing to write, and a count of what just arrived would be the one field left\n // describing a query nobody asked about.\n if (list.mode !== 'unknown') writePagination({ ...list.pagination, currentViewCount: list.items.length })\n\n return list.items\n } catch (err: unknown) {\n // Built once and handed to both, the way the batch does it: half the work on the failure path,\n // and one place that could go wrong instead of two.\n const context = { system, entity, url: requestedUrl(client, url, options, err, dispatched) }\n\n throw report(mapApiError(err, context), context)\n }\n }\n\n return { execute, abort: abortable.abort, loading: abortable.loading }\n}\n\nexport type UseApiFetchListReturnType<T> = {\n execute: (\n pagination: Ref<Pagination>,\n filterData: FilterData<any>,\n filterConfig: FilterConfig<any>,\n params?: FetchListParams\n ) => Promise<T[]>\n abort: () => void\n /**\n * True while this instance has a request in flight, false once the last one settles.\n *\n * It is here so a caller does not have to keep its own: the hand-rolled version is a ref cleared\n * in a `finally`, and that `finally` belongs to whichever call ended -- including one that\n * `cancelPrevious` just superseded, which turns the spinner off while the call the user is waiting\n * for is still running. This one never dips between a superseded call and the one that replaced it.\n */\n loading: Ref<boolean>\n}\n","import { type DatatableSortBy, SortOrder, type SortOrderType } from '@/composables/system/datatableColumns'\nimport { type Ref, ref } from 'vue'\nimport { isNull, isString, isUndefined } from '@/utils/common'\n\nexport interface Pagination {\n sortBy: DatatableSortBy\n page: number\n rowsPerPage: number\n rowsNumber: number\n hasNextPage: null | boolean\n currentViewCount: number\n totalCount: number\n}\n\ninterface PaginationOptions {\n rowsPerPage: number\n}\n\nconst createDefaultPaginationOptions = () => {\n return {\n rowsPerPage: 25,\n }\n}\n\nexport function usePagination(\n sortKey: string | null,\n sortOrder: SortOrderType = SortOrder.Desc,\n options: Partial<PaginationOptions> = {},\n externalPaginationRef?: Ref<Pagination>\n): UsePaginationReturnType {\n const mergedOptions = { ...createDefaultPaginationOptions(), ...options }\n\n const pagination =\n externalPaginationRef ??\n ref<Pagination>({\n sortBy: isNull(sortKey) ? null : { key: sortKey, order: sortOrder },\n page: 1,\n rowsPerPage: mergedOptions.rowsPerPage,\n rowsNumber: 0,\n hasNextPage: null,\n currentViewCount: 0,\n totalCount: 0,\n })\n\n /**\n * Update sorting for the datatable.\n * Supported call variants:\n * 1) setSortBy(sortBy: DatatableSortBy) — pass a DatatableSortBy object\n * 2) setSortBy(sortKey: string, sortOrder: SortOrderType) — pass key and order separately\n */\n function setSortBy(sortBy: DatatableSortBy): void\n function setSortBy(sortKey: string, sortOrder: SortOrderType): void\n function setSortBy(arg1: DatatableSortBy | string, arg2?: SortOrderType): void {\n if (isString(arg1)) {\n pagination.value = {\n ...pagination.value,\n sortBy: { key: arg1, order: arg2 as SortOrderType },\n }\n return\n }\n\n const sortBy = arg1\n if (isNull(sortBy) || isUndefined(sortBy)) {\n pagination.value = { ...pagination.value, sortBy }\n return\n }\n pagination.value = { ...pagination.value, sortBy: { key: sortBy.key, order: sortBy.order } }\n }\n\n const setPage = (page: number) => {\n pagination.value = { ...pagination.value, page }\n }\n\n const incrementPage = () => {\n pagination.value = { ...pagination.value, page: pagination.value.page + 1 }\n return pagination.value.page\n }\n\n return {\n pagination,\n setSortBy,\n setPage,\n incrementPage,\n }\n}\n\ninterface UsePaginationReturnType {\n pagination: Ref<Pagination>\n setSortBy: (sortBy: DatatableSortBy) => void\n setPage: (page: number) => void\n incrementPage: () => number\n}\n","import { AnzuFatalError } from '@/model/error/AnzuFatalError'\nimport { AnzuApiResponseCodeError } from '@/model/error/AnzuApiResponseCodeError'\nimport { replaceUrlParameters, type UrlParams } from '@/services/api/apiHelper'\nimport { isValidHTTPStatus } from '@/utils/response'\nimport type { AxiosRequestConfig } from 'axios'\nimport { HTTP_STATUS_NO_CONTENT } from '@/composables/statusCodes'\nimport type { DocId, IntegerId } from '@/types/common'\nimport { isDefined, isUndefined } from '@/utils/common'\nimport type { Ref } from 'vue'\nimport type { AxiosClientFn } from '@/labs/api/client'\nimport { useApiQueryBuilder } from '@/labs/api/useApiQueryBuilder'\nimport { mapApiError, report } from '@/labs/api/apiErrors'\nimport { createAbortable, hasBody, ownedByHelper, requestedUrl } from '@/labs/api/request'\nimport { readListBody } from '@/labs/api/listBody'\n\nexport type UseApiFetchByIdsParams = {\n client: AxiosClientFn\n system: string\n entity: string\n urlTemplate?: string\n urlParams?: UrlParams\n /** Anything axios takes except what this helper decides: the method, the url, the body and the signal. */\n options?: Omit<AxiosRequestConfig, 'method' | 'url' | 'data' | 'signal'>\n isSearchApi?: boolean\n field?: string\n cancelPrevious?: boolean\n}\n\nexport type FetchByIdsParams = {\n urlTemplate?: string\n urlParams?: UrlParams\n /** Stops this one call, leaving the instance's other calls alone. */\n signal?: AbortSignal\n}\n\n/** The `filter_in` query that fetches exactly the ids asked for, in one request. */\nconst generateByIdsApiQuery = (ids: IntegerId[] | DocId[], isSearchApi: boolean, field = 'id'): string => {\n const { querySetLimit, querySetOffset, querySetOrder, queryBuild, queryAddFilter, queryAdd } = useApiQueryBuilder()\n const limit = ids.length // todo add batch fetch\n querySetLimit(limit)\n querySetOffset(1, limit)\n querySetOrder(field, false)\n if (isSearchApi) queryAdd(field, ids.join(','))\n else queryAddFilter('in', field, ids.join(','))\n\n return queryBuild()\n}\n\nexport const useApiFetchByIds = <T>(params: UseApiFetchByIdsParams): UseApiFetchByIdsReturnType<T> => {\n const {\n client,\n system,\n entity,\n urlTemplate,\n urlParams,\n options = {},\n isSearchApi = false,\n field = 'id',\n cancelPrevious = false,\n } = params\n const abortable = createAbortable({ cancelPrevious })\n\n const execute = async (ids: DocId[] | IntegerId[], fetchParams: FetchByIdsParams = {}): Promise<T[]> => {\n const { urlTemplate: urlTemplateOverride, urlParams: urlParamsOverride, signal } = fetchParams\n\n // Assigned inside `run`, once, at the moment there is a url to ask for; undefined until then,\n // which is what a failure before dispatch honestly reports.\n let url: string | undefined\n // The config axios used, kept for the failures this helper raises after reading the response:\n // they carry no config of their own, and rebuilding one describes the request as the client\n // would send it now rather than as it was sent.\n let dispatched: AxiosRequestConfig | undefined\n\n try {\n const res = await abortable.run((abortSignal) => {\n // Derived inside `run`, the way the list does it: `run` opens the generation and, with\n // `cancelPrevious`, stops the call before this one, so work done ahead of it would let a\n // call that never dispatches leave its predecessor running. Inside the try as well, so a\n // caller that forgot the template gets the same error class as every other failure rather\n // than a bare `Error`.\n const template = isDefined(urlTemplateOverride) ? urlTemplateOverride : urlTemplate\n if (isUndefined(template)) throw new AnzuFatalError(undefined, 'Url template is undefined')\n\n const resolvedParams = isDefined(urlParamsOverride) ? urlParamsOverride : urlParams\n const baseUrl = isUndefined(resolvedParams) ? template : replaceUrlParameters(template, resolvedParams)\n const requestUrl = baseUrl + generateByIdsApiQuery(ids, isSearchApi, field)\n const instance = client()\n\n // Recorded last, when nothing between here and the call can throw any more: a client factory\n // that fails is a request that never happened, and the report says so by naming no url.\n url = requestUrl\n\n return instance.get(requestUrl, { ...ownedByHelper(options), signal: abortSignal })\n }, signal)\n\n dispatched = res.config\n // The url the report will name, so a message and the context beside it cannot disagree about\n // which request failed when an interceptor rewrote it on the way out.\n const asSent = () => requestedUrl(client, url, options, undefined, dispatched)\n if (!isValidHTTPStatus(res.status)) throw new AnzuApiResponseCodeError(res.status)\n\n // Nothing matched the ids -- an empty answer, not a broken one.\n if (res.status === HTTP_STATUS_NO_CONTENT) return []\n\n if (!hasBody(res)) {\n throw new AnzuApiResponseCodeError(res.status, undefined, 'Expected a response body, url: ' + asSent())\n }\n\n return readListBody<T>(res.data, res.status, asSent()).items\n } catch (err: unknown) {\n // Built once and handed to both, the way the batch does it: half the work on the failure path,\n // and one place that could go wrong instead of two.\n const context = { system, entity, url: requestedUrl(client, url, options, err, dispatched) }\n\n throw report(mapApiError(err, context), context)\n }\n }\n\n return { execute, abort: abortable.abort, loading: abortable.loading }\n}\n\nexport type UseApiFetchByIdsReturnType<T> = {\n execute: (ids: DocId[] | IntegerId[], params?: FetchByIdsParams) => Promise<T[]>\n abort: () => void\n /**\n * True while this instance has a request in flight, false once the last one settles.\n *\n * It is here so a caller does not have to keep its own: the hand-rolled version is a ref cleared\n * in a `finally`, and that `finally` belongs to whichever call ended -- including one that\n * `cancelPrevious` just superseded, which turns the spinner off while the call the user is waiting\n * for is still running. This one never dips between a superseded call and the one that replaced it.\n */\n loading: Ref<boolean>\n}\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport { computed, inject } from 'vue'\nimport { isNull, isUndefined } from '@/utils/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\ninterface BooleanSelectOption {\n value: 0 | 1 | -1\n title: string\n}\n\nconst props = withDefaults(\n defineProps<{\n name: string\n allT?: string\n trueT?: string\n falseT?: string\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-boolean',\n allT: 'common.model.all',\n trueT: 'common.model.boolean.true',\n falseT: 'common.model.boolean.false',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get(): BooleanSelectOption {\n if (isUndefined(filterData[props.name]) || isNull(filterData[props.name]))\n return {\n value: -1,\n title: t(props.allT),\n }\n return filterData[props.name] ? { value: 1, title: t(props.trueT) } : { value: 0, title: t(props.falseT) }\n },\n set(newValue: BooleanSelectOption) {\n let returnValue: null | boolean = null\n if (newValue?.value === 1) returnValue = true\n if (newValue?.value === 0) returnValue = false\n filterData[props.name] = returnValue\n updateSelected()\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst items = computed<BooleanSelectOption[]>(() => {\n return [\n { value: -1, title: t(props.allT) },\n { value: 1, title: t(props.trueT) },\n { value: 0, title: t(props.falseT) },\n ]\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (modelValue.value.value === -1) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value.title, value: modelValue.value.value }])\n}\n</script>\n\n<template>\n <VSelect\n v-model=\"modelValue\"\n :data-cy=\"dataCy\"\n :label=\"label\"\n :items=\"items\"\n :clearable=\"!filterConfigCurrent.mandatory && modelValue.value !== -1\"\n return-object\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { useI18n } from 'vue-i18n'\nimport { computed, inject } from 'vue'\nimport { isNull, isUndefined } from '@/utils/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\ninterface BooleanSelectOption {\n value: 0 | 1 | -1\n title: string\n}\n\nconst props = withDefaults(\n defineProps<{\n name: string\n allT?: string\n trueT?: string\n falseT?: string\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-boolean',\n allT: 'common.model.all',\n trueT: 'common.model.boolean.true',\n falseT: 'common.model.boolean.false',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get(): BooleanSelectOption {\n if (isUndefined(filterData[props.name]) || isNull(filterData[props.name]))\n return {\n value: -1,\n title: t(props.allT),\n }\n return filterData[props.name] ? { value: 1, title: t(props.trueT) } : { value: 0, title: t(props.falseT) }\n },\n set(newValue: BooleanSelectOption) {\n let returnValue: null | boolean = null\n if (newValue?.value === 1) returnValue = true\n if (newValue?.value === 0) returnValue = false\n filterData[props.name] = returnValue\n updateSelected()\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst items = computed<BooleanSelectOption[]>(() => {\n return [\n { value: -1, title: t(props.allT) },\n { value: 1, title: t(props.trueT) },\n { value: 0, title: t(props.falseT) },\n ]\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (modelValue.value.value === -1) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value.title, value: modelValue.value.value }])\n}\n</script>\n\n<template>\n <VSelect\n v-model=\"modelValue\"\n :data-cy=\"dataCy\"\n :label=\"label\"\n :items=\"items\"\n :clearable=\"!filterConfigCurrent.mandatory && modelValue.value !== -1\"\n return-object\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { isBoolean, isNumber, isString, isUndefined } from '@/utils/common'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n placeholder: undefined,\n dataCy: 'filter-string',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (isNumber(modelValue.value)) {\n filterSelected.value.set(props.name, [{ title: modelValue.value + '', value: modelValue.value }])\n return\n }\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through would leave the\n // chip naming a value the query no longer carries.\n if (!isString(modelValue.value) || modelValue.value.length === 0) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value, value: modelValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected()\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VTextField\n v-model=\"modelValue\"\n :label=\"label\"\n :placeholder=\"placeholderComputed\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @blur=\"updateSelected\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { isBoolean, isNumber, isString, isUndefined } from '@/utils/common'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n placeholder: undefined,\n dataCy: 'filter-string',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (isNumber(modelValue.value)) {\n filterSelected.value.set(props.name, [{ title: modelValue.value + '', value: modelValue.value }])\n return\n }\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through would leave the\n // chip naming a value the query no longer carries.\n if (!isString(modelValue.value) || modelValue.value.length === 0) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value, value: modelValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected()\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VTextField\n v-model=\"modelValue\"\n :label=\"label\"\n :placeholder=\"placeholderComputed\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @blur=\"updateSelected\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isArray, isBoolean, isEmpty, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { type FilterConfig, type FilterData, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterInnerConfigKey,\n FilterInnerDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype ModelValueType = T | T[] | null | undefined\n\nconst props = withDefaults(\n defineProps<{\n name: string\n fetchItems: (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n ) => Promise<ValueObjectOption<T>[]>\n fetchItemsByIds: (ids: T[]) => Promise<ValueObjectOption<T>[]>\n filterByField: string\n filterSortBy?: DatatableSortBy\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n minSearchChars?: number\n minSearchText?: string | undefined\n placeholder?: string | undefined\n }>(),\n {\n filterSortBy: null,\n prefetch: false,\n minSearchChars: 2,\n minSearchText: undefined,\n placeholder: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig) ||\n isUndefined(filterInnerConfig) ||\n isUndefined(filterInnerData)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterByFieldProp = props.filterByField\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterSortByProp = props.filterSortBy\n\nif (isUndefined(filterInnerConfig.fields[filterByFieldProp]) || isUndefined(filterInnerData[filterByFieldProp])) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${filterByFieldProp}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst SEARCH_DEBOUNCE_MS = 300\n\nconst selected = ref<any>([])\nconst search = ref('')\nconst isFocused = ref(false)\nconst modelValueAutocomplete = ref<ValueObjectOption<T> | ValueObjectOption<T>[] | null>(null)\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst onBlur = () => {\n isFocused.value = false\n}\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { pagination } = usePagination(isNull(filterSortByProp) ? null : filterSortByProp.key, filterSortByProp?.order)\n\nconst fetchedItems = ref<ValueObjectOption<T>[]>([])\nconst selectedItemsCache = ref<ValueObjectOption<T>[]>([])\nconst isFirstLoad = ref(true)\nconst prefetchCompleted = ref(false)\n\nconst allItems = computed<ValueObjectOption<T>[]>(() => {\n const itemsMap = new Map<T, ValueObjectOption<T>>()\n const addToMap = (items: ValueObjectOption<T>[]) => {\n items.forEach((item) => {\n itemsMap.set(item.value, {\n value: item.value,\n title: item.title,\n subtitle: item.subtitle,\n } as ValueObjectOption<T>)\n })\n }\n\n addToMap(selectedItemsCache.value as ValueObjectOption<T>[])\n addToMap(fetchedItems.value as ValueObjectOption<T>[])\n\n return Array.from(itemsMap.values())\n})\n\nconst loading = ref(false)\n\nconst resetToEmptyState = (value: ModelValueType) => {\n selectedItemsCache.value = []\n selected.value = isArray(value) ? [] : null\n modelValueAutocomplete.value = isArray(value) ? [] : null\n updateFilterSelected(selected.value)\n}\n\nconst updateSelected = (value: T[] | T) => {\n const findItem = (id: T): ValueObjectOption<T> =>\n allItems.value.find((obj) => obj.value === id) ?? ({ title: `${id}`, value: id } as ValueObjectOption<T>)\n return isArray(value) ? value.map(findItem) : findItem(value)\n}\n\nconst loadListItems = async (ids: T[] | T) => {\n loading.value = true\n\n try {\n const idsArray = isArray(ids) ? ids : [ids]\n try {\n selectedItemsCache.value = await props.fetchItemsByIds(idsArray)\n const selectedNewValue = updateSelected(ids)\n selected.value = selectedNewValue\n modelValueAutocomplete.value = selectedNewValue\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n }\n return selectedItemsCache.value\n } finally {\n loading.value = false\n }\n}\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loading.value = true\n filterInnerData[filterByFieldProp] = query\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (error) {\n showErrorsDefault(error)\n } finally {\n loading.value = false\n }\n}\n\nconst tryAutoFetch = async (mode: 'focus' | 'hover' | 'mounted') => {\n if (props.prefetch === false || props.prefetch !== mode) return\n if (loading.value) return\n if (prefetchCompleted.value) return\n\n loading.value = true\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) {\n fetchedItems.value = res\n }\n prefetchCompleted.value = true\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst onFocus = async () => {\n isFocused.value = true\n await tryAutoFetch('focus')\n}\n\nconst onMouseEnter = async () => {\n await tryAutoFetch('hover')\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!filterConfigCurrent.value.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!filterConfigCurrent.value.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n clearField()\n}\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (newValue.length > 0 && newValue.length < props.minSearchChars) return\n if (newValue.length === 0 && props.prefetch === false) {\n fetchedItems.value = []\n return\n }\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n },\n { debounce: SEARCH_DEBOUNCE_MS }\n)\n\nconst checkFirstLoad = async () => {\n await tryAutoFetch('mounted')\n}\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst noDataText = computed(() => {\n if (loading.value) {\n return '$vuetify.loading'\n }\n if (fetchedItems.value.length === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nconst onSelectedUpdate = (newValue: any) => {\n filterConfig.touched = true\n let final: null | string | number | string[] | number[] = null\n if (isArray(newValue)) {\n final = newValue.map((item: any) => item.value) as string[] | number[]\n } else if (!isNull(newValue)) {\n final = newValue.value\n }\n filterData[props.name] = final\n emit('change')\n}\n\nconst updateFilterSelected = (\n newValue: ValueObjectOption<string | number> | ValueObjectOption<string | number>[] | null\n) => {\n filterSelected.value.delete(props.name)\n if ((isArray(newValue) && newValue.length === 0) || isNull(newValue)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((item) => ({ title: item.title, value: item.value }))\n )\n return\n }\n filterSelected.value.set(props.name, [{ title: newValue.title, value: newValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n async (newValueFilterData, oldValueFilterData) => {\n if (newValueFilterData === oldValueFilterData || isBoolean(newValueFilterData)) return\n const newValue = newValueFilterData as ModelValueType\n if (isFirstLoad.value) {\n isFirstLoad.value = false\n await checkFirstLoad()\n }\n if (isEmpty(newValue)) {\n resetToEmptyState(newValue)\n if (!isUndefined(oldValueFilterData)) {\n apiRequestCounter.value++\n await apiSearch('', apiRequestCounter.value)\n }\n return\n }\n await loadListItems(newValue as T[] | T)\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"selected\"\n :items=\"allItems\"\n no-filter\n :placeholder=\"placeholderComputed\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :label=\"label\"\n :chips=\"filterConfigCurrent.multiple\"\n :loading=\"loading\"\n hide-details\n return-object\n autocomplete=\"off\"\n :no-data-text=\"noDataText\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onSelectedUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <template\n v-if=\"loading\"\n #no-data\n >\n <VListItem :title=\"t('$vuetify.loading')\" />\n </template>\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n :title=\"internalItem.raw.title\"\n :subtitle=\"internalItem.raw.subtitle\"\n />\n </template>\n <template #chip=\"{ props: chipProps, internalItem }\">\n <VChip\n :closable=\"chipProps.closable as boolean\"\n size=\"small\"\n :text=\"`${internalItem.title} (${internalItem.raw.subtitle})`\"\n :disabled=\"internalItem.props.disabled\"\n >\n {{ internalItem.raw.title }}\n <span\n v-if=\"internalItem.raw.subtitle\"\n class=\"font-italic pl-1\"\n >\n ({{ internalItem.raw.subtitle }})\n </span>\n </VChip>\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isArray, isBoolean, isEmpty, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { type FilterConfig, type FilterData, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterInnerConfigKey,\n FilterInnerDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype ModelValueType = T | T[] | null | undefined\n\nconst props = withDefaults(\n defineProps<{\n name: string\n fetchItems: (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n ) => Promise<ValueObjectOption<T>[]>\n fetchItemsByIds: (ids: T[]) => Promise<ValueObjectOption<T>[]>\n filterByField: string\n filterSortBy?: DatatableSortBy\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n minSearchChars?: number\n minSearchText?: string | undefined\n placeholder?: string | undefined\n }>(),\n {\n filterSortBy: null,\n prefetch: false,\n minSearchChars: 2,\n minSearchText: undefined,\n placeholder: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig) ||\n isUndefined(filterInnerConfig) ||\n isUndefined(filterInnerData)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterByFieldProp = props.filterByField\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterSortByProp = props.filterSortBy\n\nif (isUndefined(filterInnerConfig.fields[filterByFieldProp]) || isUndefined(filterInnerData[filterByFieldProp])) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${filterByFieldProp}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst SEARCH_DEBOUNCE_MS = 300\n\nconst selected = ref<any>([])\nconst search = ref('')\nconst isFocused = ref(false)\nconst modelValueAutocomplete = ref<ValueObjectOption<T> | ValueObjectOption<T>[] | null>(null)\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst onBlur = () => {\n isFocused.value = false\n}\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { pagination } = usePagination(isNull(filterSortByProp) ? null : filterSortByProp.key, filterSortByProp?.order)\n\nconst fetchedItems = ref<ValueObjectOption<T>[]>([])\nconst selectedItemsCache = ref<ValueObjectOption<T>[]>([])\nconst isFirstLoad = ref(true)\nconst prefetchCompleted = ref(false)\n\nconst allItems = computed<ValueObjectOption<T>[]>(() => {\n const itemsMap = new Map<T, ValueObjectOption<T>>()\n const addToMap = (items: ValueObjectOption<T>[]) => {\n items.forEach((item) => {\n itemsMap.set(item.value, {\n value: item.value,\n title: item.title,\n subtitle: item.subtitle,\n } as ValueObjectOption<T>)\n })\n }\n\n addToMap(selectedItemsCache.value as ValueObjectOption<T>[])\n addToMap(fetchedItems.value as ValueObjectOption<T>[])\n\n return Array.from(itemsMap.values())\n})\n\nconst loading = ref(false)\n\nconst resetToEmptyState = (value: ModelValueType) => {\n selectedItemsCache.value = []\n selected.value = isArray(value) ? [] : null\n modelValueAutocomplete.value = isArray(value) ? [] : null\n updateFilterSelected(selected.value)\n}\n\nconst updateSelected = (value: T[] | T) => {\n const findItem = (id: T): ValueObjectOption<T> =>\n allItems.value.find((obj) => obj.value === id) ?? ({ title: `${id}`, value: id } as ValueObjectOption<T>)\n return isArray(value) ? value.map(findItem) : findItem(value)\n}\n\nconst loadListItems = async (ids: T[] | T) => {\n loading.value = true\n\n try {\n const idsArray = isArray(ids) ? ids : [ids]\n try {\n selectedItemsCache.value = await props.fetchItemsByIds(idsArray)\n const selectedNewValue = updateSelected(ids)\n selected.value = selectedNewValue\n modelValueAutocomplete.value = selectedNewValue\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n }\n return selectedItemsCache.value\n } finally {\n loading.value = false\n }\n}\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loading.value = true\n filterInnerData[filterByFieldProp] = query\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (error) {\n showErrorsDefault(error)\n } finally {\n loading.value = false\n }\n}\n\nconst tryAutoFetch = async (mode: 'focus' | 'hover' | 'mounted') => {\n if (props.prefetch === false || props.prefetch !== mode) return\n if (loading.value) return\n if (prefetchCompleted.value) return\n\n loading.value = true\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) {\n fetchedItems.value = res\n }\n prefetchCompleted.value = true\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst onFocus = async () => {\n isFocused.value = true\n await tryAutoFetch('focus')\n}\n\nconst onMouseEnter = async () => {\n await tryAutoFetch('hover')\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!filterConfigCurrent.value.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!filterConfigCurrent.value.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n clearField()\n}\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (newValue.length > 0 && newValue.length < props.minSearchChars) return\n if (newValue.length === 0 && props.prefetch === false) {\n fetchedItems.value = []\n return\n }\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n },\n { debounce: SEARCH_DEBOUNCE_MS }\n)\n\nconst checkFirstLoad = async () => {\n await tryAutoFetch('mounted')\n}\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst noDataText = computed(() => {\n if (loading.value) {\n return '$vuetify.loading'\n }\n if (fetchedItems.value.length === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nconst onSelectedUpdate = (newValue: any) => {\n filterConfig.touched = true\n let final: null | string | number | string[] | number[] = null\n if (isArray(newValue)) {\n final = newValue.map((item: any) => item.value) as string[] | number[]\n } else if (!isNull(newValue)) {\n final = newValue.value\n }\n filterData[props.name] = final\n emit('change')\n}\n\nconst updateFilterSelected = (\n newValue: ValueObjectOption<string | number> | ValueObjectOption<string | number>[] | null\n) => {\n filterSelected.value.delete(props.name)\n if ((isArray(newValue) && newValue.length === 0) || isNull(newValue)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((item) => ({ title: item.title, value: item.value }))\n )\n return\n }\n filterSelected.value.set(props.name, [{ title: newValue.title, value: newValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n async (newValueFilterData, oldValueFilterData) => {\n if (newValueFilterData === oldValueFilterData || isBoolean(newValueFilterData)) return\n const newValue = newValueFilterData as ModelValueType\n if (isFirstLoad.value) {\n isFirstLoad.value = false\n await checkFirstLoad()\n }\n if (isEmpty(newValue)) {\n resetToEmptyState(newValue)\n if (!isUndefined(oldValueFilterData)) {\n apiRequestCounter.value++\n await apiSearch('', apiRequestCounter.value)\n }\n return\n }\n await loadListItems(newValue as T[] | T)\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"selected\"\n :items=\"allItems\"\n no-filter\n :placeholder=\"placeholderComputed\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :label=\"label\"\n :chips=\"filterConfigCurrent.multiple\"\n :loading=\"loading\"\n hide-details\n return-object\n autocomplete=\"off\"\n :no-data-text=\"noDataText\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onSelectedUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <template\n v-if=\"loading\"\n #no-data\n >\n <VListItem :title=\"t('$vuetify.loading')\" />\n </template>\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n :title=\"internalItem.raw.title\"\n :subtitle=\"internalItem.raw.subtitle\"\n />\n </template>\n <template #chip=\"{ props: chipProps, internalItem }\">\n <VChip\n :closable=\"chipProps.closable as boolean\"\n size=\"small\"\n :text=\"`${internalItem.title} (${internalItem.raw.subtitle})`\"\n :disabled=\"internalItem.props.disabled\"\n >\n {{ internalItem.raw.title }}\n <span\n v-if=\"internalItem.raw.subtitle\"\n class=\"font-italic pl-1\"\n >\n ({{ internalItem.raw.subtitle }})\n </span>\n </VChip>\n </template>\n </VAutocomplete>\n</template>\n","export function isOneOf<T>(value: T, enumValues: T[]): boolean {\n return enumValues.includes(value)\n}\n","<script lang=\"ts\" setup>\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { cloneDeep, isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport type { DocId, IntegerId } from '@/types/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterInnerConfigKey,\n FilterInnerDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { type FilterConfig, type FilterData, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { isOneOf } from '@/utils/enum'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype FetchItemsMinimalByIdsType = ((ids: IntegerId[]) => Promise<any[]>) | ((ids: DocId[]) => Promise<any[]>)\n\ntype FetchItemsMinimalType = (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n) => Promise<any[]>\n\nconst props = withDefaults(\n defineProps<{\n name: string\n fetchItemsMinimal: FetchItemsMinimalType\n fetchItemsMinimalByIds: FetchItemsMinimalByIdsType\n filterByField: string\n filterSortBy?: DatatableSortBy\n placeholder?: string | undefined\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n searchMinChars?: number\n itemTitle?: string\n itemValue?: string\n }>(),\n {\n filterSortBy: null,\n placeholder: undefined,\n prefetch: false,\n searchMinChars: 2,\n itemTitle: 'name',\n itemValue: 'id',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig) ||\n isUndefined(filterInnerConfig) ||\n isUndefined(filterInnerData)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter config. ` +\n `Name is '${props.name}' and available options are ${Object.keys(filterData).join(', ')}.`\n )\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerConfig.fields[props.filterByField]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerData[props.filterByField])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${props.filterByField}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst selected = ref<any>([])\nconst search = ref('')\nconst isFocused = ref(false)\nconst autoFetchTimer: Ref<ReturnType<typeof setTimeout> | undefined> = ref(undefined)\n\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst onBlur = () => {\n isFocused.value = false\n}\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { pagination } = usePagination(\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isNull(props.filterSortBy) ? null : props.filterSortBy.key,\n props.filterSortBy?.order\n)\nconst fetchedItems = ref<any[]>([])\nconst selectedItemsCache = ref<any[]>([])\n\nconst allItems = computed<ValueObjectOption<DocId | IntegerId>[]>(() => {\n const final = new Map()\n const finalRaw: Map<IntegerId | DocId, any> = new Map()\n selectedItemsCache.value.forEach((value) => {\n if (value.raw) {\n final.set(value.raw[props.itemValue], value.raw[props.itemTitle])\n finalRaw.set(value.raw[props.itemValue], cloneDeep(value.raw))\n } else {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n }\n })\n fetchedItems.value.forEach((value) => {\n if (value.raw) {\n final.set(value.raw[props.itemValue], value.raw[props.itemTitle])\n finalRaw.set(value.raw[props.itemValue], cloneDeep(value.raw))\n } else {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n }\n })\n return Array.from(final, ([key, value]) => {\n return { value: key, title: value, raw: finalRaw.get(key) }\n })\n})\n\nconst loading = ref(false)\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loading.value = true\n filterInnerData[props.filterByField] = query\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst findLocalDataByValues = (values: Array<DocId | IntegerId>) => {\n const found = allItems.value.filter((item: ValueObjectOption<string | number>) => values.includes(item.value))\n return ([] as ValueObjectOption<string | number>[]).concat(found)\n}\n\nconst tryToLoadFromLocalData = async (newValue: string | number | Array<string | number>) => {\n let count = 1\n let foundItems: ValueObjectOption<string | number>[] = []\n if (isArray(newValue)) {\n count = newValue.length\n foundItems = findLocalDataByValues(newValue)\n } else {\n foundItems = findLocalDataByValues([newValue])\n }\n selectedItemsCache.value = foundItems\n return foundItems.length === count\n}\n\nconst autoFetched = ref(false)\n\nconst clearAutoFetchTimer = () => {\n clearTimeout(autoFetchTimer.value)\n autoFetchTimer.value = undefined\n}\n\nconst autoFetch = async () => {\n clearAutoFetchTimer()\n if (autoFetched.value === true) return\n autoFetched.value = true\n loading.value = true\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) fetchedItems.value = res\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst onFocus = () => {\n isFocused.value = true\n if (props.prefetch === false) return\n clearAutoFetchTimer()\n autoFetch()\n}\n\nconst onMouseEnter = () => {\n if (props.prefetch === 'focus' || props.prefetch === false) return\n clearAutoFetchTimer()\n autoFetch()\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!filterConfigCurrent.value.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!filterConfigCurrent.value.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst onSelectedUpdate = (newValue: any) => {\n filterConfig.touched = true\n let final: null | string | number | string[] | number[] = null\n if (isArray(newValue)) {\n final = newValue.map((item: any) => item.value) as string[] | number[]\n } else if (!isNull(newValue)) {\n final = newValue.value\n }\n filterData[props.name] = final\n emit('change')\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n clearField()\n}\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateFilterSelected = (\n newValue: ValueObjectOption<string | number> | ValueObjectOption<string | number>[] | null\n) => {\n filterSelected.value.delete(props.name)\n if ((isArray(newValue) && newValue.length === 0) || isNull(newValue)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((item) => ({ title: item.title, value: item.value }))\n )\n return\n }\n filterSelected.value.set(props.name, [{ title: newValue.title, value: newValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n async (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n selectedItemsCache.value = []\n if (filterConfigCurrent.value.multiple) {\n selected.value = []\n } else {\n selected.value = null\n }\n updateFilterSelected(selected.value)\n if (autoFetched.value === true || isOneOf(props.prefetch, ['hover', 'focus', false])) return\n autoFetchTimer.value = setTimeout(() => {\n autoFetch()\n }, 3000)\n return\n }\n const found = await tryToLoadFromLocalData(newValue)\n if (found) {\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))\n updateFilterSelected(selected.value)\n return\n }\n if (isArray(newValue)) {\n loading.value = true\n try {\n selectedItemsCache.value = await props.fetchItemsMinimalByIds(newValue as Array<IntegerId & DocId>)\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n return\n }\n loading.value = true\n try {\n selectedItemsCache.value = await props.fetchItemsMinimalByIds([newValue as DocId & IntegerId])\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))[0]\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n },\n { immediate: true }\n)\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue.length < props.searchMinChars) return\n if (newValue !== oldValue) {\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n }\n },\n { debounce: 300 }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"selected\"\n :items=\"allItems\"\n no-filter\n :placeholder=\"placeholderComputed\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :label=\"label\"\n :chips=\"filterConfigCurrent.multiple\"\n :loading=\"loading\"\n hide-details\n return-object\n autocomplete=\"off\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onSelectedUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <!-- @vue-skip -->\n <template #item=\"{ props: itemProps, internalItem: itemItem }\">\n <slot\n name=\"item\"\n :item=\"itemItem\"\n :props=\"itemProps\"\n >\n <VListItem\n v-bind=\"itemProps\"\n :title=\"itemItem.raw.title\"\n :subtitle=\"itemItem.raw.subtitle\"\n />\n </slot>\n </template>\n <!-- @vue-skip -->\n <template #chip=\"{ props: chipProps, internalItem: chipItem }\">\n <slot\n name=\"chip\"\n :props=\"chipProps\"\n :item=\"chipItem\"\n >\n <VChip\n v-bind=\"chipProps\"\n :text=\"chipItem.title\"\n />\n </slot>\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup>\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { cloneDeep, isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport type { DocId, IntegerId } from '@/types/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterInnerConfigKey,\n FilterInnerDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { type FilterConfig, type FilterData, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { isOneOf } from '@/utils/enum'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype FetchItemsMinimalByIdsType = ((ids: IntegerId[]) => Promise<any[]>) | ((ids: DocId[]) => Promise<any[]>)\n\ntype FetchItemsMinimalType = (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n) => Promise<any[]>\n\nconst props = withDefaults(\n defineProps<{\n name: string\n fetchItemsMinimal: FetchItemsMinimalType\n fetchItemsMinimalByIds: FetchItemsMinimalByIdsType\n filterByField: string\n filterSortBy?: DatatableSortBy\n placeholder?: string | undefined\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n searchMinChars?: number\n itemTitle?: string\n itemValue?: string\n }>(),\n {\n filterSortBy: null,\n placeholder: undefined,\n prefetch: false,\n searchMinChars: 2,\n itemTitle: 'name',\n itemValue: 'id',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig) ||\n isUndefined(filterInnerConfig) ||\n isUndefined(filterInnerData)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter config. ` +\n `Name is '${props.name}' and available options are ${Object.keys(filterData).join(', ')}.`\n )\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerConfig.fields[props.filterByField]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerData[props.filterByField])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${props.filterByField}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst selected = ref<any>([])\nconst search = ref('')\nconst isFocused = ref(false)\nconst autoFetchTimer: Ref<ReturnType<typeof setTimeout> | undefined> = ref(undefined)\n\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst onBlur = () => {\n isFocused.value = false\n}\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { pagination } = usePagination(\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isNull(props.filterSortBy) ? null : props.filterSortBy.key,\n props.filterSortBy?.order\n)\nconst fetchedItems = ref<any[]>([])\nconst selectedItemsCache = ref<any[]>([])\n\nconst allItems = computed<ValueObjectOption<DocId | IntegerId>[]>(() => {\n const final = new Map()\n const finalRaw: Map<IntegerId | DocId, any> = new Map()\n selectedItemsCache.value.forEach((value) => {\n if (value.raw) {\n final.set(value.raw[props.itemValue], value.raw[props.itemTitle])\n finalRaw.set(value.raw[props.itemValue], cloneDeep(value.raw))\n } else {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n }\n })\n fetchedItems.value.forEach((value) => {\n if (value.raw) {\n final.set(value.raw[props.itemValue], value.raw[props.itemTitle])\n finalRaw.set(value.raw[props.itemValue], cloneDeep(value.raw))\n } else {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n }\n })\n return Array.from(final, ([key, value]) => {\n return { value: key, title: value, raw: finalRaw.get(key) }\n })\n})\n\nconst loading = ref(false)\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loading.value = true\n filterInnerData[props.filterByField] = query\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst findLocalDataByValues = (values: Array<DocId | IntegerId>) => {\n const found = allItems.value.filter((item: ValueObjectOption<string | number>) => values.includes(item.value))\n return ([] as ValueObjectOption<string | number>[]).concat(found)\n}\n\nconst tryToLoadFromLocalData = async (newValue: string | number | Array<string | number>) => {\n let count = 1\n let foundItems: ValueObjectOption<string | number>[] = []\n if (isArray(newValue)) {\n count = newValue.length\n foundItems = findLocalDataByValues(newValue)\n } else {\n foundItems = findLocalDataByValues([newValue])\n }\n selectedItemsCache.value = foundItems\n return foundItems.length === count\n}\n\nconst autoFetched = ref(false)\n\nconst clearAutoFetchTimer = () => {\n clearTimeout(autoFetchTimer.value)\n autoFetchTimer.value = undefined\n}\n\nconst autoFetch = async () => {\n clearAutoFetchTimer()\n if (autoFetched.value === true) return\n autoFetched.value = true\n loading.value = true\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) fetchedItems.value = res\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n}\n\nconst onFocus = () => {\n isFocused.value = true\n if (props.prefetch === false) return\n clearAutoFetchTimer()\n autoFetch()\n}\n\nconst onMouseEnter = () => {\n if (props.prefetch === 'focus' || props.prefetch === false) return\n clearAutoFetchTimer()\n autoFetch()\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!filterConfigCurrent.value.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!filterConfigCurrent.value.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst onSelectedUpdate = (newValue: any) => {\n filterConfig.touched = true\n let final: null | string | number | string[] | number[] = null\n if (isArray(newValue)) {\n final = newValue.map((item: any) => item.value) as string[] | number[]\n } else if (!isNull(newValue)) {\n final = newValue.value\n }\n filterData[props.name] = final\n emit('change')\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n clearField()\n}\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateFilterSelected = (\n newValue: ValueObjectOption<string | number> | ValueObjectOption<string | number>[] | null\n) => {\n filterSelected.value.delete(props.name)\n if ((isArray(newValue) && newValue.length === 0) || isNull(newValue)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((item) => ({ title: item.title, value: item.value }))\n )\n return\n }\n filterSelected.value.set(props.name, [{ title: newValue.title, value: newValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n async (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n selectedItemsCache.value = []\n if (filterConfigCurrent.value.multiple) {\n selected.value = []\n } else {\n selected.value = null\n }\n updateFilterSelected(selected.value)\n if (autoFetched.value === true || isOneOf(props.prefetch, ['hover', 'focus', false])) return\n autoFetchTimer.value = setTimeout(() => {\n autoFetch()\n }, 3000)\n return\n }\n const found = await tryToLoadFromLocalData(newValue)\n if (found) {\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))\n updateFilterSelected(selected.value)\n return\n }\n if (isArray(newValue)) {\n loading.value = true\n try {\n selectedItemsCache.value = await props.fetchItemsMinimalByIds(newValue as Array<IntegerId & DocId>)\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n return\n }\n loading.value = true\n try {\n selectedItemsCache.value = await props.fetchItemsMinimalByIds([newValue as DocId & IntegerId])\n selected.value = selectedItemsCache.value.map((item) => ({\n title: item.title,\n value: item.value,\n }))[0]\n updateFilterSelected(selected.value)\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loading.value = false\n }\n },\n { immediate: true }\n)\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue.length < props.searchMinChars) return\n if (newValue !== oldValue) {\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n }\n },\n { debounce: 300 }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"selected\"\n :items=\"allItems\"\n no-filter\n :placeholder=\"placeholderComputed\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :label=\"label\"\n :chips=\"filterConfigCurrent.multiple\"\n :loading=\"loading\"\n hide-details\n return-object\n autocomplete=\"off\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onSelectedUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <!-- @vue-skip -->\n <template #item=\"{ props: itemProps, internalItem: itemItem }\">\n <slot\n name=\"item\"\n :item=\"itemItem\"\n :props=\"itemProps\"\n >\n <VListItem\n v-bind=\"itemProps\"\n :title=\"itemItem.raw.title\"\n :subtitle=\"itemItem.raw.subtitle\"\n />\n </slot>\n </template>\n <!-- @vue-skip -->\n <template #chip=\"{ props: chipProps, internalItem: chipItem }\">\n <slot\n name=\"chip\"\n :props=\"chipProps\"\n :item=\"chipItem\"\n >\n <VChip\n v-bind=\"chipProps\"\n :text=\"chipItem.title\"\n />\n </slot>\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup>\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { computed, inject, watch, getCurrentInstance } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { type AllowedFilterValues, useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n items: ValueObjectOption<string | number>[]\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-value',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter config. ` +\n `Name is '${props.name}' and available options are ${Object.keys(filterData).join(', ')}.`\n )\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n updateSelected(newValue)\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = (newValue: AllowedFilterValues) => {\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through to `items.find`\n // would find nothing and leave the previous chip in place, naming a value the query no longer\n // carries.\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((modelItemValue) => {\n const found = props.items.find((item) => item.value === modelItemValue)\n if (found) return { title: found.title, value: found.value }\n return { title: modelItemValue as string, value: modelItemValue as string }\n })\n )\n return\n }\n const found = props.items.find((item) => item.value === newValue)\n if (found) {\n filterSelected.value.set(props.name, [{ title: found.title as string, value: found.value as string }])\n }\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected(newValue)\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"modelValue\"\n :items=\"items\"\n :chips=\"filterConfigCurrent.multiple\"\n :label=\"label\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { computed, inject, watch, getCurrentInstance } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { type AllowedFilterValues, useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n items: ValueObjectOption<string | number>[]\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-value',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterData) ||\n isUndefined(filterConfig)\n) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter config. ` +\n `Name is '${props.name}' and available options are ${Object.keys(filterData).join(', ')}.`\n )\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n updateSelected(newValue)\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = (newValue: AllowedFilterValues) => {\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through to `items.find`\n // would find nothing and leave the previous chip in place, naming a value the query no longer\n // carries.\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n filterSelected.value.delete(props.name)\n return\n }\n if (isArray(newValue)) {\n filterSelected.value.set(\n props.name,\n newValue.map((modelItemValue) => {\n const found = props.items.find((item) => item.value === modelItemValue)\n if (found) return { title: found.title, value: found.value }\n return { title: modelItemValue as string, value: modelItemValue as string }\n })\n )\n return\n }\n const found = props.items.find((item) => item.value === newValue)\n if (found) {\n filterSelected.value.set(props.name, [{ title: found.title as string, value: found.value as string }])\n }\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected(newValue)\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"modelValue\"\n :items=\"items\"\n :chips=\"filterConfigCurrent.multiple\"\n :label=\"label\"\n :multiple=\"filterConfigCurrent.multiple\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, nextTick, ref, watch } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { type AllowedFilterValues, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n TimeIntervalSpecialOptions,\n type TimeIntervalToolsValue,\n useFilterTimeIntervalValidators,\n useTimeIntervalOptions,\n} from '@/labs/filters/filterTimeIntervalTools'\nimport ADialogToolbar from '@/components/ADialogToolbar.vue'\nimport AFormDatetimePicker from '@/components/form/AFormDatetimePicker.vue'\nimport type { DatetimeUTCNullable } from '@/types/common'\nimport ARow from '@/components/ARow.vue'\nimport { dateTimeNow, dateTimePretty, isDatetimeUTC } from '@/utils/datetime'\nimport { useAlerts } from '@/composables/system/alerts'\nimport type { ValueObjectOption } from '@/types/ValueObject'\n\nconst props = withDefaults(\n defineProps<{\n nameFrom: string\n nameUntil: string\n allowed?: TimeIntervalToolsValue[]\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n allowed: undefined,\n placeholder: undefined,\n dataCy: 'filter-time-interval',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.nameFrom]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.nameUntil]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.nameFrom]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.nameUntil])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.nameFrom]\n },\n set(newValue) {\n filterData[props.nameFrom] = newValue\n updateSelected(newValue)\n filterConfig.touched = true\n nextTick(() => {\n emit('change')\n })\n },\n})\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { timeIntervalOptions, getTimeIntervalOption } = useTimeIntervalOptions(props.allowed)\nconst modelInternal = ref<TimeIntervalToolsValue>(null)\nconst dialogCustom = ref(false)\nconst dialogData = ref<{ from: DatetimeUTCNullable; until: DatetimeUTCNullable }>({\n from: null,\n until: dateTimeNow(),\n})\nconst displayFromTo = ref(false)\n\nconst { v$ } = useFilterTimeIntervalValidators(dialogData)\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.nameFrom])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\nconst { showValidationError } = useAlerts()\n\nconst onClear = () => {\n clearField()\n // Clearing means \"back to the default\", which is not always \"everything\" - a pair with an\n // absolute default keeps its window. Since the value then does not change, neither watcher runs,\n // so the display and the chip are re-derived here. Showing \"everything\" while the query still\n // carries the old window would make the control lie about what the list contains.\n syncDisplayToValue(filterData[props.nameFrom])\n updateSelected(filterData[props.nameFrom])\n}\n\nconst onDialogConfirm = () => {\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return\n }\n displayFromTo.value = true\n dialogCustom.value = false\n filterData[props.nameUntil] = dialogData.value.until\n modelValue.value = dialogData.value.from\n}\n\ndefineExpose({ onClear })\n\nconst onDialogClose = () => {\n dialogCustom.value = false\n modelInternal.value = null\n}\n\nconst clearField = () => {\n clearOne(props.nameFrom, filterData, filterConfig)\n clearOne(props.nameUntil, filterData, filterConfig)\n filterSelected.value.delete(props.nameFrom)\n}\n\nconst updateSelected = (fromValue: AllowedFilterValues) => {\n if (isArray(fromValue) || isBoolean(fromValue)) return\n if (isNull(fromValue) || isUndefined(fromValue)) {\n filterSelected.value.delete(props.nameFrom)\n return\n }\n const found = getTimeIntervalOption(fromValue as TimeIntervalToolsValue)\n if (!found && isDatetimeUTC(fromValue)) {\n const customOption = getTimeIntervalOption(TimeIntervalSpecialOptions.Custom)!\n filterSelected.value.set(props.nameFrom, [\n {\n title:\n customOption.title +\n ': ' +\n dateTimePretty(dialogData.value.from) +\n ' - ' +\n dateTimePretty(dialogData.value.until),\n value: fromValue,\n },\n ])\n return\n }\n if (!found) return\n filterSelected.value.set(props.nameFrom, [{ title: found.title, value: fromValue }])\n}\n\nconst onEditInterval = (clear = false) => {\n v$.value.$reset()\n if (clear) {\n dialogData.value.from = null\n dialogData.value.until = dateTimeNow()\n }\n dialogCustom.value = true\n}\n\n/** What the control shows is derived from the value, never assumed. */\nconst syncDisplayToValue = (newValue: AllowedFilterValues) => {\n if (isArray(newValue) || isBoolean(newValue)) return\n displayFromTo.value = false\n if (isUndefined(newValue) || isNull(newValue)) {\n modelInternal.value = null\n return\n }\n const found = getTimeIntervalOption(newValue as TimeIntervalToolsValue)\n const filterDataUntil = filterData[props.nameUntil]\n if (!found && isDatetimeUTC(newValue) && isDatetimeUTC(filterDataUntil)) {\n modelInternal.value = TimeIntervalSpecialOptions.Custom\n dialogData.value.from = newValue\n dialogData.value.until = filterDataUntil\n displayFromTo.value = true\n }\n if (found) {\n modelInternal.value = found.value\n }\n}\n\nwatch(modelValue, syncDisplayToValue, { immediate: true })\n\n// Reset clears every field back to its default and wipes the chips. For a pair whose default is\n// null that is the whole story, but an absolute default survives the reset - the value does not\n// change, so no watcher runs, and the control would keep showing a range with no chip beside it.\n// The wrapper bumps this counter after clearing, which is the one signal that a reset happened.\nwatch(submitResetCounter, () => {\n syncDisplayToValue(filterData[props.nameFrom])\n updateSelected(filterData[props.nameFrom])\n})\n\nwatch(\n [() => filterData[props.nameFrom], () => filterData[props.nameUntil]],\n ([fromNewValue, untilNewValue], [fromOldValue, untilOldValue]) => {\n if (fromNewValue === fromOldValue && untilNewValue === untilOldValue) return\n updateSelected(fromNewValue)\n },\n { immediate: true }\n)\n\nconst onInternalItemChange = (item: ValueObjectOption<TimeIntervalToolsValue>) => {\n if (item.value === TimeIntervalSpecialOptions.Custom) {\n onEditInterval(true)\n return\n }\n filterData[props.nameUntil] = null\n modelValue.value = item.value\n}\n</script>\n\n<template>\n <VTextarea\n v-if=\"displayFromTo\"\n :label=\"label\"\n :model-value=\"dateTimePretty(dialogData.from) + ' - ' + dateTimePretty(dialogData.until)\"\n readonly\n rows=\"1\"\n auto-grow\n hide-details\n append-inner-icon=\"mdi-menu-down\"\n clearable\n class=\"cursor-pointer\"\n @click:clear.stop=\"onClear\"\n @click.stop=\"onEditInterval()\"\n />\n <VSelect\n v-else\n v-model=\"modelInternal\"\n item-title=\"title\"\n item-value=\"value\"\n :label=\"label\"\n :clearable=\"!isNull(modelInternal)\"\n no-filter\n :data-cy=\"dataCy\"\n :items=\"timeIntervalOptions\"\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"onClear\"\n >\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n @click=\"onInternalItemChange(internalItem)\"\n />\n </template>\n </VSelect>\n <VDialog\n v-if=\"dialogCustom\"\n :model-value=\"true\"\n width=\"auto\"\n :min-width=\"360\"\n >\n <VCard>\n <ADialogToolbar @on-cancel=\"onDialogClose\">\n <slot name=\"title\">\n {{ label }}\n </slot>\n </ADialogToolbar>\n <VCardText>\n <ARow>\n <AFormDatetimePicker\n v-model=\"dialogData.from\"\n :v=\"v$.dialogData.from\"\n :label=\"t('common.filter.timeInterval.from')\"\n required\n />\n </ARow>\n <ARow>\n <AFormDatetimePicker\n v-model=\"dialogData.until\"\n :v=\"v$.dialogData.until\"\n :label=\"t('common.filter.timeInterval.until')\"\n required\n />\n </ARow>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <ABtnTertiary\n data-cy=\"button-cancel\"\n @click.stop=\"onDialogClose\"\n >\n {{ t('common.button.cancel') }}\n </ABtnTertiary>\n <ABtnPrimary\n data-cy=\"button-confirm\"\n @click.stop=\"onDialogConfirm\"\n >\n {{ t('common.button.confirm') }}\n </ABtnPrimary>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n\n<style lang=\"scss\" scoped>\n.v-text-field.cursor-pointer {\n ::v-deep(.v-field),\n ::v-deep(.v-field__input) {\n cursor: pointer;\n }\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, inject, nextTick, ref, watch } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isBoolean, isNull, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { type AllowedFilterValues, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport {\n TimeIntervalSpecialOptions,\n type TimeIntervalToolsValue,\n useFilterTimeIntervalValidators,\n useTimeIntervalOptions,\n} from '@/labs/filters/filterTimeIntervalTools'\nimport ADialogToolbar from '@/components/ADialogToolbar.vue'\nimport AFormDatetimePicker from '@/components/form/AFormDatetimePicker.vue'\nimport type { DatetimeUTCNullable } from '@/types/common'\nimport ARow from '@/components/ARow.vue'\nimport { dateTimeNow, dateTimePretty, isDatetimeUTC } from '@/utils/datetime'\nimport { useAlerts } from '@/composables/system/alerts'\nimport type { ValueObjectOption } from '@/types/ValueObject'\n\nconst props = withDefaults(\n defineProps<{\n nameFrom: string\n nameUntil: string\n allowed?: TimeIntervalToolsValue[]\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n allowed: undefined,\n placeholder: undefined,\n dataCy: 'filter-time-interval',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.nameFrom]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.nameUntil]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.nameFrom]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.nameUntil])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.nameFrom]\n },\n set(newValue) {\n filterData[props.nameFrom] = newValue\n updateSelected(newValue)\n filterConfig.touched = true\n nextTick(() => {\n emit('change')\n })\n },\n})\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { timeIntervalOptions, getTimeIntervalOption } = useTimeIntervalOptions(props.allowed)\nconst modelInternal = ref<TimeIntervalToolsValue>(null)\nconst dialogCustom = ref(false)\nconst dialogData = ref<{ from: DatetimeUTCNullable; until: DatetimeUTCNullable }>({\n from: null,\n until: dateTimeNow(),\n})\nconst displayFromTo = ref(false)\n\nconst { v$ } = useFilterTimeIntervalValidators(dialogData)\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.nameFrom])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\nconst { showValidationError } = useAlerts()\n\nconst onClear = () => {\n clearField()\n // Clearing means \"back to the default\", which is not always \"everything\" - a pair with an\n // absolute default keeps its window. Since the value then does not change, neither watcher runs,\n // so the display and the chip are re-derived here. Showing \"everything\" while the query still\n // carries the old window would make the control lie about what the list contains.\n syncDisplayToValue(filterData[props.nameFrom])\n updateSelected(filterData[props.nameFrom])\n}\n\nconst onDialogConfirm = () => {\n v$.value.$touch()\n if (v$.value.$invalid) {\n showValidationError()\n return\n }\n displayFromTo.value = true\n dialogCustom.value = false\n filterData[props.nameUntil] = dialogData.value.until\n modelValue.value = dialogData.value.from\n}\n\ndefineExpose({ onClear })\n\nconst onDialogClose = () => {\n dialogCustom.value = false\n modelInternal.value = null\n}\n\nconst clearField = () => {\n clearOne(props.nameFrom, filterData, filterConfig)\n clearOne(props.nameUntil, filterData, filterConfig)\n filterSelected.value.delete(props.nameFrom)\n}\n\nconst updateSelected = (fromValue: AllowedFilterValues) => {\n if (isArray(fromValue) || isBoolean(fromValue)) return\n if (isNull(fromValue) || isUndefined(fromValue)) {\n filterSelected.value.delete(props.nameFrom)\n return\n }\n const found = getTimeIntervalOption(fromValue as TimeIntervalToolsValue)\n if (!found && isDatetimeUTC(fromValue)) {\n const customOption = getTimeIntervalOption(TimeIntervalSpecialOptions.Custom)!\n filterSelected.value.set(props.nameFrom, [\n {\n title:\n customOption.title +\n ': ' +\n dateTimePretty(dialogData.value.from) +\n ' - ' +\n dateTimePretty(dialogData.value.until),\n value: fromValue,\n },\n ])\n return\n }\n if (!found) return\n filterSelected.value.set(props.nameFrom, [{ title: found.title, value: fromValue }])\n}\n\nconst onEditInterval = (clear = false) => {\n v$.value.$reset()\n if (clear) {\n dialogData.value.from = null\n dialogData.value.until = dateTimeNow()\n }\n dialogCustom.value = true\n}\n\n/** What the control shows is derived from the value, never assumed. */\nconst syncDisplayToValue = (newValue: AllowedFilterValues) => {\n if (isArray(newValue) || isBoolean(newValue)) return\n displayFromTo.value = false\n if (isUndefined(newValue) || isNull(newValue)) {\n modelInternal.value = null\n return\n }\n const found = getTimeIntervalOption(newValue as TimeIntervalToolsValue)\n const filterDataUntil = filterData[props.nameUntil]\n if (!found && isDatetimeUTC(newValue) && isDatetimeUTC(filterDataUntil)) {\n modelInternal.value = TimeIntervalSpecialOptions.Custom\n dialogData.value.from = newValue\n dialogData.value.until = filterDataUntil\n displayFromTo.value = true\n }\n if (found) {\n modelInternal.value = found.value\n }\n}\n\nwatch(modelValue, syncDisplayToValue, { immediate: true })\n\n// Reset clears every field back to its default and wipes the chips. For a pair whose default is\n// null that is the whole story, but an absolute default survives the reset - the value does not\n// change, so no watcher runs, and the control would keep showing a range with no chip beside it.\n// The wrapper bumps this counter after clearing, which is the one signal that a reset happened.\nwatch(submitResetCounter, () => {\n syncDisplayToValue(filterData[props.nameFrom])\n updateSelected(filterData[props.nameFrom])\n})\n\nwatch(\n [() => filterData[props.nameFrom], () => filterData[props.nameUntil]],\n ([fromNewValue, untilNewValue], [fromOldValue, untilOldValue]) => {\n if (fromNewValue === fromOldValue && untilNewValue === untilOldValue) return\n updateSelected(fromNewValue)\n },\n { immediate: true }\n)\n\nconst onInternalItemChange = (item: ValueObjectOption<TimeIntervalToolsValue>) => {\n if (item.value === TimeIntervalSpecialOptions.Custom) {\n onEditInterval(true)\n return\n }\n filterData[props.nameUntil] = null\n modelValue.value = item.value\n}\n</script>\n\n<template>\n <VTextarea\n v-if=\"displayFromTo\"\n :label=\"label\"\n :model-value=\"dateTimePretty(dialogData.from) + ' - ' + dateTimePretty(dialogData.until)\"\n readonly\n rows=\"1\"\n auto-grow\n hide-details\n append-inner-icon=\"mdi-menu-down\"\n clearable\n class=\"cursor-pointer\"\n @click:clear.stop=\"onClear\"\n @click.stop=\"onEditInterval()\"\n />\n <VSelect\n v-else\n v-model=\"modelInternal\"\n item-title=\"title\"\n item-value=\"value\"\n :label=\"label\"\n :clearable=\"!isNull(modelInternal)\"\n no-filter\n :data-cy=\"dataCy\"\n :items=\"timeIntervalOptions\"\n hide-details\n autocomplete=\"off\"\n @click:clear.stop=\"onClear\"\n >\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n @click=\"onInternalItemChange(internalItem)\"\n />\n </template>\n </VSelect>\n <VDialog\n v-if=\"dialogCustom\"\n :model-value=\"true\"\n width=\"auto\"\n :min-width=\"360\"\n >\n <VCard>\n <ADialogToolbar @on-cancel=\"onDialogClose\">\n <slot name=\"title\">\n {{ label }}\n </slot>\n </ADialogToolbar>\n <VCardText>\n <ARow>\n <AFormDatetimePicker\n v-model=\"dialogData.from\"\n :v=\"v$.dialogData.from\"\n :label=\"t('common.filter.timeInterval.from')\"\n required\n />\n </ARow>\n <ARow>\n <AFormDatetimePicker\n v-model=\"dialogData.until\"\n :v=\"v$.dialogData.until\"\n :label=\"t('common.filter.timeInterval.until')\"\n required\n />\n </ARow>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <ABtnTertiary\n data-cy=\"button-cancel\"\n @click.stop=\"onDialogClose\"\n >\n {{ t('common.button.cancel') }}\n </ABtnTertiary>\n <ABtnPrimary\n data-cy=\"button-confirm\"\n @click.stop=\"onDialogConfirm\"\n >\n {{ t('common.button.confirm') }}\n </ABtnPrimary>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n\n<style lang=\"scss\" scoped>\n.v-text-field.cursor-pointer {\n ::v-deep(.v-field),\n ::v-deep(.v-field__input) {\n cursor: pointer;\n }\n}\n</style>\n","export const datatableSlotName = (columnName: string, prefix = 'item') => {\n return prefix + '.' + columnName\n}\n","<script setup lang=\"ts\">\nconst props = withDefaults(\n defineProps<{\n name: string\n }>(),\n {}\n)\n</script>\n\n<template>\n <div>{{ props.name }}</div>\n</template>\n","<script setup lang=\"ts\">\nconst props = withDefaults(\n defineProps<{\n name: string\n }>(),\n {}\n)\n</script>\n\n<template>\n <div>{{ props.name }}</div>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport ADatetimePicker from '@/components/datetime/ADatetimePicker.vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isString, isUndefined } from '@/utils/common'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport type { DatetimeUTCNullable } from '@/types/common'\nimport { dateTimePretty } from '@/utils/datetime'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-datepicker',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name] as DatetimeUTCNullable\n },\n set(newValue: DatetimeUTCNullable) {\n filterData[props.name] = newValue\n updateSelected()\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst { t } = useI18n()\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n // `clearOne` writes the value the picker was about to emit, so its own emit is skipped as\n // unchanged and the model setter below never runs - the bookkeeping has to happen here.\n filterConfig.touched = true\n emit('change')\n}\n\nconst updateSelected = () => {\n // Unlike its siblings this component has no watcher on `filterData`, so `updateSelected` only\n // ever runs from the model setter - which `ADatetimePicker` suppresses for a programmatic\n // change. Deleting the chip here would be dead code. The gap that does exist is the opposite\n // one: a datetime restored from a hash or local storage never shows a chip at all. Adding the\n // watcher is not mechanical - it makes `clearField` recreate the chip for a non-empty default,\n // and starts showing datetime chips on eight lists that have none today.\n if (!isString(modelValue.value) || modelValue.value.length === 0) return\n filterSelected.value.set(props.name, [{ title: dateTimePretty(modelValue.value), value: modelValue.value }])\n}\n</script>\n\n<template>\n <ADatetimePicker\n v-model=\"modelValue\"\n :data-cy=\"dataCy\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :default-value=\"filterConfigCurrent.default as DatetimeUTCNullable\"\n :label=\"label\"\n v-bind=\"$attrs\"\n @after-clear=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport ADatetimePicker from '@/components/datetime/ADatetimePicker.vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { isString, isUndefined } from '@/utils/common'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport type { DatetimeUTCNullable } from '@/types/common'\nimport { dateTimePretty } from '@/utils/datetime'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n dataCy?: string\n }>(),\n {\n dataCy: 'filter-datepicker',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name] as DatetimeUTCNullable\n },\n set(newValue: DatetimeUTCNullable) {\n filterData[props.name] = newValue\n updateSelected()\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst { t } = useI18n()\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n // `clearOne` writes the value the picker was about to emit, so its own emit is skipped as\n // unchanged and the model setter below never runs - the bookkeeping has to happen here.\n filterConfig.touched = true\n emit('change')\n}\n\nconst updateSelected = () => {\n // Unlike its siblings this component has no watcher on `filterData`, so `updateSelected` only\n // ever runs from the model setter - which `ADatetimePicker` suppresses for a programmatic\n // change. Deleting the chip here would be dead code. The gap that does exist is the opposite\n // one: a datetime restored from a hash or local storage never shows a chip at all. Adding the\n // watcher is not mechanical - it makes `clearField` recreate the chip for a non-empty default,\n // and starts showing datetime chips on eight lists that have none today.\n if (!isString(modelValue.value) || modelValue.value.length === 0) return\n filterSelected.value.set(props.name, [{ title: dateTimePretty(modelValue.value), value: modelValue.value }])\n}\n</script>\n\n<template>\n <ADatetimePicker\n v-model=\"modelValue\"\n :data-cy=\"dataCy\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :default-value=\"filterConfigCurrent.default as DatetimeUTCNullable\"\n :label=\"label\"\n v-bind=\"$attrs\"\n @after-clear=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { computed, inject, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { isBoolean, isNumber, isString, isUndefined } from '@/utils/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n placeholder: undefined,\n dataCy: 'filter-integer',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (isNumber(modelValue.value)) {\n filterSelected.value.set(props.name, [{ title: modelValue.value + '', value: modelValue.value }])\n return\n }\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through would leave the\n // chip naming a value the query no longer carries.\n if (!isString(modelValue.value) || modelValue.value.length === 0) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value, value: modelValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected()\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VTextField\n v-model=\"modelValue\"\n :label=\"label\"\n :placeholder=\"placeholderComputed\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @blur=\"updateSelected\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { computed, inject, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { isBoolean, isNumber, isString, isUndefined } from '@/utils/common'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n placeholder?: string | undefined\n dataCy?: string\n }>(),\n {\n placeholder: undefined,\n dataCy: 'filter-integer',\n }\n)\nconst emit = defineEmits<{\n (e: 'change'): void\n}>()\n\nconst submitResetCounter = inject(FilterSubmitResetCounterKey)\nconst filterSelected = inject(FilterSelectedKey)\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\n\nif (\n isUndefined(submitResetCounter) ||\n isUndefined(filterSelected) ||\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name]) ||\n isUndefined(filterData) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterData[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst modelValue = computed({\n get() {\n return filterData[props.name]\n },\n set(newValue) {\n filterData[props.name] = newValue\n filterConfig.touched = true\n emit('change')\n },\n})\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst { t } = useI18n()\n\nconst label = computed(() => {\n return filterConfigCurrent.value.titleT ? t(filterConfigCurrent.value.titleT) : undefined\n})\n\nconst placeholderComputed = computed(() => {\n if (!isUndefined(props.placeholder)) return props.placeholder\n if (filterConfigCurrent.value.variant === 'startsWith') return t('common.model.filterPlaceholder.startsWith')\n if (filterConfigCurrent.value.variant === 'eq') return t('common.model.filterPlaceholder.eq')\n if (filterConfigCurrent.value.variant === 'search') return t('common.model.filterPlaceholder.contains')\n return ''\n})\n\nconst { clearOne } = useFilterClearHelpers()\n\nconst clearField = () => {\n clearOne(props.name, filterData, filterConfig)\n filterSelected.value.delete(props.name)\n}\n\nconst updateSelected = () => {\n if (isNumber(modelValue.value)) {\n filterSelected.value.set(props.name, [{ title: modelValue.value + '', value: modelValue.value }])\n return\n }\n // `null` reaches here when the filter is reset from outside - loading a hash clears every field\n // before applying it, and the chip has to go with the value. Falling through would leave the\n // chip naming a value the query no longer carries.\n if (!isString(modelValue.value) || modelValue.value.length === 0) {\n filterSelected.value.delete(props.name)\n return\n }\n filterSelected.value.set(props.name, [{ title: modelValue.value, value: modelValue.value }])\n}\n\nwatch(\n () => filterData[props.name],\n (newValue, oldValue) => {\n if (newValue === oldValue || isBoolean(newValue)) return\n updateSelected()\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VTextField\n v-model=\"modelValue\"\n :label=\"label\"\n :placeholder=\"placeholderComputed\"\n :clearable=\"!filterConfigCurrent.mandatory\"\n :data-cy=\"dataCy\"\n hide-details\n autocomplete=\"off\"\n @blur=\"updateSelected\"\n @click:clear.stop=\"clearField\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport { FilterConfigKey } from '@/labs/filters/filterInjectionKeys'\nimport { isUndefined } from '@/utils/common'\nimport AFilterEmpty from '@/labs/filters/AFilterEmpty.vue'\nimport AFilterString from '@/labs/filters/AFilterString.vue'\nimport AFilterBooleanSelect from '@/labs/filters/AFilterBooleanSelect.vue'\nimport AFilterDatetimePicker from '@/labs/filters/AFilterDatetimePicker.vue'\nimport AFilterInteger from '@/labs/filters/AFilterInteger.vue'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n }>(),\n {}\n)\n\nconst filterConfig = inject(FilterConfigKey)\n\nif (\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst componentComputed = computed(() => {\n if (filterConfigCurrent.value.render.skip) return AFilterEmpty\n switch (filterConfigCurrent.value.type) {\n case 'string':\n return AFilterString\n case 'datetime':\n return AFilterDatetimePicker\n case 'boolean':\n return AFilterBooleanSelect\n case 'integer':\n return AFilterInteger\n default:\n return AFilterEmpty\n }\n})\n</script>\n\n<template>\n <component\n :is=\"componentComputed\"\n :name=\"name\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport { FilterConfigKey } from '@/labs/filters/filterInjectionKeys'\nimport { isUndefined } from '@/utils/common'\nimport AFilterEmpty from '@/labs/filters/AFilterEmpty.vue'\nimport AFilterString from '@/labs/filters/AFilterString.vue'\nimport AFilterBooleanSelect from '@/labs/filters/AFilterBooleanSelect.vue'\nimport AFilterDatetimePicker from '@/labs/filters/AFilterDatetimePicker.vue'\nimport AFilterInteger from '@/labs/filters/AFilterInteger.vue'\n\nconst props = withDefaults(\n defineProps<{\n name: string\n }>(),\n {}\n)\n\nconst filterConfig = inject(FilterConfigKey)\n\nif (\n isUndefined(filterConfig) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterConfig.fields[props.name])\n) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst filterConfigCurrent = computed(() => filterConfig.fields[props.name])\n\nconst componentComputed = computed(() => {\n if (filterConfigCurrent.value.render.skip) return AFilterEmpty\n switch (filterConfigCurrent.value.type) {\n case 'string':\n return AFilterString\n case 'datetime':\n return AFilterDatetimePicker\n case 'boolean':\n return AFilterBooleanSelect\n case 'integer':\n return AFilterInteger\n default:\n return AFilterEmpty\n }\n})\n</script>\n\n<template>\n <component\n :is=\"componentComputed\"\n :name=\"name\"\n />\n</template>\n","import { createFilter, createFilterStore, type MakeFilterOption } from '@/labs/filters/filterFactory'\n\nexport function useUserAdminConfigInnerFilter(system: string, subject: string = 'userAdminConfig') {\n const filterFields = [\n { name: 'user' as const, default: null },\n { name: 'configType' as const, default: null },\n { name: 'layoutType' as const, default: null },\n { name: 'systemResource' as const, default: null },\n { name: 'customName' as const, default: null },\n { name: 'defaultConfig' as const, default: null },\n ] satisfies readonly MakeFilterOption[]\n\n const { filterConfig, filterData } = createFilter(filterFields, createFilterStore(filterFields), {\n system,\n subject,\n })\n\n return {\n filterConfig,\n filterData,\n }\n}\n","import type { AnzuUserAndTimeTrackingAware } from '@/types/AnzuUserAndTimeTrackingAware'\nimport type { SortableItemDataAware } from '@/components/sortable/sortableUtils'\nimport type { IntegerId } from '@/types/common'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\n\nexport interface UserAdminConfig<TData = UserAdminConfigDataFilterBookmark | UserAdminConfigDataPinnedWidgets>\n extends AnzuUserAndTimeTrackingAware, SortableItemDataAware {\n id: IntegerId\n user: IntegerId\n configType: UserAdminConfigTypeType\n layoutType: UserAdminConfigLayoutTypeType\n systemResource: string\n customName: string\n defaultConfig: boolean\n data: TData\n position: number\n _resourceName: 'userAdminConfig'\n _system: string\n}\n\nexport const UserAdminConfigType = {\n PinnedWidgets: 'pinnedWidgets',\n FilterBookmark: 'filterBookmark',\n} as const\nexport const UserAdminConfigTypeDefault = UserAdminConfigType.PinnedWidgets\nexport type UserAdminConfigTypeType = (typeof UserAdminConfigType)[keyof typeof UserAdminConfigType]\n\nexport const UserAdminConfigLayoutType = {\n Desktop: 'desktop',\n Mobile: 'mobile',\n} as const\nexport const UserAdminConfigLayoutTypeDefault = UserAdminConfigLayoutType.Desktop\nexport type UserAdminConfigLayoutTypeType = (typeof UserAdminConfigLayoutType)[keyof typeof UserAdminConfigLayoutType]\n\nexport interface UserAdminConfigDataFilterBookmark {\n filter: string\n datatableHiddenColumns?: string[]\n sortBy?: DatatableSortBy\n}\n\nexport type UserAdminConfigDataPinnedWidgets<TVariant extends string = string> = Array<{\n variant: TVariant\n position: number\n}>\n","import { acceptHMRUpdate, defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { useUserAdminConfigInnerFilter } from '@/labs/filters/UserAdminConfigFilter'\nimport { type UserAdminConfig, type UserAdminConfigLayoutTypeType, UserAdminConfigType } from '@/types/UserAdminConfig'\nimport type { IntegerId } from '@/types/common'\nimport type { UseApiFetchListReturnType } from '@/labs/api/useApiFetchList'\nimport { usePagination } from '@/labs/filters/pagination'\nimport { SortOrder } from '@/composables/system/datatableColumns'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\n\ninterface CacheItem<T = UserAdminConfig> {\n lastUsed: number\n items: T[]\n /**\n * The entry is known to be behind the server. It keeps its rows -- the filter bar reads them\n * straight out of this map and dropping them would blank it on screen -- but the next reader is\n * sent to the server instead of being handed them as current.\n */\n stale?: boolean\n}\n\nconst MAX_BOOKMARKS = 3\nexport const MAX_BOOKMARK_ITEMS = 8\n\nexport const useFilterBookmarkStore = defineStore('filterBookmarkStore', () => {\n const bookmarks = ref(new Map<string, CacheItem>())\n const error = ref(false)\n // A forced refetch can be asked for again before the first one has answered -- the bookmark\n // dialog does exactly that on every entry to its manage tab. Only the newest answer per key is\n // allowed to become the cache; an older one landing after it would put the filter bar back to\n // what it showed two refreshes ago.\n const fetchSequence = new Map<string, number>()\n\n function generateKey(layoutType: UserAdminConfigLayoutTypeType, systemResource: string) {\n return `userAdminConfig/${systemResource}/${layoutType}/`\n }\n\n function removeOldestBookmark() {\n let oldestKey: string | null = null\n let oldestTime = Infinity\n bookmarks.value.forEach((value, bookmarkKey) => {\n if (value.lastUsed < oldestTime) {\n oldestTime = value.lastUsed\n oldestKey = bookmarkKey\n }\n })\n if (oldestKey !== null) {\n bookmarks.value.delete(oldestKey)\n }\n }\n\n async function getBookmarks(\n identifier: {\n user: IntegerId\n layoutType: UserAdminConfigLayoutTypeType\n systemResource: string\n },\n useApiFetch: () => UseApiFetchListReturnType<UserAdminConfig>,\n forceFetch: boolean = false\n ): Promise<UserAdminConfig[] | null> {\n error.value = false\n const key = generateKey(identifier.layoutType, identifier.systemResource)\n const now = Date.now()\n\n if (!forceFetch) {\n const cached = bookmarks.value.get(key)\n if (cached && !cached.stale) {\n cached.lastUsed = now\n return [...cached.items]\n }\n }\n\n const { pagination } = usePagination('position', SortOrder.Asc, {\n rowsPerPage: MAX_BOOKMARK_ITEMS,\n })\n const { start: system, end: resource } = stringSplitOnFirstOccurrence(identifier.systemResource, '_')\n const { filterConfig, filterData } = useUserAdminConfigInnerFilter(system, resource)\n filterData.configType = UserAdminConfigType.FilterBookmark\n filterData.layoutType = identifier.layoutType\n filterData.systemResource = identifier.systemResource\n filterData.user = identifier.user\n\n const sequence = (fetchSequence.get(key) ?? 0) + 1\n fetchSequence.set(key, sequence)\n\n let items: UserAdminConfig[]\n try {\n const { execute } = useApiFetch()\n items = await execute(pagination, filterData, filterConfig)\n if (fetchSequence.get(key) === sequence) {\n bookmarks.value.set(key, { lastUsed: now, items })\n }\n } catch (e) {\n // An overtaken answer says nothing about the newer one that replaced it, failure included.\n if (fetchSequence.get(key) === sequence) {\n error.value = true\n // A forced refetch is asked for because something is known to have changed, so a failed one\n // leaves nothing to trust in the cache either.\n markStale(key)\n }\n // `null`, not an empty array: \"there are no bookmarks\" and \"this request died\" are different\n // answers, and the caller can only tell them apart if they look different. The `error` flag is\n // one per store, so it cannot say which request it belongs to.\n return null\n }\n\n if (bookmarks.value.size > MAX_BOOKMARKS) {\n removeOldestBookmark()\n }\n\n // A copy, never the array the cache holds. `addOne` pushes into that one so the filter bar\n // picks the new bookmark up on the spot, and a caller that keeps what it was handed -- the\n // manage dialog keeps it as its editor's model -- would otherwise get that row pushed into its\n // list from the outside, where it reads as something the user added and never saved.\n return [...items]\n }\n\n /**\n * What a new bookmark needs to know: how many there are, which is what the cap is checked\n * against, and the highest position in use, which is what it has to sort after.\n *\n * The two are not the same number. Positions go dense only when the manage dialog saves an\n * order -- it renumbers exactly the rows it sends -- so a row created while another was pending\n * deletion leaves a gap behind, and from then on the count is lower than the highest position.\n * Deriving a new position from the count would then hand it one already in use: two rows on the\n * same position, which the list has no second key to order by, or with more than one deletion a\n * position below a row created earlier.\n */\n async function fetchBookmarkStats(\n identifier: {\n user: IntegerId\n layoutType: UserAdminConfigLayoutTypeType\n systemResource: string\n },\n useApiFetch: () => UseApiFetchListReturnType<UserAdminConfig>\n ): Promise<{ count: number; maxPosition: number }> {\n error.value = false\n const { pagination } = usePagination('position', SortOrder.Asc, {\n rowsPerPage: MAX_BOOKMARK_ITEMS + 1,\n })\n const { start: system, end: resource } = stringSplitOnFirstOccurrence(identifier.systemResource, '_')\n const { filterConfig, filterData } = useUserAdminConfigInnerFilter(system, resource)\n filterData.configType = UserAdminConfigType.FilterBookmark\n filterData.layoutType = identifier.layoutType\n filterData.systemResource = identifier.systemResource\n filterData.user = identifier.user\n\n try {\n const { execute } = useApiFetch()\n // The page is capped one above the maximum a user may have, so a list long enough to hide the\n // real highest position is also one the count refuses to add to. Read across the rows rather\n // than off the last one: taking the last would tie this to the sort order asked for above,\n // and flipping that would quietly turn the highest position into the lowest -- with nothing\n // to show for it, since the order the bar draws comes from a different call.\n const res = await execute(pagination, filterData, filterConfig)\n return {\n count: res.length,\n maxPosition: res.length > 0 ? Math.max(...res.map((item) => item.position)) : 0,\n }\n } catch (e) {\n error.value = true\n // `Infinity` keeps what a failed count has always done: refuse the add rather than create a\n // bookmark past a cap nobody could check.\n return { count: Infinity, maxPosition: 0 }\n }\n }\n\n /**\n * A write straight into what is cached is newer than any answer already on its way, so it counts\n * as an answer of its own. Without this an in-flight fetch -- issued before the write, so its\n * rows know nothing about it -- would come back and overwrite the cache, taking the write with\n * it, and only the next forced fetch would bring it back.\n */\n function supersedeInFlight(key: string) {\n fetchSequence.set(key, (fetchSequence.get(key) ?? 0) + 1)\n }\n\n function addOne(key: string, data: UserAdminConfig) {\n const cached = bookmarks.value.get(key)\n // Nothing cached means nothing to add to and nothing to protect: superseding here would throw\n // away the answer of a fetch already on its way and leave the bar with no bookmarks at all,\n // which is worse than it missing the one just created until the next refresh brings it.\n if (!cached) return\n cached.items.push(data)\n supersedeInFlight(key)\n }\n\n /**\n * Drop one bookmark from what is cached, in place, the way `addOne` adds one -- so a delete that\n * went through stops being offered by a filter bar that is already on screen. It reads this map\n * straight and does not fetch again for itself.\n */\n function removeOne(key: string, id: IntegerId) {\n const cached = bookmarks.value.get(key)\n if (!cached) return\n cached.items = cached.items.filter((item) => item.id !== id)\n supersedeInFlight(key)\n }\n\n /**\n * Say that what is cached under this key is behind the server -- after a write whose refresh did\n * not happen, or one that failed. The rows stay readable for whoever is already showing them; the\n * next read goes to the server.\n */\n function markStale(key: string) {\n const cached = bookmarks.value.get(key)\n if (cached) cached.stale = true\n }\n\n return {\n bookmarks,\n error,\n getBookmarks,\n generateKey,\n addOne,\n removeOne,\n markStale,\n fetchBookmarkStats,\n }\n})\n\nif (import.meta.hot) {\n import.meta.hot.accept(acceptHMRUpdate(useFilterBookmarkStore, import.meta.hot))\n}\n","import type { AxiosInstance } from 'axios'\nimport { useApiFetchList } from '@/labs/api/useApiFetchList'\nimport type { IntegerId } from '@/types/common'\nimport type { UserAdminConfig } from '@/types/UserAdminConfig'\nimport { useApiCommand, useApiRequest } from '@/labs/api/useApiRequest'\n\nexport const END_POINT = '/adm/v1/user-admin-config'\nconst ENTITY = 'userAdminConfig'\n\nexport function useUserAdminConfigApi(\n client: () => AxiosInstance,\n system: string,\n entity: string = ENTITY,\n endPoint: string = END_POINT\n) {\n const useFetchUserAdminConfigList = () =>\n useApiFetchList<UserAdminConfig>({ client, system, entity, urlTemplate: END_POINT })\n\n const fetchUserAdminConfig = (id: IntegerId) => {\n const { execute } = useApiRequest<UserAdminConfig>({\n client,\n method: 'GET',\n system,\n entity,\n })\n return execute({ urlTemplate: endPoint + '/:id', urlParams: { id } })\n }\n\n const createUserAdminConfig = (data: UserAdminConfig) => {\n const { execute } = useApiRequest<UserAdminConfig, UserAdminConfig>({\n client,\n method: 'POST',\n system,\n entity,\n })\n return execute({ urlTemplate: endPoint, body: data })\n }\n\n const updateUserAdminConfig = (id: IntegerId, data: UserAdminConfig) => {\n const { execute } = useApiRequest<UserAdminConfig, UserAdminConfig>({\n client,\n method: 'PUT',\n system,\n entity,\n })\n return execute({ urlTemplate: endPoint + '/:id', urlParams: { id }, body: data })\n }\n\n const deleteUserAdminConfig = (id: IntegerId) => {\n const { execute } = useApiCommand({ client, method: 'DELETE', system, entity })\n return execute({ urlTemplate: endPoint + '/:id', urlParams: { id } })\n }\n\n const updateUserAdminConfigPositions = (ids: IntegerId[]) => {\n const { execute } = useApiRequest<{ userAdminConfigs: IntegerId[] }, { userAdminConfigs: IntegerId[] }>({\n client,\n method: 'PATCH',\n system,\n entity,\n })\n return execute({\n urlTemplate: endPoint + '/update-positions',\n body: { userAdminConfigs: ids },\n })\n }\n\n return {\n useFetchUserAdminConfigList,\n fetchUserAdminConfig,\n createUserAdminConfig,\n updateUserAdminConfig,\n deleteUserAdminConfig,\n updateUserAdminConfigPositions,\n }\n}\n","<script lang=\"ts\" setup>\nimport { computed, inject, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useFilterBookmarkStore } from '@/labs/filters/bookmarksStore'\nimport { useUserAdminConfigApi } from '@/labs/filters/userAdminConfig'\nimport type { AxiosInstance } from 'axios'\nimport {\n type UserAdminConfig,\n type UserAdminConfigDataFilterBookmark,\n UserAdminConfigLayoutType,\n} from '@/types/UserAdminConfig'\nimport type { IntegerId } from '@/types/common'\nimport { useResizeObserver, watchThrottled } from '@vueuse/core'\nimport { cloneDeep, isDefined, isNull, isString, isUndefined } from '@/utils/common'\nimport {\n DatatablePaginationKey,\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { type FilterData, useFilterHelpers } from '@/labs/filters/filterFactory'\nimport { stringToBooleanExact, stringToNumber } from '@/utils/string'\n\nconst props = withDefaults(\n defineProps<{\n client: () => AxiosInstance\n userId: IntegerId\n system: string\n subject: string\n }>(),\n {}\n)\n\nconst emit = defineEmits<{\n (e: 'submit'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: true,\n})\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst pagination = inject(DatatablePaginationKey)\nconst filterSelected = inject(FilterSelectedKey)\n\nif (isUndefined(pagination) || isUndefined(filterConfig) || isUndefined(filterData) || isUndefined(filterSelected)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst loading = ref(false)\nconst toolbarRef = useTemplateRef('toolbar')\nconst toolbarWidth = ref(300)\nconst visibleItemsCount = ref(1000)\n\nconst filterBookmarkStore = useFilterBookmarkStore()\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { useFetchUserAdminConfigList } = useUserAdminConfigApi(props.client, props.system)\n\nconst systemResource = props.system + '_' + props.subject\n\nconst loadBookmarks = async (force = false) => {\n loading.value = true\n await filterBookmarkStore.getBookmarks(\n {\n user: props.userId,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList,\n force\n )\n loading.value = false\n}\n\nconst { deserializeFilters } = useFilterHelpers(filterData, filterConfig)\n\nconst onItemClick = (item: UserAdminConfig) => {\n const config = item.data as UserAdminConfigDataFilterBookmark\n if (isDefined(config.datatableHiddenColumns) && isDefined(datatableHiddenColumns.value)) {\n datatableHiddenColumns.value = config.datatableHiddenColumns\n }\n if (isDefined(config.sortBy)) {\n pagination.value = {\n ...pagination.value,\n sortBy: { key: config.sortBy!.key, order: config.sortBy!.order },\n }\n }\n const deserialized = deserializeFilters(config.filter)\n if (isNull(deserialized)) return\n for (const filterName in filterData) {\n const key = filterName as keyof FilterData\n let value = deserialized.filters[key]\n if (isUndefined(value) && filterConfig.fields[key]?.clearable) {\n filterData[key] = cloneDeep(filterConfig.fields[key].default)\n filterSelected.value.delete(key)\n continue\n }\n if (isString(value)) {\n const tryConvertNumber = stringToNumber(value)\n if (!isNull(tryConvertNumber)) {\n value = tryConvertNumber\n } else {\n // If not a number, try to convert to boolean\n const tryConvertBoolean = stringToBooleanExact(value)\n if (!isNull(tryConvertBoolean)) {\n value = tryConvertBoolean\n }\n }\n }\n filterData[key] = value\n }\n emit('submit')\n}\n\nconst THREE_DOTS_WIDTH = 32\n\nconst calculateVisible = async (totalWidth: number) => {\n const container = toolbarRef.value\n if (isNull(container)) return\n visibleItemsCount.value = 1000\n await nextTick()\n let cumulativeWidth = 0\n let visible = 0\n for (let i = 0; i < container.children.length; i++) {\n const child = container.children[i] as HTMLElement\n const childWidth = child.offsetWidth\n cumulativeWidth += childWidth\n if (cumulativeWidth >= totalWidth - THREE_DOTS_WIDTH) {\n break\n }\n visible++\n }\n visibleItemsCount.value = visible\n}\n\nuseResizeObserver(toolbarRef, (entries) => {\n if (entries[0]) {\n toolbarWidth.value = entries[0].contentRect.width\n }\n})\n\nwatchThrottled(\n toolbarWidth,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n calculateVisible(newValue)\n },\n { throttle: 1000 }\n)\n\nconst items = computed(() => {\n const key = filterBookmarkStore.generateKey(UserAdminConfigLayoutType.Desktop, systemResource)\n const result = filterBookmarkStore.bookmarks.get(key)\n return result?.items ?? []\n})\n\nconst itemsComputed = computed(() => {\n const visible = visibleItemsCount.value\n return {\n visible: items.value.slice(0, visible),\n hidden: items.value.slice(visible),\n }\n})\n\nwatch([loading, () => items.value.length], ([newLoading]) => {\n if (newLoading === true || isNull(toolbarRef.value)) return\n toolbarWidth.value = toolbarRef.value.clientWidth\n nextTick(() => {\n calculateVisible(toolbarWidth.value)\n })\n})\n\nonMounted(() => {\n loadBookmarks()\n})\n</script>\n\n<template>\n <div\n ref=\"toolbar\"\n :key=\"items.length\"\n class=\"w-100 d-flex overflow-hidden align-center mb-1\"\n >\n <div v-if=\"loading\" />\n <template v-else>\n <div\n v-for=\"item in itemsComputed.visible\"\n :key=\"item.id\"\n class=\"white-space-nowrap\"\n >\n <VBtn\n variant=\"text\"\n prepend-icon=\"mdi-bookmark-outline\"\n size=\"small\"\n class=\"mr-1 mb-1 bg-grey-lighten-4 text-grey-darken-3\"\n @click=\"onItemClick(item)\"\n >\n {{ item.customName }}\n </VBtn>\n </div>\n <VMenu\n v-if=\"itemsComputed.hidden.length > 0\"\n location=\"bottom\"\n >\n <template #activator=\"{ props: activatorProps }\">\n <VBtn\n icon=\"mdi-menu-down\"\n size=\"x-small\"\n :width=\"28\"\n :height=\"28\"\n v-bind=\"activatorProps\"\n />\n </template>\n <VList density=\"compact\">\n <VListItem\n v-for=\"item in itemsComputed.hidden\"\n :key=\"item.id\"\n @click=\"onItemClick(item)\"\n >\n <VListItemTitle>{{ item.customName }}</VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </template>\n </div>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport { useFilterBookmarkStore } from '@/labs/filters/bookmarksStore'\nimport { useUserAdminConfigApi } from '@/labs/filters/userAdminConfig'\nimport type { AxiosInstance } from 'axios'\nimport {\n type UserAdminConfig,\n type UserAdminConfigDataFilterBookmark,\n UserAdminConfigLayoutType,\n} from '@/types/UserAdminConfig'\nimport type { IntegerId } from '@/types/common'\nimport { useResizeObserver, watchThrottled } from '@vueuse/core'\nimport { cloneDeep, isDefined, isNull, isString, isUndefined } from '@/utils/common'\nimport {\n DatatablePaginationKey,\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport { type FilterData, useFilterHelpers } from '@/labs/filters/filterFactory'\nimport { stringToBooleanExact, stringToNumber } from '@/utils/string'\n\nconst props = withDefaults(\n defineProps<{\n client: () => AxiosInstance\n userId: IntegerId\n system: string\n subject: string\n }>(),\n {}\n)\n\nconst emit = defineEmits<{\n (e: 'submit'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: true,\n})\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst pagination = inject(DatatablePaginationKey)\nconst filterSelected = inject(FilterSelectedKey)\n\nif (isUndefined(pagination) || isUndefined(filterConfig) || isUndefined(filterData) || isUndefined(filterSelected)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst loading = ref(false)\nconst toolbarRef = useTemplateRef('toolbar')\nconst toolbarWidth = ref(300)\nconst visibleItemsCount = ref(1000)\n\nconst filterBookmarkStore = useFilterBookmarkStore()\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { useFetchUserAdminConfigList } = useUserAdminConfigApi(props.client, props.system)\n\nconst systemResource = props.system + '_' + props.subject\n\nconst loadBookmarks = async (force = false) => {\n loading.value = true\n await filterBookmarkStore.getBookmarks(\n {\n user: props.userId,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList,\n force\n )\n loading.value = false\n}\n\nconst { deserializeFilters } = useFilterHelpers(filterData, filterConfig)\n\nconst onItemClick = (item: UserAdminConfig) => {\n const config = item.data as UserAdminConfigDataFilterBookmark\n if (isDefined(config.datatableHiddenColumns) && isDefined(datatableHiddenColumns.value)) {\n datatableHiddenColumns.value = config.datatableHiddenColumns\n }\n if (isDefined(config.sortBy)) {\n pagination.value = {\n ...pagination.value,\n sortBy: { key: config.sortBy!.key, order: config.sortBy!.order },\n }\n }\n const deserialized = deserializeFilters(config.filter)\n if (isNull(deserialized)) return\n for (const filterName in filterData) {\n const key = filterName as keyof FilterData\n let value = deserialized.filters[key]\n if (isUndefined(value) && filterConfig.fields[key]?.clearable) {\n filterData[key] = cloneDeep(filterConfig.fields[key].default)\n filterSelected.value.delete(key)\n continue\n }\n if (isString(value)) {\n const tryConvertNumber = stringToNumber(value)\n if (!isNull(tryConvertNumber)) {\n value = tryConvertNumber\n } else {\n // If not a number, try to convert to boolean\n const tryConvertBoolean = stringToBooleanExact(value)\n if (!isNull(tryConvertBoolean)) {\n value = tryConvertBoolean\n }\n }\n }\n filterData[key] = value\n }\n emit('submit')\n}\n\nconst THREE_DOTS_WIDTH = 32\n\nconst calculateVisible = async (totalWidth: number) => {\n const container = toolbarRef.value\n if (isNull(container)) return\n visibleItemsCount.value = 1000\n await nextTick()\n let cumulativeWidth = 0\n let visible = 0\n for (let i = 0; i < container.children.length; i++) {\n const child = container.children[i] as HTMLElement\n const childWidth = child.offsetWidth\n cumulativeWidth += childWidth\n if (cumulativeWidth >= totalWidth - THREE_DOTS_WIDTH) {\n break\n }\n visible++\n }\n visibleItemsCount.value = visible\n}\n\nuseResizeObserver(toolbarRef, (entries) => {\n if (entries[0]) {\n toolbarWidth.value = entries[0].contentRect.width\n }\n})\n\nwatchThrottled(\n toolbarWidth,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n calculateVisible(newValue)\n },\n { throttle: 1000 }\n)\n\nconst items = computed(() => {\n const key = filterBookmarkStore.generateKey(UserAdminConfigLayoutType.Desktop, systemResource)\n const result = filterBookmarkStore.bookmarks.get(key)\n return result?.items ?? []\n})\n\nconst itemsComputed = computed(() => {\n const visible = visibleItemsCount.value\n return {\n visible: items.value.slice(0, visible),\n hidden: items.value.slice(visible),\n }\n})\n\nwatch([loading, () => items.value.length], ([newLoading]) => {\n if (newLoading === true || isNull(toolbarRef.value)) return\n toolbarWidth.value = toolbarRef.value.clientWidth\n nextTick(() => {\n calculateVisible(toolbarWidth.value)\n })\n})\n\nonMounted(() => {\n loadBookmarks()\n})\n</script>\n\n<template>\n <div\n ref=\"toolbar\"\n :key=\"items.length\"\n class=\"w-100 d-flex overflow-hidden align-center mb-1\"\n >\n <div v-if=\"loading\" />\n <template v-else>\n <div\n v-for=\"item in itemsComputed.visible\"\n :key=\"item.id\"\n class=\"white-space-nowrap\"\n >\n <VBtn\n variant=\"text\"\n prepend-icon=\"mdi-bookmark-outline\"\n size=\"small\"\n class=\"mr-1 mb-1 bg-grey-lighten-4 text-grey-darken-3\"\n @click=\"onItemClick(item)\"\n >\n {{ item.customName }}\n </VBtn>\n </div>\n <VMenu\n v-if=\"itemsComputed.hidden.length > 0\"\n location=\"bottom\"\n >\n <template #activator=\"{ props: activatorProps }\">\n <VBtn\n icon=\"mdi-menu-down\"\n size=\"x-small\"\n :width=\"28\"\n :height=\"28\"\n v-bind=\"activatorProps\"\n />\n </template>\n <VList density=\"compact\">\n <VListItem\n v-for=\"item in itemsComputed.hidden\"\n :key=\"item.id\"\n @click=\"onItemClick(item)\"\n >\n <VListItemTitle>{{ item.customName }}</VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </template>\n </div>\n</template>\n","import { computed, type ComputedRef, type Ref } from 'vue'\nimport { useElementSize } from '@vueuse/core'\n\n// Aligns JS-driven layout decisions (close button variant, mobile title icon)\n// with the CSS `@container le-shell` queries which fire on the editor's own\n// width rather than the viewport. Default threshold matches the 768/769 split\n// in `_shared.scss` and per-component narrow-container blocks.\nexport function useContainerWidth(\n el: Ref<HTMLElement | null | undefined>,\n threshold = 769\n): { width: Ref<number>; isNarrow: ComputedRef<boolean> } {\n const { width } = useElementSize(el)\n const isNarrow = computed(() => width.value > 0 && width.value < threshold)\n return { width, isNarrow }\n}\n","import { computed, type ComputedRef } from 'vue'\nimport { useMediaQuery } from '@vueuse/core'\n\n// Which reorder affordances does this device get? The two questions are deliberately independent,\n// because a device can answer yes to both — and then it gets both.\n//\n// The rule (Pointer Events / dnd-kit / pragmatic-drag-and-drop all land here): never detect a device\n// in order to HIDE a way to act. A hybrid — a touchscreen laptop, a convertible, a stylus tablet —\n// switches input mid-session, so any prediction strands the user at the exact moment they reach for\n// the row: fold the laptop, try to drag with a finger, and the page scrolls instead. Offering both\n// removes that moment entirely, and it is what the rest of this library already does — outside the\n// chips layout the arrows are always present in reorder mode and the handle is an addition to them.\n\n// Can the user press-grab-move-release the way a mouse does? `(any-pointer: fine)` is true when ANY\n// available input is precise — a mouse, a trackpad or a pen, all of which can drag. Its negation is\n// \"coarse input only\", the one case where dragging genuinely does not work.\n//\n// Note this is NOT \"is it a phone\": a laptop with a touchscreen driven by a mouse must keep its\n// handle. Asking `(any-pointer: coarse)` here instead took it away, and two users on identical\n// browsers saw different affordances purely because one laptop had a touch panel.\n//\n// Where matchMedia is unavailable the query reads false → treated as touch → arrows, the safe\n// direction: the fallback always works.\nexport function useIsTouchDevice(): ComputedRef<boolean> {\n const hasFinePointer = useMediaQuery('(any-pointer: fine)')\n\n return computed<boolean>(() => !hasFinePointer.value)\n}\n\n// Could a finger be used here at all? Deliberately NOT the inverse of the above — a hybrid answers\n// true to both. Layouts that would otherwise swap the arrows out for the handle keep them wherever\n// this is true, so a user who puts the mouse down is never left with an affordance they cannot use.\nexport function useHasCoarsePointer(): ComputedRef<boolean> {\n const coarsePointer = useMediaQuery('(any-pointer: coarse)')\n\n return computed<boolean>(() => coarsePointer.value)\n}\n","import { computed, ref, watch, type ComputedRef, type Ref } from 'vue'\nimport type { ListEditorKey } from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface KeyboardNavViewItem {\n key: ListEditorKey\n expanded?: boolean\n canExpand?: boolean\n canIndent?: boolean\n canOutdent?: boolean\n}\n\nexport type KeyboardNavVariant = 'flat' | 'sortable' | 'nested'\n\nexport interface KeyboardNavOptions {\n viewItems: ComputedRef<KeyboardNavViewItem[]>\n variant: KeyboardNavVariant\n isReorderMode: Ref<boolean> | ComputedRef<boolean>\n disabled?: Ref<boolean> | ComputedRef<boolean>\n\n isEditing: (key: ListEditorKey) => boolean\n\n onToggleEdit?: (key: ListEditorKey) => void\n onCancelEdit?: (key: ListEditorKey) => void\n\n onMoveUp?: (key: ListEditorKey) => void\n onMoveDown?: (key: ListEditorKey) => void\n onMoveTop?: (key: ListEditorKey) => void\n onMoveBottom?: (key: ListEditorKey) => void\n\n onIndent?: (key: ListEditorKey) => void\n onOutdent?: (key: ListEditorKey) => void\n onToggleChildren?: (key: ListEditorKey, expand: boolean) => void\n\n onCancelReorder?: () => void\n}\n\nexport interface KeyboardNavApi {\n focusedKey: Ref<ListEditorKey | null>\n grabbedKey: Ref<ListEditorKey | null>\n /** 0-based index of the grabbed row in the current ordering, or -1 if no grab. */\n grabbedIndex: ComputedRef<number>\n /** Total count of rows currently in the editor. */\n totalCount: ComputedRef<number>\n isFocused: (key: ListEditorKey) => boolean\n isGrabbed: (key: ListEditorKey) => boolean\n rowTabindex: (key: ListEditorKey) => number\n setFocus: (key: ListEditorKey | null) => void\n releaseGrab: () => void\n handleKeydown: (key: ListEditorKey, e: KeyboardEvent) => void\n}\n\n// Roving tabindex + keyboard navigation for list-editor rows. Single tabstop\n// per editor; arrow keys move an internal pointer; reorder mode adds a \"grab\"\n// state where Enter/Space picks up the focused row and arrows move it.\nexport function useKeyboardNav(options: KeyboardNavOptions): KeyboardNavApi {\n const focusedKey = ref<ListEditorKey | null>(null)\n const grabbedKey = ref<ListEditorKey | null>(null)\n\n const orderedKeys = computed<ListEditorKey[]>(() => options.viewItems.value.map((v) => v.key))\n\n const isFocused = (key: ListEditorKey): boolean => focusedKey.value === key\n const isGrabbed = (key: ListEditorKey): boolean => grabbedKey.value === key\n\n const grabbedIndex = computed<number>(() => {\n if (grabbedKey.value === null) return -1\n return orderedKeys.value.indexOf(grabbedKey.value)\n })\n\n const totalCount = computed<number>(() => orderedKeys.value.length)\n\n function rowTabindex(key: ListEditorKey): number {\n const ordered = orderedKeys.value\n if (ordered.length === 0) return -1\n if (focusedKey.value === null) return ordered[0] === key ? 0 : -1\n return focusedKey.value === key ? 0 : -1\n }\n\n function focusRowElement(key: ListEditorKey | null) {\n if (key === null || typeof document === 'undefined') return\n void Promise.resolve().then(() => {\n const el = document.querySelector<HTMLElement>(`[data-id=\"${CSS.escape(String(key))}\"]`)\n el?.focus()\n })\n }\n\n function setFocus(key: ListEditorKey | null) {\n focusedKey.value = key\n focusRowElement(key)\n }\n\n // When the focused row is removed (e.g. via delete), fall to the row that\n // took its slot, or to the new last row if it was at the end. Without this,\n // focus vanishes to <body> after a delete and the user has to Tab back in.\n // We snapshot the previous ordering so we can look up where the focused key\n // *was* — by the time the watcher fires, the key is already gone from `now`.\n // eslint-disable-next-line vue/no-ref-object-reactivity-loss\n let prevOrderedKeys: ListEditorKey[] = [...orderedKeys.value]\n watch(orderedKeys, (now) => {\n if (focusedKey.value === null) {\n prevOrderedKeys = [...now]\n return\n }\n if (now.includes(focusedKey.value)) {\n prevOrderedKeys = [...now]\n return\n }\n if (now.length === 0) {\n focusedKey.value = null\n prevOrderedKeys = []\n return\n }\n const oldIndex = prevOrderedKeys.indexOf(focusedKey.value)\n const fallbackIndex = Math.min(Math.max(oldIndex, 0), now.length - 1)\n setFocus(now[fallbackIndex])\n prevOrderedKeys = [...now]\n })\n\n // Releasing a grab when the grabbed row is no longer in the list — keeps the\n // grab state consistent if the row gets removed externally.\n watch(orderedKeys, (now) => {\n if (grabbedKey.value !== null && !now.includes(grabbedKey.value)) {\n grabbedKey.value = null\n }\n })\n\n function releaseGrab() {\n grabbedKey.value = null\n }\n\n function isFormField(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n return !!el?.matches?.('input, textarea, select, [contenteditable], [contenteditable=\"true\"]')\n }\n\n function handleKeydown(key: ListEditorKey, e: KeyboardEvent) {\n if (options.disabled?.value) return\n\n const ordered = orderedKeys.value\n const i = ordered.indexOf(key)\n if (i < 0) return\n\n const focusedItem = options.viewItems.value[i]\n const inReorder = options.isReorderMode.value\n const isGrabbedNow = grabbedKey.value === key\n const grabbedSomewhere = grabbedKey.value !== null\n\n // Form fields keep native key behavior (cursor, newlines, selection) for\n // every key except Escape. Esc still closes the edit panel even mid-typing.\n const onFormField = isFormField(e.target)\n\n switch (e.key) {\n case 'ArrowUp':\n if (onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow) {\n options.onMoveUp?.(key)\n } else if (i > 0) {\n setFocus(ordered[i - 1])\n }\n return\n\n case 'ArrowDown':\n if (onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow) {\n options.onMoveDown?.(key)\n } else if (i < ordered.length - 1) {\n setFocus(ordered[i + 1])\n }\n return\n\n case 'Home':\n if (onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow) {\n options.onMoveTop?.(key)\n } else if (ordered.length > 0) {\n setFocus(ordered[0])\n }\n return\n\n case 'End':\n if (onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow) {\n options.onMoveBottom?.(key)\n } else if (ordered.length > 0) {\n setFocus(ordered[ordered.length - 1])\n }\n return\n\n case 'ArrowLeft':\n if (options.variant !== 'nested' || onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow && focusedItem.canOutdent) {\n options.onOutdent?.(key)\n } else if (focusedItem.expanded) {\n options.onToggleChildren?.(key, false)\n }\n return\n\n case 'ArrowRight':\n if (options.variant !== 'nested' || onFormField) return\n e.preventDefault()\n if (inReorder && isGrabbedNow && focusedItem.canIndent) {\n options.onIndent?.(key)\n } else if (focusedItem.canExpand && !focusedItem.expanded) {\n options.onToggleChildren?.(key, true)\n }\n return\n\n case 'Enter':\n case ' ': // Space\n if (onFormField) return\n e.preventDefault()\n if (inReorder) {\n if (isGrabbedNow) {\n grabbedKey.value = null\n } else {\n grabbedKey.value = key\n }\n } else {\n options.onToggleEdit?.(key)\n }\n return\n\n case 'Escape':\n if (grabbedSomewhere) {\n e.preventDefault()\n grabbedKey.value = null\n return\n }\n if (inReorder) {\n e.preventDefault()\n options.onCancelReorder?.()\n return\n }\n if (options.isEditing(key)) {\n e.preventDefault()\n options.onCancelEdit?.(key)\n return\n }\n return\n\n default:\n return\n }\n }\n\n return {\n focusedKey,\n grabbedKey,\n grabbedIndex,\n totalCount,\n isFocused,\n isGrabbed,\n rowTabindex,\n setFocus,\n releaseGrab,\n handleKeydown,\n }\n}\n","/**!\n * Sortable 1.15.7\n * @author\tRubaXa <trash@rubaxa.org>\n * @author\towenm <owen23355@gmail.com>\n * @license MIT\n */\nfunction _arrayLikeToArray(r, a) {\n (null == a || a > r.length) && (a = r.length);\n for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];\n return n;\n}\nfunction _arrayWithoutHoles(r) {\n if (Array.isArray(r)) return _arrayLikeToArray(r);\n}\nfunction _defineProperty(e, r, t) {\n return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n value: t,\n enumerable: !0,\n configurable: !0,\n writable: !0\n }) : e[r] = t, e;\n}\nfunction _extends() {\n return _extends = Object.assign ? Object.assign.bind() : function (n) {\n for (var e = 1; e < arguments.length; e++) {\n var t = arguments[e];\n for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);\n }\n return n;\n }, _extends.apply(null, arguments);\n}\nfunction _iterableToArray(r) {\n if (\"undefined\" != typeof Symbol && null != r[Symbol.iterator] || null != r[\"@@iterator\"]) return Array.from(r);\n}\nfunction _nonIterableSpread() {\n throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\");\n}\nfunction ownKeys(e, r) {\n var t = Object.keys(e);\n if (Object.getOwnPropertySymbols) {\n var o = Object.getOwnPropertySymbols(e);\n r && (o = o.filter(function (r) {\n return Object.getOwnPropertyDescriptor(e, r).enumerable;\n })), t.push.apply(t, o);\n }\n return t;\n}\nfunction _objectSpread2(e) {\n for (var r = 1; r < arguments.length; r++) {\n var t = null != arguments[r] ? arguments[r] : {};\n r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {\n _defineProperty(e, r, t[r]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n });\n }\n return e;\n}\nfunction _objectWithoutProperties(e, t) {\n if (null == e) return {};\n var o,\n r,\n i = _objectWithoutPropertiesLoose(e, t);\n if (Object.getOwnPropertySymbols) {\n var n = Object.getOwnPropertySymbols(e);\n for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);\n }\n return i;\n}\nfunction _objectWithoutPropertiesLoose(r, e) {\n if (null == r) return {};\n var t = {};\n for (var n in r) if ({}.hasOwnProperty.call(r, n)) {\n if (-1 !== e.indexOf(n)) continue;\n t[n] = r[n];\n }\n return t;\n}\nfunction _toConsumableArray(r) {\n return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread();\n}\nfunction _toPrimitive(t, r) {\n if (\"object\" != typeof t || !t) return t;\n var e = t[Symbol.toPrimitive];\n if (void 0 !== e) {\n var i = e.call(t, r || \"default\");\n if (\"object\" != typeof i) return i;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (\"string\" === r ? String : Number)(t);\n}\nfunction _toPropertyKey(t) {\n var i = _toPrimitive(t, \"string\");\n return \"symbol\" == typeof i ? i : i + \"\";\n}\nfunction _typeof(o) {\n \"@babel/helpers - typeof\";\n\n return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) {\n return typeof o;\n } : function (o) {\n return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o;\n }, _typeof(o);\n}\nfunction _unsupportedIterableToArray(r, a) {\n if (r) {\n if (\"string\" == typeof r) return _arrayLikeToArray(r, a);\n var t = {}.toString.call(r).slice(8, -1);\n return \"Object\" === t && r.constructor && (t = r.constructor.name), \"Map\" === t || \"Set\" === t ? Array.from(r) : \"Arguments\" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;\n }\n}\n\nvar version = \"1.15.7\";\n\nfunction userAgent(pattern) {\n if (typeof window !== 'undefined' && window.navigator) {\n return !! /*@__PURE__*/navigator.userAgent.match(pattern);\n }\n}\nvar IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\\.|msie|iemobile|Windows Phone)/i);\nvar Edge = userAgent(/Edge/i);\nvar FireFox = userAgent(/firefox/i);\nvar Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);\nvar IOS = userAgent(/iP(ad|od|hone)/i);\nvar ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);\n\nvar captureMode = {\n capture: false,\n passive: false\n};\nfunction on(el, event, fn) {\n el.addEventListener(event, fn, !IE11OrLess && captureMode);\n}\nfunction off(el, event, fn) {\n el.removeEventListener(event, fn, !IE11OrLess && captureMode);\n}\nfunction matches( /**HTMLElement*/el, /**String*/selector) {\n if (!selector) return;\n selector[0] === '>' && (selector = selector.substring(1));\n if (el) {\n try {\n if (el.matches) {\n return el.matches(selector);\n } else if (el.msMatchesSelector) {\n return el.msMatchesSelector(selector);\n } else if (el.webkitMatchesSelector) {\n return el.webkitMatchesSelector(selector);\n }\n } catch (_) {\n return false;\n }\n }\n return false;\n}\nfunction getParentOrHost(el) {\n return el.host && el !== document && el.host.nodeType && el.host !== el ? el.host : el.parentNode;\n}\nfunction closest( /**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {\n if (el) {\n ctx = ctx || document;\n do {\n if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {\n return el;\n }\n if (el === ctx) break;\n /* jshint boss:true */\n } while (el = getParentOrHost(el));\n }\n return null;\n}\nvar R_SPACE = /\\s+/g;\nfunction toggleClass(el, name, state) {\n if (el && name) {\n if (el.classList) {\n el.classList[state ? 'add' : 'remove'](name);\n } else {\n var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');\n el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');\n }\n }\n}\nfunction css(el, prop, val) {\n var style = el && el.style;\n if (style) {\n if (val === void 0) {\n if (document.defaultView && document.defaultView.getComputedStyle) {\n val = document.defaultView.getComputedStyle(el, '');\n } else if (el.currentStyle) {\n val = el.currentStyle;\n }\n return prop === void 0 ? val : val[prop];\n } else {\n if (!(prop in style) && prop.indexOf('webkit') === -1) {\n prop = '-webkit-' + prop;\n }\n style[prop] = val + (typeof val === 'string' ? '' : 'px');\n }\n }\n}\nfunction matrix(el, selfOnly) {\n var appliedTransforms = '';\n if (typeof el === 'string') {\n appliedTransforms = el;\n } else {\n do {\n var transform = css(el, 'transform');\n if (transform && transform !== 'none') {\n appliedTransforms = transform + ' ' + appliedTransforms;\n }\n /* jshint boss:true */\n } while (!selfOnly && (el = el.parentNode));\n }\n var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;\n /*jshint -W056 */\n return matrixFn && new matrixFn(appliedTransforms);\n}\nfunction find(ctx, tagName, iterator) {\n if (ctx) {\n var list = ctx.getElementsByTagName(tagName),\n i = 0,\n n = list.length;\n if (iterator) {\n for (; i < n; i++) {\n iterator(list[i], i);\n }\n }\n return list;\n }\n return [];\n}\nfunction getWindowScrollingElement() {\n var scrollingElement = document.scrollingElement;\n if (scrollingElement) {\n return scrollingElement;\n } else {\n return document.documentElement;\n }\n}\n\n/**\r\n * Returns the \"bounding client rect\" of given element\r\n * @param {HTMLElement} el The element whose boundingClientRect is wanted\r\n * @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container\r\n * @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr\r\n * @param {[Boolean]} undoScale Whether the container's scale() should be undone\r\n * @param {[HTMLElement]} container The parent the element will be placed in\r\n * @return {Object} The boundingClientRect of el, with specified adjustments\r\n */\nfunction getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {\n if (!el.getBoundingClientRect && el !== window) return;\n var elRect, top, left, bottom, right, height, width;\n if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {\n elRect = el.getBoundingClientRect();\n top = elRect.top;\n left = elRect.left;\n bottom = elRect.bottom;\n right = elRect.right;\n height = elRect.height;\n width = elRect.width;\n } else {\n top = 0;\n left = 0;\n bottom = window.innerHeight;\n right = window.innerWidth;\n height = window.innerHeight;\n width = window.innerWidth;\n }\n if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {\n // Adjust for translate()\n container = container || el.parentNode;\n\n // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)\n // Not needed on <= IE11\n if (!IE11OrLess) {\n do {\n if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {\n var containerRect = container.getBoundingClientRect();\n\n // Set relative to edges of padding box of container\n top -= containerRect.top + parseInt(css(container, 'border-top-width'));\n left -= containerRect.left + parseInt(css(container, 'border-left-width'));\n bottom = top + elRect.height;\n right = left + elRect.width;\n break;\n }\n /* jshint boss:true */\n } while (container = container.parentNode);\n }\n }\n if (undoScale && el !== window) {\n // Adjust for scale()\n var elMatrix = matrix(container || el),\n scaleX = elMatrix && elMatrix.a,\n scaleY = elMatrix && elMatrix.d;\n if (elMatrix) {\n top /= scaleY;\n left /= scaleX;\n width /= scaleX;\n height /= scaleY;\n bottom = top + height;\n right = left + width;\n }\n }\n return {\n top: top,\n left: left,\n bottom: bottom,\n right: right,\n width: width,\n height: height\n };\n}\n\n/**\r\n * Checks if a side of an element is scrolled past a side of its parents\r\n * @param {HTMLElement} el The element who's side being scrolled out of view is in question\r\n * @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')\r\n * @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')\r\n * @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element\r\n */\nfunction isScrolledPast(el, elSide, parentSide) {\n var parent = getParentAutoScrollElement(el, true),\n elSideVal = getRect(el)[elSide];\n\n /* jshint boss:true */\n while (parent) {\n var parentSideVal = getRect(parent)[parentSide],\n visible = void 0;\n if (parentSide === 'top' || parentSide === 'left') {\n visible = elSideVal >= parentSideVal;\n } else {\n visible = elSideVal <= parentSideVal;\n }\n if (!visible) return parent;\n if (parent === getWindowScrollingElement()) break;\n parent = getParentAutoScrollElement(parent, false);\n }\n return false;\n}\n\n/**\r\n * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)\r\n * and non-draggable elements\r\n * @param {HTMLElement} el The parent element\r\n * @param {Number} childNum The index of the child\r\n * @param {Object} options Parent Sortable's options\r\n * @return {HTMLElement} The child at index childNum, or null if not found\r\n */\nfunction getChild(el, childNum, options, includeDragEl) {\n var currentChild = 0,\n i = 0,\n children = el.children;\n while (i < children.length) {\n if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {\n if (currentChild === childNum) {\n return children[i];\n }\n currentChild++;\n }\n i++;\n }\n return null;\n}\n\n/**\r\n * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)\r\n * @param {HTMLElement} el Parent element\r\n * @param {selector} selector Any other elements that should be ignored\r\n * @return {HTMLElement} The last child, ignoring ghostEl\r\n */\nfunction lastChild(el, selector) {\n var last = el.lastElementChild;\n while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {\n last = last.previousElementSibling;\n }\n return last || null;\n}\n\n/**\r\n * Returns the index of an element within its parent for a selected set of\r\n * elements\r\n * @param {HTMLElement} el\r\n * @param {selector} selector\r\n * @return {number}\r\n */\nfunction index(el, selector) {\n var index = 0;\n if (!el || !el.parentNode) {\n return -1;\n }\n\n /* jshint boss:true */\n while (el = el.previousElementSibling) {\n if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {\n index++;\n }\n }\n return index;\n}\n\n/**\r\n * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.\r\n * The value is returned in real pixels.\r\n * @param {HTMLElement} el\r\n * @return {Array} Offsets in the format of [left, top]\r\n */\nfunction getRelativeScrollOffset(el) {\n var offsetLeft = 0,\n offsetTop = 0,\n winScroller = getWindowScrollingElement();\n if (el) {\n do {\n var elMatrix = matrix(el),\n scaleX = elMatrix.a,\n scaleY = elMatrix.d;\n offsetLeft += el.scrollLeft * scaleX;\n offsetTop += el.scrollTop * scaleY;\n } while (el !== winScroller && (el = el.parentNode));\n }\n return [offsetLeft, offsetTop];\n}\n\n/**\r\n * Returns the index of the object within the given array\r\n * @param {Array} arr Array that may or may not hold the object\r\n * @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find\r\n * @return {Number} The index of the object in the array, or -1\r\n */\nfunction indexOfObject(arr, obj) {\n for (var i in arr) {\n if (!arr.hasOwnProperty(i)) continue;\n for (var key in obj) {\n if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);\n }\n }\n return -1;\n}\nfunction getParentAutoScrollElement(el, includeSelf) {\n // skip to window\n if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();\n var elem = el;\n var gotSelf = false;\n do {\n // we don't need to get elem css if it isn't even overflowing in the first place (performance)\n if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {\n var elemCSS = css(elem);\n if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {\n if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();\n if (gotSelf || includeSelf) return elem;\n gotSelf = true;\n }\n }\n /* jshint boss:true */\n } while (elem = elem.parentNode);\n return getWindowScrollingElement();\n}\nfunction extend(dst, src) {\n if (dst && src) {\n for (var key in src) {\n if (src.hasOwnProperty(key)) {\n dst[key] = src[key];\n }\n }\n }\n return dst;\n}\nfunction isRectEqual(rect1, rect2) {\n return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);\n}\nvar _throttleTimeout;\nfunction throttle(callback, ms) {\n return function () {\n if (!_throttleTimeout) {\n var args = arguments,\n _this = this;\n if (args.length === 1) {\n callback.call(_this, args[0]);\n } else {\n callback.apply(_this, args);\n }\n _throttleTimeout = setTimeout(function () {\n _throttleTimeout = void 0;\n }, ms);\n }\n };\n}\nfunction cancelThrottle() {\n clearTimeout(_throttleTimeout);\n _throttleTimeout = void 0;\n}\nfunction scrollBy(el, x, y) {\n el.scrollLeft += x;\n el.scrollTop += y;\n}\nfunction clone(el) {\n var Polymer = window.Polymer;\n var $ = window.jQuery || window.Zepto;\n if (Polymer && Polymer.dom) {\n return Polymer.dom(el).cloneNode(true);\n } else if ($) {\n return $(el).clone(true)[0];\n } else {\n return el.cloneNode(true);\n }\n}\nfunction setRect(el, rect) {\n css(el, 'position', 'absolute');\n css(el, 'top', rect.top);\n css(el, 'left', rect.left);\n css(el, 'width', rect.width);\n css(el, 'height', rect.height);\n}\nfunction unsetRect(el) {\n css(el, 'position', '');\n css(el, 'top', '');\n css(el, 'left', '');\n css(el, 'width', '');\n css(el, 'height', '');\n}\nfunction getChildContainingRectFromElement(container, options, ghostEl) {\n var rect = {};\n Array.from(container.children).forEach(function (child) {\n var _rect$left, _rect$top, _rect$right, _rect$bottom;\n if (!closest(child, options.draggable, container, false) || child.animated || child === ghostEl) return;\n var childRect = getRect(child);\n rect.left = Math.min((_rect$left = rect.left) !== null && _rect$left !== void 0 ? _rect$left : Infinity, childRect.left);\n rect.top = Math.min((_rect$top = rect.top) !== null && _rect$top !== void 0 ? _rect$top : Infinity, childRect.top);\n rect.right = Math.max((_rect$right = rect.right) !== null && _rect$right !== void 0 ? _rect$right : -Infinity, childRect.right);\n rect.bottom = Math.max((_rect$bottom = rect.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : -Infinity, childRect.bottom);\n });\n rect.width = rect.right - rect.left;\n rect.height = rect.bottom - rect.top;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\nvar expando = 'Sortable' + new Date().getTime();\n\nfunction AnimationStateManager() {\n var animationStates = [],\n animationCallbackId;\n return {\n captureAnimationState: function captureAnimationState() {\n animationStates = [];\n if (!this.options.animation) return;\n var children = [].slice.call(this.el.children);\n children.forEach(function (child) {\n if (css(child, 'display') === 'none' || child === Sortable.ghost) return;\n animationStates.push({\n target: child,\n rect: getRect(child)\n });\n var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect);\n\n // If animating: compensate for current animation\n if (child.thisAnimationDuration) {\n var childMatrix = matrix(child, true);\n if (childMatrix) {\n fromRect.top -= childMatrix.f;\n fromRect.left -= childMatrix.e;\n }\n }\n child.fromRect = fromRect;\n });\n },\n addAnimationState: function addAnimationState(state) {\n animationStates.push(state);\n },\n removeAnimationState: function removeAnimationState(target) {\n animationStates.splice(indexOfObject(animationStates, {\n target: target\n }), 1);\n },\n animateAll: function animateAll(callback) {\n var _this = this;\n if (!this.options.animation) {\n clearTimeout(animationCallbackId);\n if (typeof callback === 'function') callback();\n return;\n }\n var animating = false,\n animationTime = 0;\n animationStates.forEach(function (state) {\n var time = 0,\n target = state.target,\n fromRect = target.fromRect,\n toRect = getRect(target),\n prevFromRect = target.prevFromRect,\n prevToRect = target.prevToRect,\n animatingRect = state.rect,\n targetMatrix = matrix(target, true);\n if (targetMatrix) {\n // Compensate for current animation\n toRect.top -= targetMatrix.f;\n toRect.left -= targetMatrix.e;\n }\n target.toRect = toRect;\n if (target.thisAnimationDuration) {\n // Could also check if animatingRect is between fromRect and toRect\n if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) &&\n // Make sure animatingRect is on line between toRect & fromRect\n (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {\n // If returning to same place as started from animation and on same axis\n time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);\n }\n }\n\n // if fromRect != toRect: animate\n if (!isRectEqual(toRect, fromRect)) {\n target.prevFromRect = fromRect;\n target.prevToRect = toRect;\n if (!time) {\n time = _this.options.animation;\n }\n _this.animate(target, animatingRect, toRect, time);\n }\n if (time) {\n animating = true;\n animationTime = Math.max(animationTime, time);\n clearTimeout(target.animationResetTimer);\n target.animationResetTimer = setTimeout(function () {\n target.animationTime = 0;\n target.prevFromRect = null;\n target.fromRect = null;\n target.prevToRect = null;\n target.thisAnimationDuration = null;\n }, time);\n target.thisAnimationDuration = time;\n }\n });\n clearTimeout(animationCallbackId);\n if (!animating) {\n if (typeof callback === 'function') callback();\n } else {\n animationCallbackId = setTimeout(function () {\n if (typeof callback === 'function') callback();\n }, animationTime);\n }\n animationStates = [];\n },\n animate: function animate(target, currentRect, toRect, duration) {\n if (duration) {\n css(target, 'transition', '');\n css(target, 'transform', '');\n var elMatrix = matrix(this.el),\n scaleX = elMatrix && elMatrix.a,\n scaleY = elMatrix && elMatrix.d,\n translateX = (currentRect.left - toRect.left) / (scaleX || 1),\n translateY = (currentRect.top - toRect.top) / (scaleY || 1);\n target.animatingX = !!translateX;\n target.animatingY = !!translateY;\n css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');\n this.forRepaintDummy = repaint(target); // repaint\n\n css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));\n css(target, 'transform', 'translate3d(0,0,0)');\n typeof target.animated === 'number' && clearTimeout(target.animated);\n target.animated = setTimeout(function () {\n css(target, 'transition', '');\n css(target, 'transform', '');\n target.animated = false;\n target.animatingX = false;\n target.animatingY = false;\n }, duration);\n }\n }\n };\n}\nfunction repaint(target) {\n return target.offsetWidth;\n}\nfunction calculateRealTime(animatingRect, fromRect, toRect, options) {\n return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;\n}\n\nvar plugins = [];\nvar defaults = {\n initializeByDefault: true\n};\nvar PluginManager = {\n mount: function mount(plugin) {\n // Set default static properties\n for (var option in defaults) {\n if (defaults.hasOwnProperty(option) && !(option in plugin)) {\n plugin[option] = defaults[option];\n }\n }\n plugins.forEach(function (p) {\n if (p.pluginName === plugin.pluginName) {\n throw \"Sortable: Cannot mount plugin \".concat(plugin.pluginName, \" more than once\");\n }\n });\n plugins.push(plugin);\n },\n pluginEvent: function pluginEvent(eventName, sortable, evt) {\n var _this = this;\n this.eventCanceled = false;\n evt.cancel = function () {\n _this.eventCanceled = true;\n };\n var eventNameGlobal = eventName + 'Global';\n plugins.forEach(function (plugin) {\n if (!sortable[plugin.pluginName]) return;\n // Fire global events if it exists in this sortable\n if (sortable[plugin.pluginName][eventNameGlobal]) {\n sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({\n sortable: sortable\n }, evt));\n }\n\n // Only fire plugin event if plugin is enabled in this sortable,\n // and plugin has event defined\n if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {\n sortable[plugin.pluginName][eventName](_objectSpread2({\n sortable: sortable\n }, evt));\n }\n });\n },\n initializePlugins: function initializePlugins(sortable, el, defaults, options) {\n plugins.forEach(function (plugin) {\n var pluginName = plugin.pluginName;\n if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;\n var initialized = new plugin(sortable, el, sortable.options);\n initialized.sortable = sortable;\n initialized.options = sortable.options;\n sortable[pluginName] = initialized;\n\n // Add default options from plugin\n _extends(defaults, initialized.defaults);\n });\n for (var option in sortable.options) {\n if (!sortable.options.hasOwnProperty(option)) continue;\n var modified = this.modifyOption(sortable, option, sortable.options[option]);\n if (typeof modified !== 'undefined') {\n sortable.options[option] = modified;\n }\n }\n },\n getEventProperties: function getEventProperties(name, sortable) {\n var eventProperties = {};\n plugins.forEach(function (plugin) {\n if (typeof plugin.eventProperties !== 'function') return;\n _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));\n });\n return eventProperties;\n },\n modifyOption: function modifyOption(sortable, name, value) {\n var modifiedValue;\n plugins.forEach(function (plugin) {\n // Plugin must exist on the Sortable\n if (!sortable[plugin.pluginName]) return;\n\n // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin\n if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {\n modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);\n }\n });\n return modifiedValue;\n }\n};\n\nfunction dispatchEvent(_ref) {\n var sortable = _ref.sortable,\n rootEl = _ref.rootEl,\n name = _ref.name,\n targetEl = _ref.targetEl,\n cloneEl = _ref.cloneEl,\n toEl = _ref.toEl,\n fromEl = _ref.fromEl,\n oldIndex = _ref.oldIndex,\n newIndex = _ref.newIndex,\n oldDraggableIndex = _ref.oldDraggableIndex,\n newDraggableIndex = _ref.newDraggableIndex,\n originalEvent = _ref.originalEvent,\n putSortable = _ref.putSortable,\n extraEventProperties = _ref.extraEventProperties;\n sortable = sortable || rootEl && rootEl[expando];\n if (!sortable) return;\n var evt,\n options = sortable.options,\n onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);\n // Support for new CustomEvent feature\n if (window.CustomEvent && !IE11OrLess && !Edge) {\n evt = new CustomEvent(name, {\n bubbles: true,\n cancelable: true\n });\n } else {\n evt = document.createEvent('Event');\n evt.initEvent(name, true, true);\n }\n evt.to = toEl || rootEl;\n evt.from = fromEl || rootEl;\n evt.item = targetEl || rootEl;\n evt.clone = cloneEl;\n evt.oldIndex = oldIndex;\n evt.newIndex = newIndex;\n evt.oldDraggableIndex = oldDraggableIndex;\n evt.newDraggableIndex = newDraggableIndex;\n evt.originalEvent = originalEvent;\n evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;\n var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));\n for (var option in allEventProperties) {\n evt[option] = allEventProperties[option];\n }\n if (rootEl) {\n rootEl.dispatchEvent(evt);\n }\n if (options[onName]) {\n options[onName].call(sortable, evt);\n }\n}\n\nvar _excluded = [\"evt\"];\nvar pluginEvent = function pluginEvent(eventName, sortable) {\n var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},\n originalEvent = _ref.evt,\n data = _objectWithoutProperties(_ref, _excluded);\n PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({\n dragEl: dragEl,\n parentEl: parentEl,\n ghostEl: ghostEl,\n rootEl: rootEl,\n nextEl: nextEl,\n lastDownEl: lastDownEl,\n cloneEl: cloneEl,\n cloneHidden: cloneHidden,\n dragStarted: moved,\n putSortable: putSortable,\n activeSortable: Sortable.active,\n originalEvent: originalEvent,\n oldIndex: oldIndex,\n oldDraggableIndex: oldDraggableIndex,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex,\n hideGhostForTarget: _hideGhostForTarget,\n unhideGhostForTarget: _unhideGhostForTarget,\n cloneNowHidden: function cloneNowHidden() {\n cloneHidden = true;\n },\n cloneNowShown: function cloneNowShown() {\n cloneHidden = false;\n },\n dispatchSortableEvent: function dispatchSortableEvent(name) {\n _dispatchEvent({\n sortable: sortable,\n name: name,\n originalEvent: originalEvent\n });\n }\n }, data));\n};\nfunction _dispatchEvent(info) {\n dispatchEvent(_objectSpread2({\n putSortable: putSortable,\n cloneEl: cloneEl,\n targetEl: dragEl,\n rootEl: rootEl,\n oldIndex: oldIndex,\n oldDraggableIndex: oldDraggableIndex,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex\n }, info));\n}\nvar dragEl,\n parentEl,\n ghostEl,\n rootEl,\n nextEl,\n lastDownEl,\n cloneEl,\n cloneHidden,\n oldIndex,\n newIndex,\n oldDraggableIndex,\n newDraggableIndex,\n activeGroup,\n putSortable,\n awaitingDragStarted = false,\n ignoreNextClick = false,\n sortables = [],\n tapEvt,\n touchEvt,\n lastDx,\n lastDy,\n tapDistanceLeft,\n tapDistanceTop,\n moved,\n lastTarget,\n lastDirection,\n pastFirstInvertThresh = false,\n isCircumstantialInvert = false,\n targetMoveDistance,\n // For positioning ghost absolutely\n ghostRelativeParent,\n ghostRelativeParentInitialScroll = [],\n // (left, top)\n\n _silent = false,\n savedInputChecked = [];\n\n/** @const */\nvar documentExists = typeof document !== 'undefined',\n PositionGhostAbsolutely = IOS,\n CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',\n // This will not pass for IE9, because IE9 DnD only works on anchors\n supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),\n supportCssPointerEvents = function () {\n if (!documentExists) return;\n // false when <= IE11\n if (IE11OrLess) {\n return false;\n }\n var el = document.createElement('x');\n el.style.cssText = 'pointer-events:auto';\n return el.style.pointerEvents === 'auto';\n }(),\n _detectDirection = function _detectDirection(el, options) {\n var elCSS = css(el),\n elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),\n child1 = getChild(el, 0, options),\n child2 = getChild(el, 1, options),\n firstChildCSS = child1 && css(child1),\n secondChildCSS = child2 && css(child2),\n firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,\n secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;\n if (elCSS.display === 'flex') {\n return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';\n }\n if (elCSS.display === 'grid') {\n return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';\n }\n if (child1 && firstChildCSS[\"float\"] && firstChildCSS[\"float\"] !== 'none') {\n var touchingSideChild2 = firstChildCSS[\"float\"] === 'left' ? 'left' : 'right';\n return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';\n }\n return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';\n },\n _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {\n var dragElS1Opp = vertical ? dragRect.left : dragRect.top,\n dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,\n dragElOppLength = vertical ? dragRect.width : dragRect.height,\n targetS1Opp = vertical ? targetRect.left : targetRect.top,\n targetS2Opp = vertical ? targetRect.right : targetRect.bottom,\n targetOppLength = vertical ? targetRect.width : targetRect.height;\n return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;\n },\n /**\r\n * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.\r\n * @param {Number} x X position\r\n * @param {Number} y Y position\r\n * @return {HTMLElement} Element of the first found nearest Sortable\r\n */\n _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {\n var ret;\n sortables.some(function (sortable) {\n var threshold = sortable[expando].options.emptyInsertThreshold;\n if (!threshold || lastChild(sortable)) return;\n var rect = getRect(sortable),\n insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,\n insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;\n if (insideHorizontally && insideVertically) {\n return ret = sortable;\n }\n });\n return ret;\n },\n _prepareGroup = function _prepareGroup(options) {\n function toFn(value, pull) {\n return function (to, from, dragEl, evt) {\n var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;\n if (value == null && (pull || sameGroup)) {\n // Default pull value\n // Default pull and put value if same group\n return true;\n } else if (value == null || value === false) {\n return false;\n } else if (pull && value === 'clone') {\n return value;\n } else if (typeof value === 'function') {\n return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);\n } else {\n var otherGroup = (pull ? to : from).options.group.name;\n return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;\n }\n };\n }\n var group = {};\n var originalGroup = options.group;\n if (!originalGroup || _typeof(originalGroup) != 'object') {\n originalGroup = {\n name: originalGroup\n };\n }\n group.name = originalGroup.name;\n group.checkPull = toFn(originalGroup.pull, true);\n group.checkPut = toFn(originalGroup.put);\n group.revertClone = originalGroup.revertClone;\n options.group = group;\n },\n _hideGhostForTarget = function _hideGhostForTarget() {\n if (!supportCssPointerEvents && ghostEl) {\n css(ghostEl, 'display', 'none');\n }\n },\n _unhideGhostForTarget = function _unhideGhostForTarget() {\n if (!supportCssPointerEvents && ghostEl) {\n css(ghostEl, 'display', '');\n }\n };\n\n// #1184 fix - Prevent click event on fallback if dragged but item not changed position\nif (documentExists && !ChromeForAndroid) {\n document.addEventListener('click', function (evt) {\n if (ignoreNextClick) {\n evt.preventDefault();\n evt.stopPropagation && evt.stopPropagation();\n evt.stopImmediatePropagation && evt.stopImmediatePropagation();\n ignoreNextClick = false;\n return false;\n }\n }, true);\n}\nvar nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {\n if (dragEl) {\n evt = evt.touches ? evt.touches[0] : evt;\n var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);\n if (nearest) {\n // Create imitation event\n var event = {};\n for (var i in evt) {\n if (evt.hasOwnProperty(i)) {\n event[i] = evt[i];\n }\n }\n event.target = event.rootEl = nearest;\n event.preventDefault = void 0;\n event.stopPropagation = void 0;\n nearest[expando]._onDragOver(event);\n }\n }\n};\nvar _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {\n if (dragEl) {\n dragEl.parentNode[expando]._isOutsideThisEl(evt.target);\n }\n};\n\n/**\r\n * @class Sortable\r\n * @param {HTMLElement} el\r\n * @param {Object} [options]\r\n */\nfunction Sortable(el, options) {\n if (!(el && el.nodeType && el.nodeType === 1)) {\n throw \"Sortable: `el` must be an HTMLElement, not \".concat({}.toString.call(el));\n }\n this.el = el; // root element\n this.options = options = _extends({}, options);\n\n // Export instance\n el[expando] = this;\n var defaults = {\n group: null,\n sort: true,\n disabled: false,\n store: null,\n handle: null,\n draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',\n swapThreshold: 1,\n // percentage; 0 <= x <= 1\n invertSwap: false,\n // invert always\n invertedSwapThreshold: null,\n // will be set to same as swapThreshold if default\n removeCloneOnHide: true,\n direction: function direction() {\n return _detectDirection(el, this.options);\n },\n ghostClass: 'sortable-ghost',\n chosenClass: 'sortable-chosen',\n dragClass: 'sortable-drag',\n ignore: 'a, img',\n filter: null,\n preventOnFilter: true,\n animation: 0,\n easing: null,\n setData: function setData(dataTransfer, dragEl) {\n dataTransfer.setData('Text', dragEl.textContent);\n },\n dropBubble: false,\n dragoverBubble: false,\n dataIdAttr: 'data-id',\n delay: 0,\n delayOnTouchOnly: false,\n touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,\n forceFallback: false,\n fallbackClass: 'sortable-fallback',\n fallbackOnBody: false,\n fallbackTolerance: 0,\n fallbackOffset: {\n x: 0,\n y: 0\n },\n // Disabled on Safari: #1571; Enabled on Safari IOS: #2244\n supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && (!Safari || IOS),\n emptyInsertThreshold: 5\n };\n PluginManager.initializePlugins(this, el, defaults);\n\n // Set default options\n for (var name in defaults) {\n !(name in options) && (options[name] = defaults[name]);\n }\n _prepareGroup(options);\n\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n\n // Setup drag mode\n this.nativeDraggable = options.forceFallback ? false : supportDraggable;\n if (this.nativeDraggable) {\n // Touch start threshold cannot be greater than the native dragstart threshold\n this.options.touchStartThreshold = 1;\n }\n\n // Bind events\n if (options.supportPointer) {\n on(el, 'pointerdown', this._onTapStart);\n } else {\n on(el, 'mousedown', this._onTapStart);\n on(el, 'touchstart', this._onTapStart);\n }\n if (this.nativeDraggable) {\n on(el, 'dragover', this);\n on(el, 'dragenter', this);\n }\n sortables.push(this.el);\n\n // Restore sorting\n options.store && options.store.get && this.sort(options.store.get(this) || []);\n\n // Add animation state manager\n _extends(this, AnimationStateManager());\n}\nSortable.prototype = /** @lends Sortable.prototype */{\n constructor: Sortable,\n _isOutsideThisEl: function _isOutsideThisEl(target) {\n if (!this.el.contains(target) && target !== this.el) {\n lastTarget = null;\n }\n },\n _getDirection: function _getDirection(evt, target) {\n return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;\n },\n _onTapStart: function _onTapStart( /** Event|TouchEvent */evt) {\n if (!evt.cancelable) return;\n var _this = this,\n el = this.el,\n options = this.options,\n preventOnFilter = options.preventOnFilter,\n type = evt.type,\n touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,\n target = (touch || evt).target,\n originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,\n filter = options.filter;\n _saveInputCheckedState(el);\n\n // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.\n if (dragEl) {\n return;\n }\n if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {\n return; // only left button and enabled\n }\n\n // cancel dnd if original target is content editable\n if (originalTarget.isContentEditable) {\n return;\n }\n\n // Safari ignores further event handling after mousedown\n if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {\n return;\n }\n target = closest(target, options.draggable, el, false);\n if (target && target.animated) {\n return;\n }\n if (lastDownEl === target) {\n // Ignoring duplicate `down`\n return;\n }\n\n // Get the index of the dragged element within its parent\n oldIndex = index(target);\n oldDraggableIndex = index(target, options.draggable);\n\n // Check filter\n if (typeof filter === 'function') {\n if (filter.call(this, evt, target, this)) {\n _dispatchEvent({\n sortable: _this,\n rootEl: originalTarget,\n name: 'filter',\n targetEl: target,\n toEl: el,\n fromEl: el\n });\n pluginEvent('filter', _this, {\n evt: evt\n });\n preventOnFilter && evt.preventDefault();\n return; // cancel dnd\n }\n } else if (filter) {\n filter = filter.split(',').some(function (criteria) {\n criteria = closest(originalTarget, criteria.trim(), el, false);\n if (criteria) {\n _dispatchEvent({\n sortable: _this,\n rootEl: criteria,\n name: 'filter',\n targetEl: target,\n fromEl: el,\n toEl: el\n });\n pluginEvent('filter', _this, {\n evt: evt\n });\n return true;\n }\n });\n if (filter) {\n preventOnFilter && evt.preventDefault();\n return; // cancel dnd\n }\n }\n if (options.handle && !closest(originalTarget, options.handle, el, false)) {\n return;\n }\n\n // Prepare `dragstart`\n this._prepareDragStart(evt, touch, target);\n },\n _prepareDragStart: function _prepareDragStart( /** Event */evt, /** Touch */touch, /** HTMLElement */target) {\n var _this = this,\n el = _this.el,\n options = _this.options,\n ownerDocument = el.ownerDocument,\n dragStartFn;\n if (target && !dragEl && target.parentNode === el) {\n var dragRect = getRect(target);\n rootEl = el;\n dragEl = target;\n parentEl = dragEl.parentNode;\n nextEl = dragEl.nextSibling;\n lastDownEl = target;\n activeGroup = options.group;\n Sortable.dragged = dragEl;\n tapEvt = {\n target: dragEl,\n clientX: (touch || evt).clientX,\n clientY: (touch || evt).clientY\n };\n tapDistanceLeft = tapEvt.clientX - dragRect.left;\n tapDistanceTop = tapEvt.clientY - dragRect.top;\n this._lastX = (touch || evt).clientX;\n this._lastY = (touch || evt).clientY;\n dragEl.style['will-change'] = 'all';\n dragStartFn = function dragStartFn() {\n pluginEvent('delayEnded', _this, {\n evt: evt\n });\n if (Sortable.eventCanceled) {\n _this._onDrop();\n return;\n }\n // Delayed drag has been triggered\n // we can re-enable the events: touchmove/mousemove\n _this._disableDelayedDragEvents();\n if (!FireFox && _this.nativeDraggable) {\n dragEl.draggable = true;\n }\n\n // Bind the events: dragstart/dragend\n _this._triggerDragStart(evt, touch);\n\n // Drag start event\n _dispatchEvent({\n sortable: _this,\n name: 'choose',\n originalEvent: evt\n });\n\n // Chosen item\n toggleClass(dragEl, options.chosenClass, true);\n };\n\n // Disable \"draggable\"\n options.ignore.split(',').forEach(function (criteria) {\n find(dragEl, criteria.trim(), _disableDraggable);\n });\n on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);\n on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);\n on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);\n if (options.supportPointer) {\n on(ownerDocument, 'pointerup', _this._onDrop);\n // Native D&D triggers pointercancel\n !this.nativeDraggable && on(ownerDocument, 'pointercancel', _this._onDrop);\n } else {\n on(ownerDocument, 'mouseup', _this._onDrop);\n on(ownerDocument, 'touchend', _this._onDrop);\n on(ownerDocument, 'touchcancel', _this._onDrop);\n }\n\n // Make dragEl draggable (must be before delay for FireFox)\n if (FireFox && this.nativeDraggable) {\n this.options.touchStartThreshold = 4;\n dragEl.draggable = true;\n }\n pluginEvent('delayStart', this, {\n evt: evt\n });\n\n // Delay is impossible for native DnD in Edge or IE\n if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {\n if (Sortable.eventCanceled) {\n this._onDrop();\n return;\n }\n // If the user moves the pointer or let go the click or touch\n // before the delay has been reached:\n // disable the delayed drag\n if (options.supportPointer) {\n on(ownerDocument, 'pointerup', _this._disableDelayedDrag);\n on(ownerDocument, 'pointercancel', _this._disableDelayedDrag);\n } else {\n on(ownerDocument, 'mouseup', _this._disableDelayedDrag);\n on(ownerDocument, 'touchend', _this._disableDelayedDrag);\n on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);\n }\n on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);\n on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);\n options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);\n _this._dragStartTimer = setTimeout(dragStartFn, options.delay);\n } else {\n dragStartFn();\n }\n }\n },\n _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler( /** TouchEvent|PointerEvent **/e) {\n var touch = e.touches ? e.touches[0] : e;\n if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {\n this._disableDelayedDrag();\n }\n },\n _disableDelayedDrag: function _disableDelayedDrag() {\n dragEl && _disableDraggable(dragEl);\n clearTimeout(this._dragStartTimer);\n this._disableDelayedDragEvents();\n },\n _disableDelayedDragEvents: function _disableDelayedDragEvents() {\n var ownerDocument = this.el.ownerDocument;\n off(ownerDocument, 'mouseup', this._disableDelayedDrag);\n off(ownerDocument, 'touchend', this._disableDelayedDrag);\n off(ownerDocument, 'touchcancel', this._disableDelayedDrag);\n off(ownerDocument, 'pointerup', this._disableDelayedDrag);\n off(ownerDocument, 'pointercancel', this._disableDelayedDrag);\n off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);\n off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);\n off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);\n },\n _triggerDragStart: function _triggerDragStart( /** Event */evt, /** Touch */touch) {\n touch = touch || evt.pointerType == 'touch' && evt;\n if (!this.nativeDraggable || touch) {\n if (this.options.supportPointer) {\n on(document, 'pointermove', this._onTouchMove);\n } else if (touch) {\n on(document, 'touchmove', this._onTouchMove);\n } else {\n on(document, 'mousemove', this._onTouchMove);\n }\n } else {\n on(dragEl, 'dragend', this);\n on(rootEl, 'dragstart', this._onDragStart);\n }\n try {\n if (document.selection) {\n _nextTick(function () {\n document.selection.empty();\n });\n } else {\n window.getSelection().removeAllRanges();\n }\n } catch (err) {}\n },\n _dragStarted: function _dragStarted(fallback, evt) {\n awaitingDragStarted = false;\n if (rootEl && dragEl) {\n pluginEvent('dragStarted', this, {\n evt: evt\n });\n if (this.nativeDraggable) {\n on(document, 'dragover', _checkOutsideTargetEl);\n }\n var options = this.options;\n\n // Apply effect\n !fallback && toggleClass(dragEl, options.dragClass, false);\n toggleClass(dragEl, options.ghostClass, true);\n Sortable.active = this;\n fallback && this._appendGhost();\n\n // Drag start event\n _dispatchEvent({\n sortable: this,\n name: 'start',\n originalEvent: evt\n });\n } else {\n this._nulling();\n }\n },\n _emulateDragOver: function _emulateDragOver() {\n if (touchEvt) {\n this._lastX = touchEvt.clientX;\n this._lastY = touchEvt.clientY;\n _hideGhostForTarget();\n var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);\n var parent = target;\n while (target && target.shadowRoot) {\n target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);\n if (target === parent) break;\n parent = target;\n }\n dragEl.parentNode[expando]._isOutsideThisEl(target);\n if (parent) {\n do {\n if (parent[expando]) {\n var inserted = void 0;\n inserted = parent[expando]._onDragOver({\n clientX: touchEvt.clientX,\n clientY: touchEvt.clientY,\n target: target,\n rootEl: parent\n });\n if (inserted && !this.options.dragoverBubble) {\n break;\n }\n }\n target = parent; // store last element\n }\n /* jshint boss:true */ while (parent = getParentOrHost(parent));\n }\n _unhideGhostForTarget();\n }\n },\n _onTouchMove: function _onTouchMove( /**TouchEvent*/evt) {\n if (tapEvt) {\n var options = this.options,\n fallbackTolerance = options.fallbackTolerance,\n fallbackOffset = options.fallbackOffset,\n touch = evt.touches ? evt.touches[0] : evt,\n ghostMatrix = ghostEl && matrix(ghostEl, true),\n scaleX = ghostEl && ghostMatrix && ghostMatrix.a,\n scaleY = ghostEl && ghostMatrix && ghostMatrix.d,\n relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),\n dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),\n dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1);\n\n // only set the status to dragging, when we are actually dragging\n if (!Sortable.active && !awaitingDragStarted) {\n if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {\n return;\n }\n this._onDragStart(evt, true);\n }\n if (ghostEl) {\n if (ghostMatrix) {\n ghostMatrix.e += dx - (lastDx || 0);\n ghostMatrix.f += dy - (lastDy || 0);\n } else {\n ghostMatrix = {\n a: 1,\n b: 0,\n c: 0,\n d: 1,\n e: dx,\n f: dy\n };\n }\n var cssMatrix = \"matrix(\".concat(ghostMatrix.a, \",\").concat(ghostMatrix.b, \",\").concat(ghostMatrix.c, \",\").concat(ghostMatrix.d, \",\").concat(ghostMatrix.e, \",\").concat(ghostMatrix.f, \")\");\n css(ghostEl, 'webkitTransform', cssMatrix);\n css(ghostEl, 'mozTransform', cssMatrix);\n css(ghostEl, 'msTransform', cssMatrix);\n css(ghostEl, 'transform', cssMatrix);\n lastDx = dx;\n lastDy = dy;\n touchEvt = touch;\n }\n evt.cancelable && evt.preventDefault();\n }\n },\n _appendGhost: function _appendGhost() {\n // Bug if using scale(): https://stackoverflow.com/questions/2637058\n // Not being adjusted for\n if (!ghostEl) {\n var container = this.options.fallbackOnBody ? document.body : rootEl,\n rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),\n options = this.options;\n\n // Position absolutely\n if (PositionGhostAbsolutely) {\n // Get relatively positioned parent\n ghostRelativeParent = container;\n while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {\n ghostRelativeParent = ghostRelativeParent.parentNode;\n }\n if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {\n if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();\n rect.top += ghostRelativeParent.scrollTop;\n rect.left += ghostRelativeParent.scrollLeft;\n } else {\n ghostRelativeParent = getWindowScrollingElement();\n }\n ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);\n }\n ghostEl = dragEl.cloneNode(true);\n toggleClass(ghostEl, options.ghostClass, false);\n toggleClass(ghostEl, options.fallbackClass, true);\n toggleClass(ghostEl, options.dragClass, true);\n css(ghostEl, 'transition', '');\n css(ghostEl, 'transform', '');\n css(ghostEl, 'box-sizing', 'border-box');\n css(ghostEl, 'margin', 0);\n css(ghostEl, 'top', rect.top);\n css(ghostEl, 'left', rect.left);\n css(ghostEl, 'width', rect.width);\n css(ghostEl, 'height', rect.height);\n css(ghostEl, 'opacity', '0.8');\n css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');\n css(ghostEl, 'zIndex', '100000');\n css(ghostEl, 'pointerEvents', 'none');\n Sortable.ghost = ghostEl;\n container.appendChild(ghostEl);\n\n // Set transform-origin\n css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');\n }\n },\n _onDragStart: function _onDragStart( /**Event*/evt, /**boolean*/fallback) {\n var _this = this;\n var dataTransfer = evt.dataTransfer;\n var options = _this.options;\n pluginEvent('dragStart', this, {\n evt: evt\n });\n if (Sortable.eventCanceled) {\n this._onDrop();\n return;\n }\n pluginEvent('setupClone', this);\n if (!Sortable.eventCanceled) {\n cloneEl = clone(dragEl);\n cloneEl.removeAttribute(\"id\");\n cloneEl.draggable = false;\n cloneEl.style['will-change'] = '';\n this._hideClone();\n toggleClass(cloneEl, this.options.chosenClass, false);\n Sortable.clone = cloneEl;\n }\n\n // #1143: IFrame support workaround\n _this.cloneId = _nextTick(function () {\n pluginEvent('clone', _this);\n if (Sortable.eventCanceled) return;\n if (!_this.options.removeCloneOnHide) {\n rootEl.insertBefore(cloneEl, dragEl);\n }\n _this._hideClone();\n _dispatchEvent({\n sortable: _this,\n name: 'clone'\n });\n });\n !fallback && toggleClass(dragEl, options.dragClass, true);\n\n // Set proper drop events\n if (fallback) {\n ignoreNextClick = true;\n _this._loopId = setInterval(_this._emulateDragOver, 50);\n } else {\n // Undo what was set in _prepareDragStart before drag started\n off(document, 'mouseup', _this._onDrop);\n off(document, 'touchend', _this._onDrop);\n off(document, 'touchcancel', _this._onDrop);\n if (dataTransfer) {\n dataTransfer.effectAllowed = 'move';\n options.setData && options.setData.call(_this, dataTransfer, dragEl);\n }\n on(document, 'drop', _this);\n\n // #1276 fix:\n css(dragEl, 'transform', 'translateZ(0)');\n }\n awaitingDragStarted = true;\n _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));\n on(document, 'selectstart', _this);\n moved = true;\n window.getSelection().removeAllRanges();\n if (Safari) {\n css(document.body, 'user-select', 'none');\n }\n },\n // Returns true - if no further action is needed (either inserted or another condition)\n _onDragOver: function _onDragOver( /**Event*/evt) {\n var el = this.el,\n target = evt.target,\n dragRect,\n targetRect,\n revert,\n options = this.options,\n group = options.group,\n activeSortable = Sortable.active,\n isOwner = activeGroup === group,\n canSort = options.sort,\n fromSortable = putSortable || activeSortable,\n vertical,\n _this = this,\n completedFired = false;\n if (_silent) return;\n function dragOverEvent(name, extra) {\n pluginEvent(name, _this, _objectSpread2({\n evt: evt,\n isOwner: isOwner,\n axis: vertical ? 'vertical' : 'horizontal',\n revert: revert,\n dragRect: dragRect,\n targetRect: targetRect,\n canSort: canSort,\n fromSortable: fromSortable,\n target: target,\n completed: completed,\n onMove: function onMove(target, after) {\n return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);\n },\n changed: changed\n }, extra));\n }\n\n // Capture animation state\n function capture() {\n dragOverEvent('dragOverAnimationCapture');\n _this.captureAnimationState();\n if (_this !== fromSortable) {\n fromSortable.captureAnimationState();\n }\n }\n\n // Return invocation when dragEl is inserted (or completed)\n function completed(insertion) {\n dragOverEvent('dragOverCompleted', {\n insertion: insertion\n });\n if (insertion) {\n // Clones must be hidden before folding animation to capture dragRectAbsolute properly\n if (isOwner) {\n activeSortable._hideClone();\n } else {\n activeSortable._showClone(_this);\n }\n if (_this !== fromSortable) {\n // Set ghost class to new sortable's ghost class\n toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);\n toggleClass(dragEl, options.ghostClass, true);\n }\n if (putSortable !== _this && _this !== Sortable.active) {\n putSortable = _this;\n } else if (_this === Sortable.active && putSortable) {\n putSortable = null;\n }\n\n // Animation\n if (fromSortable === _this) {\n _this._ignoreWhileAnimating = target;\n }\n _this.animateAll(function () {\n dragOverEvent('dragOverAnimationComplete');\n _this._ignoreWhileAnimating = null;\n });\n if (_this !== fromSortable) {\n fromSortable.animateAll();\n fromSortable._ignoreWhileAnimating = null;\n }\n }\n\n // Null lastTarget if it is not inside a previously swapped element\n if (target === dragEl && !dragEl.animated || target === el && !target.animated) {\n lastTarget = null;\n }\n\n // no bubbling and not fallback\n if (!options.dragoverBubble && !evt.rootEl && target !== document) {\n dragEl.parentNode[expando]._isOutsideThisEl(evt.target);\n\n // Do not detect for empty insert if already inserted\n !insertion && nearestEmptyInsertDetectEvent(evt);\n }\n !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();\n return completedFired = true;\n }\n\n // Call when dragEl has been inserted\n function changed() {\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n _dispatchEvent({\n sortable: _this,\n name: 'change',\n toEl: el,\n newIndex: newIndex,\n newDraggableIndex: newDraggableIndex,\n originalEvent: evt\n });\n }\n if (evt.preventDefault !== void 0) {\n evt.cancelable && evt.preventDefault();\n }\n target = closest(target, options.draggable, el, true);\n dragOverEvent('dragOver');\n if (Sortable.eventCanceled) return completedFired;\n if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {\n return completed(false);\n }\n ignoreNextClick = false;\n if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list\n : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {\n vertical = this._getDirection(evt, target) === 'vertical';\n dragRect = getRect(dragEl);\n dragOverEvent('dragOverValid');\n if (Sortable.eventCanceled) return completedFired;\n if (revert) {\n parentEl = rootEl; // actualization\n capture();\n this._hideClone();\n dragOverEvent('revert');\n if (!Sortable.eventCanceled) {\n if (nextEl) {\n rootEl.insertBefore(dragEl, nextEl);\n } else {\n rootEl.appendChild(dragEl);\n }\n }\n return completed(true);\n }\n var elLastChild = lastChild(el, options.draggable);\n if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {\n // Insert to end of list\n\n // If already at end of list: Do not insert\n if (elLastChild === dragEl) {\n return completed(false);\n }\n\n // if there is a last element, it is the target\n if (elLastChild && el === evt.target) {\n target = elLastChild;\n }\n if (target) {\n targetRect = getRect(target);\n }\n if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {\n capture();\n if (elLastChild && elLastChild.nextSibling) {\n // the last draggable element is not the last node\n el.insertBefore(dragEl, elLastChild.nextSibling);\n } else {\n el.appendChild(dragEl);\n }\n parentEl = el; // actualization\n\n changed();\n return completed(true);\n }\n } else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {\n // Insert to start of list\n var firstChild = getChild(el, 0, options, true);\n if (firstChild === dragEl) {\n return completed(false);\n }\n target = firstChild;\n targetRect = getRect(target);\n if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {\n capture();\n el.insertBefore(dragEl, firstChild);\n parentEl = el; // actualization\n\n changed();\n return completed(true);\n }\n } else if (target.parentNode === el) {\n targetRect = getRect(target);\n var direction = 0,\n targetBeforeFirstSwap,\n differentLevel = dragEl.parentNode !== el,\n differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),\n side1 = vertical ? 'top' : 'left',\n scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),\n scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;\n if (lastTarget !== target) {\n targetBeforeFirstSwap = targetRect[side1];\n pastFirstInvertThresh = false;\n isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;\n }\n direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);\n var sibling;\n if (direction !== 0) {\n // Check if target is beside dragEl in respective direction (ignoring hidden elements)\n var dragIndex = index(dragEl);\n do {\n dragIndex -= direction;\n sibling = parentEl.children[dragIndex];\n } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));\n }\n // If dragEl is already beside target: Do not insert\n if (direction === 0 || sibling === target) {\n return completed(false);\n }\n lastTarget = target;\n lastDirection = direction;\n var nextSibling = target.nextElementSibling,\n after = false;\n after = direction === 1;\n var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);\n if (moveVector !== false) {\n if (moveVector === 1 || moveVector === -1) {\n after = moveVector === 1;\n }\n _silent = true;\n setTimeout(_unsilent, 30);\n capture();\n if (after && !nextSibling) {\n el.appendChild(dragEl);\n } else {\n target.parentNode.insertBefore(dragEl, after ? nextSibling : target);\n }\n\n // Undo chrome's scroll adjustment (has no effect on other browsers)\n if (scrolledPastTop) {\n scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);\n }\n parentEl = dragEl.parentNode; // actualization\n\n // must be done before animation\n if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {\n targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);\n }\n changed();\n return completed(true);\n }\n }\n if (el.contains(dragEl)) {\n return completed(false);\n }\n }\n return false;\n },\n _ignoreWhileAnimating: null,\n _offMoveEvents: function _offMoveEvents() {\n off(document, 'mousemove', this._onTouchMove);\n off(document, 'touchmove', this._onTouchMove);\n off(document, 'pointermove', this._onTouchMove);\n off(document, 'dragover', nearestEmptyInsertDetectEvent);\n off(document, 'mousemove', nearestEmptyInsertDetectEvent);\n off(document, 'touchmove', nearestEmptyInsertDetectEvent);\n },\n _offUpEvents: function _offUpEvents() {\n var ownerDocument = this.el.ownerDocument;\n off(ownerDocument, 'mouseup', this._onDrop);\n off(ownerDocument, 'touchend', this._onDrop);\n off(ownerDocument, 'pointerup', this._onDrop);\n off(ownerDocument, 'pointercancel', this._onDrop);\n off(ownerDocument, 'touchcancel', this._onDrop);\n off(document, 'selectstart', this);\n },\n _onDrop: function _onDrop( /**Event*/evt) {\n var el = this.el,\n options = this.options;\n\n // Get the index of the dragged element within its parent\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n pluginEvent('drop', this, {\n evt: evt\n });\n parentEl = dragEl && dragEl.parentNode;\n\n // Get again after plugin event\n newIndex = index(dragEl);\n newDraggableIndex = index(dragEl, options.draggable);\n if (Sortable.eventCanceled) {\n this._nulling();\n return;\n }\n awaitingDragStarted = false;\n isCircumstantialInvert = false;\n pastFirstInvertThresh = false;\n clearInterval(this._loopId);\n clearTimeout(this._dragStartTimer);\n _cancelNextTick(this.cloneId);\n _cancelNextTick(this._dragStartId);\n\n // Unbind events\n if (this.nativeDraggable) {\n off(document, 'drop', this);\n off(el, 'dragstart', this._onDragStart);\n }\n this._offMoveEvents();\n this._offUpEvents();\n if (Safari) {\n css(document.body, 'user-select', '');\n }\n css(dragEl, 'transform', '');\n if (evt) {\n if (moved) {\n evt.cancelable && evt.preventDefault();\n !options.dropBubble && evt.stopPropagation();\n }\n ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);\n if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {\n // Remove clone(s)\n cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);\n }\n if (dragEl) {\n if (this.nativeDraggable) {\n off(dragEl, 'dragend', this);\n }\n _disableDraggable(dragEl);\n dragEl.style['will-change'] = '';\n\n // Remove classes\n // ghostClass is added in dragStarted\n if (moved && !awaitingDragStarted) {\n toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);\n }\n toggleClass(dragEl, this.options.chosenClass, false);\n\n // Drag stop event\n _dispatchEvent({\n sortable: this,\n name: 'unchoose',\n toEl: parentEl,\n newIndex: null,\n newDraggableIndex: null,\n originalEvent: evt\n });\n if (rootEl !== parentEl) {\n if (newIndex >= 0) {\n // Add event\n _dispatchEvent({\n rootEl: parentEl,\n name: 'add',\n toEl: parentEl,\n fromEl: rootEl,\n originalEvent: evt\n });\n\n // Remove event\n _dispatchEvent({\n sortable: this,\n name: 'remove',\n toEl: parentEl,\n originalEvent: evt\n });\n\n // drag from one list and drop into another\n _dispatchEvent({\n rootEl: parentEl,\n name: 'sort',\n toEl: parentEl,\n fromEl: rootEl,\n originalEvent: evt\n });\n _dispatchEvent({\n sortable: this,\n name: 'sort',\n toEl: parentEl,\n originalEvent: evt\n });\n }\n putSortable && putSortable.save();\n } else {\n if (newIndex !== oldIndex) {\n if (newIndex >= 0) {\n // drag & drop within the same list\n _dispatchEvent({\n sortable: this,\n name: 'update',\n toEl: parentEl,\n originalEvent: evt\n });\n _dispatchEvent({\n sortable: this,\n name: 'sort',\n toEl: parentEl,\n originalEvent: evt\n });\n }\n }\n }\n if (Sortable.active) {\n /* jshint eqnull:true */\n if (newIndex == null || newIndex === -1) {\n newIndex = oldIndex;\n newDraggableIndex = oldDraggableIndex;\n }\n _dispatchEvent({\n sortable: this,\n name: 'end',\n toEl: parentEl,\n originalEvent: evt\n });\n\n // Save sorting\n this.save();\n }\n }\n }\n this._nulling();\n },\n _nulling: function _nulling() {\n pluginEvent('nulling', this);\n rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;\n var el = this.el;\n savedInputChecked.forEach(function (checkEl) {\n if (el.contains(checkEl)) {\n checkEl.checked = true;\n }\n });\n savedInputChecked.length = lastDx = lastDy = 0;\n },\n handleEvent: function handleEvent( /**Event*/evt) {\n switch (evt.type) {\n case 'drop':\n case 'dragend':\n this._onDrop(evt);\n break;\n case 'dragenter':\n case 'dragover':\n if (dragEl) {\n this._onDragOver(evt);\n _globalDragOver(evt);\n }\n break;\n case 'selectstart':\n evt.preventDefault();\n break;\n }\n },\n /**\r\n * Serializes the item into an array of string.\r\n * @returns {String[]}\r\n */\n toArray: function toArray() {\n var order = [],\n el,\n children = this.el.children,\n i = 0,\n n = children.length,\n options = this.options;\n for (; i < n; i++) {\n el = children[i];\n if (closest(el, options.draggable, this.el, false)) {\n order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));\n }\n }\n return order;\n },\n /**\r\n * Sorts the elements according to the array.\r\n * @param {String[]} order order of the items\r\n */\n sort: function sort(order, useAnimation) {\n var items = {},\n rootEl = this.el;\n this.toArray().forEach(function (id, i) {\n var el = rootEl.children[i];\n if (closest(el, this.options.draggable, rootEl, false)) {\n items[id] = el;\n }\n }, this);\n useAnimation && this.captureAnimationState();\n order.forEach(function (id) {\n if (items[id]) {\n rootEl.removeChild(items[id]);\n rootEl.appendChild(items[id]);\n }\n });\n useAnimation && this.animateAll();\n },\n /**\r\n * Save the current sorting\r\n */\n save: function save() {\n var store = this.options.store;\n store && store.set && store.set(this);\n },\n /**\r\n * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.\r\n * @param {HTMLElement} el\r\n * @param {String} [selector] default: `options.draggable`\r\n * @returns {HTMLElement|null}\r\n */\n closest: function closest$1(el, selector) {\n return closest(el, selector || this.options.draggable, this.el, false);\n },\n /**\r\n * Set/get option\r\n * @param {string} name\r\n * @param {*} [value]\r\n * @returns {*}\r\n */\n option: function option(name, value) {\n var options = this.options;\n if (value === void 0) {\n return options[name];\n } else {\n var modifiedValue = PluginManager.modifyOption(this, name, value);\n if (typeof modifiedValue !== 'undefined') {\n options[name] = modifiedValue;\n } else {\n options[name] = value;\n }\n if (name === 'group') {\n _prepareGroup(options);\n }\n }\n },\n /**\r\n * Destroy\r\n */\n destroy: function destroy() {\n pluginEvent('destroy', this);\n var el = this.el;\n el[expando] = null;\n off(el, 'mousedown', this._onTapStart);\n off(el, 'touchstart', this._onTapStart);\n off(el, 'pointerdown', this._onTapStart);\n if (this.nativeDraggable) {\n off(el, 'dragover', this);\n off(el, 'dragenter', this);\n }\n // Remove draggable attributes\n Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {\n el.removeAttribute('draggable');\n });\n this._onDrop();\n this._disableDelayedDragEvents();\n sortables.splice(sortables.indexOf(this.el), 1);\n this.el = el = null;\n },\n _hideClone: function _hideClone() {\n if (!cloneHidden) {\n pluginEvent('hideClone', this);\n if (Sortable.eventCanceled) return;\n css(cloneEl, 'display', 'none');\n if (this.options.removeCloneOnHide && cloneEl.parentNode) {\n cloneEl.parentNode.removeChild(cloneEl);\n }\n cloneHidden = true;\n }\n },\n _showClone: function _showClone(putSortable) {\n if (putSortable.lastPutMode !== 'clone') {\n this._hideClone();\n return;\n }\n if (cloneHidden) {\n pluginEvent('showClone', this);\n if (Sortable.eventCanceled) return;\n\n // show clone at dragEl or original position\n if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {\n rootEl.insertBefore(cloneEl, dragEl);\n } else if (nextEl) {\n rootEl.insertBefore(cloneEl, nextEl);\n } else {\n rootEl.appendChild(cloneEl);\n }\n if (this.options.group.revertClone) {\n this.animate(dragEl, cloneEl);\n }\n css(cloneEl, 'display', '');\n cloneHidden = false;\n }\n }\n};\nfunction _globalDragOver( /**Event*/evt) {\n if (evt.dataTransfer) {\n evt.dataTransfer.dropEffect = 'move';\n }\n evt.cancelable && evt.preventDefault();\n}\nfunction _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {\n var evt,\n sortable = fromEl[expando],\n onMoveFn = sortable.options.onMove,\n retVal;\n // Support for new CustomEvent feature\n if (window.CustomEvent && !IE11OrLess && !Edge) {\n evt = new CustomEvent('move', {\n bubbles: true,\n cancelable: true\n });\n } else {\n evt = document.createEvent('Event');\n evt.initEvent('move', true, true);\n }\n evt.to = toEl;\n evt.from = fromEl;\n evt.dragged = dragEl;\n evt.draggedRect = dragRect;\n evt.related = targetEl || toEl;\n evt.relatedRect = targetRect || getRect(toEl);\n evt.willInsertAfter = willInsertAfter;\n evt.originalEvent = originalEvent;\n fromEl.dispatchEvent(evt);\n if (onMoveFn) {\n retVal = onMoveFn.call(sortable, evt, originalEvent);\n }\n return retVal;\n}\nfunction _disableDraggable(el) {\n el.draggable = false;\n}\nfunction _unsilent() {\n _silent = false;\n}\nfunction _ghostIsFirst(evt, vertical, sortable) {\n var firstElRect = getRect(getChild(sortable.el, 0, sortable.options, true));\n var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);\n var spacer = 10;\n return vertical ? evt.clientX < childContainingRect.left - spacer || evt.clientY < firstElRect.top && evt.clientX < firstElRect.right : evt.clientY < childContainingRect.top - spacer || evt.clientY < firstElRect.bottom && evt.clientX < firstElRect.left;\n}\nfunction _ghostIsLast(evt, vertical, sortable) {\n var lastElRect = getRect(lastChild(sortable.el, sortable.options.draggable));\n var childContainingRect = getChildContainingRectFromElement(sortable.el, sortable.options, ghostEl);\n var spacer = 10;\n return vertical ? evt.clientX > childContainingRect.right + spacer || evt.clientY > lastElRect.bottom && evt.clientX > lastElRect.left : evt.clientY > childContainingRect.bottom + spacer || evt.clientX > lastElRect.right && evt.clientY > lastElRect.top;\n}\nfunction _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {\n var mouseOnAxis = vertical ? evt.clientY : evt.clientX,\n targetLength = vertical ? targetRect.height : targetRect.width,\n targetS1 = vertical ? targetRect.top : targetRect.left,\n targetS2 = vertical ? targetRect.bottom : targetRect.right,\n invert = false;\n if (!invertSwap) {\n // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold\n if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {\n // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2\n // check if past first invert threshold on side opposite of lastDirection\n if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {\n // past first invert threshold, do not restrict inverted threshold to dragEl shadow\n pastFirstInvertThresh = true;\n }\n if (!pastFirstInvertThresh) {\n // dragEl shadow (target move distance shadow)\n if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow\n : mouseOnAxis > targetS2 - targetMoveDistance) {\n return -lastDirection;\n }\n } else {\n invert = true;\n }\n } else {\n // Regular\n if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {\n return _getInsertDirection(target);\n }\n }\n }\n invert = invert || invertSwap;\n if (invert) {\n // Invert of regular\n if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {\n return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;\n }\n }\n return 0;\n}\n\n/**\r\n * Gets the direction dragEl must be swapped relative to target in order to make it\r\n * seem that dragEl has been \"inserted\" into that element's position\r\n * @param {HTMLElement} target The target whose position dragEl is being inserted at\r\n * @return {Number} Direction dragEl must be swapped\r\n */\nfunction _getInsertDirection(target) {\n if (index(dragEl) < index(target)) {\n return 1;\n } else {\n return -1;\n }\n}\n\n/**\r\n * Generate id\r\n * @param {HTMLElement} el\r\n * @returns {String}\r\n * @private\r\n */\nfunction _generateId(el) {\n var str = el.tagName + el.className + el.src + el.href + el.textContent,\n i = str.length,\n sum = 0;\n while (i--) {\n sum += str.charCodeAt(i);\n }\n return sum.toString(36);\n}\nfunction _saveInputCheckedState(root) {\n savedInputChecked.length = 0;\n var inputs = root.getElementsByTagName('input');\n var idx = inputs.length;\n while (idx--) {\n var el = inputs[idx];\n el.checked && savedInputChecked.push(el);\n }\n}\nfunction _nextTick(fn) {\n return setTimeout(fn, 0);\n}\nfunction _cancelNextTick(id) {\n return clearTimeout(id);\n}\n\n// Fixed #973:\nif (documentExists) {\n on(document, 'touchmove', function (evt) {\n if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {\n evt.preventDefault();\n }\n });\n}\n\n// Export utils\nSortable.utils = {\n on: on,\n off: off,\n css: css,\n find: find,\n is: function is(el, selector) {\n return !!closest(el, selector, el, false);\n },\n extend: extend,\n throttle: throttle,\n closest: closest,\n toggleClass: toggleClass,\n clone: clone,\n index: index,\n nextTick: _nextTick,\n cancelNextTick: _cancelNextTick,\n detectDirection: _detectDirection,\n getChild: getChild,\n expando: expando\n};\n\n/**\r\n * Get the Sortable instance of an element\r\n * @param {HTMLElement} element The element\r\n * @return {Sortable|undefined} The instance of Sortable\r\n */\nSortable.get = function (element) {\n return element[expando];\n};\n\n/**\r\n * Mount a plugin to Sortable\r\n * @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted\r\n */\nSortable.mount = function () {\n for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {\n plugins[_key] = arguments[_key];\n }\n if (plugins[0].constructor === Array) plugins = plugins[0];\n plugins.forEach(function (plugin) {\n if (!plugin.prototype || !plugin.prototype.constructor) {\n throw \"Sortable: Mounted plugin must be a constructor function, not \".concat({}.toString.call(plugin));\n }\n if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);\n PluginManager.mount(plugin);\n });\n};\n\n/**\r\n * Create sortable instance\r\n * @param {HTMLElement} el\r\n * @param {Object} [options]\r\n */\nSortable.create = function (el, options) {\n return new Sortable(el, options);\n};\n\n// Export\nSortable.version = version;\n\nvar autoScrolls = [],\n scrollEl,\n scrollRootEl,\n scrolling = false,\n lastAutoScrollX,\n lastAutoScrollY,\n touchEvt$1,\n pointerElemChangedInterval;\nfunction AutoScrollPlugin() {\n function AutoScroll() {\n this.defaults = {\n scroll: true,\n forceAutoScrollFallback: false,\n scrollSensitivity: 30,\n scrollSpeed: 10,\n bubbleScroll: true\n };\n\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n }\n AutoScroll.prototype = {\n dragStarted: function dragStarted(_ref) {\n var originalEvent = _ref.originalEvent;\n if (this.sortable.nativeDraggable) {\n on(document, 'dragover', this._handleAutoScroll);\n } else {\n if (this.options.supportPointer) {\n on(document, 'pointermove', this._handleFallbackAutoScroll);\n } else if (originalEvent.touches) {\n on(document, 'touchmove', this._handleFallbackAutoScroll);\n } else {\n on(document, 'mousemove', this._handleFallbackAutoScroll);\n }\n }\n },\n dragOverCompleted: function dragOverCompleted(_ref2) {\n var originalEvent = _ref2.originalEvent;\n // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)\n if (!this.options.dragOverBubble && !originalEvent.rootEl) {\n this._handleAutoScroll(originalEvent);\n }\n },\n drop: function drop() {\n if (this.sortable.nativeDraggable) {\n off(document, 'dragover', this._handleAutoScroll);\n } else {\n off(document, 'pointermove', this._handleFallbackAutoScroll);\n off(document, 'touchmove', this._handleFallbackAutoScroll);\n off(document, 'mousemove', this._handleFallbackAutoScroll);\n }\n clearPointerElemChangedInterval();\n clearAutoScrolls();\n cancelThrottle();\n },\n nulling: function nulling() {\n touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;\n autoScrolls.length = 0;\n },\n _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {\n this._handleAutoScroll(evt, true);\n },\n _handleAutoScroll: function _handleAutoScroll(evt, fallback) {\n var _this = this;\n var x = (evt.touches ? evt.touches[0] : evt).clientX,\n y = (evt.touches ? evt.touches[0] : evt).clientY,\n elem = document.elementFromPoint(x, y);\n touchEvt$1 = evt;\n\n // IE does not seem to have native autoscroll,\n // Edge's autoscroll seems too conditional,\n // MACOS Safari does not have autoscroll,\n // Firefox and Chrome are good\n if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {\n autoScroll(evt, this.options, elem, fallback);\n\n // Listener for pointer element change\n var ogElemScroller = getParentAutoScrollElement(elem, true);\n if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {\n pointerElemChangedInterval && clearPointerElemChangedInterval();\n // Detect for pointer elem change, emulating native DnD behaviour\n pointerElemChangedInterval = setInterval(function () {\n var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);\n if (newElem !== ogElemScroller) {\n ogElemScroller = newElem;\n clearAutoScrolls();\n }\n autoScroll(evt, _this.options, newElem, fallback);\n }, 10);\n lastAutoScrollX = x;\n lastAutoScrollY = y;\n }\n } else {\n // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll\n if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {\n clearAutoScrolls();\n return;\n }\n autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);\n }\n }\n };\n return _extends(AutoScroll, {\n pluginName: 'scroll',\n initializeByDefault: true\n });\n}\nfunction clearAutoScrolls() {\n autoScrolls.forEach(function (autoScroll) {\n clearInterval(autoScroll.pid);\n });\n autoScrolls = [];\n}\nfunction clearPointerElemChangedInterval() {\n clearInterval(pointerElemChangedInterval);\n}\nvar autoScroll = throttle(function (evt, options, rootEl, isFallback) {\n // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521\n if (!options.scroll) return;\n var x = (evt.touches ? evt.touches[0] : evt).clientX,\n y = (evt.touches ? evt.touches[0] : evt).clientY,\n sens = options.scrollSensitivity,\n speed = options.scrollSpeed,\n winScroller = getWindowScrollingElement();\n var scrollThisInstance = false,\n scrollCustomFn;\n\n // New scroll root, set scrollEl\n if (scrollRootEl !== rootEl) {\n scrollRootEl = rootEl;\n clearAutoScrolls();\n scrollEl = options.scroll;\n scrollCustomFn = options.scrollFn;\n if (scrollEl === true) {\n scrollEl = getParentAutoScrollElement(rootEl, true);\n }\n }\n var layersOut = 0;\n var currentParent = scrollEl;\n do {\n var el = currentParent,\n rect = getRect(el),\n top = rect.top,\n bottom = rect.bottom,\n left = rect.left,\n right = rect.right,\n width = rect.width,\n height = rect.height,\n canScrollX = void 0,\n canScrollY = void 0,\n scrollWidth = el.scrollWidth,\n scrollHeight = el.scrollHeight,\n elCSS = css(el),\n scrollPosX = el.scrollLeft,\n scrollPosY = el.scrollTop;\n if (el === winScroller) {\n canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');\n canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');\n } else {\n canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');\n canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');\n }\n var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);\n var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);\n if (!autoScrolls[layersOut]) {\n for (var i = 0; i <= layersOut; i++) {\n if (!autoScrolls[i]) {\n autoScrolls[i] = {};\n }\n }\n }\n if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {\n autoScrolls[layersOut].el = el;\n autoScrolls[layersOut].vx = vx;\n autoScrolls[layersOut].vy = vy;\n clearInterval(autoScrolls[layersOut].pid);\n if (vx != 0 || vy != 0) {\n scrollThisInstance = true;\n /* jshint loopfunc:true */\n autoScrolls[layersOut].pid = setInterval(function () {\n // emulate drag over during autoscroll (fallback), emulating native DnD behaviour\n if (isFallback && this.layer === 0) {\n Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely\n }\n var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;\n var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;\n if (typeof scrollCustomFn === 'function') {\n if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {\n return;\n }\n }\n scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);\n }.bind({\n layer: layersOut\n }), 24);\n }\n }\n layersOut++;\n } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));\n scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not\n}, 30);\n\nvar drop = function drop(_ref) {\n var originalEvent = _ref.originalEvent,\n putSortable = _ref.putSortable,\n dragEl = _ref.dragEl,\n activeSortable = _ref.activeSortable,\n dispatchSortableEvent = _ref.dispatchSortableEvent,\n hideGhostForTarget = _ref.hideGhostForTarget,\n unhideGhostForTarget = _ref.unhideGhostForTarget;\n if (!originalEvent) return;\n var toSortable = putSortable || activeSortable;\n hideGhostForTarget();\n var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;\n var target = document.elementFromPoint(touch.clientX, touch.clientY);\n unhideGhostForTarget();\n if (toSortable && !toSortable.el.contains(target)) {\n dispatchSortableEvent('spill');\n this.onSpill({\n dragEl: dragEl,\n putSortable: putSortable\n });\n }\n};\nfunction Revert() {}\nRevert.prototype = {\n startIndex: null,\n dragStart: function dragStart(_ref2) {\n var oldDraggableIndex = _ref2.oldDraggableIndex;\n this.startIndex = oldDraggableIndex;\n },\n onSpill: function onSpill(_ref3) {\n var dragEl = _ref3.dragEl,\n putSortable = _ref3.putSortable;\n this.sortable.captureAnimationState();\n if (putSortable) {\n putSortable.captureAnimationState();\n }\n var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);\n if (nextSibling) {\n this.sortable.el.insertBefore(dragEl, nextSibling);\n } else {\n this.sortable.el.appendChild(dragEl);\n }\n this.sortable.animateAll();\n if (putSortable) {\n putSortable.animateAll();\n }\n },\n drop: drop\n};\n_extends(Revert, {\n pluginName: 'revertOnSpill'\n});\nfunction Remove() {}\nRemove.prototype = {\n onSpill: function onSpill(_ref4) {\n var dragEl = _ref4.dragEl,\n putSortable = _ref4.putSortable;\n var parentSortable = putSortable || this.sortable;\n parentSortable.captureAnimationState();\n dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);\n parentSortable.animateAll();\n },\n drop: drop\n};\n_extends(Remove, {\n pluginName: 'removeOnSpill'\n});\n\nvar lastSwapEl;\nfunction SwapPlugin() {\n function Swap() {\n this.defaults = {\n swapClass: 'sortable-swap-highlight'\n };\n }\n Swap.prototype = {\n dragStart: function dragStart(_ref) {\n var dragEl = _ref.dragEl;\n lastSwapEl = dragEl;\n },\n dragOverValid: function dragOverValid(_ref2) {\n var completed = _ref2.completed,\n target = _ref2.target,\n onMove = _ref2.onMove,\n activeSortable = _ref2.activeSortable,\n changed = _ref2.changed,\n cancel = _ref2.cancel;\n if (!activeSortable.options.swap) return;\n var el = this.sortable.el,\n options = this.options;\n if (target && target !== el) {\n var prevSwapEl = lastSwapEl;\n if (onMove(target) !== false) {\n toggleClass(target, options.swapClass, true);\n lastSwapEl = target;\n } else {\n lastSwapEl = null;\n }\n if (prevSwapEl && prevSwapEl !== lastSwapEl) {\n toggleClass(prevSwapEl, options.swapClass, false);\n }\n }\n changed();\n completed(true);\n cancel();\n },\n drop: function drop(_ref3) {\n var activeSortable = _ref3.activeSortable,\n putSortable = _ref3.putSortable,\n dragEl = _ref3.dragEl;\n var toSortable = putSortable || this.sortable;\n var options = this.options;\n lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);\n if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {\n if (dragEl !== lastSwapEl) {\n toSortable.captureAnimationState();\n if (toSortable !== activeSortable) activeSortable.captureAnimationState();\n swapNodes(dragEl, lastSwapEl);\n toSortable.animateAll();\n if (toSortable !== activeSortable) activeSortable.animateAll();\n }\n }\n },\n nulling: function nulling() {\n lastSwapEl = null;\n }\n };\n return _extends(Swap, {\n pluginName: 'swap',\n eventProperties: function eventProperties() {\n return {\n swapItem: lastSwapEl\n };\n }\n });\n}\nfunction swapNodes(n1, n2) {\n var p1 = n1.parentNode,\n p2 = n2.parentNode,\n i1,\n i2;\n if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;\n i1 = index(n1);\n i2 = index(n2);\n if (p1.isEqualNode(p2) && i1 < i2) {\n i2++;\n }\n p1.insertBefore(n2, p1.children[i1]);\n p2.insertBefore(n1, p2.children[i2]);\n}\n\nvar multiDragElements = [],\n multiDragClones = [],\n lastMultiDragSelect,\n // for selection with modifier key down (SHIFT)\n multiDragSortable,\n initialFolding = false,\n // Initial multi-drag fold when drag started\n folding = false,\n // Folding any other time\n dragStarted = false,\n dragEl$1,\n clonesFromRect,\n clonesHidden;\nfunction MultiDragPlugin() {\n function MultiDrag(sortable) {\n // Bind all private methods\n for (var fn in this) {\n if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {\n this[fn] = this[fn].bind(this);\n }\n }\n if (!sortable.options.avoidImplicitDeselect) {\n if (sortable.options.supportPointer) {\n on(document, 'pointerup', this._deselectMultiDrag);\n } else {\n on(document, 'mouseup', this._deselectMultiDrag);\n on(document, 'touchend', this._deselectMultiDrag);\n }\n }\n on(document, 'keydown', this._checkKeyDown);\n on(document, 'keyup', this._checkKeyUp);\n this.defaults = {\n selectedClass: 'sortable-selected',\n multiDragKey: null,\n avoidImplicitDeselect: false,\n setData: function setData(dataTransfer, dragEl) {\n var data = '';\n if (multiDragElements.length && multiDragSortable === sortable) {\n multiDragElements.forEach(function (multiDragElement, i) {\n data += (!i ? '' : ', ') + multiDragElement.textContent;\n });\n } else {\n data = dragEl.textContent;\n }\n dataTransfer.setData('Text', data);\n }\n };\n }\n MultiDrag.prototype = {\n multiDragKeyDown: false,\n isMultiDrag: false,\n delayStartGlobal: function delayStartGlobal(_ref) {\n var dragged = _ref.dragEl;\n dragEl$1 = dragged;\n },\n delayEnded: function delayEnded() {\n this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);\n },\n setupClone: function setupClone(_ref2) {\n var sortable = _ref2.sortable,\n cancel = _ref2.cancel;\n if (!this.isMultiDrag) return;\n for (var i = 0; i < multiDragElements.length; i++) {\n multiDragClones.push(clone(multiDragElements[i]));\n multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;\n multiDragClones[i].draggable = false;\n multiDragClones[i].style['will-change'] = '';\n toggleClass(multiDragClones[i], this.options.selectedClass, false);\n multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);\n }\n sortable._hideClone();\n cancel();\n },\n clone: function clone(_ref3) {\n var sortable = _ref3.sortable,\n rootEl = _ref3.rootEl,\n dispatchSortableEvent = _ref3.dispatchSortableEvent,\n cancel = _ref3.cancel;\n if (!this.isMultiDrag) return;\n if (!this.options.removeCloneOnHide) {\n if (multiDragElements.length && multiDragSortable === sortable) {\n insertMultiDragClones(true, rootEl);\n dispatchSortableEvent('clone');\n cancel();\n }\n }\n },\n showClone: function showClone(_ref4) {\n var cloneNowShown = _ref4.cloneNowShown,\n rootEl = _ref4.rootEl,\n cancel = _ref4.cancel;\n if (!this.isMultiDrag) return;\n insertMultiDragClones(false, rootEl);\n multiDragClones.forEach(function (clone) {\n css(clone, 'display', '');\n });\n cloneNowShown();\n clonesHidden = false;\n cancel();\n },\n hideClone: function hideClone(_ref5) {\n var _this = this;\n var sortable = _ref5.sortable,\n cloneNowHidden = _ref5.cloneNowHidden,\n cancel = _ref5.cancel;\n if (!this.isMultiDrag) return;\n multiDragClones.forEach(function (clone) {\n css(clone, 'display', 'none');\n if (_this.options.removeCloneOnHide && clone.parentNode) {\n clone.parentNode.removeChild(clone);\n }\n });\n cloneNowHidden();\n clonesHidden = true;\n cancel();\n },\n dragStartGlobal: function dragStartGlobal(_ref6) {\n var sortable = _ref6.sortable;\n if (!this.isMultiDrag && multiDragSortable) {\n multiDragSortable.multiDrag._deselectMultiDrag();\n }\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.sortableIndex = index(multiDragElement);\n });\n\n // Sort multi-drag elements\n multiDragElements = multiDragElements.sort(function (a, b) {\n return a.sortableIndex - b.sortableIndex;\n });\n dragStarted = true;\n },\n dragStarted: function dragStarted(_ref7) {\n var _this2 = this;\n var sortable = _ref7.sortable;\n if (!this.isMultiDrag) return;\n if (this.options.sort) {\n // Capture rects,\n // hide multi drag elements (by positioning them absolute),\n // set multi drag elements rects to dragRect,\n // show multi drag elements,\n // animate to rects,\n // unset rects & remove from DOM\n\n sortable.captureAnimationState();\n if (this.options.animation) {\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n css(multiDragElement, 'position', 'absolute');\n });\n var dragRect = getRect(dragEl$1, false, true, true);\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n setRect(multiDragElement, dragRect);\n });\n folding = true;\n initialFolding = true;\n }\n }\n sortable.animateAll(function () {\n folding = false;\n initialFolding = false;\n if (_this2.options.animation) {\n multiDragElements.forEach(function (multiDragElement) {\n unsetRect(multiDragElement);\n });\n }\n\n // Remove all auxiliary multidrag items from el, if sorting enabled\n if (_this2.options.sort) {\n removeMultiDragElements();\n }\n });\n },\n dragOver: function dragOver(_ref8) {\n var target = _ref8.target,\n completed = _ref8.completed,\n cancel = _ref8.cancel;\n if (folding && ~multiDragElements.indexOf(target)) {\n completed(false);\n cancel();\n }\n },\n revert: function revert(_ref9) {\n var fromSortable = _ref9.fromSortable,\n rootEl = _ref9.rootEl,\n sortable = _ref9.sortable,\n dragRect = _ref9.dragRect;\n if (multiDragElements.length > 1) {\n // Setup unfold animation\n multiDragElements.forEach(function (multiDragElement) {\n sortable.addAnimationState({\n target: multiDragElement,\n rect: folding ? getRect(multiDragElement) : dragRect\n });\n unsetRect(multiDragElement);\n multiDragElement.fromRect = dragRect;\n fromSortable.removeAnimationState(multiDragElement);\n });\n folding = false;\n insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);\n }\n },\n dragOverCompleted: function dragOverCompleted(_ref10) {\n var sortable = _ref10.sortable,\n isOwner = _ref10.isOwner,\n insertion = _ref10.insertion,\n activeSortable = _ref10.activeSortable,\n parentEl = _ref10.parentEl,\n putSortable = _ref10.putSortable;\n var options = this.options;\n if (insertion) {\n // Clones must be hidden before folding animation to capture dragRectAbsolute properly\n if (isOwner) {\n activeSortable._hideClone();\n }\n initialFolding = false;\n // If leaving sort:false root, or already folding - Fold to new location\n if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {\n // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible\n var dragRectAbsolute = getRect(dragEl$1, false, true, true);\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n setRect(multiDragElement, dragRectAbsolute);\n\n // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted\n // while folding, and so that we can capture them again because old sortable will no longer be fromSortable\n parentEl.appendChild(multiDragElement);\n });\n folding = true;\n }\n\n // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out\n if (!isOwner) {\n // Only remove if not folding (folding will remove them anyways)\n if (!folding) {\n removeMultiDragElements();\n }\n if (multiDragElements.length > 1) {\n var clonesHiddenBefore = clonesHidden;\n activeSortable._showClone(sortable);\n\n // Unfold animation for clones if showing from hidden\n if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {\n multiDragClones.forEach(function (clone) {\n activeSortable.addAnimationState({\n target: clone,\n rect: clonesFromRect\n });\n clone.fromRect = clonesFromRect;\n clone.thisAnimationDuration = null;\n });\n }\n } else {\n activeSortable._showClone(sortable);\n }\n }\n }\n },\n dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {\n var dragRect = _ref11.dragRect,\n isOwner = _ref11.isOwner,\n activeSortable = _ref11.activeSortable;\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.thisAnimationDuration = null;\n });\n if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {\n clonesFromRect = _extends({}, dragRect);\n var dragMatrix = matrix(dragEl$1, true);\n clonesFromRect.top -= dragMatrix.f;\n clonesFromRect.left -= dragMatrix.e;\n }\n },\n dragOverAnimationComplete: function dragOverAnimationComplete() {\n if (folding) {\n folding = false;\n removeMultiDragElements();\n }\n },\n drop: function drop(_ref12) {\n var evt = _ref12.originalEvent,\n rootEl = _ref12.rootEl,\n parentEl = _ref12.parentEl,\n sortable = _ref12.sortable,\n dispatchSortableEvent = _ref12.dispatchSortableEvent,\n oldIndex = _ref12.oldIndex,\n putSortable = _ref12.putSortable;\n var toSortable = putSortable || this.sortable;\n if (!evt) return;\n var options = this.options,\n children = parentEl.children;\n\n // Multi-drag selection\n if (!dragStarted) {\n if (options.multiDragKey && !this.multiDragKeyDown) {\n this._deselectMultiDrag();\n }\n toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));\n if (!~multiDragElements.indexOf(dragEl$1)) {\n multiDragElements.push(dragEl$1);\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'select',\n targetEl: dragEl$1,\n originalEvent: evt\n });\n\n // Modifier activated, select from last to dragEl\n if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {\n var lastIndex = index(lastMultiDragSelect),\n currentIndex = index(dragEl$1);\n if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {\n (function () {\n // Must include lastMultiDragSelect (select it), in case modified selection from no selection\n // (but previous selection existed)\n var n, i;\n if (currentIndex > lastIndex) {\n i = lastIndex;\n n = currentIndex;\n } else {\n i = currentIndex;\n n = lastIndex + 1;\n }\n var filter = options.filter;\n for (; i < n; i++) {\n if (~multiDragElements.indexOf(children[i])) continue;\n // Check if element is draggable\n if (!closest(children[i], options.draggable, parentEl, false)) continue;\n // Check if element is filtered\n var filtered = filter && (typeof filter === 'function' ? filter.call(sortable, evt, children[i], sortable) : filter.split(',').some(function (criteria) {\n return closest(children[i], criteria.trim(), parentEl, false);\n }));\n if (filtered) continue;\n toggleClass(children[i], options.selectedClass, true);\n multiDragElements.push(children[i]);\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'select',\n targetEl: children[i],\n originalEvent: evt\n });\n }\n })();\n }\n } else {\n lastMultiDragSelect = dragEl$1;\n }\n multiDragSortable = toSortable;\n } else {\n multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);\n lastMultiDragSelect = null;\n dispatchEvent({\n sortable: sortable,\n rootEl: rootEl,\n name: 'deselect',\n targetEl: dragEl$1,\n originalEvent: evt\n });\n }\n }\n\n // Multi-drag drop\n if (dragStarted && this.isMultiDrag) {\n folding = false;\n // Do not \"unfold\" after around dragEl if reverted\n if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {\n var dragRect = getRect(dragEl$1),\n multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');\n if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;\n toSortable.captureAnimationState();\n if (!initialFolding) {\n if (options.animation) {\n dragEl$1.fromRect = dragRect;\n multiDragElements.forEach(function (multiDragElement) {\n multiDragElement.thisAnimationDuration = null;\n if (multiDragElement !== dragEl$1) {\n var rect = folding ? getRect(multiDragElement) : dragRect;\n multiDragElement.fromRect = rect;\n\n // Prepare unfold animation\n toSortable.addAnimationState({\n target: multiDragElement,\n rect: rect\n });\n }\n });\n }\n\n // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert\n // properly they must all be removed\n removeMultiDragElements();\n multiDragElements.forEach(function (multiDragElement) {\n if (children[multiDragIndex]) {\n parentEl.insertBefore(multiDragElement, children[multiDragIndex]);\n } else {\n parentEl.appendChild(multiDragElement);\n }\n multiDragIndex++;\n });\n\n // If initial folding is done, the elements may have changed position because they are now\n // unfolding around dragEl, even though dragEl may not have his index changed, so update event\n // must be fired here as Sortable will not.\n if (oldIndex === index(dragEl$1)) {\n var update = false;\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement.sortableIndex !== index(multiDragElement)) {\n update = true;\n return;\n }\n });\n if (update) {\n dispatchSortableEvent('update');\n dispatchSortableEvent('sort');\n }\n }\n }\n\n // Must be done after capturing individual rects (scroll bar)\n multiDragElements.forEach(function (multiDragElement) {\n unsetRect(multiDragElement);\n });\n toSortable.animateAll();\n }\n multiDragSortable = toSortable;\n }\n\n // Remove clones if necessary\n if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {\n multiDragClones.forEach(function (clone) {\n clone.parentNode && clone.parentNode.removeChild(clone);\n });\n }\n },\n nullingGlobal: function nullingGlobal() {\n this.isMultiDrag = dragStarted = false;\n multiDragClones.length = 0;\n },\n destroyGlobal: function destroyGlobal() {\n this._deselectMultiDrag();\n off(document, 'pointerup', this._deselectMultiDrag);\n off(document, 'mouseup', this._deselectMultiDrag);\n off(document, 'touchend', this._deselectMultiDrag);\n off(document, 'keydown', this._checkKeyDown);\n off(document, 'keyup', this._checkKeyUp);\n },\n _deselectMultiDrag: function _deselectMultiDrag(evt) {\n if (typeof dragStarted !== \"undefined\" && dragStarted) return;\n\n // Only deselect if selection is in this sortable\n if (multiDragSortable !== this.sortable) return;\n\n // Only deselect if target is not item in this sortable\n if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;\n\n // Only deselect if left click\n if (evt && evt.button !== 0) return;\n while (multiDragElements.length) {\n var el = multiDragElements[0];\n toggleClass(el, this.options.selectedClass, false);\n multiDragElements.shift();\n dispatchEvent({\n sortable: this.sortable,\n rootEl: this.sortable.el,\n name: 'deselect',\n targetEl: el,\n originalEvent: evt\n });\n }\n },\n _checkKeyDown: function _checkKeyDown(evt) {\n if (evt.key === this.options.multiDragKey) {\n this.multiDragKeyDown = true;\n }\n },\n _checkKeyUp: function _checkKeyUp(evt) {\n if (evt.key === this.options.multiDragKey) {\n this.multiDragKeyDown = false;\n }\n }\n };\n return _extends(MultiDrag, {\n // Static methods & properties\n pluginName: 'multiDrag',\n utils: {\n /**\r\n * Selects the provided multi-drag item\r\n * @param {HTMLElement} el The element to be selected\r\n */\n select: function select(el) {\n var sortable = el.parentNode[expando];\n if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;\n if (multiDragSortable && multiDragSortable !== sortable) {\n multiDragSortable.multiDrag._deselectMultiDrag();\n multiDragSortable = sortable;\n }\n toggleClass(el, sortable.options.selectedClass, true);\n multiDragElements.push(el);\n },\n /**\r\n * Deselects the provided multi-drag item\r\n * @param {HTMLElement} el The element to be deselected\r\n */\n deselect: function deselect(el) {\n var sortable = el.parentNode[expando],\n index = multiDragElements.indexOf(el);\n if (!sortable || !sortable.options.multiDrag || !~index) return;\n toggleClass(el, sortable.options.selectedClass, false);\n multiDragElements.splice(index, 1);\n }\n },\n eventProperties: function eventProperties() {\n var _this3 = this;\n var oldIndicies = [],\n newIndicies = [];\n multiDragElements.forEach(function (multiDragElement) {\n oldIndicies.push({\n multiDragElement: multiDragElement,\n index: multiDragElement.sortableIndex\n });\n\n // multiDragElements will already be sorted if folding\n var newIndex;\n if (folding && multiDragElement !== dragEl$1) {\n newIndex = -1;\n } else if (folding) {\n newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');\n } else {\n newIndex = index(multiDragElement);\n }\n newIndicies.push({\n multiDragElement: multiDragElement,\n index: newIndex\n });\n });\n return {\n items: _toConsumableArray(multiDragElements),\n clones: [].concat(multiDragClones),\n oldIndicies: oldIndicies,\n newIndicies: newIndicies\n };\n },\n optionListeners: {\n multiDragKey: function multiDragKey(key) {\n key = key.toLowerCase();\n if (key === 'ctrl') {\n key = 'Control';\n } else if (key.length > 1) {\n key = key.charAt(0).toUpperCase() + key.substr(1);\n }\n return key;\n }\n }\n });\n}\nfunction insertMultiDragElements(clonesInserted, rootEl) {\n multiDragElements.forEach(function (multiDragElement, i) {\n var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];\n if (target) {\n rootEl.insertBefore(multiDragElement, target);\n } else {\n rootEl.appendChild(multiDragElement);\n }\n });\n}\n\n/**\r\n * Insert multi-drag clones\r\n * @param {[Boolean]} elementsInserted Whether the multi-drag elements are inserted\r\n * @param {HTMLElement} rootEl\r\n */\nfunction insertMultiDragClones(elementsInserted, rootEl) {\n multiDragClones.forEach(function (clone, i) {\n var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];\n if (target) {\n rootEl.insertBefore(clone, target);\n } else {\n rootEl.appendChild(clone);\n }\n });\n}\nfunction removeMultiDragElements() {\n multiDragElements.forEach(function (multiDragElement) {\n if (multiDragElement === dragEl$1) return;\n multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);\n });\n}\n\nSortable.mount(new AutoScrollPlugin());\nSortable.mount(Remove, Revert);\n\nexport default Sortable;\nexport { MultiDragPlugin as MultiDrag, Sortable, SwapPlugin as Swap };\n","import { isRef, nextTick, toValue, watch } from \"vue\";\nimport { defaultDocument, tryOnMounted, tryOnScopeDispose, unrefElement } from \"@vueuse/core\";\nimport Sortable from \"sortablejs\";\n//#region useSortable/index.ts\n/**\n* Wrapper for sortablejs.\n* @param el\n* @param list\n* @param options\n*/\nfunction useSortable(el, list, options = {}) {\n\tlet sortable;\n\tconst { document = defaultDocument, watchElement = false, ...resetOptions } = options;\n\tconst defaultOptions = { onUpdate: (e) => {\n\t\tmoveArrayElement(list, e.oldIndex, e.newIndex, e);\n\t} };\n\tconst cleanup = () => {\n\t\tsortable === null || sortable === void 0 || sortable.destroy();\n\t\tsortable = void 0;\n\t};\n\tconst initSortable = (target) => {\n\t\tif (!target || sortable !== void 0) return;\n\t\tsortable = new Sortable(target, {\n\t\t\t...defaultOptions,\n\t\t\t...resetOptions\n\t\t});\n\t};\n\tconst start = () => {\n\t\tconst target = typeof el === \"string\" ? document === null || document === void 0 ? void 0 : document.querySelector(el) : unrefElement(el);\n\t\tif (target) initSortable(target);\n\t};\n\tconst option = (name, value) => {\n\t\tif (value !== void 0) sortable === null || sortable === void 0 || sortable.option(name, value);\n\t\telse return sortable === null || sortable === void 0 ? void 0 : sortable.option(name);\n\t};\n\tlet stopWatch;\n\tif (watchElement && typeof el !== \"string\") stopWatch = watch(() => unrefElement(el), (newElement) => {\n\t\tcleanup();\n\t\tif (newElement) initSortable(newElement);\n\t}, {\n\t\timmediate: true,\n\t\tflush: \"post\"\n\t});\n\telse tryOnMounted(start);\n\tconst stop = () => {\n\t\tcleanup();\n\t};\n\ttryOnScopeDispose(() => {\n\t\tstopWatch === null || stopWatch === void 0 || stopWatch();\n\t\tcleanup();\n\t});\n\treturn {\n\t\tstop,\n\t\tstart,\n\t\toption\n\t};\n}\n/**\n* Inserts a element into the DOM at a given index.\n* @param parentElement\n* @param element\n* @param {number} index\n* @see https://github.com/Alfred-Skyblue/vue-draggable-plus/blob/a3829222095e1949bf2c9a20979d7b5930e66f14/src/utils/index.ts#L81C1-L94C2\n*/\nfunction insertNodeAt(parentElement, element, index) {\n\tconst refElement = parentElement.children[index];\n\tparentElement.insertBefore(element, refElement);\n}\n/**\n* Removes a node from the DOM.\n* @param {Node} node\n* @see https://github.com/Alfred-Skyblue/vue-draggable-plus/blob/a3829222095e1949bf2c9a20979d7b5930e66f14/src/utils/index.ts#L96C1-L102C2\n*/\nfunction removeNode(node) {\n\tif (node.parentNode) node.parentNode.removeChild(node);\n}\nfunction moveArrayElement(list, from, to, e = null) {\n\tif (e != null) {\n\t\tremoveNode(e.item);\n\t\tinsertNodeAt(e.from, e.item, from);\n\t}\n\tconst _valueIsRef = isRef(list);\n\tconst array = _valueIsRef ? [...toValue(list)] : toValue(list);\n\tif (to >= 0 && to < array.length) {\n\t\tconst element = array.splice(from, 1)[0];\n\t\tnextTick(() => {\n\t\t\tarray.splice(to, 0, element);\n\t\t\tif (_valueIsRef) list.value = array;\n\t\t});\n\t}\n}\n//#endregion\nexport { insertNodeAt, moveArrayElement, removeNode, useSortable };\n","export interface RenumberPositionsOptions {\n /** Item field holding the position. Defaults to `'position'`. */\n positionField?: string\n /** Multiplier applied to the 1-based index (e.g. 10 → 10, 20, 30…). Defaults to `1`. */\n positionMultiplier?: number\n}\n\n/** Non-mutating sort by ascending `position` (in-place `sort` would trigger reactivity). */\nexport const sortByPosition = <TItem extends { position: number }>(items: TItem[]): TItem[] =>\n [...items].sort((a, b) => a.position - b.position)\n\n/**\n * Non-mutating deep `sortByPosition`. Sorts the top-level array, then for every\n * item carrying one of `childKeys` as an array, recursively sorts that nested\n * array too. The same `childKeys` apply at every depth and keys absent on a node\n * are skipped — so pass the UNION of nested position-bearing array fields across\n * the whole shape (e.g. `['contentItems', 'boxPositionIncludes']`).\n *\n * Same non-mutating contract as `sortByPosition`: only nodes that actually have a\n * nested array are shallow-cloned; leaf nodes and untouched branches keep their\n * reference. Use it to normalize an API response's ordering before it becomes\n * store state, in one call, for nested collections.\n */\nexport const sortByPositionDeep = <TItem extends { position: number }>(\n items: TItem[],\n childKeys: string[] = []\n): TItem[] =>\n sortByPosition(items).map((item) => {\n let next = item\n for (const key of childKeys) {\n const child = (item as Record<string, any>)[key]\n if (Array.isArray(child)) {\n if (next === item) next = { ...item }\n ;(next as Record<string, any>)[key] = sortByPositionDeep(child, childKeys)\n }\n }\n return next\n })\n\n/**\n * Non-mutating renumber to sequential positions matching array order — the same\n * renumbering the editors apply on commit. Unchanged items stay reference-equal.\n */\nexport const renumberPositions = <TItem extends Record<string, any>>(\n items: TItem[],\n options: RenumberPositionsOptions = {}\n): TItem[] => {\n const positionField = options.positionField ?? 'position'\n const positionMultiplier = options.positionMultiplier ?? 1\n return items.map((item, idx) => {\n const newPosition = (idx + 1) * positionMultiplier\n if (item[positionField] === newPosition) return item\n return { ...item, [positionField]: newPosition }\n })\n}\n\n/**\n * Reassign the EXISTING position values to the current array order.\n *\n * For consumers whose position is a meaningful absolute number rather than an opaque ordinal (e.g. a\n * CMS page whose backend interleaves these rows with another collection on the same numeric scale),\n * a reorder must move rows THROUGH the existing slots instead of rewriting them: `A:10, B:310` with\n * A and B swapped becomes `B:10, A:310` — the value set {10, 310} is untouched.\n *\n * Non-mutating; unchanged items stay reference-equal. Rows whose position is missing or non-numeric\n * are left alone and warn in dev — silently inventing a value here would produce a wrong payload.\n */\nexport const preservePositionValues = <TItem extends Record<string, any>>(\n items: TItem[],\n options: RenumberPositionsOptions = {}\n): TItem[] => {\n const positionField = options.positionField ?? 'position'\n const values = items.map((i) => i[positionField])\n const usable = values.every((v) => typeof v === 'number' && Number.isFinite(v))\n if (!usable) {\n console.warn(\n `[listEditor] position strategy \"preserve-values\" needs a finite numeric \\`${positionField}\\` ` +\n 'on every row; found ' +\n JSON.stringify(values) +\n ' — leaving positions untouched.'\n )\n return items\n }\n if (new Set(values).size !== values.length) {\n console.warn(\n `[listEditor] position strategy \"preserve-values\" found DUPLICATE \\`${positionField}\\` values ` +\n JSON.stringify(values) +\n ' — the resulting order is not well defined relative to any interleaved collection.'\n )\n }\n const slots = [...(values as number[])].sort((a, b) => a - b)\n return items.map((item, idx) =>\n item[positionField] === slots[idx] ? item : { ...item, [positionField]: slots[idx] }\n )\n}\n","let seq = 0\n\n/**\n * Unique negative temp id for new (unsaved) list rows.\n *\n * Row keys must be unique per row — duplicate or missing keys break dirty\n * tracking, validation rails and reorder targeting. A single module-wide\n * negative sequence guarantees uniqueness across all factories (two domain\n * factories can no longer both hand out `-1`), and can never collide with\n * persisted ids, which are positive. The backend assigns real ids on save.\n */\nexport const nextListEditorTempId = (): number => --seq\n","import {\n computed,\n reactive,\n ref,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowUnwrapRef,\n} from 'vue'\nimport type { ListEditorKey, ListEditorValidationState, PositionHint } from '@/labs/listEditor/types/listEditorTypes'\nimport { preservePositionValues, renumberPositions } from '@/labs/listEditor/utils/positions'\nimport { nextListEditorTempId } from '@/labs/listEditor/utils/tempId'\nimport { cloneDeep } from '@/utils/common'\n\n/** Per-row validity. `true` (or `{ valid: true }`) = VALID. Only `valid: false` blocks save. */\nexport type ListEditorValidationResult = boolean | { valid: boolean; state?: 'invalid' | 'warning'; message?: string }\n\nexport type GetKey<TItem> = keyof TItem | ((item: TItem) => ListEditorKey)\n/**\n * How the managed order field is maintained.\n * - `renumber` (default) — positions are opaque ordinals: every write rewrites them to a clean\n * `(index + 1) * multiplier` series.\n * - `preserve-values` — positions are meaningful ABSOLUTE numbers (e.g. a CMS page interleaves its\n * rows with another collection on the same numeric scale, so rewriting 10/310 to 100/200 would\n * move unrelated items). A REORDER then only swaps rows through the EXISTING slots: the set of\n * values is kept and reassigned, ascending, to the new row order. It is a reorder policy, not a\n * normalization policy — `add` keeps the position the factory/consumer supplied, `delete` leaves\n * holes rather than compacting.\n *\n * Per-action exceptions go through `strategyOverrides` (e.g. base `preserve-values` +\n * `{ remove: 'renumber' }` to keep absolute values on reorder/save but still close the gap on delete).\n */\nexport type PositionStrategy = 'renumber' | 'preserve-values'\n\n/** Which mutation is asking for positions to be (re)assigned. */\nexport type PositionAction = 'add' | 'update' | 'remove' | 'move' | 'payload'\n\nexport type PositionOption<TItem> =\n | false\n | keyof TItem\n | {\n field: keyof TItem\n multiplier?: number\n strategy?: PositionStrategy\n /**\n * Per-action override of `strategy`. Each entry replaces the base strategy for that one\n * action only; omitted actions inherit `strategy`. This is what lets a consumer mix policies\n * without a bespoke preset — the behaviour is visible at the call site, one action per key.\n */\n strategyOverrides?: Partial<Record<PositionAction, PositionStrategy>>\n }\n\nexport interface ListEditorChanges<TItem> {\n added: TItem[]\n updated: TItem[]\n moved: TItem[]\n deleted: TItem[]\n reparented: TItem[]\n}\n\nexport interface UseListEditorControllerOptions<TItem extends Record<string, any>> {\n /** Read the live list (the editor's v-model, or a consumer store getter). */\n get: () => TItem[]\n /** Write the list back. */\n set: (items: TItem[]) => void\n /** New-row factory. Optional for read-only / no-add lists. Should mint a stable temp id. */\n factory?: () => TItem\n /** Stable row identity. Default `'id'`. Never point this at the position field. */\n getKey?: GetKey<TItem>\n /** Managed order field. Default `'position'`. `false` opts out of position management. */\n position?: PositionOption<TItem>\n /**\n * Extra top-level fields to drop from the dirty content-hash (position is\n * always dropped). For a child collection a separate nested editor already\n * tracks, so editing a child doesn't flip the parent row amber. Still in the\n * payload — only the dirty comparison ignores it. Reactive (accepts a getter/ref).\n */\n dirtyExclude?: MaybeRefOrGetter<string[]>\n /** Per-row validity — `true` = valid. Drives the red rail + `hasErrors`. */\n validate?: (item: TItem) => ListEditorValidationResult\n /** Custom dirty predicate (override the default content-diff). */\n isDirty?: (current: TItem, saved: TItem | undefined) => boolean\n /** Custom save payload (overrides `getPayload`). */\n payload?: (items: TItem[]) => TItem[]\n /** Resolve a saved row's key on commit (default: existing key, else mint a temp id). */\n commitKey?: (saved: TItem, previous: TItem | undefined) => ListEditorKey\n /** Normalize server rows before they become the new baseline on commit. */\n normalizeSaved?: (savedItems: TItem[]) => TItem[]\n}\n\nexport interface ListEditorHandle<TItem extends Record<string, any>> {\n items: ComputedRef<TItem[]>\n hasUnsaved: ComputedRef<boolean>\n /** Count of distinct unconfirmed changes (added/edited/moved rows + deferred-deletion tombstones). */\n unsavedCount: ComputedRef<number>\n hasErrors: ComputedRef<boolean>\n invalidKeys: ComputedRef<Set<ListEditorKey>>\n /** Amber: is this row added / edited / moved since the last commit? */\n isUnsaved: (key: ListEditorKey) => boolean\n /** Red rail (gated): 'invalid' only once the row is unsaved or `validateAll()` ran. */\n rowState: (item: TItem, key: ListEditorKey, editing?: boolean) => ListEditorValidationState\n /** Force-show all invalid rows + return whether the list is valid. The save guard. */\n validateAll: () => boolean\n /** Normalized ordered array for a full-DTO save. */\n getPayload: () => TItem[]\n /** Change-set for partial-save endpoints. */\n getChanges: () => ListEditorChanges<TItem>\n /** Adopt saved rows as the new baseline; backfill keys; clear unsaved/submitted. */\n commit: (savedItems?: TItem[]) => void\n /** Discard unsaved edits back to the last committed baseline (or given items). */\n reset: (items?: TItem[]) => void\n addItem: (item?: TItem, hint?: PositionHint) => ListEditorKey | undefined\n updateItem: (key: ListEditorKey, next: TItem | Partial<TItem> | ((current: TItem) => TItem)) => void\n /** Remove a row. `trackDeleted: false` (immediate mode) skips the deferred-deletion tombstone. */\n deleteItem: (key: ListEditorKey, opts?: { trackDeleted?: boolean }) => void\n /** Clear a deferred-deletion tombstone (the caller re-inserts the row, e.g. reorder Cancel). */\n restoreDeleted: (key: ListEditorKey) => void\n moveItem: (fromIndex: number, toIndex: number) => void\n /** Drop the \"moved\" flag for the given keys (or all) without touching edits/adds — e.g. reorder Cancel. */\n clearMoved: (keys?: Iterable<ListEditorKey>) => void\n /** Escape hatch: a row form (e.g. vuelidate) reports its own validity instead of `validate`. */\n registerValidity: (key: ListEditorKey, isValid: () => boolean) => () => void\n}\n\n/**\n * The shape a CONSUMER sees when it reads a list-editor handle through a template/function ref.\n * Vue's `expose` proxy unwraps every exposed ref, so the reactive fields (`hasUnsaved`, `hasErrors`,\n * `unsavedCount`, …) arrive as plain VALUES here, not `Ref`s: read `handle.hasUnsaved` (a boolean),\n * never `handle.hasUnsaved.value` (that is `undefined`). Type your `useTemplateRef` / collected-ref\n * maps with this so a stray `.value` is a compile error instead of a silently-dead guard/save-gate.\n */\nexport type ExposedListEditorHandle<TItem extends Record<string, any>> = ShallowUnwrapRef<ListEditorHandle<TItem>>\n\n/**\n * Component-owned state controller for the list editors (v2). Owns row keys,\n * declared dirty tracking (no fragile whole-list JSON diff on volatile fields),\n * validation summary, position renumbering, and the save lifecycle — exposed as\n * a `ListEditorHandle`. Created internally by an editor (default) or lifted by a\n * consumer via `useListEditor()` + `:editor` so the state survives unmount/remount.\n */\nexport function useListEditorController<TItem extends Record<string, any>>(\n options: UseListEditorControllerOptions<TItem>\n): ListEditorHandle<TItem> {\n const keyField = (typeof options.getKey === 'function' ? null : (options.getKey ?? 'id')) as keyof TItem | null\n const keyOf = (item: TItem): ListEditorKey =>\n typeof options.getKey === 'function' ? options.getKey(item) : (item[keyField as keyof TItem] as ListEditorKey)\n\n const positionOpt = options.position ?? 'position'\n const managedPosition = positionOpt !== false\n const positionField = (\n typeof positionOpt === 'object' ? positionOpt.field : positionOpt === false ? 'position' : positionOpt\n ) as string\n const positionMultiplier = typeof positionOpt === 'object' && positionOpt.multiplier ? positionOpt.multiplier : 1\n const positionStrategy: PositionStrategy = (typeof positionOpt === 'object' && positionOpt.strategy) || 'renumber'\n const positionOverrides: Partial<Record<PositionAction, PositionStrategy>> =\n (typeof positionOpt === 'object' && positionOpt.strategyOverrides) || {}\n\n const items = computed<TItem[]>(() => options.get())\n\n // Baseline = last committed snapshot. `hashes` powers content-diff dirty\n // (position excluded so a reorder never marks a row dirty); `rows` powers `reset`.\n const dirtyExclude = computed<string[]>(() => toValue(options.dirtyExclude) ?? [])\n // Temp ids are client identity bookkeeping, never content. `ensureKeys` mints one INTO the model\n // for rows the server returns without a key — and for a NESTED editor that write happens on mount,\n // i.e. when a parent row is merely expanded to be read. The parent hashes the whole row, so without\n // this the seed would retroactively invalidate the parent's baseline and expanding a row to LOOK at\n // it would mark it unsaved (QA 85050 batch 10 BUG-02). Only negative NUMBERS are stripped —\n // persisted ids are positive (see `nextListEditorTempId`), so real ids still count as content, and\n // a genuinely added row still differs by its other fields.\n const stripTempIds = (_k: string, v: unknown): unknown =>\n _k === 'id' && typeof v === 'number' && v < 0 ? undefined : v\n const normalize = (item: TItem): string => {\n const copy = { ...item } as Record<string, unknown>\n if (managedPosition) delete copy[positionField]\n for (const f of dirtyExclude.value) delete copy[f]\n return JSON.stringify(copy, stripTempIds)\n }\n const baselineHashes = ref(new Map<ListEditorKey, string>()) as Ref<Map<ListEditorKey, string>>\n const baselineRows = ref<TItem[]>([]) as Ref<TItem[]>\n const captureBaseline = (rows: TItem[]) => {\n const map = new Map<ListEditorKey, string>()\n for (const r of rows) map.set(keyOf(r), normalize(r))\n baselineHashes.value = map\n // Deep clone: a shallow `{...r}` shares nested refs with the live row, so an\n // in-place mutation would drift the baseline (reset/re-hash read stale data).\n baselineRows.value = rows.map((r) => cloneDeep(r))\n }\n // Re-hash when the excluded-field set changes. `sync` so baseline + live\n // normalize() never disagree mid-flush (which would flash every row amber).\n watch(\n dirtyExclude,\n () => {\n const map = new Map<ListEditorKey, string>()\n for (const r of baselineRows.value) map.set(keyOf(r), normalize(r))\n baselineHashes.value = map\n },\n { flush: 'sync' }\n )\n // Ensure every row has a resolvable, UNIQUE key before the first baseline\n // capture. Server rows lacking the key field (e.g. no `id` and no custom\n // get-key → keyOf() is undefined for ALL of them) would collapse to a single\n // baseline entry and read as perpetually unsaved even on a clean load\n // (QA 85050 BUG-03). Mint a temp id for those rows — exactly what commit()\n // already does on save (line ~299). Rows that DO resolve a key (the common\n // case) are untouched, so id-backed editors are unaffected.\n const ensureKeys = (rows: TItem[]): { rows: TItem[]; changed: boolean } => {\n if (!keyField) return { rows, changed: false }\n let changed = false\n const next = rows.map((item) => {\n const k = keyOf(item)\n if (k === undefined || k === null) {\n changed = true\n return { ...item, [keyField]: nextListEditorTempId() } as TItem\n }\n return item\n })\n return { rows: next, changed }\n }\n const seeded = ensureKeys(options.get())\n if (seeded.changed) options.set(seeded.rows)\n // Capture from the seeded array directly (not a re-read of options.get()): when\n // set() emits through v-model the prop update is async, so options.get() would\n // still return the pre-mint colliding rows here. Mirrors commit()'s pattern.\n captureBaseline(seeded.rows)\n\n // Declared structural state the content-diff can't see.\n const movedKeys = ref(new Set<ListEditorKey>()) as Ref<Set<ListEditorKey>>\n const deletedRows = ref<TItem[]>([]) as Ref<TItem[]>\n const submitted = ref(false)\n // Reactive so a row form (re)registering its validity re-runs `invalidKeys`/`rowState`.\n const registeredValidity = reactive(new Map<ListEditorKey, () => boolean>())\n\n const isItemDirty = (item: TItem, key: ListEditorKey): boolean => {\n if (options.isDirty) {\n const saved = baselineRows.value.find((r) => keyOf(r) === key)\n return options.isDirty(item, saved)\n }\n const baseHash = baselineHashes.value.get(key)\n if (baseHash === undefined) return true // added\n if (baseHash !== normalize(item)) return true // edited\n return movedKeys.value.has(key) // moved (content-invisible)\n }\n\n // Gate the validation rail on \"has this row actually been edited\" rather than just \"is it\n // unsaved\", so a freshly added still-untouched row is amber but not yet red. `addedBaseline` =\n // first-seen content hash of each ADDED row; `editedKeys` = STICKY set of rows whose content has\n // since diverged from that first-seen / committed baseline. Sticky like vuelidate `$dirty`: once\n // edited a row stays dirty until commit/reset, so clearing a field back to empty keeps the rail\n // consistent with the field's own error state. Position / `dirtyExclude` are normalized out, so a\n // reorder never counts as an edit.\n const addedBaseline = ref(new Map<ListEditorKey, string>()) as Ref<Map<ListEditorKey, string>>\n const editedKeys = ref(new Set<ListEditorKey>()) as Ref<Set<ListEditorKey>>\n watch(\n items,\n (rows) => {\n const live = new Set<ListEditorKey>()\n for (const r of rows) {\n const key = keyOf(r)\n live.add(key)\n if (!baselineHashes.value.has(key) && !addedBaseline.value.has(key)) {\n addedBaseline.value.set(key, normalize(r))\n }\n if (!editedKeys.value.has(key)) {\n const base = baselineHashes.value.get(key) ?? addedBaseline.value.get(key)\n if (base !== undefined && base !== normalize(r)) editedKeys.value.add(key)\n }\n }\n const stale: ListEditorKey[] = []\n for (const key of addedBaseline.value.keys()) if (!live.has(key)) stale.push(key)\n for (const key of stale) addedBaseline.value.delete(key)\n // A deferred-deleted key that becomes live again (re-add before save) must drop its tombstone —\n // otherwise it would both render and still count/report as deleted.\n if (deletedRows.value.some((r) => live.has(keyOf(r)))) {\n deletedRows.value = deletedRows.value.filter((r) => !live.has(keyOf(r)))\n }\n },\n { immediate: true, deep: true }\n )\n\n const isRowEdited = (key: ListEditorKey): boolean => editedKeys.value.has(key)\n\n const unsavedKeys = computed<Set<ListEditorKey>>(() => {\n const out = new Set<ListEditorKey>()\n for (const item of options.get()) {\n const key = keyOf(item)\n if (isItemDirty(item, key)) out.add(key)\n }\n return out\n })\n\n const isUnsaved = (key: ListEditorKey): boolean => unsavedKeys.value.has(key)\n const hasUnsaved = computed<boolean>(() => unsavedKeys.value.size > 0 || deletedRows.value.length > 0)\n\n // Count of DISTINCT unconfirmed changes = union of live dirty keys (added / edited / moved) and\n // deferred-deletion tombstones. A key that is both live and tombstoned (delete-then-re-add) counts\n // once; a deleted row (no longer live) adds one. Drives the \"N unconfirmed changes\" indicator, so a\n // delete lights up as a change even though the row itself is gone.\n const unsavedCount = computed<number>(() => {\n const keys = new Set<ListEditorKey>(unsavedKeys.value)\n for (const r of deletedRows.value) keys.add(keyOf(r))\n return keys.size\n })\n\n const resolveValidity = (item: TItem, key: ListEditorKey): { invalid: boolean; warning: boolean } => {\n const registered = registeredValidity.get(key)\n if (registered) return { invalid: !registered(), warning: false }\n if (!options.validate) return { invalid: false, warning: false }\n const r = options.validate(item)\n if (typeof r === 'boolean') return { invalid: !r, warning: false }\n return { invalid: !r.valid, warning: r.valid && r.state === 'warning' }\n }\n\n const invalidKeys = computed<Set<ListEditorKey>>(() => {\n const out = new Set<ListEditorKey>()\n for (const item of options.get()) {\n const key = keyOf(item)\n if (resolveValidity(item, key).invalid) out.add(key)\n }\n return out\n })\n const hasErrors = computed<boolean>(() => invalidKeys.value.size > 0)\n\n // Red rail gated behind \"row has been edited\" (content changed since add/baseline — mirrors the\n // field's vuelidate `$dirty`) or an explicit validateAll() — so a freshly added still-untouched\n // row stays amber (not red) and a loaded-but-invalid row doesn't light up before interaction,\n // while a save attempt reveals every offender (mounted or collapsed).\n const rowState = (item: TItem, key: ListEditorKey, editing = false): ListEditorValidationState => {\n const { invalid, warning } = resolveValidity(item, key)\n // Red rail for an invalid row that is edited, unsaved (added), or after a save attempt. A row being\n // filled in reads amber (not red) and goes red once collapsed — but a save attempt (`submitted`,\n // which also reveals collapsed offenders) always reds it, even while open. (QA 85050 batch 7)\n if (invalid) {\n if (submitted.value) return 'invalid'\n if (editing) return null\n return isRowEdited(key) || isUnsaved(key) ? 'invalid' : null\n }\n if (warning) return 'warning'\n return null\n }\n\n const validateAll = (): boolean => {\n submitted.value = true\n return invalidKeys.value.size === 0\n }\n\n // Resolve the policy for THIS action: a per-action override wins, else the base strategy.\n // Under 'preserve-values' only a move reassigns (through the existing kept slots); every other\n // action leaves positions as-is (add keeps the handed value, delete leaves a hole, update/payload\n // never touch them). Under 'renumber' every action rewrites to a clean `(index+1)*multiplier`.\n const renumber = (arr: TItem[], action: PositionAction): TItem[] => {\n if (!managedPosition) return arr\n const strategy = positionOverrides[action] ?? positionStrategy\n if (strategy === 'preserve-values') {\n return action === 'move' ? preservePositionValues(arr, { positionField }) : arr\n }\n return renumberPositions(arr, { positionField, positionMultiplier })\n }\n\n const write = (arr: TItem[], action: PositionAction) => options.set(renumber(arr, action))\n\n const getPayload = (): TItem[] =>\n options.payload ? options.payload(options.get()) : renumber(options.get(), 'payload')\n\n const getChanges = (): ListEditorChanges<TItem> => {\n const added: TItem[] = []\n const updated: TItem[] = []\n const moved: TItem[] = []\n for (const item of options.get()) {\n const key = keyOf(item)\n const baseHash = baselineHashes.value.get(key)\n if (baseHash === undefined) added.push(item)\n else if (baseHash !== normalize(item)) updated.push(item)\n if (movedKeys.value.has(key)) moved.push(item)\n }\n return { added, updated, moved, deleted: [...deletedRows.value], reparented: [] }\n }\n\n const commit = (savedItems?: TItem[]): void => {\n const source = savedItems ?? options.get()\n const normalized = options.normalizeSaved ? options.normalizeSaved(source) : source\n const next = normalized.map((item) => {\n const key = options.commitKey\n ? options.commitKey(\n item,\n baselineRows.value.find((r) => keyOf(r) === keyOf(item))\n )\n : keyOf(item)\n if (key === undefined || key === null) {\n return keyField ? ({ ...item, [keyField]: nextListEditorTempId() } as TItem) : item\n }\n return item\n })\n options.set(next)\n captureBaseline(next)\n movedKeys.value = new Set()\n deletedRows.value = []\n addedBaseline.value = new Map()\n editedKeys.value = new Set()\n submitted.value = false\n }\n\n const reset = (rows?: TItem[]): void => {\n options.set(rows ?? baselineRows.value.map((r) => cloneDeep(r)))\n movedKeys.value = new Set()\n deletedRows.value = []\n addedBaseline.value = new Map()\n editedKeys.value = new Set()\n submitted.value = false\n }\n\n const indexOfKey = (arr: TItem[], key: ListEditorKey): number => arr.findIndex((x) => keyOf(x) === key)\n\n const addItem = (item?: TItem, hint?: PositionHint): ListEditorKey | undefined => {\n const row = item ?? options.factory?.()\n if (row === undefined) return undefined // no item + no factory (read-only list) → no-op\n const arr = [...options.get()]\n let at = arr.length\n if (hint?.afterId !== undefined) {\n const i = indexOfKey(arr, hint.afterId)\n at = i === -1 ? arr.length : i + 1\n } else if (hint?.index !== undefined) {\n at = Math.max(0, Math.min(hint.index, arr.length))\n }\n arr.splice(at, 0, row)\n write(arr, 'add')\n return keyOf(row)\n }\n\n const updateItem = (key: ListEditorKey, next: TItem | Partial<TItem> | ((current: TItem) => TItem)): void => {\n const arr = [...options.get()]\n const i = indexOfKey(arr, key)\n if (i === -1) return\n const current = arr[i]\n const resolved =\n typeof next === 'function'\n ? (next as (c: TItem) => TItem)(current)\n : ({ ...current, ...(next as Partial<TItem>) } as TItem)\n arr[i] = resolved\n write(arr, 'update')\n }\n\n const deleteItem = (key: ListEditorKey, opts?: { trackDeleted?: boolean }): void => {\n const arr = [...options.get()]\n const i = indexOfKey(arr, key)\n if (i === -1) return\n const [removed] = arr.splice(i, 1)\n // A previously-saved row that's removed is a DEFERRED deletion: reported in the change-set and\n // counted as one unconfirmed change (`unsavedCount`) until save. `trackDeleted: false` (immediate\n // mode — the row is already deleted on the backend) skips the tombstone so it does NOT read as\n // unsaved. An unsaved temp row just vanishes either way.\n if (baselineHashes.value.has(key) && opts?.trackDeleted !== false) {\n deletedRows.value = [...deletedRows.value, removed]\n }\n movedKeys.value.delete(key)\n write(arr, 'remove')\n }\n\n // Un-tombstone a deferred-deleted row. Re-inserting the row into the model is the caller's job\n // (e.g. reorder Cancel restoring the pre-session snapshot); this only clears the deletion record so\n // `deletedRows` / `unsavedCount` / `getChanges().deleted` stay consistent.\n const restoreDeleted = (key: ListEditorKey): void => {\n deletedRows.value = deletedRows.value.filter((r) => keyOf(r) !== key)\n }\n\n const moveItem = (fromIndex: number, toIndex: number): void => {\n const arr = [...options.get()]\n if (fromIndex < 0 || fromIndex >= arr.length || toIndex < 0 || toIndex >= arr.length) return\n if (fromIndex === toIndex) return\n const [el] = arr.splice(fromIndex, 1)\n arr.splice(toIndex, 0, el)\n movedKeys.value.add(keyOf(el))\n write(arr, 'move')\n }\n\n // Reorder Cancel restores the pre-session order, so the moves are undone — drop\n // just those keys' \"moved\" flag (edits/adds stay dirty). No arg = clear all.\n const clearMoved = (keys?: Iterable<ListEditorKey>): void => {\n if (keys === undefined) {\n movedKeys.value = new Set()\n return\n }\n const next = new Set(movedKeys.value)\n for (const key of keys) next.delete(key)\n movedKeys.value = next\n }\n\n const registerValidity = (key: ListEditorKey, isValid: () => boolean): (() => void) => {\n registeredValidity.set(key, isValid)\n return () => registeredValidity.delete(key)\n }\n\n return {\n items,\n hasUnsaved,\n unsavedCount,\n hasErrors,\n invalidKeys,\n isUnsaved,\n rowState,\n validateAll,\n getPayload,\n getChanges,\n commit,\n reset,\n addItem,\n updateItem,\n deleteItem,\n restoreDeleted,\n moveItem,\n clearMoved,\n registerValidity,\n }\n}\n","import { computed, type ComputedRef, type Ref } from 'vue'\nimport { cloneDeep, isUndefined } from '@/utils/common'\nimport type {\n ListEditorKey,\n ListViewItem,\n NestedTree,\n NestedTreeNode,\n PositionHint,\n} from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface NestedViewItem<TItem> extends ListViewItem<TItem> {\n node: NestedTreeNode<TItem>\n depth: number\n parent: TItem | null\n parentKey: ListEditorKey | null\n childrenCount: number\n hasChildren: boolean\n childrenAllowed: boolean\n siblingIndex: number\n siblingCount: number\n firstInParent: boolean\n lastInParent: boolean\n canAddChild: boolean\n canIndent: boolean\n canOutdent: boolean\n}\n\nexport interface UseNestedListEditorOptions {\n keyField?: string\n /**\n * Resolve a row's key; takes precedence over `keyField`. Pass the controller's\n * `keyOf` so tree ops key rows the same way as dirty/validity tracking — incl.\n * a FUNCTION get-key, which `keyField` lookup would miss.\n */\n getKey?: (data: any) => ListEditorKey\n positionField?: string\n parentField?: string\n positionMultiplier?: number\n maxDepth: number\n expandedKeys?: Ref<Set<ListEditorKey>>\n}\n\nexport interface NestedListEditorApi<TItem extends Record<string, any>> {\n viewItems: ComputedRef<NestedViewItem<TItem>[]>\n findNode: (id: ListEditorKey) => {\n node: NestedTreeNode<TItem> | null\n parent: NestedTreeNode<TItem> | null\n }\n addItem: (\n data: TItem,\n hint?: PositionHint & {\n parentId?: ListEditorKey | null\n asFirstChild?: boolean\n childrenAllowed?: boolean\n }\n ) => NestedTree<TItem>\n deleteItem: (id: ListEditorKey) => NestedTree<TItem>\n updateItem: (id: ListEditorKey, data: TItem, markDirty?: boolean) => NestedTree<TItem>\n moveUp: (id: ListEditorKey) => NestedTree<TItem> | null\n moveDown: (id: ListEditorKey) => NestedTree<TItem> | null\n moveTop: (id: ListEditorKey) => NestedTree<TItem> | null\n moveBottom: (id: ListEditorKey) => NestedTree<TItem> | null\n indent: (id: ListEditorKey) => NestedTree<TItem> | null\n outdent: (id: ListEditorKey) => NestedTree<TItem> | null\n moveTo: (id: ListEditorKey, targetParentId: ListEditorKey | null, targetIndex: number) => NestedTree<TItem> | null\n recalculatePositions: (model: NestedTree<TItem>) => NestedTree<TItem>\n calculateSubtreeDepth: (node: NestedTreeNode<TItem>) => number\n}\n\nconst DEFAULT_KEY_FIELD = 'id'\nconst DEFAULT_POSITION_FIELD = 'position'\nconst DEFAULT_PARENT_FIELD = 'parent'\n\n/**\n * Nested list editor core. Pure data behavior shared by ANestedSortableListEditor.\n * Works on a tree of `{ data, children, meta }` nodes — shape-compatible with the\n * legacy `SortableNested` wrapper so migration can pass existing data through\n * unchanged. Mutators return a cloned tree and also assign it to `model.value`.\n */\nexport function useNestedListEditor<TItem extends Record<string, any>>(\n model: Ref<NestedTree<TItem>>,\n options: UseNestedListEditorOptions\n): NestedListEditorApi<TItem> {\n const keyField = options.keyField ?? DEFAULT_KEY_FIELD\n const resolveKey = options.getKey\n const positionField = options.positionField ?? DEFAULT_POSITION_FIELD\n const parentField = options.parentField ?? DEFAULT_PARENT_FIELD\n const positionMultiplier = options.positionMultiplier ?? 1\n const maxDepth = options.maxDepth\n\n const getKey = (data: TItem): ListEditorKey => (resolveKey ? resolveKey(data) : (data[keyField] as ListEditorKey))\n\n const calculateSubtreeDepth = (node: NestedTreeNode<TItem>): number => {\n if (!node.children || node.children.length === 0) return 1\n let max = 0\n for (const child of node.children) {\n const d = calculateSubtreeDepth(child)\n if (d > max) max = d\n }\n return max + 1\n }\n\n const findNode = (\n id: ListEditorKey,\n arr: NestedTreeNode<TItem>[] = model.value.children,\n parent: NestedTreeNode<TItem> | null = null\n ): { node: NestedTreeNode<TItem> | null; parent: NestedTreeNode<TItem> | null } => {\n for (const item of arr) {\n if (getKey(item.data) === id) return { node: item, parent }\n if (item.children && item.children.length > 0) {\n const found = findNode(id, item.children, item)\n if (found.node) return found\n }\n }\n return { node: null, parent: null }\n }\n\n const recalculateSiblings = (siblings: NestedTreeNode<TItem>[]) => {\n let pos = 1 * positionMultiplier\n for (const sibling of siblings) {\n if (sibling.data[positionField] !== pos) {\n ;(sibling.data as any)[positionField] = pos\n // Flag dirty so a partial-subset save persists the new position;\n // otherwise reorders are lost on reload and rows collide on old positions.\n sibling.meta.dirty = true\n }\n pos += positionMultiplier\n }\n }\n\n const recalculateAll = (tree: NestedTree<TItem>) => {\n const walk = (arr: NestedTreeNode<TItem>[]) => {\n recalculateSiblings(arr)\n for (const item of arr) if (item.children && item.children.length) walk(item.children)\n }\n walk(tree.children)\n }\n\n const recalculatePositions = (tree: NestedTree<TItem>): NestedTree<TItem> => {\n const cloned = cloneDeep(tree) as NestedTree<TItem>\n recalculateAll(cloned)\n return cloned\n }\n\n const buildViewItems = (tree: NestedTree<TItem>): NestedViewItem<TItem>[] => {\n const flat: NestedViewItem<TItem>[] = []\n const expandedKeys = options.expandedKeys?.value\n let flatIndex = 0\n const walk = (nodes: NestedTreeNode<TItem>[], depth: number, parentNode: NestedTreeNode<TItem> | null) => {\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i]\n const key = getKey(node.data)\n const childrenAllowed = !isUndefined(node.children)\n const hasChildren = childrenAllowed && (node.children?.length ?? 0) > 0\n const childrenCount = node.children?.length ?? 0\n const isExpanded = expandedKeys ? expandedKeys.has(key) : true\n const remainingDepth = maxDepth - (depth + 1)\n const canAddChild = childrenAllowed && remainingDepth > 0\n const canOutdent = depth > 0\n const canIndent = i > 0\n flat.push({\n key,\n index: flatIndex++,\n raw: node.data,\n position: node.data[positionField] as number | undefined,\n node,\n depth,\n parent: parentNode?.data ?? null,\n parentKey: parentNode ? getKey(parentNode.data) : null,\n childrenCount,\n hasChildren,\n childrenAllowed,\n siblingIndex: i,\n siblingCount: nodes.length,\n firstInParent: i === 0,\n lastInParent: i === nodes.length - 1,\n canAddChild,\n canIndent,\n canOutdent,\n })\n if (hasChildren && isExpanded) {\n walk(node.children as NestedTreeNode<TItem>[], depth + 1, node)\n }\n }\n }\n walk(tree.children, 0, null)\n return flat\n }\n\n const viewItems = computed<NestedViewItem<TItem>[]>(() => buildViewItems(model.value))\n\n const insertAfter = (siblings: NestedTreeNode<TItem>[], afterIdx: number, newNode: NestedTreeNode<TItem>) => {\n siblings.splice(afterIdx + 1, 0, newNode)\n }\n\n const resolveInsertIndex = (siblings: NestedTreeNode<TItem>[], hint?: PositionHint): number => {\n if (!hint) return siblings.length\n if (hint.afterId !== undefined) {\n const idx = siblings.findIndex((s) => getKey(s.data) === hint.afterId)\n return idx === -1 ? siblings.length : idx + 1\n }\n if (hint.afterIndex !== undefined) {\n if (hint.afterIndex < 0) return siblings.length\n return Math.min(hint.afterIndex + 1, siblings.length)\n }\n if (hint.index !== undefined) {\n return Math.max(0, Math.min(hint.index, siblings.length))\n }\n return siblings.length\n }\n\n const addItem = (\n data: TItem,\n hint?: PositionHint & {\n parentId?: ListEditorKey | null\n asFirstChild?: boolean\n childrenAllowed?: boolean\n }\n ): NestedTree<TItem> => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const childrenAllowed = hint?.childrenAllowed ?? true\n const newNode: NestedTreeNode<TItem> = {\n data: cloneDeep(data) as TItem,\n children: childrenAllowed ? [] : undefined,\n meta: { dirty: false },\n }\n\n let targetSiblings: NestedTreeNode<TItem>[] = cloned.children\n let parentNode: NestedTreeNode<TItem> | null = null\n\n if (hint?.parentId !== undefined && hint.parentId !== null) {\n const { node } = findNode(hint.parentId, cloned.children)\n if (node && node.children) {\n targetSiblings = node.children\n parentNode = node\n }\n }\n\n if (hint?.afterId !== undefined) {\n const { node: afterNode, parent: afterParent } = findNode(hint.afterId, cloned.children)\n if (afterNode) {\n const siblings = afterParent ? (afterParent.children as NestedTreeNode<TItem>[]) : cloned.children\n const idx = siblings.indexOf(afterNode)\n if (idx !== -1) {\n insertAfter(siblings, idx, newNode)\n ;(newNode.data as any)[parentField] = afterParent ? getKey(afterParent.data) : null\n recalculateSiblings(siblings)\n model.value = cloned\n return cloned\n }\n }\n }\n\n const insertIdx = hint?.asFirstChild ? 0 : resolveInsertIndex(targetSiblings, hint)\n targetSiblings.splice(insertIdx, 0, newNode)\n ;(newNode.data as any)[parentField] = parentNode ? getKey(parentNode.data) : null\n recalculateSiblings(targetSiblings)\n model.value = cloned\n return cloned\n }\n\n const deleteItem = (id: ListEditorKey): NestedTree<TItem> => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const { node, parent } = findNode(id, cloned.children)\n if (!node) return cloned\n const siblings = parent ? (parent.children as NestedTreeNode<TItem>[]) : cloned.children\n const idx = siblings.indexOf(node)\n if (idx === -1) return cloned\n siblings.splice(idx, 1)\n recalculateSiblings(siblings)\n model.value = cloned\n return cloned\n }\n\n const updateItem = (id: ListEditorKey, data: TItem, markDirty = true): NestedTree<TItem> => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const { node } = findNode(id, cloned.children)\n if (!node) return cloned\n node.data = cloneDeep(data) as TItem\n // An edit must be persisted by partial-subset saves. `markDirty=false` is for\n // snapshot restore on edit-cancel, which must NOT flag the node dirty.\n if (markDirty) node.meta.dirty = true\n model.value = cloned\n return cloned\n }\n\n const swapSiblings = (\n cloned: NestedTree<TItem>,\n id: ListEditorKey,\n getTargetIndex: (siblings: NestedTreeNode<TItem>[], currentIdx: number) => number | null\n ): NestedTree<TItem> | null => {\n const { node, parent } = findNode(id, cloned.children)\n if (!node) return null\n const siblings = parent ? (parent.children as NestedTreeNode<TItem>[]) : cloned.children\n const idx = siblings.indexOf(node)\n if (idx === -1) return null\n const target = getTargetIndex(siblings, idx)\n if (target === null || target === idx) return null\n const [removed] = siblings.splice(idx, 1)\n siblings.splice(target, 0, removed)\n recalculateSiblings(siblings)\n return cloned\n }\n\n const moveUp = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const res = swapSiblings(cloned, id, (_s, idx) => (idx > 0 ? idx - 1 : null))\n if (res) model.value = res\n return res\n }\n\n const moveDown = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const res = swapSiblings(cloned, id, (s, idx) => (idx < s.length - 1 ? idx + 1 : null))\n if (res) model.value = res\n return res\n }\n\n const moveTop = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const res = swapSiblings(cloned, id, (_s, idx) => (idx > 0 ? 0 : null))\n if (res) model.value = res\n return res\n }\n\n const moveBottom = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const res = swapSiblings(cloned, id, (s, idx) => (idx < s.length - 1 ? s.length - 1 : null))\n if (res) model.value = res\n return res\n }\n\n /**\n * Indent: move the item under its previous sibling as its last child.\n * Fails if: no previous sibling, previous sibling doesn't allow children,\n * or the resulting depth would exceed maxDepth.\n */\n const indent = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const { node, parent } = findNode(id, cloned.children)\n if (!node) return null\n const siblings = parent ? (parent.children as NestedTreeNode<TItem>[]) : cloned.children\n const idx = siblings.indexOf(node)\n if (idx <= 0) return null\n const prev = siblings[idx - 1]\n if (isUndefined(prev.children)) return null\n const subtreeDepth = calculateSubtreeDepth(node)\n const prevDepth = calculateParentDepth(cloned, getKey(prev.data))\n if (prevDepth + 1 + subtreeDepth > maxDepth) return null\n\n siblings.splice(idx, 1)\n prev.children!.push(node)\n ;(node.data as any)[parentField] = getKey(prev.data)\n // Persist the reparent even when the position number is unchanged (QA 85050 BUG-13).\n node.meta.dirty = true\n recalculateSiblings(siblings)\n recalculateSiblings(prev.children!)\n model.value = cloned\n return cloned\n }\n\n /**\n * Outdent: move the item up one level — it becomes the next sibling of its current parent.\n * Fails if the item is already at root.\n */\n const outdent = (id: ListEditorKey): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const { node, parent } = findNode(id, cloned.children)\n if (!node || !parent) return null\n\n const { parent: grandParent } = findNode(getKey(parent.data), cloned.children)\n const grandSiblings = grandParent ? (grandParent.children as NestedTreeNode<TItem>[]) : cloned.children\n const parentIdx = grandSiblings.indexOf(parent)\n if (parentIdx === -1) return null\n\n const currentSiblings = parent.children as NestedTreeNode<TItem>[]\n const idx = currentSiblings.indexOf(node)\n if (idx === -1) return null\n currentSiblings.splice(idx, 1)\n grandSiblings.splice(parentIdx + 1, 0, node)\n ;(node.data as any)[parentField] = grandParent ? getKey(grandParent.data) : null\n // Persist the reparent even when the position number is unchanged (QA 85050 BUG-13).\n node.meta.dirty = true\n\n recalculateSiblings(currentSiblings)\n recalculateSiblings(grandSiblings)\n model.value = cloned\n return cloned\n }\n\n const calculateParentDepth = (tree: NestedTree<TItem>, id: ListEditorKey): number => {\n const walk = (arr: NestedTreeNode<TItem>[], depth: number): number | null => {\n for (const item of arr) {\n if (getKey(item.data) === id) return depth\n if (item.children && item.children.length) {\n const d = walk(item.children, depth + 1)\n if (d !== null) return d\n }\n }\n return null\n }\n return walk(tree.children, 0) ?? 0\n }\n\n /**\n * Move a node to a specific parent at a specific index. Used by drag/drop.\n * Respects maxDepth — returns null if the move would exceed it.\n */\n const moveTo = (\n id: ListEditorKey,\n targetParentId: ListEditorKey | null,\n targetIndex: number\n ): NestedTree<TItem> | null => {\n const cloned = cloneDeep(model.value) as NestedTree<TItem>\n const { node, parent } = findNode(id, cloned.children)\n if (!node) return null\n\n if (targetParentId !== null) {\n const isDescendant = (n: NestedTreeNode<TItem>): boolean => {\n if (!n.children) return false\n for (const c of n.children) {\n if (getKey(c.data) === targetParentId) return true\n if (isDescendant(c)) return true\n }\n return false\n }\n if (getKey(node.data) === targetParentId || isDescendant(node)) return null\n }\n\n let targetSiblings: NestedTreeNode<TItem>[]\n let newParentNode: NestedTreeNode<TItem> | null = null\n let newParentDepth = 0\n if (targetParentId === null) {\n targetSiblings = cloned.children\n newParentDepth = 0\n } else {\n const { node: targetParent } = findNode(targetParentId, cloned.children)\n if (!targetParent || isUndefined(targetParent.children)) return null\n targetSiblings = targetParent.children\n newParentNode = targetParent\n newParentDepth = calculateParentDepth(cloned, targetParentId) + 1\n }\n\n const subtreeDepth = calculateSubtreeDepth(node)\n if (newParentDepth + subtreeDepth > maxDepth) return null\n\n const sourceSiblings = parent ? (parent.children as NestedTreeNode<TItem>[]) : cloned.children\n const sourceIdx = sourceSiblings.indexOf(node)\n if (sourceIdx === -1) return null\n\n const samelist = sourceSiblings === targetSiblings\n const [removed] = sourceSiblings.splice(sourceIdx, 1)\n let insertAt = targetIndex\n if (samelist && sourceIdx < targetIndex) insertAt = targetIndex - 1\n insertAt = Math.max(0, Math.min(insertAt, targetSiblings.length))\n targetSiblings.splice(insertAt, 0, removed)\n ;(removed.data as any)[parentField] = newParentNode ? getKey(newParentNode.data) : null\n // Flag explicitly: a reparent at an unchanged position number (root pos 2 →\n // a group's 2nd child, also pos 2) isn't caught by recalculateSiblings, so the\n // partial save would omit it and the child reverts to root on reload (BUG-13).\n removed.meta.dirty = true\n\n if (!samelist) recalculateSiblings(sourceSiblings)\n recalculateSiblings(targetSiblings)\n model.value = cloned\n return cloned\n }\n\n return {\n viewItems,\n findNode,\n addItem,\n deleteItem,\n updateItem,\n moveUp,\n moveDown,\n moveTop,\n moveBottom,\n indent,\n outdent,\n moveTo,\n recalculatePositions,\n calculateSubtreeDepth,\n }\n}\n","import {\n computed,\n reactive,\n ref,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowUnwrapRef,\n} from 'vue'\nimport type {\n ListEditorKey,\n ListEditorValidationState,\n NestedPositionHint,\n NestedTree,\n NestedTreeNode,\n} from '@/labs/listEditor/types/listEditorTypes'\nimport { useNestedListEditor, type NestedViewItem } from '@/labs/listEditor/composables/useNestedListEditor'\nimport type {\n GetKey,\n ListEditorValidationResult,\n PositionOption,\n PositionStrategy,\n} from '@/labs/listEditor/composables/useListEditorController'\nimport { nextListEditorTempId } from '@/labs/listEditor/utils/tempId'\nimport { cloneDeep } from '@/utils/common'\n\nexport type { ListEditorValidationResult, GetKey, PositionOption, PositionStrategy }\n\n/** Flattened ordered row carrying its resolved key (for change-sets + payload). */\nexport interface NestedListEditorChanges<TItem> {\n added: TItem[]\n updated: TItem[]\n moved: TItem[]\n deleted: TItem[]\n /**\n * Rows whose parent changed since the last commit (BUG-13 — persisted even\n * when the position number is unchanged).\n */\n reparented: TItem[]\n}\n\nexport interface UseNestedListEditorControllerOptions<TItem extends Record<string, any>> {\n /** Read the live tree (the editor's v-model, or a consumer store getter). */\n get: () => NestedTree<TItem>\n /** Write the tree back. */\n set: (tree: NestedTree<TItem>) => void\n /** New-row factory. Optional for read-only / no-add trees. Should mint a stable temp id. */\n factory?: () => TItem\n /** Stable row identity. Default `'id'`. Never point this at the position field. */\n getKey?: GetKey<TItem>\n /** Managed order field. Default `'position'`. `false` opts out of position management. */\n position?: PositionOption<TItem>\n /** Parent-key field written onto reparented rows. Default `'parent'`. */\n parentField?: string\n /** Maximum nesting depth (1-based). Enforced by indent/outdent/moveTo. */\n maxDepth: number\n /**\n * Extra top-level fields to drop from the dirty content-hash (position +\n * parent are always dropped). Same purpose as the flat controller — a child\n * collection tracked by a separate editor shouldn't flip its owner amber.\n * Accepts a getter/ref so a `computed` set is honoured reactively.\n */\n dirtyExclude?: MaybeRefOrGetter<string[]>\n /** Per-row validity — `true` = valid. Drives the red rail + `hasErrors`. */\n validate?: (item: TItem) => ListEditorValidationResult\n /** Custom dirty predicate (override the default `meta.dirty ∪ content-diff`). */\n isDirty?: (current: TItem, saved: TItem | undefined) => boolean\n /** Custom save payload (overrides `getPayload`). Receives the flattened ordered rows. */\n payload?: (items: TItem[]) => TItem[]\n /** Resolve a saved row's key on commit (default: existing key, else mint a temp id). */\n commitKey?: (saved: TItem, previous: TItem | undefined) => ListEditorKey\n /** Normalize the server tree before it becomes the new baseline on commit. */\n normalizeSaved?: (saved: NestedTree<TItem>) => NestedTree<TItem>\n}\n\n/**\n * Tree-shaped state controller for the nested list editor (v2). A superset of\n * the flat `ListEditorHandle`: same dirty/validate/commit/reset semantics, but\n * the row set is a flattened ordered projection of a `NestedTree` and the\n * mutators are tree ops (indent / outdent / moveTo / addChild …) delegated to\n * `useNestedListEditor`. Each flattened payload row carries its resolved\n * `position` and parent key written onto it.\n */\nexport interface NestedListEditorHandle<TItem extends Record<string, any>> {\n /** Flattened ordered rows (depth-first), matching the rendered order. */\n items: ComputedRef<TItem[]>\n /** Tree view rows (key/index/raw/depth/parent…), as consumed by the renderer. */\n viewItems: ComputedRef<NestedViewItem<TItem>[]>\n hasUnsaved: ComputedRef<boolean>\n /** Count of distinct unconfirmed changes (added/edited/moved/reparented rows + deferred deletions). */\n unsavedCount: ComputedRef<number>\n hasErrors: ComputedRef<boolean>\n invalidKeys: ComputedRef<Set<ListEditorKey>>\n /** Amber: is this row added / edited / moved / reparented since the last commit? */\n isUnsaved: (key: ListEditorKey) => boolean\n /** Red rail (gated): 'invalid' only once the row is unsaved or `validateAll()` ran. */\n rowState: (item: TItem, key: ListEditorKey, editing?: boolean) => ListEditorValidationState\n /** Force-show all invalid rows + return whether the tree is valid. The save guard. */\n validateAll: () => boolean\n /** Flattened ordered array (each row carrying its resolved position + parent key) for a full-DTO save. */\n getPayload: () => TItem[]\n /** Change-set for partial-save endpoints (added/updated/moved/deleted/reparented), keyed. */\n getChanges: () => NestedListEditorChanges<TItem>\n /** Adopt the saved tree as the new baseline; backfill keys; clear dirty/submitted. */\n commit: (saved?: NestedTree<TItem>) => void\n /** Discard unsaved edits back to the last committed baseline (or a given tree). */\n reset: (tree?: NestedTree<TItem>) => void\n\n // Tree mutations — delegate to useNestedListEditor (which carries BUG-13).\n addItem: (item?: TItem, hint?: NestedPositionHint) => void\n addAfter: (afterKey: ListEditorKey, item?: TItem, childrenAllowed?: boolean) => void\n addChild: (parentKey: ListEditorKey, item?: TItem, childrenAllowed?: boolean) => void\n updateItem: (key: ListEditorKey, data: TItem, markDirty?: boolean) => void\n deleteItem: (key: ListEditorKey, opts?: { trackDeleted?: boolean }) => void\n restoreDeleted: (key: ListEditorKey) => void\n moveUp: (key: ListEditorKey) => boolean\n moveDown: (key: ListEditorKey) => boolean\n moveTop: (key: ListEditorKey) => boolean\n moveBottom: (key: ListEditorKey) => boolean\n indent: (key: ListEditorKey) => boolean\n outdent: (key: ListEditorKey) => boolean\n moveTo: (key: ListEditorKey, targetParentKey: ListEditorKey | null, targetIndex: number) => boolean\n recalculatePositions: () => void\n\n /** Escape hatch: a row form (e.g. vuelidate) reports its own validity instead of `validate`. */\n registerValidity: (key: ListEditorKey, isValid: () => boolean) => () => void\n\n // Internal handles the editor needs to drive the tree directly (find a node,\n // subtree depth for drag, the underlying `editor.moveTo` returning the tree).\n findNode: (key: ListEditorKey) => {\n node: NestedTreeNode<TItem> | null\n parent: NestedTreeNode<TItem> | null\n }\n calculateSubtreeDepth: (node: NestedTreeNode<TItem>) => number\n}\n\n/**\n * Consumer-facing shape of a nested-list-editor handle read through a template/function ref — Vue's\n * `expose` proxy unwraps the exposed refs, so read `handle.hasUnsaved` (a boolean), not\n * `handle.hasUnsaved.value`. See {@link ExposedListEditorHandle}.\n *\n * The `ANestedSortableListEditor` component also exposes `hasUnsavedChanges` (a legacy alias of\n * `hasUnsaved`, likewise a ComputedRef → unwrapped to a boolean here) — included so it can't be\n * `.value`-read by accident. Its imperative-only extras (addAfterId / resetDirtyBaseline / expand /\n * reorder / …) are not refs and carry no unwrap hazard; intersect them in the consumer if you call them.\n */\nexport type ExposedNestedListEditorHandle<TItem extends Record<string, any>> = ShallowUnwrapRef<\n NestedListEditorHandle<TItem>\n> & {\n hasUnsavedChanges: boolean\n}\n\nconst flatten = <TItem extends Record<string, any>>(tree: NestedTree<TItem>): TItem[] => {\n const out: TItem[] = []\n const walk = (nodes: NestedTreeNode<TItem>[]) => {\n for (const n of nodes) {\n out.push(n.data)\n if (n.children && n.children.length) walk(n.children)\n }\n }\n walk(tree.children)\n return out\n}\n\nconst walkNodes = <TItem extends Record<string, any>>(\n tree: NestedTree<TItem>,\n visit: (node: NestedTreeNode<TItem>) => void\n): void => {\n const walk = (nodes: NestedTreeNode<TItem>[]) => {\n for (const n of nodes) {\n visit(n)\n if (n.children && n.children.length) walk(n.children)\n }\n }\n walk(tree.children)\n}\n\nexport function useNestedListEditorController<TItem extends Record<string, any>>(\n options: UseNestedListEditorControllerOptions<TItem>\n): NestedListEditorHandle<TItem> {\n const keyField = (typeof options.getKey === 'function' ? null : (options.getKey ?? 'id')) as keyof TItem | null\n const keyOf = (item: TItem): ListEditorKey =>\n typeof options.getKey === 'function' ? options.getKey(item) : (item[keyField as keyof TItem] as ListEditorKey)\n const keyFieldName = (keyField ?? 'id') as string\n\n const positionOpt = options.position ?? 'position'\n const managedPosition = positionOpt !== false\n const positionField = (\n typeof positionOpt === 'object' ? positionOpt.field : positionOpt === false ? 'position' : positionOpt\n ) as string\n const positionMultiplier = typeof positionOpt === 'object' && positionOpt.multiplier ? positionOpt.multiplier : 1\n const parentField = options.parentField ?? 'parent'\n\n // Two-way bridge to the consumer's tree: the composable's per-op\n // `model.value = cloned` writes back via `set`, the getter re-reads live edits.\n const model = computed<NestedTree<TItem>>({\n get: () => options.get(),\n set: (v) => options.set(v),\n }) as unknown as Ref<NestedTree<TItem>>\n\n const tree = useNestedListEditor<TItem>(model, {\n keyField: keyFieldName,\n // Pass the controller's keyOf so tree ops resolve keys identically to\n // invalidKeys/dirty tracking — supports a function get-key, not just a field.\n getKey: keyOf,\n positionField,\n parentField,\n positionMultiplier,\n maxDepth: options.maxDepth,\n })\n\n const items = computed<TItem[]>(() => flatten(options.get()))\n const viewItems = tree.viewItems\n\n // Baseline = last committed snapshot. `hashes` powers content-diff dirty\n // (position + parent excluded so a reorder/reparent never lights up via the\n // content hash — meta.dirty / the reparented set carries those instead).\n const dirtyExclude = computed<string[]>(() => toValue(options.dirtyExclude) ?? [])\n const normalize = (item: TItem): string => {\n const copy = { ...item } as Record<string, unknown>\n if (managedPosition) delete copy[positionField]\n delete copy[parentField]\n for (const f of dirtyExclude.value) delete copy[f]\n return JSON.stringify(copy)\n }\n const baselineHashes = ref(new Map<ListEditorKey, string>()) as Ref<Map<ListEditorKey, string>>\n // Parent-key per row at baseline — drives reparented detection (BUG-13).\n const baselineParents = ref(new Map<ListEditorKey, ListEditorKey | null>()) as Ref<\n Map<ListEditorKey, ListEditorKey | null>\n >\n const baselineTree = ref<NestedTree<TItem> | null>(null) as Ref<NestedTree<TItem> | null>\n\n const cloneTree = (t: NestedTree<TItem>): NestedTree<TItem> => cloneDeep(t)\n\n const captureBaseline = (t: NestedTree<TItem>) => {\n const hashes = new Map<ListEditorKey, string>()\n const parents = new Map<ListEditorKey, ListEditorKey | null>()\n const walk = (nodes: NestedTreeNode<TItem>[], parentKey: ListEditorKey | null) => {\n for (const n of nodes) {\n const key = keyOf(n.data)\n hashes.set(key, normalize(n.data))\n parents.set(key, parentKey)\n if (n.children && n.children.length) walk(n.children, key)\n }\n }\n walk(t.children, null)\n baselineHashes.value = hashes\n baselineParents.value = parents\n baselineTree.value = cloneTree(t)\n }\n captureBaseline(options.get())\n // Re-hash when the excluded-field set changes; `sync` so baseline + live\n // normalize() never disagree mid-flush. (Mirrors the flat controller.)\n watch(\n dirtyExclude,\n () => {\n if (!baselineTree.value) return\n const hashes = new Map<ListEditorKey, string>()\n walkNodes(baselineTree.value, (n) => hashes.set(keyOf(n.data), normalize(n.data)))\n baselineHashes.value = hashes\n },\n { flush: 'sync' }\n )\n\n const submitted = ref(false)\n // Reactive so a row form (re)registering its validity re-runs invalidKeys/rowState.\n const registeredValidity = reactive(new Map<ListEditorKey, () => boolean>())\n\n // Amber = added OR content-edited OR reparented (vs baseline). Position is\n // excluded, so a displaced sibling's pure renumber is NOT amber (matches the flat\n // editor + the \"only the actively-moved subtree lights up\" UX); BUG-13 adds the\n // parent-changed signal so a reparent registers even at an unchanged position\n // number. `getChanges().moved` reads meta.dirty, so displaced siblings' new\n // positions are still persisted; `hasPendingMove` (below) feeds the leave guard.\n const isItemDirty = (node: NestedTreeNode<TItem>, key: ListEditorKey, parentKey: ListEditorKey | null): boolean => {\n if (options.isDirty) {\n const saved = baselineTreeRow(key)\n return options.isDirty(node.data, saved)\n }\n const baseHash = baselineHashes.value.get(key)\n if (baseHash === undefined) return true // added\n if (baseHash !== normalize(node.data)) return true // content-edited (pos/parent excluded)\n // Reparented vs baseline (BUG-13).\n if (baselineParents.value.has(key)) {\n const baseParent = baselineParents.value.get(key) ?? null\n if ((baseParent ?? null) !== (parentKey ?? null)) return true\n }\n return false\n }\n\n // `addedBaseline` = first-seen content hash of each ADDED node; `editedKeys` = STICKY set of\n // nodes whose content has since diverged. Gates the validation rail on \"has this row been edited\"\n // rather than just \"is it unsaved\" (sticky like vuelidate `$dirty`) — mirrors the flat controller.\n const addedBaseline = ref(new Map<ListEditorKey, string>()) as Ref<Map<ListEditorKey, string>>\n const editedKeys = ref(new Set<ListEditorKey>()) as Ref<Set<ListEditorKey>>\n // Deferred-deletion tombstones (baseline keys removed but not yet saved). Immediate deletes skip\n // this so they don't read as unsaved. Drives hasUnsaved / unsavedCount / getChanges().deleted.\n const deletedKeys = ref(new Set<ListEditorKey>()) as Ref<Set<ListEditorKey>>\n watch(\n () => options.get(),\n (tree) => {\n const live = new Set<ListEditorKey>()\n walkNodes(tree, (n) => {\n const key = keyOf(n.data)\n live.add(key)\n if (!baselineHashes.value.has(key) && !addedBaseline.value.has(key)) {\n addedBaseline.value.set(key, normalize(n.data))\n }\n if (!editedKeys.value.has(key)) {\n const base = baselineHashes.value.get(key) ?? addedBaseline.value.get(key)\n if (base !== undefined && base !== normalize(n.data)) editedKeys.value.add(key)\n }\n })\n const stale: ListEditorKey[] = []\n for (const key of addedBaseline.value.keys()) if (!live.has(key)) stale.push(key)\n for (const key of stale) addedBaseline.value.delete(key)\n // A tombstoned key that becomes live again (re-add before save) drops its tombstone.\n const revived: ListEditorKey[] = []\n for (const key of deletedKeys.value) if (live.has(key)) revived.push(key)\n for (const key of revived) deletedKeys.value.delete(key)\n },\n { immediate: true, deep: true }\n )\n\n const isRowEdited = (key: ListEditorKey): boolean => editedKeys.value.has(key)\n\n const baselineTreeRow = (key: ListEditorKey): TItem | undefined => {\n if (!baselineTree.value) return undefined\n let hit: TItem | undefined\n walkNodes(baselineTree.value, (n) => {\n if (hit === undefined && keyOf(n.data) === key) hit = n.data\n })\n return hit\n }\n\n const treeHasKey = (key: ListEditorKey): boolean => {\n let found = false\n walkNodes(options.get(), (n) => {\n if (!found && keyOf(n.data) === key) found = true\n })\n return found\n }\n\n const unsavedKeys = computed<Set<ListEditorKey>>(() => {\n const out = new Set<ListEditorKey>()\n const walk = (nodes: NestedTreeNode<TItem>[], parentKey: ListEditorKey | null) => {\n for (const n of nodes) {\n const key = keyOf(n.data)\n if (isItemDirty(n, key, parentKey)) out.add(key)\n if (n.children && n.children.length) walk(n.children, key)\n }\n }\n walk(options.get().children, null)\n return out\n })\n\n const isUnsaved = (key: ListEditorKey): boolean => unsavedKeys.value.has(key)\n // A pure position reorder sets meta.dirty (recalculateSiblings) but is deliberately\n // kept OUT of per-row amber (only the actively-moved subtree lights up). It IS a\n // pending change though, so it must arm the leave guard — surface it as an aggregate\n // signal (M2b) that survives Apply and clears on commit (which resets meta.dirty).\n const hasPendingMove = computed<boolean>(() => {\n let found = false\n walkNodes(options.get(), (n) => {\n if (n.meta.dirty) found = true\n })\n return found\n })\n const hasUnsaved = computed<boolean>(\n () => unsavedKeys.value.size > 0 || deletedKeys.value.size > 0 || hasPendingMove.value\n )\n // Distinct unconfirmed changes = union of live dirty keys (added/edited/moved/reparented) and\n // deferred-deletion tombstones. Drives the \"N unconfirmed changes\" indicator.\n const unsavedCount = computed<number>(() => {\n const keys = new Set<ListEditorKey>(unsavedKeys.value)\n for (const key of deletedKeys.value) keys.add(key)\n return keys.size\n })\n\n const resolveValidity = (item: TItem, key: ListEditorKey): { invalid: boolean; warning: boolean } => {\n const registered = registeredValidity.get(key)\n if (registered) return { invalid: !registered(), warning: false }\n if (!options.validate) return { invalid: false, warning: false }\n const r = options.validate(item)\n if (typeof r === 'boolean') return { invalid: !r, warning: false }\n return { invalid: !r.valid, warning: r.valid && r.state === 'warning' }\n }\n\n const invalidKeys = computed<Set<ListEditorKey>>(() => {\n const out = new Set<ListEditorKey>()\n walkNodes(options.get(), (n) => {\n const key = keyOf(n.data)\n if (resolveValidity(n.data, key).invalid) out.add(key)\n })\n return out\n })\n const hasErrors = computed<boolean>(() => invalidKeys.value.size > 0)\n\n // Red rail for an invalid row that has been edited, is unsaved (added), or after a save attempt —\n // mirrors the flat controller. The editor suppresses the red while the row is the one being edited,\n // so a still-being-filled row reads amber and only goes red once collapsed. (QA 85050 batch 7)\n const rowState = (item: TItem, key: ListEditorKey, editing = false): ListEditorValidationState => {\n const { invalid, warning } = resolveValidity(item, key)\n // See flat controller: red when edited/unsaved/submitted, amber while being filled, red once\n // collapsed; a save attempt (`submitted`) reds it even while open. (QA 85050 batch 7)\n if (invalid) {\n if (submitted.value) return 'invalid'\n if (editing) return null\n return isRowEdited(key) || isUnsaved(key) ? 'invalid' : null\n }\n if (warning) return 'warning'\n return null\n }\n\n const validateAll = (): boolean => {\n submitted.value = true\n return invalidKeys.value.size === 0\n }\n\n // Flattened ordered payload; parent key is resolved from tree structure (so a\n // reparent is reflected even if the node's own parent field lagged).\n const buildPayload = (): TItem[] => {\n const out: TItem[] = []\n const walk = (nodes: NestedTreeNode<TItem>[], parentKey: ListEditorKey | null) => {\n for (const n of nodes) {\n const row = { ...n.data } as TItem\n ;(row as Record<string, unknown>)[parentField] = parentKey\n out.push(row)\n if (n.children && n.children.length) walk(n.children, keyOf(n.data))\n }\n }\n walk(options.get().children, null)\n return out\n }\n\n const getPayload = (): TItem[] => (options.payload ? options.payload(buildPayload()) : buildPayload())\n\n const getChanges = (): NestedListEditorChanges<TItem> => {\n const added: TItem[] = []\n const updated: TItem[] = []\n const moved: TItem[] = []\n const reparented: TItem[] = []\n const payload = buildPayload()\n const byKey = new Map<ListEditorKey, TItem>()\n for (const row of payload) byKey.set(keyOf(row), row)\n\n walkNodes(options.get(), (n) => {\n const key = keyOf(n.data)\n const row = byKey.get(key) ?? n.data\n const baseHash = baselineHashes.value.get(key)\n if (baseHash === undefined) {\n added.push(row)\n } else if (baseHash !== normalize(n.data)) {\n updated.push(row)\n }\n // meta.dirty without a content change => a move/reparent (position/parent\n // changed). recalculateSiblings + BUG-13 set meta.dirty on those.\n if (baseHash !== undefined && n.meta.dirty && baseHash === normalize(n.data)) {\n moved.push(row)\n }\n // Reparented = parent key differs from baseline (subset of moved, but\n // surfaced separately for partial-multi saves that re-link parents).\n if (baselineParents.value.has(key)) {\n const baseParent = baselineParents.value.get(key) ?? null\n const nowParent = (row as Record<string, unknown>)[parentField] as ListEditorKey | null\n if ((baseParent ?? null) !== (nowParent ?? null)) reparented.push(row)\n }\n })\n\n // Deferred deletions come from the tombstone set, so an IMMEDIATE delete (already persisted on the\n // backend, no tombstone) does not re-appear here as a local deleted change.\n const deleted: TItem[] = []\n for (const key of deletedKeys.value) {\n const row = baselineTreeRow(key)\n if (row !== undefined) deleted.push(row)\n }\n return { added, updated, moved, deleted, reparented }\n }\n\n const commit = (saved?: NestedTree<TItem>): void => {\n const source = saved ?? options.get()\n const normalized = options.normalizeSaved ? options.normalizeSaved(source) : source\n // Backfill missing keys + clear meta.dirty on the committed tree.\n const next = cloneTree(normalized)\n walkNodes(next, (n) => {\n const previous = baselineTreeRow(keyOf(n.data))\n const resolvedKey = options.commitKey ? options.commitKey(n.data, previous) : keyOf(n.data)\n if (resolvedKey === undefined || resolvedKey === null) {\n if (keyField) (n.data as Record<string, unknown>)[keyFieldName] = nextListEditorTempId()\n }\n n.meta.dirty = false\n })\n options.set(next)\n captureBaseline(next)\n addedBaseline.value = new Map()\n editedKeys.value = new Set()\n deletedKeys.value = new Set()\n submitted.value = false\n }\n\n const reset = (t?: NestedTree<TItem>): void => {\n const restore = t ?? (baselineTree.value ? cloneTree(baselineTree.value) : options.get())\n options.set(restore)\n addedBaseline.value = new Map()\n editedKeys.value = new Set()\n deletedKeys.value = new Set()\n submitted.value = false\n }\n\n // --- Tree mutations (delegate to useNestedListEditor) -----------------------\n\n const addItem = (item?: TItem, hint?: NestedPositionHint): void => {\n const data = item ?? options.factory?.()\n if (data === undefined) return // no item + no factory (read-only) → no-op\n tree.addItem(data, hint)\n }\n const addAfter = (afterKey: ListEditorKey, item?: TItem, childrenAllowed = true): void => {\n const data = item ?? options.factory?.()\n if (data === undefined) return\n tree.addItem(data, { afterId: afterKey, childrenAllowed })\n }\n const addChild = (parentKey: ListEditorKey, item?: TItem, childrenAllowed = true): void => {\n const data = item ?? options.factory?.()\n if (data === undefined) return\n tree.addItem(data, { parentId: parentKey, childrenAllowed })\n }\n const updateItem = (key: ListEditorKey, data: TItem, markDirty = true): void => {\n tree.updateItem(key, data, markDirty)\n }\n const deleteItem = (key: ListEditorKey, opts?: { trackDeleted?: boolean }): void => {\n // A previously-saved row removed in deferred mode is tombstoned (counts as unsaved + reported in\n // getChanges().deleted). `trackDeleted: false` (immediate — already deleted on the backend) skips it.\n // `treeHasKey` guards against a phantom tombstone: an immediate delete removes the row in the\n // component's own handler (trackDeleted:false), then the consumer's removeById re-calls deleteItem\n // for the now-gone key — without the guard that second call would tombstone a baseline row that is\n // already deleted, surfacing a bogus unconfirmed change.\n if (baselineHashes.value.has(key) && opts?.trackDeleted !== false && treeHasKey(key)) {\n deletedKeys.value.add(key)\n }\n tree.deleteItem(key)\n }\n\n const restoreDeleted = (key: ListEditorKey): void => {\n deletedKeys.value.delete(key)\n }\n const moveUp = (key: ListEditorKey): boolean => tree.moveUp(key) !== null\n const moveDown = (key: ListEditorKey): boolean => tree.moveDown(key) !== null\n const moveTop = (key: ListEditorKey): boolean => tree.moveTop(key) !== null\n const moveBottom = (key: ListEditorKey): boolean => tree.moveBottom(key) !== null\n const indent = (key: ListEditorKey): boolean => tree.indent(key) !== null\n const outdent = (key: ListEditorKey): boolean => tree.outdent(key) !== null\n const moveTo = (key: ListEditorKey, targetParentKey: ListEditorKey | null, targetIndex: number): boolean =>\n tree.moveTo(key, targetParentKey, targetIndex) !== null\n const recalculatePositions = (): void => {\n options.set(tree.recalculatePositions(options.get()))\n }\n\n const registerValidity = (key: ListEditorKey, isValid: () => boolean): (() => void) => {\n registeredValidity.set(key, isValid)\n return () => registeredValidity.delete(key)\n }\n\n return {\n items,\n viewItems,\n hasUnsaved,\n unsavedCount,\n hasErrors,\n invalidKeys,\n isUnsaved,\n rowState,\n validateAll,\n getPayload,\n getChanges,\n commit,\n reset,\n addItem,\n addAfter,\n addChild,\n updateItem,\n deleteItem,\n restoreDeleted,\n moveUp,\n moveDown,\n moveTop,\n moveBottom,\n indent,\n outdent,\n moveTo,\n recalculatePositions,\n registerValidity,\n findNode: tree.findNode,\n calculateSubtreeDepth: tree.calculateSubtreeDepth,\n }\n}\n","import {\n effectScope,\n getCurrentInstance,\n getCurrentScope,\n inject,\n onBeforeUnmount,\n onScopeDispose,\n provide,\n shallowRef,\n toValue,\n type EffectScope,\n type InjectionKey,\n type ShallowRef,\n} from 'vue'\nimport type { ListEditorKey } from '@/labs/listEditor/types/listEditorTypes'\nimport {\n useListEditorController,\n type ListEditorHandle,\n type UseListEditorControllerOptions,\n} from '@/labs/listEditor/composables/useListEditorController'\nimport {\n useNestedListEditorController,\n type NestedListEditorHandle,\n type UseNestedListEditorControllerOptions,\n} from '@/labs/listEditor/composables/useNestedListEditorController'\n\n/**\n * The instance-bound controller options an editor re-supplies on EVERY (re)mount. `get`/`set` close\n * over the editor instance's `modelValue`/`emit`, and `factory`/`validate`/`dirtyExclude` over its\n * props — a remounted editor is a NEW instance, so a persisted controller must read all of them\n * through the live binding (see `useListEditorStateEntry`), never through the closures of the dead\n * instance that happened to create it.\n */\nexport type ListEditorStateBindings<TItem extends Record<string, any>> = Pick<\n UseListEditorControllerOptions<TItem>,\n 'get' | 'set' | 'factory' | 'getKey' | 'position' | 'dirtyExclude' | 'validate'\n>\n\nexport type NestedListEditorStateBindings<TItem extends Record<string, any>> = Pick<\n UseNestedListEditorControllerOptions<TItem>,\n 'get' | 'set' | 'factory' | 'getKey' | 'position' | 'parentField' | 'maxDepth' | 'dirtyExclude' | 'validate'\n>\n\n/** What a `state-key`'d editor gets back: its persisted handle + the scope to hand to ITS own rows. */\nexport interface ListEditorStateEntry<THandle> {\n handle: THandle\n /** Scope for this editor's `#item` slot subtree — persisted alongside the entry, so a\n * grand-nested `state-key`'d editor survives this editor's unmount too. */\n childScope: ListEditorStateScope | null\n}\n\ninterface StateEntry {\n scope: EffectScope\n live: ShallowRef<any>\n handle: unknown\n children: ListEditorStateScope | null\n /** uid of the editor instance currently bound to this entry (`null` = parked, no live editor). */\n boundUid: number | null\n}\n\n/**\n * A keyed registry of list-editor state controllers, owned by an ANCESTOR (the editor that provides\n * it for its `#item` slot subtree) and living in that ancestor's `effectScope` — NOT in the scope of\n * the transient editor component that resolves it. That is the whole point: a nested editor's `#item`\n * slot is behind a `v-if`, so collapsing a row UNMOUNTS the nested editor; a component-owned\n * controller dies with it and a brand-new one re-baselines the already-edited data on re-expand,\n * losing amber / movedKeys / editedKeys / tombstones / the submitted (red-rail) flag.\n */\nexport interface ListEditorStateScope {\n /** Unique per scope instance; namespaces the row prefixes this scope mints (and can prune). */\n readonly id: string\n /**\n * First call for `key` CREATES the controller inside this scope (via `create`, from the calling\n * editor's own bindings) and registers it. Every later call REBINDS the registered controller to\n * the (new) calling instance's bindings and returns it — state intact.\n */\n resolve<TBindings extends object, THandle>(\n key: string,\n bindings: TBindings,\n create: (live: ShallowRef<TBindings>) => THandle,\n uid?: number | null\n ): THandle\n /**\n * The editor bound to `key` is unmounting: park the entry — its model accessors are swapped for a\n * frozen read + a no-op write so the orphaned controller can never read or write through the dead\n * instance's `modelValue`/`emit`. No-op when another instance has already rebound (mount-before-\n * unmount ordering), which is why the caller passes its uid.\n */\n release<TBindings extends object>(key: string, uid: number | null, park: (bindings: TBindings) => TBindings): void\n /** Child scope of a registered entry (created lazily inside the entry's effect scope). */\n childScope(key: string): ListEditorStateScope | null\n /** The state-key prefix for a row — hosts thread it down and suffix it per nested list. */\n prefixFor(rowKey: ListEditorKey): string\n /** Dispose the entries of rows that no longer exist (keys minted from `prefixFor` only). */\n retainOwners(liveRowKeys: Iterable<ListEditorKey>): void\n has(key: string): boolean\n size(): number\n dispose(): void\n}\n\nexport const ListEditorStateScopeKey: InjectionKey<ListEditorStateScope> = Symbol(\n 'le.stateScope'\n) as InjectionKey<ListEditorStateScope>\n\nlet scopeSeq = 0\n\n/**\n * Create a scope. The internal `effectScope` is NOT detached: it attaches to whatever scope creates\n * it — the providing editor's component scope (so everything stops on its unmount) or a persisted\n * ENTRY's scope (so a nested editor's own row scope outlives the editor exactly as its controller\n * does).\n */\nexport function createListEditorStateScope(): ListEditorStateScope {\n const id = `les${++scopeSeq}`\n const entries = new Map<string, StateEntry>()\n const root = effectScope()\n\n const disposeEntry = (key: string, entry: StateEntry): void => {\n entry.children?.dispose()\n entry.scope.stop()\n entries.delete(key)\n }\n\n const scope: ListEditorStateScope = {\n id,\n resolve<TBindings extends object, THandle>(\n key: string,\n bindings: TBindings,\n create: (live: ShallowRef<TBindings>) => THandle,\n uid: number | null = null\n ): THandle {\n const existing = entries.get(key)\n if (existing) {\n if (existing.boundUid !== null && uid !== null && existing.boundUid !== uid) {\n console.warn(\n `[list-editor] two editors are mounted under the same state-key \"${key}\". ` +\n 'They would share one state controller — give each editor a unique state-key ' +\n '(e.g. suffix the row prefix with the list name).'\n )\n }\n existing.boundUid = uid\n // THE REBIND. `live` is a shallowRef, so this assignment invalidates every controller\n // computed that read it (`items` first) — the persisted controller now reads and writes\n // the LIVE editor instance's model instead of the dead one it was created from.\n existing.live.value = bindings\n return existing.handle as THandle\n }\n const entryScope = root.active ? (root.run(() => effectScope()) as EffectScope) : effectScope()\n const live = shallowRef(bindings) as ShallowRef<TBindings>\n const handle = entryScope.run(() => create(live)) as THandle\n entries.set(key, { scope: entryScope, live, handle, children: null, boundUid: uid })\n return handle\n },\n release<TBindings extends object>(key: string, uid: number | null, park: (bindings: TBindings) => TBindings): void {\n const entry = entries.get(key)\n if (!entry || entry.boundUid !== uid) return\n entry.boundUid = null\n entry.live.value = park(entry.live.value as TBindings)\n },\n childScope(key: string): ListEditorStateScope | null {\n const entry = entries.get(key)\n if (!entry) return null\n if (!entry.children) {\n entry.children = entry.scope.run(() => createListEditorStateScope()) ?? null\n }\n return entry.children\n },\n prefixFor(rowKey: ListEditorKey): string {\n return `${id}:${String(rowKey)}`\n },\n retainOwners(liveRowKeys: Iterable<ListEditorKey>): void {\n if (entries.size === 0) return\n const livePrefixes: string[] = []\n for (const rowKey of liveRowKeys) livePrefixes.push(`${id}:${String(rowKey)}`)\n const ownPrefix = `${id}:`\n for (const [key, entry] of entries) {\n // Keys the host invented itself (not derived from `prefixFor`) carry no row ownership —\n // they are only disposed with the scope.\n if (!key.startsWith(ownPrefix)) continue\n const alive = livePrefixes.some((p) => key === p || key.startsWith(`${p}:`))\n if (!alive) disposeEntry(key, entry)\n }\n },\n has(key: string): boolean {\n return entries.has(key)\n },\n size(): number {\n return entries.size\n },\n dispose(): void {\n for (const [key, entry] of entries) disposeEntry(key, entry)\n entries.clear()\n root.stop()\n },\n }\n\n if (getCurrentScope()) onScopeDispose(() => scope.dispose())\n\n return scope\n}\n\n/**\n * Provide the row-state scope for an editor's `#item` slot subtree. A `state-key`'d editor passes\n * the `childScope` of its own persisted entry (so the chain survives at any depth); a plain editor\n * creates a component-owned scope that dies with it.\n */\nexport function provideListEditorStateScope(inherited: ListEditorStateScope | null): ListEditorStateScope {\n const scope = inherited ?? createListEditorStateScope()\n provide(ListEditorStateScopeKey, scope)\n return scope\n}\n\nconst parkBindings = <TBindings extends { get: () => any; set: (value: any) => void }>(\n bindings: TBindings\n): TBindings => {\n const parked = bindings.get()\n return { ...bindings, get: () => parked, set: () => undefined }\n}\n\n/**\n * Resolve this editor's controller from the nearest ancestor scope under `stateKey` (or `null` when\n * the editor has no `state-key`, or no ancestor provides a scope → today's component-owned\n * controller, unchanged).\n *\n * The controller is built from the FIRST mounting instance's own props, but every instance-bound\n * option is read through `live` — the shallowRef the scope swaps on each (re)mount. `getKey` and\n * `position` are static per tag, so the controller reads them once (it derives its key field at\n * construction); everything else is indirected.\n */\nexport function useListEditorStateEntry<TItem extends Record<string, any>>(\n stateKey: string | undefined,\n bindings: ListEditorStateBindings<TItem>\n): ListEditorStateEntry<ListEditorHandle<TItem>> | null {\n const scope = inject(ListEditorStateScopeKey, null)\n if (!stateKey || !scope) return null\n const uid = getCurrentInstance()?.uid ?? null\n const handle = scope.resolve<ListEditorStateBindings<TItem>, ListEditorHandle<TItem>>(\n stateKey,\n bindings,\n (live) =>\n useListEditorController<TItem>({\n get: () => live.value.get(),\n set: (items) => live.value.set(items),\n // `factory?.()` → undefined reproduces the \"no factory\" no-op of `addItem` exactly.\n factory: (() => live.value.factory?.()) as () => TItem,\n getKey: live.value.getKey,\n position: live.value.position,\n dirtyExclude: () => toValue(live.value.dirtyExclude) ?? [],\n // `?? true` reproduces the \"no validate\" always-valid branch.\n validate: (item) => live.value.validate?.(item) ?? true,\n }),\n uid\n )\n if (getCurrentInstance()) {\n onBeforeUnmount(() => scope.release<ListEditorStateBindings<TItem>>(stateKey, uid, parkBindings))\n }\n return { handle, childScope: scope.childScope(stateKey) }\n}\n\n/** Tree-shaped twin of `useListEditorStateEntry` for ANestedSortableListEditor. */\nexport function useNestedListEditorStateEntry<TItem extends Record<string, any>>(\n stateKey: string | undefined,\n bindings: NestedListEditorStateBindings<TItem>\n): ListEditorStateEntry<NestedListEditorHandle<TItem>> | null {\n const scope = inject(ListEditorStateScopeKey, null)\n if (!stateKey || !scope) return null\n const uid = getCurrentInstance()?.uid ?? null\n const handle = scope.resolve<NestedListEditorStateBindings<TItem>, NestedListEditorHandle<TItem>>(\n stateKey,\n bindings,\n (live) =>\n useNestedListEditorController<TItem>({\n get: () => live.value.get(),\n set: (tree) => live.value.set(tree),\n factory: (() => live.value.factory?.()) as () => TItem,\n getKey: live.value.getKey,\n position: live.value.position,\n parentField: live.value.parentField,\n maxDepth: live.value.maxDepth,\n dirtyExclude: () => toValue(live.value.dirtyExclude) ?? [],\n validate: (item) => live.value.validate?.(item) ?? true,\n }),\n uid\n )\n if (getCurrentInstance()) {\n onBeforeUnmount(() => scope.release<NestedListEditorStateBindings<TItem>>(stateKey, uid, parkBindings))\n }\n return { handle, childScope: scope.childScope(stateKey) }\n}\n","// Compact (collapsed) display text for a list-editor row. Used by every\n// editor variant when the consumer didn't provide an `#item-compact` slot.\n// Consumers must opt in explicitly via `compactField` — there is NO implicit\n// fallback to common field names. Returns empty string otherwise; provide\n// the `#item-compact` slot for anything richer.\nexport function resolveCompactText<TItem extends Record<string, any>>(\n raw: TItem,\n options: { compactField?: string | null }\n): string {\n if (!options.compactField) return ''\n // A dotted path reads through nested objects (`texts.title`), which is how most entities in\n // these admins carry their label. A key without a dot behaves exactly as it always did, and a\n // path that runs into a missing or non-object step yields '' rather than throwing.\n let v: unknown = raw\n for (const segment of options.compactField.split('.')) {\n if (v === null || typeof v !== 'object') return ''\n v = (v as Record<string, unknown>)[segment]\n }\n return v == null || v === '' ? '' : String(v)\n}\n","import {\n computed,\n getCurrentInstance,\n inject,\n onBeforeUnmount,\n provide,\n reactive,\n type ComputedRef,\n type InjectionKey,\n} from 'vue'\n\n/**\n * One named, savable section the unsaved-changes confirm dialog can name back\n * to the user. `dirty` is evaluated reactively inside the section's getter.\n */\nexport interface UnsavedSectionDescriptor {\n label: string\n dirty: boolean\n}\n\n/**\n * Getter returning a single descriptor, or an array of them for a component\n * that owns several sub-sections (e.g. page positions in one PageContentsManage).\n */\nexport type UnsavedSectionSource = () => UnsavedSectionDescriptor | UnsavedSectionDescriptor[]\n\nexport interface UnsavedSectionRegistry {\n register: (id: symbol, source: ComputedRef<UnsavedSectionDescriptor[]>) => void\n unregister: (id: symbol) => void\n /** Labels of every registered section currently flagged dirty. */\n dirtyLabels: ComputedRef<string[]>\n}\n\nexport const UnsavedSectionKey = Symbol('unsaved.sections') as InjectionKey<UnsavedSectionRegistry>\n\nexport function createUnsavedSectionRegistry(): UnsavedSectionRegistry {\n const sources = reactive(new Map<symbol, ComputedRef<UnsavedSectionDescriptor[]>>())\n\n const dirtyLabels = computed<string[]>(() => {\n const out: string[] = []\n for (const source of sources.values()) {\n for (const descriptor of source.value) {\n if (descriptor.dirty) out.push(descriptor.label)\n }\n }\n return out\n })\n\n return {\n register(id, source) {\n sources.set(id, source)\n },\n unregister(id) {\n sources.delete(id)\n },\n dirtyLabels,\n }\n}\n\n/**\n * Creates a registry and `provide`s it for descendants. Called internally by\n * `useUnsavedChangesGuard` so the guard host automatically supplies one.\n */\nexport function provideUnsavedSectionRegistry(): UnsavedSectionRegistry {\n const registry = createUnsavedSectionRegistry()\n if (getCurrentInstance()) provide(UnsavedSectionKey, registry)\n return registry\n}\n\n/**\n * Registers one or more named sections so the unsaved-changes confirm dialog\n * can tell the user *which* parts are dirty instead of a generic message.\n *\n * Pass a getter returning a descriptor — or an array of descriptors when the\n * component owns several sub-sections (e.g. one PageContentsManage owns N page\n * positions). No-op when called outside a guarded route (inject returns null).\n */\nexport function useUnsavedSection(source: UnsavedSectionSource): void {\n const registry = inject(UnsavedSectionKey, null)\n if (!registry) return\n if (!getCurrentInstance()) return\n\n const id = Symbol('unsaved.section')\n const normalized = computed<UnsavedSectionDescriptor[]>(() => {\n const resolved = source()\n return Array.isArray(resolved) ? resolved : [resolved]\n })\n\n registry.register(id, normalized)\n onBeforeUnmount(() => registry.unregister(id))\n}\n","import { ref, type Ref } from 'vue'\n\nexport interface UseDeleteDialogOptions<TItem, ViewItem> {\n /**\n * Confirm hook — called before any destructive work. Returning `false`\n * aborts the delete silently; rejecting is treated the same as the caller's\n * `onDelete` rejecting (error message surfaced in the dialog).\n */\n onDeleteConfirm?: (item: TItem) => Promise<boolean> | boolean\n /**\n * Destructive work hook — consumer-side deletion (e.g. API call). If it\n * throws, the error is surfaced in the dialog and the local state is not\n * mutated.\n */\n onDelete?: (item: TItem) => Promise<void> | void\n /**\n * Called once the delete has succeeded end-to-end. The consumer performs\n * the editor mutation + clears component-local state here (editingKeys,\n * editingSnapshots, expanded flags, etc.). Keeping this step outside the\n * composable is deliberate — it lets each editor variant own its\n * per-component state shape without leaking it into the shared code.\n */\n onDeleted: (item: ViewItem) => void\n /**\n * Runs at click time. When true, the confirmation dialog is skipped and\n * delete proceeds immediately. Lets callers bypass the dialog for\n * specific modes (e.g. chips) without threading a prop through.\n */\n disableDeleteConfirm: () => boolean\n}\n\nexport interface UseDeleteDialogApi<ViewItem> {\n deleteDialog: Ref<boolean>\n deleteTarget: Ref<ViewItem | null>\n deleteInFlight: Ref<boolean>\n deleteError: Ref<string | null>\n performDelete: (vi: ViewItem) => Promise<boolean>\n onDeleteClick: (vi: ViewItem) => Promise<void>\n onDeleteDialogConfirm: () => Promise<void>\n onDeleteDialogCancel: () => void\n}\n\n/**\n * Delete-flow state + handlers shared across list-editor variants. Owns the\n * dialog boolean, the target row, the in-flight flag and the error string;\n * dispatches to the caller's confirm/delete/deleted hooks in the right order.\n *\n * Pure behaviour — no template, no editor dependency. The dialog markup\n * stays in each component (it references component-local slots and refs).\n */\nexport function useDeleteDialog<\n TItem extends Record<string, any>,\n ViewItem extends { key: string | number; raw: TItem },\n>(options: UseDeleteDialogOptions<TItem, ViewItem>): UseDeleteDialogApi<ViewItem> {\n const deleteDialog = ref(false)\n const deleteTarget = ref<ViewItem | null>(null) as Ref<ViewItem | null>\n const deleteInFlight = ref(false)\n const deleteError = ref<string | null>(null)\n\n const performDelete = async (vi: ViewItem): Promise<boolean> => {\n deleteError.value = null\n if (options.onDeleteConfirm) {\n const ok = await options.onDeleteConfirm(vi.raw)\n if (!ok) return false\n }\n if (options.onDelete) {\n deleteInFlight.value = true\n try {\n await options.onDelete(vi.raw)\n } catch (err) {\n deleteInFlight.value = false\n deleteError.value = err instanceof Error ? err.message : String(err)\n return false\n }\n deleteInFlight.value = false\n }\n options.onDeleted(vi)\n return true\n }\n\n const onDeleteClick = async (vi: ViewItem) => {\n if (options.disableDeleteConfirm()) {\n await performDelete(vi)\n return\n }\n deleteTarget.value = vi\n deleteError.value = null\n deleteDialog.value = true\n }\n\n const onDeleteDialogConfirm = async () => {\n if (!deleteTarget.value) return\n const ok = await performDelete(deleteTarget.value as ViewItem)\n if (ok) {\n deleteDialog.value = false\n deleteTarget.value = null\n }\n }\n\n const onDeleteDialogCancel = () => {\n if (deleteInFlight.value) return\n deleteDialog.value = false\n deleteTarget.value = null\n deleteError.value = null\n }\n\n return {\n deleteDialog,\n deleteTarget,\n deleteInFlight,\n deleteError,\n performDelete,\n onDeleteClick,\n onDeleteDialogConfirm,\n onDeleteDialogCancel,\n }\n}\n","import { nextTick, ref, watch, type ComputedRef, type Ref } from 'vue'\nimport { cloneDeep } from '@/utils/common'\nimport type { ListEditorKey } from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface UseInlineEditingOptions<TItem> {\n /** Scrolling container; scopes the auto-scroll `querySelector` to this instance. */\n rowsContainer: Ref<HTMLElement | null>\n /** Per-row selector to scroll into view (flat `.a-le-row`, nested `.a-le-row-wrapper`); needs a `[data-id]`. */\n rowSelector: string\n /** When false, auto-open-on-add is a no-op (e.g. chips mode, or no `#item` slot). */\n isInlineEdit: ComputedRef<boolean>\n /** Revert callback — the flat/nested `updateItem` signatures differ, so the consumer applies the snapshot. */\n restoreSnapshot: (key: ListEditorKey, data: TItem) => void\n /** Watch source: keys the auto-open reacts to (flat maps modelValue, nested walks the tree). */\n watchKeys: () => ListEditorKey[]\n /** Resolve raw data for a key to snapshot before editing; `null` aborts the auto-open. */\n findEntry: (key: ListEditorKey) => { data: TItem } | null\n /** Nested-only: expand ancestors so the auto-opened row is visible. */\n afterAutoOpen?: (key: ListEditorKey) => void\n}\n\nexport interface UseInlineEditingApi<TItem, ViewItem> {\n editingKeys: Ref<Set<ListEditorKey>>\n editingSnapshots: Ref<Map<ListEditorKey, TItem>>\n pendingAutoOpen: Ref<boolean>\n clearEditing: () => void\n beginEdit: (vi: ViewItem) => void\n cancelEdit: (vi: ViewItem) => void\n commitEdit: (vi: ViewItem) => void\n closeEdit: (vi: ViewItem) => void\n requestAutoOpen: () => void\n}\n\n/**\n * Inline-edit lifecycle shared across list-editor variants: the editing-key\n * set, per-key revert snapshots, and the auto-open + scroll-into-view of a\n * newly appended row. Agnostic of the editor composable via `restoreSnapshot`.\n */\nexport function useInlineEditing<\n TItem extends Record<string, any>,\n ViewItem extends { key: ListEditorKey; raw: TItem },\n>(options: UseInlineEditingOptions<TItem>): UseInlineEditingApi<TItem, ViewItem> {\n const editingKeys = ref<Set<ListEditorKey>>(new Set())\n const editingSnapshots = ref(new Map<ListEditorKey, TItem>()) as Ref<Map<ListEditorKey, TItem>>\n const pendingAutoOpen = ref(false)\n\n const clearEditing = () => {\n editingKeys.value.clear()\n editingSnapshots.value.clear()\n }\n\n const beginEdit = (vi: ViewItem) => {\n if (!editingSnapshots.value.has(vi.key)) {\n editingSnapshots.value.set(vi.key, cloneDeep(vi.raw) as TItem)\n }\n editingKeys.value.add(vi.key)\n }\n\n const cancelEdit = (vi: ViewItem) => {\n const snap = editingSnapshots.value.get(vi.key)\n if (snap) {\n options.restoreSnapshot(vi.key, snap as TItem)\n }\n editingKeys.value.delete(vi.key)\n editingSnapshots.value.delete(vi.key)\n }\n\n const commitEdit = (vi: ViewItem) => {\n editingKeys.value.delete(vi.key)\n editingSnapshots.value.delete(vi.key)\n }\n\n const closeEdit = (vi: ViewItem) => {\n editingKeys.value.delete(vi.key)\n editingSnapshots.value.delete(vi.key)\n }\n\n const requestAutoOpen = () => {\n pendingAutoOpen.value = true\n }\n\n watch(options.watchKeys, (newKeys, oldKeys) => {\n if (!pendingAutoOpen.value) return\n pendingAutoOpen.value = false\n const oldSet = new Set(oldKeys ?? [])\n const addedKey = newKeys.find((k) => !oldSet.has(k))\n if (addedKey === undefined) return\n if (!options.isInlineEdit.value) return\n const entry = options.findEntry(addedKey)\n if (!entry) return\n if (!editingSnapshots.value.has(addedKey)) {\n editingSnapshots.value.set(addedKey, cloneDeep(entry.data) as TItem)\n }\n editingKeys.value.add(addedKey)\n options.afterAutoOpen?.(addedKey)\n // Double nextTick so the inline-edit body has rendered before we scroll;\n // `block: 'center'` since `'nearest'` no-ops on partially-visible rows.\n nextTick(() => {\n nextTick(() => {\n const el = options.rowsContainer.value?.querySelector<HTMLElement>(\n `${options.rowSelector}[data-id=\"${CSS.escape(String(addedKey))}\"]`\n )\n el?.scrollIntoView({ block: 'center', behavior: 'smooth' })\n })\n })\n })\n\n return {\n editingKeys,\n editingSnapshots,\n pendingAutoOpen,\n clearEditing,\n beginEdit,\n cancelEdit,\n commitEdit,\n closeEdit,\n requestAutoOpen,\n }\n}\n","import type { ListEditorKey } from '@/labs/listEditor/types/listEditorTypes'\n\n/**\n * Runs `validateAll()` and, on failure, opens each invalid row via `reveal()`\n * so a blocked save shows WHICH rows are wrong (QA 85050 B4-17). Shared by all\n * variants; `reveal` does the per-variant opening (nested also expands ancestors).\n */\nexport function validateAllAndReveal(\n controller: { validateAll: () => boolean; invalidKeys: { value: Set<ListEditorKey> } },\n reveal: (key: ListEditorKey) => void\n): boolean {\n const valid = controller.validateAll()\n if (!valid) {\n for (const key of controller.invalidKeys.value) reveal(key)\n }\n return valid\n}\n","import { watch, type ComputedRef } from 'vue'\nimport useVuelidate from '@vuelidate/core'\nimport type { ListEditorValidationScope } from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface UseListEditorScopeValidityOptions {\n /**\n * The editor's aggregate validity — the controller's `hasErrors`, a computed over ALL raw rows\n * via the `:validate` predicate (so it reflects collapsed/unmounted rows too).\n */\n hasErrors: ComputedRef<boolean>\n /**\n * The consumer's vuelidate `$scope`. `undefined` = not wired (no-op, legacy behavior);\n * `false` = explicit opt-out (the save flow calls the editor `validateAll()` itself).\n */\n validationScope: ListEditorValidationScope | false | undefined\n /**\n * Reveal every invalid row (open it + show the red rail) — pass the editor's own\n * `validateAllAndReveal` routine so nested editors also expand ancestors.\n */\n reveal: () => void\n /**\n * Whether the editor got a `:validate` predicate. `hasErrors` is driven solely by it\n * (row-form vuelidate feeds a separate display registry, not `hasErrors`), so a scope\n * wired WITHOUT `:validate` yields `hasErrors === false` forever — a silently-dead gate.\n * Passed so this composable can warn (dev) instead of failing open.\n */\n validateProvided: boolean\n}\n\n/**\n * Bridges the editor's aggregate row validity into the consumer's vuelidate scope collector, so a\n * plain `v$.value.$touch(); if (v$.value.$invalid) return` save gate BLOCKS (and reveals) even a\n * COLLAPSED invalid row — whose own row-form vuelidate has unmounted and deregistered.\n *\n * The editor is always mounted and `hasErrors` scans all raw rows, so the collector sees rows\n * regardless of expand state. `$invalid` reflects validity immediately (no touch needed → the save\n * blocks synchronously); the `$dirty` watch mirrors the collector's `$touch()` to open the offenders.\n *\n * Opt-in: a no-op unless `validationScope` is a real scope, so an editor without the prop behaves\n * exactly as before.\n */\nexport function useListEditorScopeValidity(options: UseListEditorScopeValidityOptions): void {\n const { hasErrors, validationScope, reveal, validateProvided } = options\n if (validationScope === undefined || validationScope === false) return\n\n // `true` = vuelidate's GLOBAL scope. A globally-scoped child is NOT collected by a parent that\n // uses a NAMED ($scope: Symbol) collector — so under the typical named save gate the bridge is\n // silently dropped. Warn: the consumer almost always wants their collector's exact scope value.\n if (validationScope === true) {\n console.warn(\n '[list-editor] `:validation-scope=\"true\"` uses vuelidate’s GLOBAL scope. If your save gate ' +\n 'collects a NAMED scope (useVuelidate({ $scope: someSymbol })), this editor’s validity is ' +\n 'NOT collected by it and the gate won’t block. Pass the SAME scope value your collector uses.'\n )\n }\n\n // A scope with no `:validate` bridges an always-false `hasErrors` — the gate never blocks. Warn\n // (dev) so the misconfiguration is visible instead of silently letting invalid rows through save.\n if (!validateProvided) {\n console.warn(\n '[list-editor] `:validation-scope` is set but `:validate` is missing. The scope save-gate ' +\n 'bridges the editor’s aggregate `hasErrors`, which is driven only by `:validate`; without ' +\n 'it the gate never blocks (hasErrors stays false). Pass `:validate` so collapsed/invalid ' +\n 'rows block the consumer save, or drop `:validation-scope` if you gate validity yourself.'\n )\n }\n\n // One editor-level child registered under the consumer's scope. The validator reads `hasErrors`\n // reactively (vuelidate's sync `$invalid` is a computed that runs it), so the collector's\n // `$invalid` tracks it. State is `hasErrors` only to give the field a (reactive) value.\n const v$ = useVuelidate(\n { listEditor: { valid: () => !hasErrors.value } },\n { listEditor: hasErrors },\n { $scope: validationScope }\n )\n\n // On save the consumer's collector `$touch()` propagates to this child (`$dirty` → true); mirror\n // the editor's `validateAll()` reveal so the blocked save opens WHICH rows are wrong.\n watch(\n () => v$.value.$dirty,\n (dirty) => {\n if (dirty && hasErrors.value) reveal()\n }\n )\n}\n","import { computed, ref, watch, type ComputedRef, type InjectionKey, type Ref } from 'vue'\nimport type { ListEditorKey } from '@/labs/listEditor/types/listEditorTypes'\n\n// Registry that lets embedded inner editors push their reorder pending-count\n// up to the nearest non-embedded outer editor. The outer's reorder toolbar\n// status (\"N pending changes\") then reflects child moves too — so toggling\n// the order of an answer inside a question increments the outer's counter\n// just like a question move would.\nexport interface SharedReorderRegistry {\n register: (\n id: symbol,\n movedCount: ComputedRef<number>,\n hasPendingChanges: ComputedRef<boolean>,\n validateAll: () => boolean\n ) => void\n unregister: (id: symbol) => void\n}\n\nexport const SharedReorderRegistryKey = Symbol('le.sharedReorderRegistry') as InjectionKey<SharedReorderRegistry>\n\nexport type ReorderModeValue = 'view' | 'reorder'\n\nexport interface UseReorderModeEmit<T> {\n reorderStart: () => void\n reorderCancel: () => void\n reorderApplied: (payload: T) => void\n reorderApplyError: (err: unknown) => void\n reorderEnd: () => void\n}\n\nexport interface UseReorderModeOptions<T> {\n /**\n * v-model-backed mode ref — the composable reads + writes, but the\n * component owns the `defineModel('mode', ...)` so external\n * `v-model:mode` bindings still flow. Passing the ref in avoids\n * duplicating the defineModel contract inside the composable.\n */\n mode: Ref<ReorderModeValue>\n /**\n * Reorder snapshot — cloned on enter, restored on cancel, cleared on\n * apply. Stays at component level (the dirty-baseline needs to read it\n * indirectly too), but the composable owns every assignment.\n */\n snapshot: Ref<T | null>\n /**\n * Keys the user has actively moved this session (drag, arrow buttons,\n * indent/outdent). Cleared on every mode transition. Stays at component\n * level because the per-row decorator reads it for the `moved` flag.\n */\n movedKeys: Ref<Set<ListEditorKey>>\n modelValue: Ref<T>\n /**\n * Deep-clone the model value for snapshotting. Caller-provided because\n * the nested tree shape and flat array shape need different serializer\n * handling (both use `cloneDeep` in practice, but the callsite already\n * imports it).\n */\n cloneModel: (m: T) => T\n applyModel: (m: T) => void\n canEnterReorder: ComputedRef<boolean>\n /**\n * Hook run after mode flips to `reorder` but before emit — nested uses\n * this to expand every branch + init sortable instances, flat uses it\n * (via nothing — the sortable initialises lazily via a watch in the\n * flat variant). Left optional.\n */\n onEnter?: () => void\n /**\n * Hook run after mode flips back to `view` on cancel — nested destroys\n * its sortable instances here. Flat doesn't need it.\n */\n onCancel?: () => void\n /**\n * Hook run after apply succeeds — nested destroys its sortable instances\n * here. Flat doesn't need it.\n */\n onApplyEnd?: () => void\n /**\n * Called from the mode watcher when mode flips externally from `view` to\n * `reorder` (e.g. v-model:mode bound by the parent) — each variant uses\n * this to clear variant-specific caches that `enterReorderMode` itself\n * also clears via its own call-site. The flat variant clears editing +\n * expanded; nested clears editing only (children-expanded stays).\n */\n onExternalEnter?: () => void\n /**\n * Called from the mode watcher when an EMBEDDED editor flips externally from\n * `reorder` back to `view` (its parent's Cancel or Apply). Embedded editors\n * have no own snapshot/apply/cancel, so this is their only exit hook — the\n * flat variant uses it to reconcile immediate (backend) deletes made during\n * the session: on a parent Cancel the parent's snapshot restore resurrects\n * the deleted row, which must be re-removed; on Apply it stayed gone (no-op).\n */\n onEmbeddedExit?: () => void\n /**\n * Async persist callback wired from the parent — identical semantics to\n * the old `props.onReorderApply`. Receives the cloned payload (array for\n * flat, tree for nested); throwing surfaces the error in the header\n * toolbar via `applyError`.\n */\n onReorderApply?: (payload: T) => Promise<void> | void\n /**\n * Optional override for the payload passed to `onReorderApply` + the\n * `reorder-applied` emit — defaults to `cloneModel(modelValue)`. Exists\n * so consumers could send a different shape than their stored snapshot\n * if the need arises; both current callers use the default.\n */\n clonePayload?: (m: T) => T\n /**\n * Embedded mode — the editor follows external mode changes but does NOT\n * own a snapshot or apply/cancel logic. The parent (a non-embedded outer\n * editor) takes a deep snapshot covering this editor's data too, so cancel\n * at the top restores everything. Used for the \"shared reorder\" pattern\n * where a single Reorder button drives multiple stacked editors.\n */\n embedded?: ComputedRef<boolean> | Ref<boolean>\n emit: UseReorderModeEmit<T>\n}\n\nexport interface UseReorderModeApi {\n applying: Ref<boolean>\n applyError: Ref<string | null>\n hasPendingChanges: ComputedRef<boolean>\n movedCount: ComputedRef<number>\n reorderMode: ComputedRef<boolean>\n enterReorderMode: () => void\n cancelReorderMode: () => void\n applyReorder: () => Promise<void>\n}\n\n/**\n * Reorder-mode state machine shared between ASortableListEditor and\n * ANestedSortableListEditor. Owns the `applying` + `applyError` flags, the\n * pending-changes counters, and the enter / cancel / apply transitions —\n * plus the mode watcher that fires when the v-model:mode flips externally.\n *\n * The snapshot and `movedKeys` sets stay at component level because the\n * per-row decorator + dirty-baseline read them directly; the composable\n * takes them as refs so it can still drive the state machine.\n */\nexport function useReorderMode<T>(options: UseReorderModeOptions<T>): UseReorderModeApi {\n const applying = ref(false)\n const applyError = ref<string | null>(null)\n\n const reorderMode = computed(() => options.mode.value === 'reorder')\n const movedCount = computed(() => options.movedKeys.value.size)\n const hasPendingChanges = computed(() => movedCount.value > 0)\n\n const clonePayload = (): T =>\n options.clonePayload ? options.clonePayload(options.modelValue.value) : options.cloneModel(options.modelValue.value)\n\n const isEmbedded = (): boolean => options.embedded?.value === true\n\n const enterReorderMode = () => {\n if (!options.canEnterReorder.value || reorderMode.value) return\n if (!isEmbedded()) {\n options.snapshot.value = options.cloneModel(options.modelValue.value)\n }\n options.movedKeys.value = new Set()\n applyError.value = null\n options.mode.value = 'reorder'\n options.onEnter?.()\n options.emit.reorderStart()\n }\n\n const cancelReorderMode = () => {\n if (!reorderMode.value) return\n if (!isEmbedded() && options.snapshot.value) {\n options.applyModel(options.snapshot.value as T)\n }\n options.snapshot.value = null\n options.movedKeys.value = new Set()\n applyError.value = null\n applying.value = false\n options.mode.value = 'view'\n options.onCancel?.()\n options.emit.reorderCancel()\n options.emit.reorderEnd()\n }\n\n const applyReorder = async () => {\n if (!reorderMode.value) return\n const payload = clonePayload()\n applyError.value = null\n if (!isEmbedded() && options.onReorderApply) {\n applying.value = true\n try {\n await options.onReorderApply(payload)\n } catch (err) {\n applying.value = false\n applyError.value = err instanceof Error ? err.message : String(err)\n options.emit.reorderApplyError(err)\n return\n }\n applying.value = false\n }\n // Deliberately keep `movedKeys` populated — consumer still has to persist\n // the new order via their own API call before rows are truly \"saved\"; we\n // let them clear the state manually via `resetDirtyBaseline` on success.\n options.snapshot.value = null\n options.mode.value = 'view'\n options.onApplyEnd?.()\n options.emit.reorderApplied(payload)\n options.emit.reorderEnd()\n }\n\n // Handle external mode flips (v-model:mode from a parent) — mirror the\n // same bookkeeping enterReorderMode / cancelReorderMode do so the state\n // stays consistent whether the transition came from a button click or a\n // parent binding. Embedded editors do NOT take a snapshot; their parent\n // (the outer non-embedded editor) owns one that covers nested data too.\n //\n // The view→reorder→view cleanup path differs between embedded and\n // non-embedded:\n // - non-embedded cancel: snapshot is set → clear state here\n // - non-embedded apply: applyReorder nulls snapshot BEFORE flipping\n // mode, so the snapshot-guarded branch is skipped → movedKeys stays\n // populated until consumer calls resetDirtyBaseline (the contract)\n // - embedded: no snapshot ever, clear state on every view transition\n // so the inner editor's movedKeys doesn't outlive a parent\n // cancel/apply (otherwise rows would render as `unsaved` after the\n // parent restores the original data)\n watch(options.mode, (newMode, oldMode) => {\n if (newMode === 'reorder' && oldMode !== 'reorder') {\n if (!isEmbedded() && !options.snapshot.value) {\n options.snapshot.value = options.cloneModel(options.modelValue.value)\n }\n options.movedKeys.value = new Set()\n options.onExternalEnter?.()\n }\n if (newMode === 'view' && oldMode === 'reorder') {\n if (options.snapshot.value) {\n options.snapshot.value = null\n options.movedKeys.value = new Set()\n applyError.value = null\n applying.value = false\n } else if (isEmbedded()) {\n options.movedKeys.value = new Set()\n applyError.value = null\n applying.value = false\n // Reconcile session immediate (backend) deletes: the parent has already flushed both props, so\n // the model reflects a Cancel's snapshot-restore (deleted row resurrected → re-remove) or an\n // Apply (row stayed gone → the re-remove is a no-op). Deferred deletes need nothing here.\n options.onEmbeddedExit?.()\n }\n }\n })\n\n return {\n applying,\n applyError,\n hasPendingChanges,\n movedCount,\n reorderMode,\n enterReorderMode,\n cancelReorderMode,\n applyReorder,\n }\n}\n","<script setup lang=\"ts\">\n// Shared delete-confirmation dialog used by all three list-editor variants.\n// The outer editors keep their own dialog-related state (open flag, in-flight,\n// error message) and supply i18n-resolved title / text / button labels — this\n// component is pure presentation plus confirm/cancel emits.\n\nexport interface Props {\n title: string\n text: string\n confirmLabel?: string\n cancelLabel?: string\n error?: string | null\n inFlight?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n confirmLabel: 'Delete',\n cancelLabel: 'Cancel',\n error: null,\n inFlight: false,\n})\n\ndefineEmits<{\n confirm: []\n cancel: []\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"420\"\n :persistent=\"inFlight\"\n >\n <VCard>\n <VCardTitle class=\"text-headline-small\">\n {{ title }}\n </VCardTitle>\n <VCardText>\n {{ text }}\n <VAlert\n v-if=\"error\"\n type=\"error\"\n variant=\"tonal\"\n density=\"compact\"\n class=\"mt-3\"\n >\n {{ error }}\n </VAlert>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n :disabled=\"inFlight\"\n @click=\"$emit('cancel')\"\n >\n {{ cancelLabel }}\n </VBtn>\n <VBtn\n color=\"error\"\n variant=\"flat\"\n :loading=\"inFlight\"\n :disabled=\"inFlight\"\n @click=\"$emit('confirm')\"\n >\n {{ confirmLabel }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n","<script setup lang=\"ts\">\n// Shared delete-confirmation dialog used by all three list-editor variants.\n// The outer editors keep their own dialog-related state (open flag, in-flight,\n// error message) and supply i18n-resolved title / text / button labels — this\n// component is pure presentation plus confirm/cancel emits.\n\nexport interface Props {\n title: string\n text: string\n confirmLabel?: string\n cancelLabel?: string\n error?: string | null\n inFlight?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n confirmLabel: 'Delete',\n cancelLabel: 'Cancel',\n error: null,\n inFlight: false,\n})\n\ndefineEmits<{\n confirm: []\n cancel: []\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"420\"\n :persistent=\"inFlight\"\n >\n <VCard>\n <VCardTitle class=\"text-headline-small\">\n {{ title }}\n </VCardTitle>\n <VCardText>\n {{ text }}\n <VAlert\n v-if=\"error\"\n type=\"error\"\n variant=\"tonal\"\n density=\"compact\"\n class=\"mt-3\"\n >\n {{ error }}\n </VAlert>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n :disabled=\"inFlight\"\n @click=\"$emit('cancel')\"\n >\n {{ cancelLabel }}\n </VBtn>\n <VBtn\n color=\"error\"\n variant=\"flat\"\n :loading=\"inFlight\"\n :disabled=\"inFlight\"\n @click=\"$emit('confirm')\"\n >\n {{ confirmLabel }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n total: number\n currentIndex: number\n itemLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n itemLabel: undefined,\n})\n\nconst emit = defineEmits<{\n confirm: [newIndex: number]\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n\nconst { t } = useI18n()\n\n// `currentIndex` is read once at setup to seed the field; subsequent changes\n// to the prop don't reset the user's typed-in value mid-edit, only re-opening\n// the dialog (via the `open` watcher below) does.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst targetPosition = ref<number>(props.currentIndex + 1)\n\nwatch(open, (now) => {\n if (now) targetPosition.value = props.currentIndex + 1\n})\n\nconst totalLabel = computed(() => Math.max(props.total, 1))\nconst isInvalid = computed<boolean>(\n () => !Number.isFinite(targetPosition.value) || targetPosition.value < 1 || targetPosition.value > totalLabel.value\n)\n\nconst onConfirm = () => {\n if (isInvalid.value) return\n const newIndex = Math.max(0, Math.min(props.total - 1, targetPosition.value - 1))\n emit('confirm', newIndex)\n open.value = false\n}\n\nconst onCancel = () => {\n open.value = false\n}\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"420\"\n persistent\n >\n <VCard>\n <VCardTitle>\n {{ t('common.sortable.moveToPosition.title') }}\n </VCardTitle>\n\n <VCardText>\n <p\n v-if=\"itemLabel\"\n class=\"text-body-medium mb-3\"\n >\n {{ t('common.sortable.moveToPosition.itemDescription', { label: itemLabel }) }}\n </p>\n <VTextField\n v-model.number=\"targetPosition\"\n type=\"number\"\n :min=\"1\"\n :max=\"totalLabel\"\n :label=\"t('common.sortable.moveToPosition.positionLabel', { max: totalLabel })\"\n :hint=\"\n t('common.sortable.moveToPosition.positionHint', {\n current: currentIndex + 1,\n max: totalLabel,\n })\n \"\n :error=\"isInvalid\"\n autofocus\n density=\"comfortable\"\n variant=\"outlined\"\n @keydown.enter.prevent=\"onConfirm\"\n />\n </VCardText>\n\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n @click=\"onCancel\"\n >\n {{ t('common.sortable.reorderCancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"elevated\"\n :disabled=\"isInvalid\"\n @click=\"onConfirm\"\n >\n {{ t('common.sortable.moveToPosition.confirm') }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n total: number\n currentIndex: number\n itemLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n itemLabel: undefined,\n})\n\nconst emit = defineEmits<{\n confirm: [newIndex: number]\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n\nconst { t } = useI18n()\n\n// `currentIndex` is read once at setup to seed the field; subsequent changes\n// to the prop don't reset the user's typed-in value mid-edit, only re-opening\n// the dialog (via the `open` watcher below) does.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst targetPosition = ref<number>(props.currentIndex + 1)\n\nwatch(open, (now) => {\n if (now) targetPosition.value = props.currentIndex + 1\n})\n\nconst totalLabel = computed(() => Math.max(props.total, 1))\nconst isInvalid = computed<boolean>(\n () => !Number.isFinite(targetPosition.value) || targetPosition.value < 1 || targetPosition.value > totalLabel.value\n)\n\nconst onConfirm = () => {\n if (isInvalid.value) return\n const newIndex = Math.max(0, Math.min(props.total - 1, targetPosition.value - 1))\n emit('confirm', newIndex)\n open.value = false\n}\n\nconst onCancel = () => {\n open.value = false\n}\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"420\"\n persistent\n >\n <VCard>\n <VCardTitle>\n {{ t('common.sortable.moveToPosition.title') }}\n </VCardTitle>\n\n <VCardText>\n <p\n v-if=\"itemLabel\"\n class=\"text-body-medium mb-3\"\n >\n {{ t('common.sortable.moveToPosition.itemDescription', { label: itemLabel }) }}\n </p>\n <VTextField\n v-model.number=\"targetPosition\"\n type=\"number\"\n :min=\"1\"\n :max=\"totalLabel\"\n :label=\"t('common.sortable.moveToPosition.positionLabel', { max: totalLabel })\"\n :hint=\"\n t('common.sortable.moveToPosition.positionHint', {\n current: currentIndex + 1,\n max: totalLabel,\n })\n \"\n :error=\"isInvalid\"\n autofocus\n density=\"comfortable\"\n variant=\"outlined\"\n @keydown.enter.prevent=\"onConfirm\"\n />\n </VCardText>\n\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n @click=\"onCancel\"\n >\n {{ t('common.sortable.reorderCancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"elevated\"\n :disabled=\"isInvalid\"\n @click=\"onConfirm\"\n >\n {{ t('common.sortable.moveToPosition.confirm') }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n title: string\n addLabel?: string | null\n canAdd?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n addLabel: null,\n canAdd: false,\n})\n\ndefineEmits<{\n add: []\n}>()\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-le-empty\">\n <h3 class=\"a-le-empty-title\">\n {{ title }}\n </h3>\n <VBtn\n v-if=\"addLabel && canAdd\"\n color=\"primary\"\n variant=\"flat\"\n prepend-icon=\"mdi-plus\"\n @click=\"$emit('add')\"\n >\n {{ addLabel || t('common.sortable.addFirst') }}\n </VBtn>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n title: string\n addLabel?: string | null\n canAdd?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n addLabel: null,\n canAdd: false,\n})\n\ndefineEmits<{\n add: []\n}>()\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-le-empty\">\n <h3 class=\"a-le-empty-title\">\n {{ title }}\n </h3>\n <VBtn\n v-if=\"addLabel && canAdd\"\n color=\"primary\"\n variant=\"flat\"\n prepend-icon=\"mdi-plus\"\n @click=\"$emit('add')\"\n >\n {{ addLabel || t('common.sortable.addFirst') }}\n </VBtn>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\n// Reorder-mode header status pill. Emits `.a-le-toolbar-status` on its root,\n// caller adds the `--pending` modifier via class binding. inheritAttrs stays\n// default so additional classes (e.g. the --pending modifier) stick to the\n// root div.\n\nexport interface Props {\n hasPendingChanges: boolean\n pendingCount: number\n error?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n error: null,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-le-toolbar-status\">\n <VIcon\n v-if=\"hasPendingChanges\"\n icon=\"mdi-circle-medium\"\n color=\"warning\"\n size=\"18\"\n />\n <span\n v-if=\"error\"\n class=\"text-body-small\"\n >\n {{ error }}\n </span>\n <span\n v-else-if=\"hasPendingChanges\"\n class=\"text-body-small\"\n >\n {{ t('common.sortable.pendingChanges', { count: pendingCount }) }}\n </span>\n <span\n v-else\n class=\"text-body-small text-medium-emphasis\"\n >\n {{ t('common.sortable.noPendingChanges') }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\n// Reorder-mode header status pill. Emits `.a-le-toolbar-status` on its root,\n// caller adds the `--pending` modifier via class binding. inheritAttrs stays\n// default so additional classes (e.g. the --pending modifier) stick to the\n// root div.\n\nexport interface Props {\n hasPendingChanges: boolean\n pendingCount: number\n error?: string | null\n}\n\nwithDefaults(defineProps<Props>(), {\n error: null,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <div class=\"a-le-toolbar-status\">\n <VIcon\n v-if=\"hasPendingChanges\"\n icon=\"mdi-circle-medium\"\n color=\"warning\"\n size=\"18\"\n />\n <span\n v-if=\"error\"\n class=\"text-body-small\"\n >\n {{ error }}\n </span>\n <span\n v-else-if=\"hasPendingChanges\"\n class=\"text-body-small\"\n >\n {{ t('common.sortable.pendingChanges', { count: pendingCount }) }}\n </span>\n <span\n v-else\n class=\"text-body-small text-medium-emphasis\"\n >\n {{ t('common.sortable.noPendingChanges') }}\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\n// Small \"unsaved\" pill (warning dot + translated label). Emits the shared\n// `.a-le-unsaved-label` class directly — the flat `.a-le-*` namespace means\n// every variant shares the same selector, no per-variant BEM prefix needed.\n// `dotOnly` (chips mode) drops the label, leaving just the inline warning dot;\n// the label is kept as a native title tooltip so the marker stays meaningful.\n\nexport interface Props {\n label?: string | null\n dotOnly?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n label: null,\n dotOnly: false,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <span\n class=\"a-le-unsaved-label\"\n :class=\"{ 'a-le-unsaved-label--dot': dotOnly }\"\n :title=\"dotOnly ? (label ?? t('common.sortable.unsaved')) : undefined\"\n >\n <VIcon\n icon=\"mdi-circle-medium\"\n size=\"12\"\n />\n <template v-if=\"!dotOnly\">\n {{ label ?? t('common.sortable.unsaved') }}\n </template>\n </span>\n</template>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\n// Small \"unsaved\" pill (warning dot + translated label). Emits the shared\n// `.a-le-unsaved-label` class directly — the flat `.a-le-*` namespace means\n// every variant shares the same selector, no per-variant BEM prefix needed.\n// `dotOnly` (chips mode) drops the label, leaving just the inline warning dot;\n// the label is kept as a native title tooltip so the marker stays meaningful.\n\nexport interface Props {\n label?: string | null\n dotOnly?: boolean\n}\n\nwithDefaults(defineProps<Props>(), {\n label: null,\n dotOnly: false,\n})\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <span\n class=\"a-le-unsaved-label\"\n :class=\"{ 'a-le-unsaved-label--dot': dotOnly }\"\n :title=\"dotOnly ? (label ?? t('common.sortable.unsaved')) : undefined\"\n >\n <VIcon\n icon=\"mdi-circle-medium\"\n size=\"12\"\n />\n <template v-if=\"!dotOnly\">\n {{ label ?? t('common.sortable.unsaved') }}\n </template>\n </span>\n</template>\n","<script setup lang=\"ts\">\n// Drag-handle icon. Emits the shared `.a-le-drag-handle` class so SortableJS\n// `handle` selectors ('.a-le-drag-handle') match across every variant.\n</script>\n\n<template>\n <VIcon\n class=\"a-le-drag-handle\"\n icon=\"mdi-drag\"\n size=\"20\"\n />\n</template>\n","<script setup lang=\"ts\">\n// Drag-handle icon. Emits the shared `.a-le-drag-handle` class so SortableJS\n// `handle` selectors ('.a-le-drag-handle') match across every variant.\n</script>\n\n<template>\n <VIcon\n class=\"a-le-drag-handle\"\n icon=\"mdi-drag\"\n size=\"20\"\n />\n</template>\n","// Shared internal constants for the list-editor variants.\n// Class names are referenced both as SortableJS option strings and as CSS\n// selectors in `_shared.scss`; centralising them avoids the typo risk that\n// comes with the same string literal living in 2+ places.\n\nexport const DRAG_GHOST_CLASS = 'a-le-row--ghost'\nexport const DRAG_CHOSEN_CLASS = 'a-le-row--chosen'\nexport const DRAG_CLASS = 'a-le-row--drag'\n","<script setup lang=\"ts\" generic=\"TItem extends Record<string, any>\">\nimport {\n nextTick,\n computed,\n inject,\n onBeforeUnmount,\n provide,\n ref,\n shallowReactive,\n shallowRef,\n useSlots,\n useTemplateRef,\n watch,\n type ComputedRef,\n} from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useContainerWidth } from '@/labs/listEditor/composables/useContainerWidth'\nimport { useHasCoarsePointer, useIsTouchDevice } from '@/labs/listEditor/composables/useIsTouchDevice'\nimport { useKeyboardNav } from '@/labs/listEditor/composables/useKeyboardNav'\nimport { useSortable } from '@vueuse/integrations/useSortable'\nimport {\n useListEditorController,\n type GetKey,\n type ListEditorHandle,\n type ListEditorValidationResult,\n type PositionAction,\n type PositionOption,\n type PositionStrategy,\n} from '@/labs/listEditor/composables/useListEditorController'\nimport {\n provideListEditorStateScope,\n useListEditorStateEntry,\n type ListEditorStateBindings,\n} from '@/labs/listEditor/composables/useListEditorStateScope'\nimport { resolveCompactText as resolveCompactTextUtil } from '@/labs/listEditor/composables/resolveCompactText'\nimport { useUnsavedSection } from '@/labs/unsavedGuard/useUnsavedSection'\nimport { useDeleteDialog } from '@/labs/listEditor/composables/useDeleteDialog'\nimport { useInlineEditing } from '@/labs/listEditor/composables/useInlineEditing'\nimport { validateAllAndReveal } from '@/labs/listEditor/utils/revealInvalidRows'\nimport { useListEditorScopeValidity } from '@/labs/listEditor/composables/useListEditorScopeValidity'\nimport {\n useReorderMode,\n SharedReorderRegistryKey,\n type SharedReorderRegistry,\n} from '@/labs/listEditor/composables/useReorderMode'\nimport LeDeleteDialog from '@/labs/listEditor/internal/LeDeleteDialog.vue'\nimport LeMoveToPositionDialog from '@/labs/listEditor/internal/LeMoveToPositionDialog.vue'\nimport LeEmptyState from '@/labs/listEditor/internal/LeEmptyState.vue'\nimport LeStatus from '@/labs/listEditor/internal/LeStatus.vue'\nimport LeUnsavedLabel from '@/labs/listEditor/internal/LeUnsavedLabel.vue'\nimport LeDragHandle from '@/labs/listEditor/internal/LeDragHandle.vue'\nimport { DRAG_GHOST_CLASS, DRAG_CHOSEN_CLASS, DRAG_CLASS } from '@/labs/listEditor/internal/constants'\nimport { cloneDeep } from '@/utils/common'\nimport { stringToInt } from '@/utils/string'\nimport type {\n ListEditorKey,\n ListEditorValidationScope,\n ListEditorValidationState,\n ListViewItem,\n} from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface DecoratedViewItem<T> extends ListViewItem<T> {\n editing: boolean\n expanded: boolean\n loading: boolean\n dirty: boolean\n moved: boolean\n unsaved: boolean\n validationState: ListEditorValidationState\n canMoveUp: boolean\n canMoveDown: boolean\n}\n\nexport type ReorderMode = 'view' | 'reorder'\n\n// Public slot scope shapes — see AListEditor for the hoisting rationale.\nexport interface RowActions<TItem> {\n edit: () => void\n save: () => Promise<void> | void\n cancel: () => void\n close: () => void\n delete: () => Promise<void>\n addAfter: () => void\n toggleExpand: () => void\n moveUp: () => void\n moveDown: () => void\n moveTop: () => void\n moveBottom: () => void\n update: (next: TItem | Partial<TItem> | ((current: TItem) => TItem)) => void\n}\nexport interface RowSlotProps<TItem extends Record<string, any>> {\n item: DecoratedViewItem<TItem>\n raw: TItem\n index: number\n key: ListEditorKey\n readonly: boolean\n disabled: boolean\n expanded: boolean\n editing: boolean\n dirty: boolean\n unsaved: boolean\n reorderMode: boolean\n moved: boolean\n canMoveUp: boolean\n canMoveDown: boolean\n touch: boolean\n /**\n * Row-scoped `state-key` prefix. Thread it down to any list editor rendered in this slot and set\n * its `:state-key=\"`${stateKeyPrefix}:someList`\"` — that editor's controller then lives in THIS\n * editor's scope and survives the row collapsing (which unmounts the whole slot subtree). Entries\n * under this prefix are disposed when the row is removed.\n */\n stateKeyPrefix: string\n actions: RowActions<TItem>\n}\nexport interface ToolbarSlotProps {\n applying: boolean\n hasPendingChanges: boolean\n movedCount: number\n error: string | null\n actions: { apply: () => Promise<void>; cancel: () => void }\n}\nexport interface ReorderToggleSlotProps {\n mode: ReorderMode\n disabled: boolean\n hasPendingChanges: boolean\n actions: { enterReorderMode: () => void; exitReorderMode: () => void }\n}\nexport interface HeaderSlotProps extends ReorderToggleSlotProps {\n title: string | null\n}\nexport interface EmptySlotProps {\n readonly: boolean\n disabled: boolean\n actions: { add: () => void }\n}\nexport interface AddButtonSlotProps {\n readonly: boolean\n disabled: boolean\n props: { onClick: () => void }\n actions: { add: () => void }\n}\nexport interface ViewBodySlotProps<TItem extends Record<string, any>> {\n items: TItem[]\n mode: ReorderMode\n actions: { enterReorderMode: () => void }\n}\n\nexport interface Props<TItem extends Record<string, any>> {\n /**\n * New-row factory (required). The add button + \"add after this item\" insert\n * `factory()` into the model directly through the controller (positions\n * renumbered) — no consumer `@add` push handler is needed.\n */\n factory?: () => TItem\n /**\n * Stable row identity. Default `'id'`. Never point this at the position field.\n * Typed `string` (not `keyof TItem`): a bare `keyof TItem` on a generic\n * component compiles to a Boolean-only runtime type that coerces `get-key=\"id\"` to `true`.\n */\n getKey?: string | ((item: TItem) => ListEditorKey)\n /**\n * Managed order field. Default `'position'`. `false` opts out. Typed `string`\n * before `false` so the runtime prop type is `[String, Boolean, Object]`:\n * `keyof TItem` would be Boolean-only, and `false` listed first would coerce\n * `position=\"position\"` (value == prop name) to `true`.\n */\n position?:\n | string\n | false\n | {\n field: string\n multiplier?: number\n strategy?: PositionStrategy\n strategyOverrides?: Partial<Record<PositionAction, PositionStrategy>>\n }\n /**\n * Extra fields to drop from the dirty content-hash (position is always\n * dropped). Use when a SEPARATE nested editor tracks a row's child collection,\n * so editing a child doesn't flip the parent amber. The field is still saved.\n */\n dirtyExclude?: string[]\n /** Per-row validity — `true` (or `{ valid: true }`) = VALID. Drives the red rail + save guard. */\n validate?: (item: TItem) => ListEditorValidationResult\n /**\n * Vuelidate `$scope` (the same one the consumer's row forms / save-gate collector use). When set,\n * the editor registers its aggregate validity under it, so a plain `v$.$invalid` save gate blocks\n * AND reveals a collapsed invalid row — no `validateAll()` call needed in the save flow. Omit to\n * keep legacy behavior (gate the save on the exposed `validateAll()` yourself); `false` opts out.\n */\n validationScope?: ListEditorValidationScope | false\n /**\n * Opt-in lifted state controller (from consumer's `useListEditorController()`)\n * so editor state survives this component's unmount/remount (pinned-widget\n * relocation). When omitted the editor owns an internal controller.\n */\n editor?: ListEditorHandle<TItem>\n /**\n * Persist this editor's controller in the nearest ANCESTOR editor's row-state scope under this\n * key, instead of owning it. Use it for an editor rendered in another editor's `#item` slot: that\n * slot is behind a `v-if`, so collapsing the row unmounts this editor and a component-owned\n * controller would re-baseline the already-edited data on re-expand (losing amber, moved rows,\n * tombstones and the red rail). Derive the key from the row slot's `stateKeyPrefix`, e.g.\n * `:state-key=\"`${stateKeyPrefix}:answers`\"`. Options stay declared here, on this tag: the\n * controller is built from THIS editor's `factory`/`get-key`/`position`/`dirty-exclude`/`validate`\n * and rebound to each new instance's model on remount. Ignored when `:editor` is passed, and a\n * no-op without an ancestor scope.\n */\n stateKey?: string\n\n readonly?: boolean\n disabled?: boolean\n loading?: boolean\n error?: string | null\n\n /** Heading above the list. A ready translated string, like every text prop here. */\n title?: string | null\n\n /**\n * Field shown in a collapsed row when no `#item-compact` slot is given. A dotted path reads\n * through nested objects (`texts.title`); a path that runs into nothing renders empty.\n */\n compactField?: string | null\n statusField?: string | null\n twoRows?: 'never' | 'mobile' | 'always'\n chips?: boolean\n\n showAddButton?: boolean\n showDeleteButton?: boolean\n showEditButton?: boolean\n showAddAfterAction?: boolean\n\n /** Label of the add button. A ready translated string; omit it for the library's own wording. */\n addLabel?: string | null\n /** Heading of the empty state. A ready translated string. */\n emptyTitle?: string | null\n\n disableRowClick?: boolean\n disableDeleteConfirm?: boolean\n /**\n * Disable unsaved-state tracking — no dirty markers, never reads as unsaved. For a list that is a\n * VIEW of data owned elsewhere (a display cache rebuilt from a parent's field, say): nothing in\n * such a component can ever clear an amber row, so it must not raise one. Mirrors `AListEditor`.\n */\n disableUnsaved?: boolean\n deleteConfirmTitle?: string | null\n deleteConfirmText?: string | null\n /**\n * How a row delete persists. `deferred` (default): the row disappears but the deletion counts as an\n * unconfirmed change until save (revertible until then, incl. via reorder Cancel). `immediate`: the\n * consumer deletes on the backend — the dialog says it is irreversible and it does NOT read as unsaved.\n */\n deleteMode?: 'immediate' | 'deferred'\n\n closeVariant?: 'auto' | 'icon' | 'labeled'\n\n loadingKeys?: Set<ListEditorKey> | null\n\n showReorderToggle?: boolean\n disableReorder?: boolean\n disableDrag?: boolean\n showMoveToPosition?: boolean\n\n /**\n * Embedded mode — nested inside another editor's `#item` slot, following a\n * shared `v-model:mode`. Hides own Reorder button + toolbar, skips the\n * snapshot/restore (the outer editor's deep snapshot covers nested data), and\n * paints lighter chrome. Pair with `v-model:mode` bound to the outer ref.\n */\n embedded?: boolean\n /**\n * Keep rows inline-editable in reorder mode. By default entering reorder\n * closes any open edit and hides the `#item` body to focus on dragging. Set\n * for a shared-reorder pair's parent, where the open row exposes its embedded\n * answers list for dragging.\n */\n allowEditInReorder?: boolean\n\n onDeleteConfirm?: (item: TItem) => Promise<boolean> | boolean\n onDelete?: (item: TItem) => Promise<void> | void\n onItemSave?: (item: TItem) => Promise<void> | void\n onReorderApply?: (items: TItem[]) => Promise<void> | void\n\n /** Register as a named unsaved-changes section under this (translated) label. */\n unsavedSectionLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props<TItem>>(), {\n factory: undefined,\n getKey: undefined,\n position: undefined,\n dirtyExclude: undefined,\n validate: undefined,\n validationScope: undefined,\n editor: undefined,\n stateKey: undefined,\n readonly: false,\n disabled: false,\n loading: false,\n error: null,\n title: null,\n compactField: null,\n statusField: null,\n twoRows: 'never',\n chips: false,\n showAddButton: true,\n showDeleteButton: true,\n showEditButton: true,\n showAddAfterAction: false,\n addLabel: null,\n emptyTitle: null,\n disableRowClick: false,\n disableDeleteConfirm: false,\n disableUnsaved: false,\n deleteConfirmTitle: null,\n deleteConfirmText: null,\n deleteMode: 'deferred',\n closeVariant: 'auto',\n loadingKeys: null,\n showReorderToggle: true,\n disableReorder: false,\n disableDrag: false,\n showMoveToPosition: false,\n embedded: false,\n allowEditInReorder: false,\n onDeleteConfirm: undefined,\n onDelete: undefined,\n onItemSave: undefined,\n onReorderApply: undefined,\n unsavedSectionLabel: undefined,\n})\n\nconst emit = defineEmits<{\n edit: [item: ListViewItem<TItem>]\n deleted: [item: ListViewItem<TItem>]\n close: [item: ListViewItem<TItem>]\n 'item-saved': [item: ListViewItem<TItem>]\n 'item-expand': [item: ListViewItem<TItem>, expanded: boolean]\n 'reorder-start': []\n 'reorder-cancel': []\n 'reorder-applied': [items: TItem[]]\n 'reorder-apply-error': [error: unknown]\n 'reorder-end': []\n}>()\n\ndefineSlots<{\n header?: (props: HeaderSlotProps) => unknown\n 'reorder-toggle'?: (props: ReorderToggleSlotProps) => unknown\n 'reorder-toolbar'?: (props: ToolbarSlotProps) => unknown\n empty?: (props: EmptySlotProps) => unknown\n 'add-button'?: (props: AddButtonSlotProps) => unknown\n 'view-body'?: (props: ViewBodySlotProps<TItem>) => unknown\n item?: (props: RowSlotProps<TItem>) => unknown\n 'item-compact'?: (props: RowSlotProps<TItem>) => unknown\n 'item-readonly'?: (props: RowSlotProps<TItem>) => unknown\n 'item-status'?: (props: RowSlotProps<TItem>) => unknown\n 'item-actions'?: (props: RowSlotProps<TItem>) => unknown\n 'item-footer'?: (props: RowSlotProps<TItem>) => unknown\n 'before-item'?: (props: RowSlotProps<TItem>) => unknown\n 'after-item'?: (props: RowSlotProps<TItem>) => unknown\n}>()\n\nconst modelValue = defineModel<TItem[]>({ required: true })\nconst mode = defineModel<ReorderMode>('mode', { default: 'view' })\n\nconst { t } = useI18n()\nconst slots = useSlots()\n\nconst rootEl = useTemplateRef<HTMLElement>('rootEl')\nconst { isNarrow } = useContainerWidth(rootEl)\n\nconst isTouch = useIsTouchDevice()\nconst hasCoarsePointer = useHasCoarsePointer()\n\n// State controller (v2). `factory`/`getKey`/`position`/`validate` are construction-time options read\n// once to seed the controller, not reactive props — hence the suppressed reactivity-loss rule.\n// Undefined options fall back to controller defaults ('id' / 'position' / always-valid).\n/* eslint-disable vue/no-setup-props-reactivity-loss */\nconst controllerOptions: ListEditorStateBindings<TItem> = {\n get: () => modelValue.value,\n set: (v) => (modelValue.value = v),\n factory: props.factory,\n getKey: props.getKey as GetKey<TItem> | undefined,\n position: props.position as PositionOption<TItem> | undefined,\n dirtyExclude: () => props.dirtyExclude ?? [],\n validate: props.validate,\n}\n// Precedence: an explicitly lifted `:editor` wins; then a `state-key`'d entry persisted in the\n// nearest ancestor editor's row-state scope (built from the options above, rebound to this instance\n// on every remount); else this component owns the controller — today's behaviour, unchanged.\nconst stateEntry = props.editor ? null : useListEditorStateEntry<TItem>(props.stateKey, controllerOptions)\nconst controller = props.editor ?? stateEntry?.handle ?? useListEditorController<TItem>(controllerOptions)\n\n// Local mirror of the controller's key resolution so rendered rows key the same\n// way the controller tracks them (v2 spec point 7).\nconst getKeyOpt = props.getKey ?? 'id'\n/* eslint-enable vue/no-setup-props-reactivity-loss */\n\n// Row-state scope for THIS editor's `#item` slot subtree: a nested editor with a `state-key` builds\n// its controller in here, so it outlives the row collapsing (which unmounts the slot). When this\n// editor is itself persisted, the scope comes from its own entry — so the chain holds at any depth.\nconst rowStateScope = provideListEditorStateScope(stateEntry?.childScope ?? null)\nconst keyOf = (item: TItem): ListEditorKey =>\n typeof getKeyOpt === 'function' ? getKeyOpt(item) : (item[getKeyOpt as keyof TItem] as ListEditorKey)\n\n// Managed position field (for the row position view field + move-to-position\n// dialog). Mirrors the controller's resolution.\nconst positionFieldName = computed<string>(() => {\n const p = props.position\n if (p === undefined) return 'position'\n if (p === false) return 'position'\n if (typeof p === 'object') return p.field as string\n return p as string\n})\n\n// Keyed render projection (key + index + raw + position); the controller owns the data.\nconst viewItems = computed<ListViewItem<TItem>[]>(() =>\n modelValue.value.map((raw, index) => ({\n key: keyOf(raw),\n index,\n raw,\n position: raw[positionFieldName.value] as number | undefined,\n }))\n)\n\n// Drop the persisted controllers of rows that no longer exist. `post` so the removed row's subtree\n// has already unmounted (its editors released their entries) before we stop their effect scopes.\nwatch(\n () => viewItems.value.map((vi) => String(vi.key)).join('|'),\n () => rowStateScope.retainOwners(viewItems.value.map((vi) => vi.key)),\n { flush: 'post' }\n)\n\nconst expandedKeys = ref<Set<ListEditorKey>>(new Set())\n\n// Reorder-session moved set — component view state, distinct from the\n// controller's persistent moved tracking. Drives the toolbar's \"N pending\n// changes\" counter; cleared on every mode transition by `useReorderMode`.\nconst movedKeys = ref<Set<ListEditorKey>>(new Set())\n// Deletes made DURING the current reorder session, split by mode. Deferred ones count in the toolbar\n// and are reverted on Cancel (row restored, tombstone cleared). Immediate (backend) ones are re-applied\n// on Cancel so they stay gone — else Cancel's snapshot-restore would resurrect a row already deleted on\n// the server (a phantom a later save could re-create).\nconst sessionDeferredDeletes = ref<Set<ListEditorKey>>(new Set())\nconst sessionImmediateDeletes = ref<Set<ListEditorKey>>(new Set())\n// Rows ADDED during the current reorder session (\"Pridať za túto položku\"). Count in the toolbar so\n// Apply enables instead of trapping the user; Cancel drops them (snapshot-restore removes rows that\n// weren't in the enter-time snapshot).\nconst sessionAddedKeys = ref<Set<ListEditorKey>>(new Set())\n// Rows MOVED during the current reorder session. On Cancel the snapshot-restore undoes the reorder, so\n// these keys' persistent \"moved\" flag must be dropped from the controller too (else they stay falsely\n// amber + arm the leave guard for a reorder that never happened). Apply keeps them (persisted on save).\nconst sessionMovedKeys = ref<Set<ListEditorKey>>(new Set())\n\nconst snapshot = shallowRef<TItem[] | null>(null)\n\nconst rowsContainer = useTemplateRef<HTMLElement>('rowsContainer')\n\nconst isInlineEdit = computed(() => !props.chips && !!slots.item)\nconst hasReadonlyDetail = computed(() => !props.chips && !!slots['item-readonly'])\n\nconst { editingKeys, editingSnapshots, clearEditing, beginEdit, cancelEdit, commitEdit, closeEdit, requestAutoOpen } =\n useInlineEditing<TItem, ListViewItem<TItem>>({\n rowsContainer,\n rowSelector: '.a-le-row',\n isInlineEdit,\n restoreSnapshot: (key, data) => controller.updateItem(key, data),\n watchKeys: () => modelValue.value.map((it) => keyOf(it)),\n findEntry: (key) => {\n const hit = modelValue.value.find((it) => keyOf(it) === key)\n return hit ? { data: hit } : null\n },\n afterAutoOpen: (key) => {\n expandedKeys.value.delete(key)\n },\n })\n\nconst canInteract = computed(() => !props.readonly && !props.disabled && !props.loading)\nconst canEnterReorder = computed(() => canInteract.value && !props.disableReorder && modelValue.value.length > 1)\n\nconst embeddedRef = computed(() => props.embedded)\nconst allowEditInReorderRef = computed(() => props.allowEditInReorder)\n\nconst {\n applying,\n applyError,\n hasPendingChanges,\n movedCount,\n reorderMode,\n enterReorderMode,\n cancelReorderMode,\n applyReorder,\n} = useReorderMode<TItem[]>({\n mode,\n snapshot,\n movedKeys,\n modelValue,\n cloneModel: (m) => cloneDeep(m) as TItem[],\n applyModel: (m) => {\n modelValue.value = m\n },\n canEnterReorder,\n embedded: embeddedRef,\n onEnter: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n if (!allowEditInReorderRef.value) {\n clearEditing()\n expandedKeys.value.clear()\n }\n },\n onExternalEnter: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n if (!allowEditInReorderRef.value) {\n clearEditing()\n expandedKeys.value.clear()\n }\n },\n // Cancel reverts the session. The composable's snapshot-restore has already brought EVERY deleted row\n // back into the model; reconcile the controller: deferred deletes are truly reverted (clear tombstone,\n // row stays), immediate deletes are re-applied (row removed again — it is gone on the backend and must\n // not resurrect or be re-created by a later save).\n onCancel: () => {\n for (const key of sessionDeferredDeletes.value) controller.restoreDeleted(key)\n for (const key of sessionImmediateDeletes.value) controller.deleteItem(key, { trackDeleted: false })\n // Snapshot-restore already undid the reorder — drop the controller's \"moved\" flag for exactly the\n // rows moved this session (edits/adds keep their amber), so a cancelled reorder leaves no false unsaved.\n controller.clearMoved(sessionMovedKeys.value)\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n // Apply keeps the session's changes (deferred deletes persist on the entity's main save; moved rows stay\n // amber in the controller until the consumer commits after their save — only reset the session tracker).\n onApplyEnd: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n // Embedded editor exit (parent Cancel or Apply — it owns the snapshot, we never do). On a parent\n // Cancel the snapshot-restore resurrects any row we deleted IMMEDIATELY on the backend; re-remove it so\n // it stays gone. On Apply it never came back, so `deleteItem` is a no-op. Deferred deletes need nothing:\n // the controller's re-add watch drops their tombstone when the restore brings the row back.\n onEmbeddedExit: () => {\n for (const key of sessionImmediateDeletes.value) controller.deleteItem(key, { trackDeleted: false })\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n onReorderApply: (items) => props.onReorderApply?.(items),\n emit: {\n reorderStart: () => emit('reorder-start'),\n reorderCancel: () => emit('reorder-cancel'),\n reorderApplied: (payload) => emit('reorder-applied', payload),\n reorderApplyError: (err) => emit('reorder-apply-error', err),\n reorderEnd: () => emit('reorder-end'),\n },\n})\n\n// Stacked-editor registry: outer collects movedCount + hasChanges from embedded\n// children for the toolbar counter. shallowReactive preserves ComputedRef\n// identity (no auto-unwrap).\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst childContributions = props.embedded\n ? null\n : shallowReactive(\n new Map<symbol, { count: ComputedRef<number>; hasChanges: ComputedRef<boolean>; validateAll: () => boolean }>()\n )\n\nif (childContributions) {\n const registry: SharedReorderRegistry = {\n register: (id, count, hasChanges, validateAll) => {\n childContributions.set(id, { count, hasChanges, validateAll })\n },\n unregister: (id) => {\n childContributions.delete(id)\n },\n }\n provide(SharedReorderRegistryKey, registry)\n}\n\n// Own session moves + each embedded child's FULL pending contribution (moves + its own deferred\n// deletes — children register `totalPendingCount`, see below). The outer's own deferred deletes are\n// added on top in `totalPendingCount`.\nconst totalMovedCount = computed<number>(() => {\n let sum = movedCount.value\n if (childContributions) {\n for (const c of childContributions.values()) sum += c.count.value\n }\n return sum\n})\n\nconst totalHasPendingChanges = computed<boolean>(() => {\n if (hasPendingChanges.value) return true\n if (childContributions) {\n for (const c of childContributions.values()) {\n if (c.hasChanges.value) return true\n }\n }\n return false\n})\n\n// Reorder-toolbar pending indicator = session moves + deferred deletes made in the session, so\n// deleting a row in reorder mode no longer reads as \"no pending changes\" and Apply stays enabled.\nconst totalPendingCount = computed<number>(\n () => totalMovedCount.value + sessionDeferredDeletes.value.size + sessionAddedKeys.value.size\n)\nconst totalPendingChanges = computed<boolean>(\n () => totalHasPendingChanges.value || sessionDeferredDeletes.value.size > 0 || sessionAddedKeys.value.size > 0\n)\n\n// An embedded editor pushes its FULL pending contribution — moves AND deferred deletes — up to the\n// nearest non-embedded outer, so deleting a row in an embedded child during a shared reorder lights up\n// the outer's toolbar (count + Apply-enabled) instead of reading \"no pending changes\". Registered after\n// `totalPendingCount`/`totalPendingChanges` so they exist (TDZ); `validateAllSelf` is a lazy thunk.\nif (props.embedded) {\n const parent = inject(SharedReorderRegistryKey, null)\n if (parent) {\n const id = Symbol('le.embedded')\n parent.register(id, totalPendingCount, totalPendingChanges, () => validateAllSelf())\n onBeforeUnmount(() => parent.unregister(id))\n }\n}\n\nconst canAdd = computed(() => canInteract.value && props.showAddButton && !reorderMode.value)\n// Chips mode keeps drag always-on (no mode toggle) on non-touch devices.\nconst dragEnabled = computed(\n () => canInteract.value && (reorderMode.value || props.chips) && !isTouch.value && !props.disableDrag\n)\n\nconst addLabelResolved = computed(() => props.addLabel ?? t('common.sortable.add'))\nconst emptyTitleResolved = computed(() => props.emptyTitle ?? t('common.sortable.emptyTitle'))\nconst deleteConfirmTitleResolved = computed(() => props.deleteConfirmTitle ?? t('common.sortable.deleteConfirmTitle'))\nconst deleteConfirmTextResolved = computed(\n () =>\n props.deleteConfirmText ??\n (props.deleteMode === 'immediate'\n ? t('common.sortable.deleteConfirmText')\n : t('common.sortable.deleteConfirmTextDeferred'))\n)\n\nconst reorderToggleVisible = computed<boolean>(\n (): boolean =>\n !props.chips && !props.embedded && props.showReorderToggle && !reorderMode.value && modelValue.value.length > 0\n)\n\n// With a title and a narrow viewport, the reorder button shrinks to an icon-only\n// round button to keep the single-line header from overflowing.\nconst compactReorderButton = computed<boolean>((): boolean => !!props.title && isNarrow.value)\n\n// Total unconfirmed-change count (added/edited/moved rows + deferred deletions) — a delete lights it\n// up even though its row is gone. Shown as a view-mode header badge + on the handle; in reorder mode\n// the toolbar status shows the session count instead.\nconst unsavedCount = controller.unsavedCount\nconst unsavedCountVisible = computed(() => !props.readonly && !props.disableUnsaved && unsavedCount.value > 0)\nconst headerVisible = computed<boolean>(\n (): boolean =>\n !!(\n props.title ||\n slots.header ||\n slots['reorder-toggle'] ||\n reorderToggleVisible.value ||\n (reorderMode.value && !props.embedded) ||\n (!reorderMode.value && unsavedCountVisible.value)\n )\n)\n\n// True when the header has substantive content (title or custom header slot).\n// When false it still renders as a slim band right-aligning just the\n// reorder/apply controls, holding height across idle ↔ reorder so it doesn't jump.\nconst headerHasContent = computed<boolean>(\n (): boolean => !!(props.title || slots.header || slots['reorder-toggle'] || slots['view-body'])\n)\n\n// Per-row Save/Cancel footer only matters with a per-item persist callback;\n// otherwise the parent form's global save flushes everything, so hide it.\nconst showInlineSaveFooter = computed(() => !!props.onItemSave)\n\n// Reorder-session moved marker (drag, arrow buttons) feeding the toolbar counter;\n// the persistent amber `unsaved` flag is the controller's.\nconst markMoved = (key: ListEditorKey) => {\n movedKeys.value.add(key)\n sessionMovedKeys.value.add(key)\n}\n\n// Per-key decorator cache — see AListEditor for rationale. `unsaved` (amber) and\n// `validationState` (red rail) come from the controller; `moved` is the\n// reorder-session flag.\nconst decoratorCache = new Map<ListEditorKey, DecoratedViewItem<TItem>>()\nconst viewItemsDecorated = computed<DecoratedViewItem<TItem>[]>(() => {\n const total = modelValue.value.length\n const next: DecoratedViewItem<TItem>[] = []\n const liveKeys = new Set<ListEditorKey>()\n for (const vi of viewItems.value) {\n liveKeys.add(vi.key)\n const editing = editingKeys.value.has(vi.key)\n const expanded = expandedKeys.value.has(vi.key)\n const loading = props.loadingKeys?.has(vi.key) ?? false\n const moved = movedKeys.value.has(vi.key)\n // readonly → no amber markers (can't have unsaved changes; also dodges a\n // mount-before-load empty baseline). (QA 85050 sweep)\n // `disableUnsaved` suppresses only the amber marker — the validation rail still shows, since\n // hiding dirty state should not hide a real error.\n const unsaved = props.disableUnsaved || props.readonly ? false : controller.isUnsaved(vi.key)\n const dirty = unsaved\n // `editing` → the controller reads amber (not red) while the row is being filled in. (QA 85050 b7)\n const validationState = controller.rowState(vi.raw, vi.key, editing)\n const canMoveUp = vi.index > 0\n const canMoveDown = vi.index < total - 1\n const cached = decoratorCache.get(vi.key)\n if (\n cached &&\n cached.raw === vi.raw &&\n cached.index === vi.index &&\n cached.position === vi.position &&\n cached.editing === editing &&\n cached.expanded === expanded &&\n cached.loading === loading &&\n cached.dirty === dirty &&\n cached.moved === moved &&\n cached.unsaved === unsaved &&\n cached.validationState === validationState &&\n cached.canMoveUp === canMoveUp &&\n cached.canMoveDown === canMoveDown\n ) {\n next.push(cached)\n continue\n }\n const decorated: DecoratedViewItem<TItem> = {\n ...vi,\n editing,\n expanded,\n loading,\n dirty,\n moved,\n unsaved,\n validationState,\n canMoveUp,\n canMoveDown,\n }\n decoratorCache.set(vi.key, decorated)\n next.push(decorated)\n }\n for (const key of decoratorCache.keys()) {\n if (!liveKeys.has(key)) decoratorCache.delete(key)\n }\n return next\n})\n\nconst isEmpty = computed(() => viewItemsDecorated.value.length === 0)\n\nconst findVi = (key: ListEditorKey): DecoratedViewItem<TItem> | undefined =>\n viewItemsDecorated.value.find((v) => v.key === key)\n\n// Programmatically open a row's inline-edit form (e.g. open auto-seeded rows on mount). Multiple\n// rows can be open at once. No-op for chips / when there is no `#item` slot.\nconst openRow = (key: ListEditorKey): void => {\n if (!isInlineEdit.value) return\n const vi = findVi(key)\n if (vi) beginEdit(vi)\n}\nconst openAll = (): void => {\n if (!isInlineEdit.value) return\n for (const vi of viewItemsDecorated.value) beginEdit(vi)\n}\n\n// Validate + reveal this editor's OWN rows (no cascade). The exposed `validateAll`\n// wraps this and also cascades into embedded children; embedded children register\n// this self-only variant so a parent save reveals their invalid rows red too.\nconst validateAllSelf = (): boolean =>\n validateAllAndReveal(controller, (key) => {\n const vi = viewItems.value.find((v) => v.key === key)\n if (vi) beginEdit(vi)\n })\n\n// Auto-bridge the editor's aggregate validity into the consumer's `validation-scope` collector so a\n// plain `$invalid` save gate blocks (and reveals) a collapsed invalid row. No-op without the prop.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss -- construction-time opt-in, read once\nuseListEditorScopeValidity({\n hasErrors: controller.hasErrors,\n validationScope: props.validationScope,\n validateProvided: props.validate !== undefined,\n reveal: validateAllSelf,\n})\n\nconst keyboardNav = useKeyboardNav({\n viewItems: computed(() => viewItemsDecorated.value.map((vi) => ({ key: vi.key }))),\n variant: 'sortable',\n isReorderMode: reorderMode,\n disabled: computed(() => !canInteract.value),\n isEditing: (key) => editingKeys.value.has(key),\n onToggleEdit: (key) => {\n const vi = findVi(key)\n if (vi) onEditClick(vi)\n },\n onCancelEdit: (key) => {\n const vi = findVi(key)\n if (vi) onCloseClick(vi)\n },\n onMoveUp: (key) => {\n const vi = findVi(key)\n if (vi) moveUp(vi.index)\n },\n onMoveDown: (key) => {\n const vi = findVi(key)\n if (vi) moveDown(vi.index)\n },\n onMoveTop: (key) => {\n const vi = findVi(key)\n if (vi) moveTop(vi.index)\n },\n onMoveBottom: (key) => {\n const vi = findVi(key)\n if (vi) moveBottom(vi.index)\n },\n onCancelReorder: () => cancelReorderMode(),\n})\n\nconst moveToPositionDialogOpen = ref<boolean>(false)\nconst moveToPositionTarget = shallowRef<DecoratedViewItem<TItem> | null>(null)\nconst moveToPositionLabel = computed<string>(() =>\n moveToPositionTarget.value ? resolveCompactText(moveToPositionTarget.value.raw) : ''\n)\nconst openMoveToPosition = (vi: DecoratedViewItem<TItem>) => {\n if (!props.showMoveToPosition) return\n moveToPositionTarget.value = vi\n moveToPositionDialogOpen.value = true\n}\nconst onMoveToPositionConfirm = (newIndex: number) => {\n const target = moveToPositionTarget.value\n moveToPositionTarget.value = null\n if (!target) return\n if (newIndex === target.index) return\n controller.moveItem(target.index, newIndex)\n markMoved(target.key)\n}\n\nconst resolveCompactText = (raw: TItem): string => resolveCompactTextUtil(raw, { compactField: props.compactField })\n\n// Always instantiate SortableJS, seeded `disabled: !dragEnabled` and kept in sync\n// by the watch below. It used to be created only when `isTouch` was false at setup\n// — but `isTouch` is a live media query (plug in a mouse, toggle device emulation),\n// and that one-shot read left the instance missing when it later flipped: the drag\n// handle rendered but dragging did nothing. The setup cost this saved on touch\n// devices is not worth a dead handle.\n/* eslint-disable vue/no-ref-object-reactivity-loss */\nconst sortable = useSortable(rowsContainer, modelValue, {\n // The rows container can mount/unmount across mode flips (e.g. a `#view-body`\n // slot in view mode, rows only in reorder mode). vueuse's default\n // `tryOnMounted` fires once and would bind to a null ref, leaving SortableJS\n // dead; `watchElement: true` re-inits whenever the ref populates.\n watchElement: true,\n handle: '.a-le-drag-handle',\n animation: 150,\n // Force the fallback renderer so `dragClass` applies to a CSS-controlled\n // clone following the cursor — a row-shaped ghost instead of the opaque\n // browser-native drag bitmap.\n forceFallback: true,\n fallbackTolerance: 3,\n fallbackOnBody: true,\n ghostClass: DRAG_GHOST_CLASS,\n chosenClass: DRAG_CHOSEN_CLASS,\n dragClass: DRAG_CLASS,\n disabled: !dragEnabled.value,\n // Own `onUpdate` REPLACES vueuse's default array-move, which moved the array\n // and renumbered positions in separate `nextTick`s — a gap that let a\n // consumer's \"sort by position\" watch re-sort on stale positions and revert\n // the drop. One synchronous `controller.moveItem` closes that window so every\n // observer sees the final order and positions at once.\n onUpdate: (event) => {\n const { oldIndex, newIndex, item, from } = event\n if (oldIndex === undefined || newIndex === undefined) return\n // Undo SortableJS's DOM relocation so Vue's keyed v-for stays the single\n // source of truth (mirrors vueuse's removeNode + insertNodeAt).\n if (item && from) {\n item.parentNode?.removeChild(item)\n from.insertBefore(item, from.children[oldIndex] ?? null)\n }\n // moveItem rewrites the array, renumbers positions, and records the moved\n // key — all synchronously.\n controller.moveItem(oldIndex, newIndex)\n },\n onEnd: (event) => {\n // Mark only the dragged row (via its data-id) moved rather than diffing the\n // whole list, so siblings that shifted index stay clean. `event.item` is the\n // `.a-le-row-wrapper` sortable item; the `[data-id]` lives on the inner `.a-le-row`.\n const el = event.item as HTMLElement\n // `:scope >` so a consumer editor nested in a `#before-item` slot (its own\n // `.a-le-row` descendants) can't shadow this row's own id.\n const raw = (el.querySelector(':scope > .a-le-row') ?? el).getAttribute('data-id')\n if (raw !== null && raw !== '') {\n // Numeric key only when `data-id` is a pure integer string (incl. negative\n // temp ids like \"-1\"); otherwise keep the UUID-style string. `n > 0`\n // wrongly sent negative ids down the string branch, landing amber on the\n // wrong key.\n const n = stringToInt(raw)\n const key: ListEditorKey = String(n) === raw ? n : raw\n markMoved(key)\n }\n },\n})\n\n// Options are built once at setup, when a `#view-body` consumer is still in view mode and\n// `dragEnabled` is false; entering reorder mode mounts the container and `watchElement` re-creates\n// SortableJS from that stale object. Hence watching the container too.\nwatch(\n [dragEnabled, rowsContainer],\n async () => {\n // after `watchElement` has re-created the instance\n await nextTick()\n sortable.option('disabled', !dragEnabled.value)\n },\n { flush: 'post' }\n)\n/* eslint-enable vue/no-ref-object-reactivity-loss */\n\n// Managed add: the controller mints + inserts `factory()` and renumbers\n// positions; the inline-editing watch picks up the new key and auto-opens it.\nconst onAddClick = () => {\n if (!canAdd.value) return\n requestAutoOpen()\n controller.addItem(undefined, undefined)\n}\n\nconst onRowAddAfterClick = (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n requestAutoOpen()\n const key = controller.addItem(undefined, { afterId: vi.key })\n // Added during a reorder session (\"Pridať za túto položku\") → count it in the toolbar.\n if (reorderMode.value && key !== undefined) sessionAddedKeys.value.add(key)\n}\n\nconst onEditClick = (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n if (reorderMode.value && !props.allowEditInReorder) return\n // Clicking edit while already editing closes the form (matches row-header click).\n if (editingKeys.value.has(vi.key)) {\n onCloseClick(vi)\n return\n }\n if (isInlineEdit.value) {\n beginEdit(vi)\n expandedKeys.value.delete(vi.key)\n }\n emit('edit', vi)\n}\n\nconst onExpandClick = (vi: ListViewItem<TItem>) => {\n if (props.disabled || props.loading) return\n if (reorderMode.value && !props.allowEditInReorder) return\n const key = vi.key\n const currentlyExpanded = expandedKeys.value.has(key)\n if (currentlyExpanded) {\n expandedKeys.value.delete(key)\n } else {\n for (const k of expandedKeys.value) expandedKeys.value.delete(k)\n expandedKeys.value.add(key)\n }\n emit('item-expand', vi, !currentlyExpanded)\n}\n\nconst isRowClickable = (vi: DecoratedViewItem<TItem>): boolean => {\n if (props.chips) return false\n if (props.disableRowClick) return false\n if (props.disabled || props.loading) return false\n if (reorderMode.value && !props.allowEditInReorder) return false\n if (vi.editing || vi.expanded) return true\n if (!props.readonly && props.showEditButton) return true\n return false\n}\n\nconst onRowClick = (vi: DecoratedViewItem<TItem>) => {\n if (!isRowClickable(vi)) return\n if (vi.editing || vi.expanded) {\n onCloseClick(vi)\n return\n }\n if (props.readonly && hasReadonlyDetail.value) {\n onExpandClick(vi)\n } else {\n onEditClick(vi)\n }\n}\n\nconst {\n deleteDialog,\n deleteInFlight,\n deleteError,\n onDeleteClick: triggerDeleteClick,\n onDeleteDialogConfirm,\n onDeleteDialogCancel,\n} = useDeleteDialog<TItem, ListViewItem<TItem>>({\n onDeleteConfirm: (raw) => (props.onDeleteConfirm ? props.onDeleteConfirm(raw) : true),\n onDelete: (raw) => props.onDelete?.(raw),\n onDeleted: (vi) => {\n editingKeys.value.delete(vi.key)\n editingSnapshots.value.delete(vi.key)\n expandedKeys.value.delete(vi.key)\n movedKeys.value.delete(vi.key)\n const deferred = props.deleteMode === 'deferred'\n // In reorder mode: a deferred delete is a reversible session change (counts in the toolbar,\n // reverts on Cancel); an immediate delete is already gone on the backend, so drop it from the\n // reorder snapshot too — else Cancel's snapshot-restore would resurrect it.\n if (reorderMode.value) {\n if (sessionAddedKeys.value.has(vi.key)) {\n // Added AND deleted within the same reorder session — net zero. The controller drops the temp\n // row with no tombstone, so it must not linger in either counter (was double-counted: L1).\n sessionAddedKeys.value.delete(vi.key)\n } else if (deferred) {\n sessionDeferredDeletes.value.add(vi.key)\n } else {\n sessionImmediateDeletes.value.add(vi.key)\n }\n }\n // Controller owns the data: temp rows vanish; a deferred saved-row delete lands in\n // `getChanges().deleted` + counts as unsaved; immediate skips the tombstone (already persisted).\n controller.deleteItem(vi.key, { trackDeleted: deferred })\n emit('deleted', vi)\n },\n disableDeleteConfirm: () => props.disableDeleteConfirm || props.chips,\n})\n\nconst onDeleteClick = async (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n await triggerDeleteClick(vi)\n}\n\nconst onSaveClick = async (vi: ListViewItem<TItem>) => {\n if (props.onItemSave) {\n await props.onItemSave(vi.raw)\n }\n commitEdit(vi)\n emit('item-saved', vi)\n}\n\nconst onCancelClick = (vi: ListViewItem<TItem>) => {\n cancelEdit(vi)\n}\n\nconst onCloseClick = (vi: ListViewItem<TItem>) => {\n closeEdit(vi)\n expandedKeys.value.delete(vi.key)\n emit('close', vi)\n}\n\nconst keyAtIndex = (idx: number): ListEditorKey | null => {\n const item = modelValue.value[idx]\n if (!item) return null\n return keyOf(item)\n}\n\nconst moveUp = (idx: number) => {\n if (idx <= 0) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, idx - 1)\n if (key !== null) markMoved(key)\n}\nconst moveDown = (idx: number) => {\n if (idx >= modelValue.value.length - 1) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, idx + 1)\n if (key !== null) markMoved(key)\n}\nconst moveTop = (idx: number) => {\n if (idx <= 0) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, 0)\n if (key !== null) markMoved(key)\n}\nconst moveBottom = (idx: number) => {\n if (idx >= modelValue.value.length - 1) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, modelValue.value.length - 1)\n if (key !== null) markMoved(key)\n}\n\n// Per-key actions cache: stable identity per row — see AListEditor for\n// rationale. Closures capture the stable key and resolve the current vi via\n// findVi at call time.\ntype ActionsBundle = {\n edit: () => void\n save: () => Promise<void> | void\n cancel: () => void\n close: () => void\n delete: () => Promise<void>\n addAfter: () => void\n toggleExpand: () => void\n moveUp: () => void\n moveDown: () => void\n moveTop: () => void\n moveBottom: () => void\n update: (next: TItem | Partial<TItem> | ((current: TItem) => TItem)) => void\n}\nconst actionsCache = new Map<ListEditorKey, ActionsBundle>()\nconst getActions = (key: ListEditorKey): ActionsBundle => {\n let actions = actionsCache.get(key)\n if (!actions) {\n actions = {\n edit: () => {\n const vi = findVi(key)\n if (vi) onEditClick(vi)\n },\n save: () => {\n const vi = findVi(key)\n if (vi) return onSaveClick(vi)\n },\n cancel: () => {\n const vi = findVi(key)\n if (vi) onCancelClick(vi)\n },\n close: () => {\n const vi = findVi(key)\n if (vi) onCloseClick(vi)\n },\n delete: async () => {\n const vi = findVi(key)\n if (vi) await onDeleteClick(vi)\n },\n addAfter: () => {\n const vi = findVi(key)\n if (vi) onRowAddAfterClick(vi)\n },\n toggleExpand: () => {\n const vi = findVi(key)\n if (vi) onExpandClick(vi)\n },\n moveUp: () => {\n const vi = findVi(key)\n if (vi) moveUp(vi.index)\n },\n moveDown: () => {\n const vi = findVi(key)\n if (vi) moveDown(vi.index)\n },\n moveTop: () => {\n const vi = findVi(key)\n if (vi) moveTop(vi.index)\n },\n moveBottom: () => {\n const vi = findVi(key)\n if (vi) moveBottom(vi.index)\n },\n update: (next) => controller.updateItem(key, next),\n }\n actionsCache.set(key, actions)\n }\n return actions\n}\nwatch(\n () => viewItemsDecorated.value,\n (now) => {\n if (actionsCache.size === 0) return\n const liveKeys = new Set(now.map((v) => v.key))\n for (const key of actionsCache.keys()) {\n if (!liveKeys.has(key)) actionsCache.delete(key)\n }\n }\n)\n\nconst buildSlotProps = (vi: DecoratedViewItem<TItem>) => ({\n item: vi,\n raw: vi.raw,\n index: vi.index,\n key: vi.key,\n readonly: props.readonly,\n disabled: props.disabled,\n expanded: vi.expanded,\n editing: vi.editing,\n dirty: vi.dirty,\n unsaved: vi.unsaved,\n reorderMode: reorderMode.value,\n moved: vi.moved,\n canMoveUp: vi.canMoveUp,\n canMoveDown: vi.canMoveDown,\n touch: isTouch.value,\n stateKeyPrefix: rowStateScope.prefixFor(vi.key),\n actions: getActions(vi.key),\n})\n\nconst toolbarSlotProps = computed(() => ({\n applying: applying.value,\n hasPendingChanges: totalPendingChanges.value,\n movedCount: totalPendingCount.value,\n error: applyError.value,\n actions: {\n apply: applyReorder,\n cancel: cancelReorderMode,\n },\n}))\n\nconst reorderToggleSlotProps = computed(() => ({\n mode: mode.value,\n disabled: !canEnterReorder.value,\n hasPendingChanges: totalHasPendingChanges.value,\n actions: {\n enterReorderMode,\n exitReorderMode: cancelReorderMode,\n },\n}))\n\n// Registers a named unsaved-changes section when the consumer passes a label.\nuseUnsavedSection(() =>\n props.unsavedSectionLabel && !props.disableUnsaved\n ? { label: props.unsavedSectionLabel, dirty: controller.hasUnsaved.value }\n : []\n)\n\n// Expose the controller handle (validateAll/getPayload/commit/etc. via\n// `useTemplateRef<ListEditorHandle<TItem>>`) plus the reorder-mode controls.\ndefineExpose<\n ListEditorHandle<TItem> & {\n enterReorderMode: () => void\n cancelReorderMode: () => void\n applyReorder: () => Promise<void>\n openRow: (key: ListEditorKey) => void\n openAll: () => void\n }\n>({\n ...controller,\n openRow,\n openAll,\n // Saving is separate from the editor's \"Apply\", so a consumer can commit while still in\n // reorder mode with an unapplied move. The reorder session (component-level `movedKeys` +\n // snapshot) is NOT controller state, so re-baseline it here too — otherwise the \"N pending\n // changes\" badge lingers after the save and a later Cancel would revert past it.\n commit: (savedItems?: TItem[]) => {\n controller.commit(savedItems)\n movedKeys.value = new Set()\n if (snapshot.value) snapshot.value = cloneDeep(modelValue.value) as TItem[]\n },\n // validateAll() also opens invalid rows so a blocked save surfaces WHICH rows\n // are wrong — their #item form mounts instead of a collapsed red rail (QA 85050\n // B4-17). The body is gated on `editing` (not `expanded`), so drive `beginEdit`.\n // Shared with AListEditor + ANestedSortableListEditor via the helper.\n validateAll: () => {\n // Cascade into embedded children — a single outer save reveals invalid rows red\n // at every nesting level (e.g. quiz question turning red must also red its answers).\n const selfValid = validateAllSelf()\n if (!childContributions) return selfValid\n let valid = selfValid\n for (const child of childContributions.values()) {\n if (!child.validateAll()) valid = false\n }\n return valid\n },\n enterReorderMode,\n cancelReorderMode,\n applyReorder,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"a-sortable-list-editor\"\n :class=\"[\n `a-sortable-list-editor--two-rows-${twoRows}`,\n `a-sortable-list-editor--mode-${mode}`,\n {\n 'a-sortable-list-editor--readonly': readonly,\n 'a-sortable-list-editor--disabled': disabled,\n 'a-sortable-list-editor--touch': isTouch,\n 'a-sortable-list-editor--drag-enabled': dragEnabled,\n 'a-sortable-list-editor--chips': chips,\n 'a-sortable-list-editor--embedded': embedded,\n 'a-sortable-list-editor--header-floating': !embedded && !chips && !headerHasContent && headerVisible,\n },\n ]\"\n >\n <div class=\"a-le-card\">\n <div\n v-if=\"headerVisible\"\n class=\"a-le-header\"\n >\n <slot\n name=\"header\"\n :title=\"title\"\n v-bind=\"reorderToggleSlotProps\"\n >\n <h3\n v-if=\"title\"\n class=\"a-le-title-heading\"\n >\n {{ title }}\n </h3>\n <span\n v-if=\"!reorderMode && unsavedCountVisible\"\n class=\"a-le-unsaved-count\"\n :data-unsaved-count=\"unsavedCount\"\n >\n {{ t('common.sortable.pendingChanges', { count: unsavedCount }) }}\n </span>\n <div class=\"a-le-header-actions\">\n <template v-if=\"reorderMode && !embedded\">\n <!-- Reorder-mode header: pending count + Cancel/Apply, sitting\n where the \"Reorder\" button lives in view mode. -->\n <slot\n name=\"reorder-toolbar\"\n v-bind=\"toolbarSlotProps\"\n >\n <LeStatus\n :class=\"{ 'a-le-toolbar-status--pending': totalPendingChanges }\"\n :has-pending-changes=\"totalPendingChanges\"\n :pending-count=\"totalPendingCount\"\n :error=\"applyError\"\n />\n <VBtn\n variant=\"text\"\n size=\"small\"\n :disabled=\"applying\"\n @click=\"cancelReorderMode\"\n >\n {{ t('common.sortable.reorderCancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"flat\"\n size=\"small\"\n prepend-icon=\"mdi-check\"\n :loading=\"applying\"\n :disabled=\"applying || !totalPendingChanges\"\n @click=\"applyReorder\"\n >\n {{ t('common.sortable.reorderApply') }}\n </VBtn>\n </slot>\n </template>\n <slot\n v-else-if=\"reorderToggleVisible\"\n name=\"reorder-toggle\"\n v-bind=\"reorderToggleSlotProps\"\n >\n <VBtn\n v-if=\"compactReorderButton\"\n variant=\"tonal\"\n color=\"primary\"\n icon\n size=\"x-small\"\n :disabled=\"!canEnterReorder\"\n @click=\"enterReorderMode\"\n >\n <VIcon\n icon=\"mdi-sort\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.reorder')\"\n />\n </VBtn>\n <VBtn\n v-else\n variant=\"tonal\"\n color=\"primary\"\n prepend-icon=\"mdi-sort\"\n size=\"small\"\n :disabled=\"!canEnterReorder\"\n @click=\"enterReorderMode\"\n >\n {{ t('common.sortable.reorder') }}\n </VBtn>\n </slot>\n </div>\n </slot>\n </div>\n\n <div\n v-if=\"loading\"\n class=\"a-le-state a-le-state--loading\"\n >\n <VProgressCircular\n indeterminate\n color=\"primary\"\n size=\"32\"\n />\n </div>\n\n <div\n v-else-if=\"error\"\n class=\"a-le-state a-le-state--error\"\n >\n <VAlert\n type=\"error\"\n variant=\"tonal\"\n density=\"compact\"\n border=\"start\"\n >\n {{ error }}\n </VAlert>\n </div>\n\n <div\n v-else-if=\"!reorderMode && $slots['view-body']\"\n class=\"a-le-view-body\"\n >\n <slot\n name=\"view-body\"\n :items=\"modelValue\"\n :mode=\"mode\"\n :actions=\"{ enterReorderMode }\"\n />\n </div>\n\n <div\n v-else-if=\"isEmpty\"\n class=\"a-le-state a-le-state--empty\"\n >\n <slot\n name=\"empty\"\n :readonly=\"readonly\"\n :disabled=\"disabled\"\n :actions=\"{ add: onAddClick }\"\n >\n <LeEmptyState\n :title=\"emptyTitleResolved\"\n :add-label=\"addLabelResolved\"\n :can-add=\"canAdd\"\n @add=\"onAddClick\"\n />\n </slot>\n </div>\n\n <div\n v-else\n ref=\"rowsContainer\"\n class=\"a-sortable-list-editor__rows\"\n >\n <div\n v-for=\"vi in viewItemsDecorated\"\n :key=\"String(vi.key)\"\n class=\"a-le-row-wrapper\"\n >\n <!-- Interstitial slots render as SIBLINGS of `.a-le-row` (inside this\n wrapper), so consumer content placed between rows never inherits the\n row's unsaved/editing/grabbed/validation tint. (QA 85050 BUG-04/05) -->\n <slot\n name=\"before-item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n\n <div\n :data-id=\"String(vi.key)\"\n role=\"listitem\"\n :tabindex=\"keyboardNav.rowTabindex(vi.key)\"\n class=\"a-le-row\"\n :class=\"{\n 'a-le-row--two-rows': twoRows === 'always',\n 'a-le-row--editing': vi.editing,\n 'a-le-row--expanded': vi.expanded,\n 'a-le-row--unsaved': vi.unsaved,\n 'a-le-row--reorder': reorderMode,\n 'a-le-row--grabbed': keyboardNav.isGrabbed(vi.key),\n 'a-le-row--clickable': isRowClickable(vi),\n [`a-le-row--validation-${vi.validationState}`]: vi.validationState !== null,\n }\"\n @keydown=\"keyboardNav.handleKeydown(vi.key, $event)\"\n >\n <div\n class=\"a-le-row-header\"\n @click=\"onRowClick(vi)\"\n >\n <LeDragHandle v-if=\"dragEnabled\" />\n\n <div class=\"a-le-row-main\">\n <slot\n name=\"item-compact\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <span class=\"a-le-title\">\n {{ resolveCompactText(vi.raw) }}\n </span>\n </slot>\n <LeUnsavedLabel\n v-if=\"vi.unsaved\"\n :dot-only=\"chips\"\n />\n </div>\n\n <div\n v-if=\"!chips && !reorderMode\"\n class=\"a-le-status\"\n >\n <slot\n name=\"item-status\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <span\n v-if=\"statusField && vi.raw[statusField] != null && vi.raw[statusField] !== ''\"\n class=\"a-le-status-badge\"\n >\n {{ vi.raw[statusField] }}\n </span>\n </slot>\n </div>\n\n <div class=\"a-le-actions\">\n <slot\n name=\"item-actions\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <template v-if=\"chips && canInteract\">\n <!-- Chips is the one layout that would otherwise swap the arrows out for the handle.\n Keep them whenever dragging is unavailable (covers `disable-drag`, which gating on\n `isTouch` did not) AND whenever a finger could be used at all — a hybrid gets both,\n so putting the mouse down never leaves the row unmovable. Every other layout here\n already keeps its arrows unconditionally in reorder mode. -->\n <template v-if=\"(!dragEnabled || hasCoarsePointer) && !disableReorder\">\n <VBtn\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n :disabled=\"!vi.canMoveUp\"\n class=\"a-le-action a-le-action--up\"\n @click.stop=\"moveUp(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-up\"\n size=\"14\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n :disabled=\"!vi.canMoveDown\"\n class=\"a-le-action a-le-action--down\"\n @click.stop=\"moveDown(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-down\"\n size=\"14\"\n />\n </VBtn>\n </template>\n <VBtn\n v-if=\"showDeleteButton\"\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n class=\"a-le-action a-le-action--chip-close\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <VIcon\n icon=\"mdi-close\"\n size=\"14\"\n />\n </VBtn>\n </template>\n <template v-else-if=\"reorderMode\">\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :disabled=\"!vi.canMoveUp\"\n class=\"mx-1 a-le-action a-le-action--up\"\n @click.stop=\"moveUp(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-up\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.moveUp')\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :disabled=\"!vi.canMoveDown\"\n class=\"mx-1 a-le-action a-le-action--down\"\n @click.stop=\"moveDown(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-down\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.moveDown')\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :active=\"false\"\n class=\"mx-1 a-le-action a-le-action--menu\"\n >\n <VIcon\n icon=\"mdi-dots-vertical\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.more')\"\n />\n <VMenu activator=\"parent\">\n <VList density=\"compact\">\n <VListItem\n :disabled=\"!vi.canMoveUp\"\n @click.stop=\"moveTop(vi.index)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-arrow-collapse-up\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToTop') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n :disabled=\"!vi.canMoveDown\"\n @click.stop=\"moveBottom(vi.index)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-arrow-collapse-down\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToBottom') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showMoveToPosition && viewItemsDecorated.length > 1\"\n @click.stop=\"openMoveToPosition(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-target\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToPosition.action') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showAddAfterAction && canInteract\"\n @click=\"onRowAddAfterClick(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-plus\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.addAfter') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showDeleteButton && canInteract\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-trash-can-outline\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.delete') }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </VBtn>\n </template>\n <template v-else>\n <VBtn\n v-if=\"showEditButton && canInteract\"\n icon\n size=\"small\"\n variant=\"tonal\"\n color=\"primary\"\n density=\"comfortable\"\n class=\"mx-1 a-le-action a-le-action--edit\"\n @click.stop=\"onEditClick(vi)\"\n >\n <VIcon\n icon=\"mdi-pencil-outline\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.edit')\"\n />\n </VBtn>\n <VBtn\n v-if=\"showDeleteButton && canInteract\"\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n class=\"mx-1 a-le-action a-le-action--delete\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <VIcon\n icon=\"mdi-trash-can-outline\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.delete')\"\n />\n </VBtn>\n <VBtn\n v-if=\"showAddAfterAction && canInteract\"\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :active=\"false\"\n class=\"mx-1 a-le-action a-le-action--menu\"\n >\n <VIcon\n icon=\"mdi-dots-vertical\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.more')\"\n />\n <VMenu activator=\"parent\">\n <VList density=\"compact\">\n <VListItem @click=\"onRowAddAfterClick(vi)\">\n <template #prepend>\n <VIcon icon=\"mdi-plus\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.addAfter') }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </VBtn>\n </template>\n </slot>\n </div>\n </div>\n\n <template v-if=\"vi.editing && (allowEditInReorder || !reorderMode) && $slots.item\">\n <div class=\"a-le-row-body\">\n <div class=\"a-le-form\">\n <slot\n name=\"item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n <slot\n name=\"item-footer\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <div\n v-if=\"showInlineSaveFooter && !reorderMode\"\n class=\"a-le-row-footer\"\n >\n <div class=\"a-le-row-footer-spacer\" />\n <VBtn\n variant=\"text\"\n :disabled=\"vi.loading\"\n @click.stop=\"onCancelClick(vi)\"\n >\n {{ t('common.button.cancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"flat\"\n prepend-icon=\"mdi-check\"\n :disabled=\"vi.loading\"\n @click.stop=\"onSaveClick(vi)\"\n >\n {{ t('common.button.save') }}\n </VBtn>\n </div>\n </slot>\n </template>\n\n <div\n v-else-if=\"$slots['item-readonly'] && (readonly || vi.expanded) && (allowEditInReorder || !reorderMode)\"\n class=\"a-le-row-body\"\n >\n <div class=\"a-le-form\">\n <slot\n name=\"item-readonly\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n </div>\n\n <slot\n name=\"after-item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n\n <slot\n v-if=\"canAdd && !loading && !error && !isEmpty\"\n name=\"add-button\"\n :readonly=\"readonly\"\n :disabled=\"disabled\"\n :props=\"{ onClick: onAddClick }\"\n :actions=\"{ add: onAddClick }\"\n >\n <button\n type=\"button\"\n class=\"a-le-row-add\"\n @click=\"onAddClick\"\n >\n <VIcon\n icon=\"mdi-plus\"\n size=\"18\"\n />\n <span>{{ addLabelResolved }}</span>\n </button>\n </slot>\n </div>\n\n <LeMoveToPositionDialog\n v-model=\"moveToPositionDialogOpen\"\n :total=\"viewItemsDecorated.length\"\n :current-index=\"moveToPositionTarget?.index ?? 0\"\n :item-label=\"moveToPositionLabel\"\n @confirm=\"onMoveToPositionConfirm\"\n />\n\n <LeDeleteDialog\n v-model=\"deleteDialog\"\n :title=\"deleteConfirmTitleResolved\"\n :text=\"deleteConfirmTextResolved\"\n :confirm-label=\"t('common.sortable.delete')\"\n :cancel-label=\"t('common.button.cancel')\"\n :error=\"deleteError\"\n :in-flight=\"deleteInFlight\"\n @confirm=\"onDeleteDialogConfirm\"\n @cancel=\"onDeleteDialogCancel\"\n />\n\n <div\n class=\"a-le-sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{\n keyboardNav.grabbedKey.value !== null\n ? t('common.sortable.keyboardGrab.status', {\n n: keyboardNav.grabbedIndex.value + 1,\n total: keyboardNav.totalCount.value,\n })\n : ''\n }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n@use './styles/tokens';\n@use './styles/shared';\n\n// Variant-specific rules: reorder-mode trims, drag clone styling, chips\n// flex-wrap layout, validation rail.\n.a-sortable-list-editor {\n &__rows {\n display: flex;\n flex-direction: column;\n }\n\n // View-mode body slot — match the row's horizontal rhythm (~16 px) with a\n // vertical inset so content doesn't sit flush against the border.\n .a-le-view-body {\n padding: 12px 16px;\n }\n\n // Reorder mode trims row-header padding since the drag handle eats some of it.\n .a-le-row--reorder .a-le-row-header {\n padding-left: 12px;\n padding-right: 8px;\n gap: 8px;\n }\n\n // Drag rendering — SortableJS clone + ghost + chosen source.\n .a-le-row--ghost {\n opacity: 0.35;\n background: var(--le-primary-state);\n }\n\n .a-le-row--chosen {\n opacity: 0.5;\n }\n\n // Floating clone following the cursor — row-shaped card with elevation; action\n // column + status badge hidden (below) so the preview stays clean.\n .a-le-row--drag {\n background: var(--le-surface);\n border: 1px solid var(--le-border);\n border-radius: var(--le-radius);\n box-shadow: var(--le-elev-3);\n max-width: 420px;\n opacity: 0.96;\n pointer-events: none;\n }\n\n .a-le-row--drag .a-le-actions,\n .a-le-row--drag .a-le-status {\n display: none;\n }\n\n // Header-only-with-reorder variant — no title/header slot, so render a slim\n // band right-aligning just the Reorder button.\n &--header-floating .a-le-header {\n justify-content: flex-end;\n padding: 6px 8px;\n min-height: 0;\n }\n\n // Embedded variant — sits inside another editor's row. Drop card chrome,\n // tighten rows, lighten background so it reads as part of the parent's body.\n &--embedded .a-le-card {\n background: transparent;\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n &--embedded .a-le-header {\n padding: 4px 0 6px;\n min-height: auto;\n background: transparent;\n border: none;\n }\n\n &--embedded .a-le-title-heading {\n font-size: 13px;\n font-weight: 500;\n color: var(--le-on-surface-medium, rgb(0 0 0 / 70%));\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n &--embedded .a-le-row {\n background: var(--le-surface);\n border: 1px solid var(--le-border);\n border-radius: 6px;\n }\n\n // The inter-row gap lives on the wrapper (the real list item). `.a-le-row` is no\n // longer its wrapper's last child once `#after-item` renders, so the old\n // `.a-le-row:last-of-type` reset stopped clearing the trailing gap. (QA 85050 BUG-04/05)\n &--embedded .a-le-row-wrapper:not(:last-child) {\n margin-bottom: 4px;\n }\n\n &--embedded .a-le-row-add {\n min-height: var(--le-row-min-height);\n padding: 0 16px;\n background: transparent;\n border: 1px dashed var(--le-border);\n border-radius: 6px;\n color: var(--le-primary);\n margin-top: 4px;\n width: 100%;\n }\n\n &--embedded .a-le-row-add:hover {\n background: var(--le-primary-state);\n border-style: solid;\n }\n\n // Chips-layout overrides — `__rows` flex-wraps into pills, `row-header` gets\n // 8 px left padding (vs 12 px in AListEditor), `drag-handle` shrinks to the\n // pill height.\n &--chips &__rows {\n display: flex;\n\n // Reset the base column direction — chips flow inline and wrap.\n flex-flow: row wrap;\n gap: 6px;\n flex: 1 1 100%;\n }\n\n &--chips .a-le-row-header {\n padding: 2px 4px 2px 8px;\n gap: 4px;\n min-height: 28px;\n }\n\n &--chips .a-le-drag-handle {\n padding: 0;\n font-size: 16px;\n }\n}\n\n// Narrow-container / mobile layout — taller rows, always-visible actions,\n// status badge dropped for room.\n/* stylelint-disable selector-max-compound-selectors */\n@container le-shell (max-width: 768px) {\n .a-sortable-list-editor {\n --le-row-min-height: 48px;\n --le-row-pad-y: 10px;\n\n .a-le-row:not(.a-le-row--editing) .a-le-status {\n display: none;\n }\n\n .a-le-row .a-le-action--edit,\n .a-le-row .a-le-action--delete,\n .a-le-row .a-le-action--menu {\n opacity: 1;\n }\n }\n}\n/* stylelint-enable selector-max-compound-selectors */\n</style>\n","<script setup lang=\"ts\" generic=\"TItem extends Record<string, any>\">\nimport {\n nextTick,\n computed,\n inject,\n onBeforeUnmount,\n provide,\n ref,\n shallowReactive,\n shallowRef,\n useSlots,\n useTemplateRef,\n watch,\n type ComputedRef,\n} from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useContainerWidth } from '@/labs/listEditor/composables/useContainerWidth'\nimport { useHasCoarsePointer, useIsTouchDevice } from '@/labs/listEditor/composables/useIsTouchDevice'\nimport { useKeyboardNav } from '@/labs/listEditor/composables/useKeyboardNav'\nimport { useSortable } from '@vueuse/integrations/useSortable'\nimport {\n useListEditorController,\n type GetKey,\n type ListEditorHandle,\n type ListEditorValidationResult,\n type PositionAction,\n type PositionOption,\n type PositionStrategy,\n} from '@/labs/listEditor/composables/useListEditorController'\nimport {\n provideListEditorStateScope,\n useListEditorStateEntry,\n type ListEditorStateBindings,\n} from '@/labs/listEditor/composables/useListEditorStateScope'\nimport { resolveCompactText as resolveCompactTextUtil } from '@/labs/listEditor/composables/resolveCompactText'\nimport { useUnsavedSection } from '@/labs/unsavedGuard/useUnsavedSection'\nimport { useDeleteDialog } from '@/labs/listEditor/composables/useDeleteDialog'\nimport { useInlineEditing } from '@/labs/listEditor/composables/useInlineEditing'\nimport { validateAllAndReveal } from '@/labs/listEditor/utils/revealInvalidRows'\nimport { useListEditorScopeValidity } from '@/labs/listEditor/composables/useListEditorScopeValidity'\nimport {\n useReorderMode,\n SharedReorderRegistryKey,\n type SharedReorderRegistry,\n} from '@/labs/listEditor/composables/useReorderMode'\nimport LeDeleteDialog from '@/labs/listEditor/internal/LeDeleteDialog.vue'\nimport LeMoveToPositionDialog from '@/labs/listEditor/internal/LeMoveToPositionDialog.vue'\nimport LeEmptyState from '@/labs/listEditor/internal/LeEmptyState.vue'\nimport LeStatus from '@/labs/listEditor/internal/LeStatus.vue'\nimport LeUnsavedLabel from '@/labs/listEditor/internal/LeUnsavedLabel.vue'\nimport LeDragHandle from '@/labs/listEditor/internal/LeDragHandle.vue'\nimport { DRAG_GHOST_CLASS, DRAG_CHOSEN_CLASS, DRAG_CLASS } from '@/labs/listEditor/internal/constants'\nimport { cloneDeep } from '@/utils/common'\nimport { stringToInt } from '@/utils/string'\nimport type {\n ListEditorKey,\n ListEditorValidationScope,\n ListEditorValidationState,\n ListViewItem,\n} from '@/labs/listEditor/types/listEditorTypes'\n\nexport interface DecoratedViewItem<T> extends ListViewItem<T> {\n editing: boolean\n expanded: boolean\n loading: boolean\n dirty: boolean\n moved: boolean\n unsaved: boolean\n validationState: ListEditorValidationState\n canMoveUp: boolean\n canMoveDown: boolean\n}\n\nexport type ReorderMode = 'view' | 'reorder'\n\n// Public slot scope shapes — see AListEditor for the hoisting rationale.\nexport interface RowActions<TItem> {\n edit: () => void\n save: () => Promise<void> | void\n cancel: () => void\n close: () => void\n delete: () => Promise<void>\n addAfter: () => void\n toggleExpand: () => void\n moveUp: () => void\n moveDown: () => void\n moveTop: () => void\n moveBottom: () => void\n update: (next: TItem | Partial<TItem> | ((current: TItem) => TItem)) => void\n}\nexport interface RowSlotProps<TItem extends Record<string, any>> {\n item: DecoratedViewItem<TItem>\n raw: TItem\n index: number\n key: ListEditorKey\n readonly: boolean\n disabled: boolean\n expanded: boolean\n editing: boolean\n dirty: boolean\n unsaved: boolean\n reorderMode: boolean\n moved: boolean\n canMoveUp: boolean\n canMoveDown: boolean\n touch: boolean\n /**\n * Row-scoped `state-key` prefix. Thread it down to any list editor rendered in this slot and set\n * its `:state-key=\"`${stateKeyPrefix}:someList`\"` — that editor's controller then lives in THIS\n * editor's scope and survives the row collapsing (which unmounts the whole slot subtree). Entries\n * under this prefix are disposed when the row is removed.\n */\n stateKeyPrefix: string\n actions: RowActions<TItem>\n}\nexport interface ToolbarSlotProps {\n applying: boolean\n hasPendingChanges: boolean\n movedCount: number\n error: string | null\n actions: { apply: () => Promise<void>; cancel: () => void }\n}\nexport interface ReorderToggleSlotProps {\n mode: ReorderMode\n disabled: boolean\n hasPendingChanges: boolean\n actions: { enterReorderMode: () => void; exitReorderMode: () => void }\n}\nexport interface HeaderSlotProps extends ReorderToggleSlotProps {\n title: string | null\n}\nexport interface EmptySlotProps {\n readonly: boolean\n disabled: boolean\n actions: { add: () => void }\n}\nexport interface AddButtonSlotProps {\n readonly: boolean\n disabled: boolean\n props: { onClick: () => void }\n actions: { add: () => void }\n}\nexport interface ViewBodySlotProps<TItem extends Record<string, any>> {\n items: TItem[]\n mode: ReorderMode\n actions: { enterReorderMode: () => void }\n}\n\nexport interface Props<TItem extends Record<string, any>> {\n /**\n * New-row factory (required). The add button + \"add after this item\" insert\n * `factory()` into the model directly through the controller (positions\n * renumbered) — no consumer `@add` push handler is needed.\n */\n factory?: () => TItem\n /**\n * Stable row identity. Default `'id'`. Never point this at the position field.\n * Typed `string` (not `keyof TItem`): a bare `keyof TItem` on a generic\n * component compiles to a Boolean-only runtime type that coerces `get-key=\"id\"` to `true`.\n */\n getKey?: string | ((item: TItem) => ListEditorKey)\n /**\n * Managed order field. Default `'position'`. `false` opts out. Typed `string`\n * before `false` so the runtime prop type is `[String, Boolean, Object]`:\n * `keyof TItem` would be Boolean-only, and `false` listed first would coerce\n * `position=\"position\"` (value == prop name) to `true`.\n */\n position?:\n | string\n | false\n | {\n field: string\n multiplier?: number\n strategy?: PositionStrategy\n strategyOverrides?: Partial<Record<PositionAction, PositionStrategy>>\n }\n /**\n * Extra fields to drop from the dirty content-hash (position is always\n * dropped). Use when a SEPARATE nested editor tracks a row's child collection,\n * so editing a child doesn't flip the parent amber. The field is still saved.\n */\n dirtyExclude?: string[]\n /** Per-row validity — `true` (or `{ valid: true }`) = VALID. Drives the red rail + save guard. */\n validate?: (item: TItem) => ListEditorValidationResult\n /**\n * Vuelidate `$scope` (the same one the consumer's row forms / save-gate collector use). When set,\n * the editor registers its aggregate validity under it, so a plain `v$.$invalid` save gate blocks\n * AND reveals a collapsed invalid row — no `validateAll()` call needed in the save flow. Omit to\n * keep legacy behavior (gate the save on the exposed `validateAll()` yourself); `false` opts out.\n */\n validationScope?: ListEditorValidationScope | false\n /**\n * Opt-in lifted state controller (from consumer's `useListEditorController()`)\n * so editor state survives this component's unmount/remount (pinned-widget\n * relocation). When omitted the editor owns an internal controller.\n */\n editor?: ListEditorHandle<TItem>\n /**\n * Persist this editor's controller in the nearest ANCESTOR editor's row-state scope under this\n * key, instead of owning it. Use it for an editor rendered in another editor's `#item` slot: that\n * slot is behind a `v-if`, so collapsing the row unmounts this editor and a component-owned\n * controller would re-baseline the already-edited data on re-expand (losing amber, moved rows,\n * tombstones and the red rail). Derive the key from the row slot's `stateKeyPrefix`, e.g.\n * `:state-key=\"`${stateKeyPrefix}:answers`\"`. Options stay declared here, on this tag: the\n * controller is built from THIS editor's `factory`/`get-key`/`position`/`dirty-exclude`/`validate`\n * and rebound to each new instance's model on remount. Ignored when `:editor` is passed, and a\n * no-op without an ancestor scope.\n */\n stateKey?: string\n\n readonly?: boolean\n disabled?: boolean\n loading?: boolean\n error?: string | null\n\n /** Heading above the list. A ready translated string, like every text prop here. */\n title?: string | null\n\n /**\n * Field shown in a collapsed row when no `#item-compact` slot is given. A dotted path reads\n * through nested objects (`texts.title`); a path that runs into nothing renders empty.\n */\n compactField?: string | null\n statusField?: string | null\n twoRows?: 'never' | 'mobile' | 'always'\n chips?: boolean\n\n showAddButton?: boolean\n showDeleteButton?: boolean\n showEditButton?: boolean\n showAddAfterAction?: boolean\n\n /** Label of the add button. A ready translated string; omit it for the library's own wording. */\n addLabel?: string | null\n /** Heading of the empty state. A ready translated string. */\n emptyTitle?: string | null\n\n disableRowClick?: boolean\n disableDeleteConfirm?: boolean\n /**\n * Disable unsaved-state tracking — no dirty markers, never reads as unsaved. For a list that is a\n * VIEW of data owned elsewhere (a display cache rebuilt from a parent's field, say): nothing in\n * such a component can ever clear an amber row, so it must not raise one. Mirrors `AListEditor`.\n */\n disableUnsaved?: boolean\n deleteConfirmTitle?: string | null\n deleteConfirmText?: string | null\n /**\n * How a row delete persists. `deferred` (default): the row disappears but the deletion counts as an\n * unconfirmed change until save (revertible until then, incl. via reorder Cancel). `immediate`: the\n * consumer deletes on the backend — the dialog says it is irreversible and it does NOT read as unsaved.\n */\n deleteMode?: 'immediate' | 'deferred'\n\n closeVariant?: 'auto' | 'icon' | 'labeled'\n\n loadingKeys?: Set<ListEditorKey> | null\n\n showReorderToggle?: boolean\n disableReorder?: boolean\n disableDrag?: boolean\n showMoveToPosition?: boolean\n\n /**\n * Embedded mode — nested inside another editor's `#item` slot, following a\n * shared `v-model:mode`. Hides own Reorder button + toolbar, skips the\n * snapshot/restore (the outer editor's deep snapshot covers nested data), and\n * paints lighter chrome. Pair with `v-model:mode` bound to the outer ref.\n */\n embedded?: boolean\n /**\n * Keep rows inline-editable in reorder mode. By default entering reorder\n * closes any open edit and hides the `#item` body to focus on dragging. Set\n * for a shared-reorder pair's parent, where the open row exposes its embedded\n * answers list for dragging.\n */\n allowEditInReorder?: boolean\n\n onDeleteConfirm?: (item: TItem) => Promise<boolean> | boolean\n onDelete?: (item: TItem) => Promise<void> | void\n onItemSave?: (item: TItem) => Promise<void> | void\n onReorderApply?: (items: TItem[]) => Promise<void> | void\n\n /** Register as a named unsaved-changes section under this (translated) label. */\n unsavedSectionLabel?: string\n}\n\nconst props = withDefaults(defineProps<Props<TItem>>(), {\n factory: undefined,\n getKey: undefined,\n position: undefined,\n dirtyExclude: undefined,\n validate: undefined,\n validationScope: undefined,\n editor: undefined,\n stateKey: undefined,\n readonly: false,\n disabled: false,\n loading: false,\n error: null,\n title: null,\n compactField: null,\n statusField: null,\n twoRows: 'never',\n chips: false,\n showAddButton: true,\n showDeleteButton: true,\n showEditButton: true,\n showAddAfterAction: false,\n addLabel: null,\n emptyTitle: null,\n disableRowClick: false,\n disableDeleteConfirm: false,\n disableUnsaved: false,\n deleteConfirmTitle: null,\n deleteConfirmText: null,\n deleteMode: 'deferred',\n closeVariant: 'auto',\n loadingKeys: null,\n showReorderToggle: true,\n disableReorder: false,\n disableDrag: false,\n showMoveToPosition: false,\n embedded: false,\n allowEditInReorder: false,\n onDeleteConfirm: undefined,\n onDelete: undefined,\n onItemSave: undefined,\n onReorderApply: undefined,\n unsavedSectionLabel: undefined,\n})\n\nconst emit = defineEmits<{\n edit: [item: ListViewItem<TItem>]\n deleted: [item: ListViewItem<TItem>]\n close: [item: ListViewItem<TItem>]\n 'item-saved': [item: ListViewItem<TItem>]\n 'item-expand': [item: ListViewItem<TItem>, expanded: boolean]\n 'reorder-start': []\n 'reorder-cancel': []\n 'reorder-applied': [items: TItem[]]\n 'reorder-apply-error': [error: unknown]\n 'reorder-end': []\n}>()\n\ndefineSlots<{\n header?: (props: HeaderSlotProps) => unknown\n 'reorder-toggle'?: (props: ReorderToggleSlotProps) => unknown\n 'reorder-toolbar'?: (props: ToolbarSlotProps) => unknown\n empty?: (props: EmptySlotProps) => unknown\n 'add-button'?: (props: AddButtonSlotProps) => unknown\n 'view-body'?: (props: ViewBodySlotProps<TItem>) => unknown\n item?: (props: RowSlotProps<TItem>) => unknown\n 'item-compact'?: (props: RowSlotProps<TItem>) => unknown\n 'item-readonly'?: (props: RowSlotProps<TItem>) => unknown\n 'item-status'?: (props: RowSlotProps<TItem>) => unknown\n 'item-actions'?: (props: RowSlotProps<TItem>) => unknown\n 'item-footer'?: (props: RowSlotProps<TItem>) => unknown\n 'before-item'?: (props: RowSlotProps<TItem>) => unknown\n 'after-item'?: (props: RowSlotProps<TItem>) => unknown\n}>()\n\nconst modelValue = defineModel<TItem[]>({ required: true })\nconst mode = defineModel<ReorderMode>('mode', { default: 'view' })\n\nconst { t } = useI18n()\nconst slots = useSlots()\n\nconst rootEl = useTemplateRef<HTMLElement>('rootEl')\nconst { isNarrow } = useContainerWidth(rootEl)\n\nconst isTouch = useIsTouchDevice()\nconst hasCoarsePointer = useHasCoarsePointer()\n\n// State controller (v2). `factory`/`getKey`/`position`/`validate` are construction-time options read\n// once to seed the controller, not reactive props — hence the suppressed reactivity-loss rule.\n// Undefined options fall back to controller defaults ('id' / 'position' / always-valid).\n/* eslint-disable vue/no-setup-props-reactivity-loss */\nconst controllerOptions: ListEditorStateBindings<TItem> = {\n get: () => modelValue.value,\n set: (v) => (modelValue.value = v),\n factory: props.factory,\n getKey: props.getKey as GetKey<TItem> | undefined,\n position: props.position as PositionOption<TItem> | undefined,\n dirtyExclude: () => props.dirtyExclude ?? [],\n validate: props.validate,\n}\n// Precedence: an explicitly lifted `:editor` wins; then a `state-key`'d entry persisted in the\n// nearest ancestor editor's row-state scope (built from the options above, rebound to this instance\n// on every remount); else this component owns the controller — today's behaviour, unchanged.\nconst stateEntry = props.editor ? null : useListEditorStateEntry<TItem>(props.stateKey, controllerOptions)\nconst controller = props.editor ?? stateEntry?.handle ?? useListEditorController<TItem>(controllerOptions)\n\n// Local mirror of the controller's key resolution so rendered rows key the same\n// way the controller tracks them (v2 spec point 7).\nconst getKeyOpt = props.getKey ?? 'id'\n/* eslint-enable vue/no-setup-props-reactivity-loss */\n\n// Row-state scope for THIS editor's `#item` slot subtree: a nested editor with a `state-key` builds\n// its controller in here, so it outlives the row collapsing (which unmounts the slot). When this\n// editor is itself persisted, the scope comes from its own entry — so the chain holds at any depth.\nconst rowStateScope = provideListEditorStateScope(stateEntry?.childScope ?? null)\nconst keyOf = (item: TItem): ListEditorKey =>\n typeof getKeyOpt === 'function' ? getKeyOpt(item) : (item[getKeyOpt as keyof TItem] as ListEditorKey)\n\n// Managed position field (for the row position view field + move-to-position\n// dialog). Mirrors the controller's resolution.\nconst positionFieldName = computed<string>(() => {\n const p = props.position\n if (p === undefined) return 'position'\n if (p === false) return 'position'\n if (typeof p === 'object') return p.field as string\n return p as string\n})\n\n// Keyed render projection (key + index + raw + position); the controller owns the data.\nconst viewItems = computed<ListViewItem<TItem>[]>(() =>\n modelValue.value.map((raw, index) => ({\n key: keyOf(raw),\n index,\n raw,\n position: raw[positionFieldName.value] as number | undefined,\n }))\n)\n\n// Drop the persisted controllers of rows that no longer exist. `post` so the removed row's subtree\n// has already unmounted (its editors released their entries) before we stop their effect scopes.\nwatch(\n () => viewItems.value.map((vi) => String(vi.key)).join('|'),\n () => rowStateScope.retainOwners(viewItems.value.map((vi) => vi.key)),\n { flush: 'post' }\n)\n\nconst expandedKeys = ref<Set<ListEditorKey>>(new Set())\n\n// Reorder-session moved set — component view state, distinct from the\n// controller's persistent moved tracking. Drives the toolbar's \"N pending\n// changes\" counter; cleared on every mode transition by `useReorderMode`.\nconst movedKeys = ref<Set<ListEditorKey>>(new Set())\n// Deletes made DURING the current reorder session, split by mode. Deferred ones count in the toolbar\n// and are reverted on Cancel (row restored, tombstone cleared). Immediate (backend) ones are re-applied\n// on Cancel so they stay gone — else Cancel's snapshot-restore would resurrect a row already deleted on\n// the server (a phantom a later save could re-create).\nconst sessionDeferredDeletes = ref<Set<ListEditorKey>>(new Set())\nconst sessionImmediateDeletes = ref<Set<ListEditorKey>>(new Set())\n// Rows ADDED during the current reorder session (\"Pridať za túto položku\"). Count in the toolbar so\n// Apply enables instead of trapping the user; Cancel drops them (snapshot-restore removes rows that\n// weren't in the enter-time snapshot).\nconst sessionAddedKeys = ref<Set<ListEditorKey>>(new Set())\n// Rows MOVED during the current reorder session. On Cancel the snapshot-restore undoes the reorder, so\n// these keys' persistent \"moved\" flag must be dropped from the controller too (else they stay falsely\n// amber + arm the leave guard for a reorder that never happened). Apply keeps them (persisted on save).\nconst sessionMovedKeys = ref<Set<ListEditorKey>>(new Set())\n\nconst snapshot = shallowRef<TItem[] | null>(null)\n\nconst rowsContainer = useTemplateRef<HTMLElement>('rowsContainer')\n\nconst isInlineEdit = computed(() => !props.chips && !!slots.item)\nconst hasReadonlyDetail = computed(() => !props.chips && !!slots['item-readonly'])\n\nconst { editingKeys, editingSnapshots, clearEditing, beginEdit, cancelEdit, commitEdit, closeEdit, requestAutoOpen } =\n useInlineEditing<TItem, ListViewItem<TItem>>({\n rowsContainer,\n rowSelector: '.a-le-row',\n isInlineEdit,\n restoreSnapshot: (key, data) => controller.updateItem(key, data),\n watchKeys: () => modelValue.value.map((it) => keyOf(it)),\n findEntry: (key) => {\n const hit = modelValue.value.find((it) => keyOf(it) === key)\n return hit ? { data: hit } : null\n },\n afterAutoOpen: (key) => {\n expandedKeys.value.delete(key)\n },\n })\n\nconst canInteract = computed(() => !props.readonly && !props.disabled && !props.loading)\nconst canEnterReorder = computed(() => canInteract.value && !props.disableReorder && modelValue.value.length > 1)\n\nconst embeddedRef = computed(() => props.embedded)\nconst allowEditInReorderRef = computed(() => props.allowEditInReorder)\n\nconst {\n applying,\n applyError,\n hasPendingChanges,\n movedCount,\n reorderMode,\n enterReorderMode,\n cancelReorderMode,\n applyReorder,\n} = useReorderMode<TItem[]>({\n mode,\n snapshot,\n movedKeys,\n modelValue,\n cloneModel: (m) => cloneDeep(m) as TItem[],\n applyModel: (m) => {\n modelValue.value = m\n },\n canEnterReorder,\n embedded: embeddedRef,\n onEnter: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n if (!allowEditInReorderRef.value) {\n clearEditing()\n expandedKeys.value.clear()\n }\n },\n onExternalEnter: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n if (!allowEditInReorderRef.value) {\n clearEditing()\n expandedKeys.value.clear()\n }\n },\n // Cancel reverts the session. The composable's snapshot-restore has already brought EVERY deleted row\n // back into the model; reconcile the controller: deferred deletes are truly reverted (clear tombstone,\n // row stays), immediate deletes are re-applied (row removed again — it is gone on the backend and must\n // not resurrect or be re-created by a later save).\n onCancel: () => {\n for (const key of sessionDeferredDeletes.value) controller.restoreDeleted(key)\n for (const key of sessionImmediateDeletes.value) controller.deleteItem(key, { trackDeleted: false })\n // Snapshot-restore already undid the reorder — drop the controller's \"moved\" flag for exactly the\n // rows moved this session (edits/adds keep their amber), so a cancelled reorder leaves no false unsaved.\n controller.clearMoved(sessionMovedKeys.value)\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n // Apply keeps the session's changes (deferred deletes persist on the entity's main save; moved rows stay\n // amber in the controller until the consumer commits after their save — only reset the session tracker).\n onApplyEnd: () => {\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n // Embedded editor exit (parent Cancel or Apply — it owns the snapshot, we never do). On a parent\n // Cancel the snapshot-restore resurrects any row we deleted IMMEDIATELY on the backend; re-remove it so\n // it stays gone. On Apply it never came back, so `deleteItem` is a no-op. Deferred deletes need nothing:\n // the controller's re-add watch drops their tombstone when the restore brings the row back.\n onEmbeddedExit: () => {\n for (const key of sessionImmediateDeletes.value) controller.deleteItem(key, { trackDeleted: false })\n sessionDeferredDeletes.value = new Set()\n sessionImmediateDeletes.value = new Set()\n sessionAddedKeys.value = new Set()\n sessionMovedKeys.value = new Set()\n },\n onReorderApply: (items) => props.onReorderApply?.(items),\n emit: {\n reorderStart: () => emit('reorder-start'),\n reorderCancel: () => emit('reorder-cancel'),\n reorderApplied: (payload) => emit('reorder-applied', payload),\n reorderApplyError: (err) => emit('reorder-apply-error', err),\n reorderEnd: () => emit('reorder-end'),\n },\n})\n\n// Stacked-editor registry: outer collects movedCount + hasChanges from embedded\n// children for the toolbar counter. shallowReactive preserves ComputedRef\n// identity (no auto-unwrap).\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst childContributions = props.embedded\n ? null\n : shallowReactive(\n new Map<symbol, { count: ComputedRef<number>; hasChanges: ComputedRef<boolean>; validateAll: () => boolean }>()\n )\n\nif (childContributions) {\n const registry: SharedReorderRegistry = {\n register: (id, count, hasChanges, validateAll) => {\n childContributions.set(id, { count, hasChanges, validateAll })\n },\n unregister: (id) => {\n childContributions.delete(id)\n },\n }\n provide(SharedReorderRegistryKey, registry)\n}\n\n// Own session moves + each embedded child's FULL pending contribution (moves + its own deferred\n// deletes — children register `totalPendingCount`, see below). The outer's own deferred deletes are\n// added on top in `totalPendingCount`.\nconst totalMovedCount = computed<number>(() => {\n let sum = movedCount.value\n if (childContributions) {\n for (const c of childContributions.values()) sum += c.count.value\n }\n return sum\n})\n\nconst totalHasPendingChanges = computed<boolean>(() => {\n if (hasPendingChanges.value) return true\n if (childContributions) {\n for (const c of childContributions.values()) {\n if (c.hasChanges.value) return true\n }\n }\n return false\n})\n\n// Reorder-toolbar pending indicator = session moves + deferred deletes made in the session, so\n// deleting a row in reorder mode no longer reads as \"no pending changes\" and Apply stays enabled.\nconst totalPendingCount = computed<number>(\n () => totalMovedCount.value + sessionDeferredDeletes.value.size + sessionAddedKeys.value.size\n)\nconst totalPendingChanges = computed<boolean>(\n () => totalHasPendingChanges.value || sessionDeferredDeletes.value.size > 0 || sessionAddedKeys.value.size > 0\n)\n\n// An embedded editor pushes its FULL pending contribution — moves AND deferred deletes — up to the\n// nearest non-embedded outer, so deleting a row in an embedded child during a shared reorder lights up\n// the outer's toolbar (count + Apply-enabled) instead of reading \"no pending changes\". Registered after\n// `totalPendingCount`/`totalPendingChanges` so they exist (TDZ); `validateAllSelf` is a lazy thunk.\nif (props.embedded) {\n const parent = inject(SharedReorderRegistryKey, null)\n if (parent) {\n const id = Symbol('le.embedded')\n parent.register(id, totalPendingCount, totalPendingChanges, () => validateAllSelf())\n onBeforeUnmount(() => parent.unregister(id))\n }\n}\n\nconst canAdd = computed(() => canInteract.value && props.showAddButton && !reorderMode.value)\n// Chips mode keeps drag always-on (no mode toggle) on non-touch devices.\nconst dragEnabled = computed(\n () => canInteract.value && (reorderMode.value || props.chips) && !isTouch.value && !props.disableDrag\n)\n\nconst addLabelResolved = computed(() => props.addLabel ?? t('common.sortable.add'))\nconst emptyTitleResolved = computed(() => props.emptyTitle ?? t('common.sortable.emptyTitle'))\nconst deleteConfirmTitleResolved = computed(() => props.deleteConfirmTitle ?? t('common.sortable.deleteConfirmTitle'))\nconst deleteConfirmTextResolved = computed(\n () =>\n props.deleteConfirmText ??\n (props.deleteMode === 'immediate'\n ? t('common.sortable.deleteConfirmText')\n : t('common.sortable.deleteConfirmTextDeferred'))\n)\n\nconst reorderToggleVisible = computed<boolean>(\n (): boolean =>\n !props.chips && !props.embedded && props.showReorderToggle && !reorderMode.value && modelValue.value.length > 0\n)\n\n// With a title and a narrow viewport, the reorder button shrinks to an icon-only\n// round button to keep the single-line header from overflowing.\nconst compactReorderButton = computed<boolean>((): boolean => !!props.title && isNarrow.value)\n\n// Total unconfirmed-change count (added/edited/moved rows + deferred deletions) — a delete lights it\n// up even though its row is gone. Shown as a view-mode header badge + on the handle; in reorder mode\n// the toolbar status shows the session count instead.\nconst unsavedCount = controller.unsavedCount\nconst unsavedCountVisible = computed(() => !props.readonly && !props.disableUnsaved && unsavedCount.value > 0)\nconst headerVisible = computed<boolean>(\n (): boolean =>\n !!(\n props.title ||\n slots.header ||\n slots['reorder-toggle'] ||\n reorderToggleVisible.value ||\n (reorderMode.value && !props.embedded) ||\n (!reorderMode.value && unsavedCountVisible.value)\n )\n)\n\n// True when the header has substantive content (title or custom header slot).\n// When false it still renders as a slim band right-aligning just the\n// reorder/apply controls, holding height across idle ↔ reorder so it doesn't jump.\nconst headerHasContent = computed<boolean>(\n (): boolean => !!(props.title || slots.header || slots['reorder-toggle'] || slots['view-body'])\n)\n\n// Per-row Save/Cancel footer only matters with a per-item persist callback;\n// otherwise the parent form's global save flushes everything, so hide it.\nconst showInlineSaveFooter = computed(() => !!props.onItemSave)\n\n// Reorder-session moved marker (drag, arrow buttons) feeding the toolbar counter;\n// the persistent amber `unsaved` flag is the controller's.\nconst markMoved = (key: ListEditorKey) => {\n movedKeys.value.add(key)\n sessionMovedKeys.value.add(key)\n}\n\n// Per-key decorator cache — see AListEditor for rationale. `unsaved` (amber) and\n// `validationState` (red rail) come from the controller; `moved` is the\n// reorder-session flag.\nconst decoratorCache = new Map<ListEditorKey, DecoratedViewItem<TItem>>()\nconst viewItemsDecorated = computed<DecoratedViewItem<TItem>[]>(() => {\n const total = modelValue.value.length\n const next: DecoratedViewItem<TItem>[] = []\n const liveKeys = new Set<ListEditorKey>()\n for (const vi of viewItems.value) {\n liveKeys.add(vi.key)\n const editing = editingKeys.value.has(vi.key)\n const expanded = expandedKeys.value.has(vi.key)\n const loading = props.loadingKeys?.has(vi.key) ?? false\n const moved = movedKeys.value.has(vi.key)\n // readonly → no amber markers (can't have unsaved changes; also dodges a\n // mount-before-load empty baseline). (QA 85050 sweep)\n // `disableUnsaved` suppresses only the amber marker — the validation rail still shows, since\n // hiding dirty state should not hide a real error.\n const unsaved = props.disableUnsaved || props.readonly ? false : controller.isUnsaved(vi.key)\n const dirty = unsaved\n // `editing` → the controller reads amber (not red) while the row is being filled in. (QA 85050 b7)\n const validationState = controller.rowState(vi.raw, vi.key, editing)\n const canMoveUp = vi.index > 0\n const canMoveDown = vi.index < total - 1\n const cached = decoratorCache.get(vi.key)\n if (\n cached &&\n cached.raw === vi.raw &&\n cached.index === vi.index &&\n cached.position === vi.position &&\n cached.editing === editing &&\n cached.expanded === expanded &&\n cached.loading === loading &&\n cached.dirty === dirty &&\n cached.moved === moved &&\n cached.unsaved === unsaved &&\n cached.validationState === validationState &&\n cached.canMoveUp === canMoveUp &&\n cached.canMoveDown === canMoveDown\n ) {\n next.push(cached)\n continue\n }\n const decorated: DecoratedViewItem<TItem> = {\n ...vi,\n editing,\n expanded,\n loading,\n dirty,\n moved,\n unsaved,\n validationState,\n canMoveUp,\n canMoveDown,\n }\n decoratorCache.set(vi.key, decorated)\n next.push(decorated)\n }\n for (const key of decoratorCache.keys()) {\n if (!liveKeys.has(key)) decoratorCache.delete(key)\n }\n return next\n})\n\nconst isEmpty = computed(() => viewItemsDecorated.value.length === 0)\n\nconst findVi = (key: ListEditorKey): DecoratedViewItem<TItem> | undefined =>\n viewItemsDecorated.value.find((v) => v.key === key)\n\n// Programmatically open a row's inline-edit form (e.g. open auto-seeded rows on mount). Multiple\n// rows can be open at once. No-op for chips / when there is no `#item` slot.\nconst openRow = (key: ListEditorKey): void => {\n if (!isInlineEdit.value) return\n const vi = findVi(key)\n if (vi) beginEdit(vi)\n}\nconst openAll = (): void => {\n if (!isInlineEdit.value) return\n for (const vi of viewItemsDecorated.value) beginEdit(vi)\n}\n\n// Validate + reveal this editor's OWN rows (no cascade). The exposed `validateAll`\n// wraps this and also cascades into embedded children; embedded children register\n// this self-only variant so a parent save reveals their invalid rows red too.\nconst validateAllSelf = (): boolean =>\n validateAllAndReveal(controller, (key) => {\n const vi = viewItems.value.find((v) => v.key === key)\n if (vi) beginEdit(vi)\n })\n\n// Auto-bridge the editor's aggregate validity into the consumer's `validation-scope` collector so a\n// plain `$invalid` save gate blocks (and reveals) a collapsed invalid row. No-op without the prop.\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss -- construction-time opt-in, read once\nuseListEditorScopeValidity({\n hasErrors: controller.hasErrors,\n validationScope: props.validationScope,\n validateProvided: props.validate !== undefined,\n reveal: validateAllSelf,\n})\n\nconst keyboardNav = useKeyboardNav({\n viewItems: computed(() => viewItemsDecorated.value.map((vi) => ({ key: vi.key }))),\n variant: 'sortable',\n isReorderMode: reorderMode,\n disabled: computed(() => !canInteract.value),\n isEditing: (key) => editingKeys.value.has(key),\n onToggleEdit: (key) => {\n const vi = findVi(key)\n if (vi) onEditClick(vi)\n },\n onCancelEdit: (key) => {\n const vi = findVi(key)\n if (vi) onCloseClick(vi)\n },\n onMoveUp: (key) => {\n const vi = findVi(key)\n if (vi) moveUp(vi.index)\n },\n onMoveDown: (key) => {\n const vi = findVi(key)\n if (vi) moveDown(vi.index)\n },\n onMoveTop: (key) => {\n const vi = findVi(key)\n if (vi) moveTop(vi.index)\n },\n onMoveBottom: (key) => {\n const vi = findVi(key)\n if (vi) moveBottom(vi.index)\n },\n onCancelReorder: () => cancelReorderMode(),\n})\n\nconst moveToPositionDialogOpen = ref<boolean>(false)\nconst moveToPositionTarget = shallowRef<DecoratedViewItem<TItem> | null>(null)\nconst moveToPositionLabel = computed<string>(() =>\n moveToPositionTarget.value ? resolveCompactText(moveToPositionTarget.value.raw) : ''\n)\nconst openMoveToPosition = (vi: DecoratedViewItem<TItem>) => {\n if (!props.showMoveToPosition) return\n moveToPositionTarget.value = vi\n moveToPositionDialogOpen.value = true\n}\nconst onMoveToPositionConfirm = (newIndex: number) => {\n const target = moveToPositionTarget.value\n moveToPositionTarget.value = null\n if (!target) return\n if (newIndex === target.index) return\n controller.moveItem(target.index, newIndex)\n markMoved(target.key)\n}\n\nconst resolveCompactText = (raw: TItem): string => resolveCompactTextUtil(raw, { compactField: props.compactField })\n\n// Always instantiate SortableJS, seeded `disabled: !dragEnabled` and kept in sync\n// by the watch below. It used to be created only when `isTouch` was false at setup\n// — but `isTouch` is a live media query (plug in a mouse, toggle device emulation),\n// and that one-shot read left the instance missing when it later flipped: the drag\n// handle rendered but dragging did nothing. The setup cost this saved on touch\n// devices is not worth a dead handle.\n/* eslint-disable vue/no-ref-object-reactivity-loss */\nconst sortable = useSortable(rowsContainer, modelValue, {\n // The rows container can mount/unmount across mode flips (e.g. a `#view-body`\n // slot in view mode, rows only in reorder mode). vueuse's default\n // `tryOnMounted` fires once and would bind to a null ref, leaving SortableJS\n // dead; `watchElement: true` re-inits whenever the ref populates.\n watchElement: true,\n handle: '.a-le-drag-handle',\n animation: 150,\n // Force the fallback renderer so `dragClass` applies to a CSS-controlled\n // clone following the cursor — a row-shaped ghost instead of the opaque\n // browser-native drag bitmap.\n forceFallback: true,\n fallbackTolerance: 3,\n fallbackOnBody: true,\n ghostClass: DRAG_GHOST_CLASS,\n chosenClass: DRAG_CHOSEN_CLASS,\n dragClass: DRAG_CLASS,\n disabled: !dragEnabled.value,\n // Own `onUpdate` REPLACES vueuse's default array-move, which moved the array\n // and renumbered positions in separate `nextTick`s — a gap that let a\n // consumer's \"sort by position\" watch re-sort on stale positions and revert\n // the drop. One synchronous `controller.moveItem` closes that window so every\n // observer sees the final order and positions at once.\n onUpdate: (event) => {\n const { oldIndex, newIndex, item, from } = event\n if (oldIndex === undefined || newIndex === undefined) return\n // Undo SortableJS's DOM relocation so Vue's keyed v-for stays the single\n // source of truth (mirrors vueuse's removeNode + insertNodeAt).\n if (item && from) {\n item.parentNode?.removeChild(item)\n from.insertBefore(item, from.children[oldIndex] ?? null)\n }\n // moveItem rewrites the array, renumbers positions, and records the moved\n // key — all synchronously.\n controller.moveItem(oldIndex, newIndex)\n },\n onEnd: (event) => {\n // Mark only the dragged row (via its data-id) moved rather than diffing the\n // whole list, so siblings that shifted index stay clean. `event.item` is the\n // `.a-le-row-wrapper` sortable item; the `[data-id]` lives on the inner `.a-le-row`.\n const el = event.item as HTMLElement\n // `:scope >` so a consumer editor nested in a `#before-item` slot (its own\n // `.a-le-row` descendants) can't shadow this row's own id.\n const raw = (el.querySelector(':scope > .a-le-row') ?? el).getAttribute('data-id')\n if (raw !== null && raw !== '') {\n // Numeric key only when `data-id` is a pure integer string (incl. negative\n // temp ids like \"-1\"); otherwise keep the UUID-style string. `n > 0`\n // wrongly sent negative ids down the string branch, landing amber on the\n // wrong key.\n const n = stringToInt(raw)\n const key: ListEditorKey = String(n) === raw ? n : raw\n markMoved(key)\n }\n },\n})\n\n// Options are built once at setup, when a `#view-body` consumer is still in view mode and\n// `dragEnabled` is false; entering reorder mode mounts the container and `watchElement` re-creates\n// SortableJS from that stale object. Hence watching the container too.\nwatch(\n [dragEnabled, rowsContainer],\n async () => {\n // after `watchElement` has re-created the instance\n await nextTick()\n sortable.option('disabled', !dragEnabled.value)\n },\n { flush: 'post' }\n)\n/* eslint-enable vue/no-ref-object-reactivity-loss */\n\n// Managed add: the controller mints + inserts `factory()` and renumbers\n// positions; the inline-editing watch picks up the new key and auto-opens it.\nconst onAddClick = () => {\n if (!canAdd.value) return\n requestAutoOpen()\n controller.addItem(undefined, undefined)\n}\n\nconst onRowAddAfterClick = (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n requestAutoOpen()\n const key = controller.addItem(undefined, { afterId: vi.key })\n // Added during a reorder session (\"Pridať za túto položku\") → count it in the toolbar.\n if (reorderMode.value && key !== undefined) sessionAddedKeys.value.add(key)\n}\n\nconst onEditClick = (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n if (reorderMode.value && !props.allowEditInReorder) return\n // Clicking edit while already editing closes the form (matches row-header click).\n if (editingKeys.value.has(vi.key)) {\n onCloseClick(vi)\n return\n }\n if (isInlineEdit.value) {\n beginEdit(vi)\n expandedKeys.value.delete(vi.key)\n }\n emit('edit', vi)\n}\n\nconst onExpandClick = (vi: ListViewItem<TItem>) => {\n if (props.disabled || props.loading) return\n if (reorderMode.value && !props.allowEditInReorder) return\n const key = vi.key\n const currentlyExpanded = expandedKeys.value.has(key)\n if (currentlyExpanded) {\n expandedKeys.value.delete(key)\n } else {\n for (const k of expandedKeys.value) expandedKeys.value.delete(k)\n expandedKeys.value.add(key)\n }\n emit('item-expand', vi, !currentlyExpanded)\n}\n\nconst isRowClickable = (vi: DecoratedViewItem<TItem>): boolean => {\n if (props.chips) return false\n if (props.disableRowClick) return false\n if (props.disabled || props.loading) return false\n if (reorderMode.value && !props.allowEditInReorder) return false\n if (vi.editing || vi.expanded) return true\n if (!props.readonly && props.showEditButton) return true\n return false\n}\n\nconst onRowClick = (vi: DecoratedViewItem<TItem>) => {\n if (!isRowClickable(vi)) return\n if (vi.editing || vi.expanded) {\n onCloseClick(vi)\n return\n }\n if (props.readonly && hasReadonlyDetail.value) {\n onExpandClick(vi)\n } else {\n onEditClick(vi)\n }\n}\n\nconst {\n deleteDialog,\n deleteInFlight,\n deleteError,\n onDeleteClick: triggerDeleteClick,\n onDeleteDialogConfirm,\n onDeleteDialogCancel,\n} = useDeleteDialog<TItem, ListViewItem<TItem>>({\n onDeleteConfirm: (raw) => (props.onDeleteConfirm ? props.onDeleteConfirm(raw) : true),\n onDelete: (raw) => props.onDelete?.(raw),\n onDeleted: (vi) => {\n editingKeys.value.delete(vi.key)\n editingSnapshots.value.delete(vi.key)\n expandedKeys.value.delete(vi.key)\n movedKeys.value.delete(vi.key)\n const deferred = props.deleteMode === 'deferred'\n // In reorder mode: a deferred delete is a reversible session change (counts in the toolbar,\n // reverts on Cancel); an immediate delete is already gone on the backend, so drop it from the\n // reorder snapshot too — else Cancel's snapshot-restore would resurrect it.\n if (reorderMode.value) {\n if (sessionAddedKeys.value.has(vi.key)) {\n // Added AND deleted within the same reorder session — net zero. The controller drops the temp\n // row with no tombstone, so it must not linger in either counter (was double-counted: L1).\n sessionAddedKeys.value.delete(vi.key)\n } else if (deferred) {\n sessionDeferredDeletes.value.add(vi.key)\n } else {\n sessionImmediateDeletes.value.add(vi.key)\n }\n }\n // Controller owns the data: temp rows vanish; a deferred saved-row delete lands in\n // `getChanges().deleted` + counts as unsaved; immediate skips the tombstone (already persisted).\n controller.deleteItem(vi.key, { trackDeleted: deferred })\n emit('deleted', vi)\n },\n disableDeleteConfirm: () => props.disableDeleteConfirm || props.chips,\n})\n\nconst onDeleteClick = async (vi: ListViewItem<TItem>) => {\n if (!canInteract.value) return\n await triggerDeleteClick(vi)\n}\n\nconst onSaveClick = async (vi: ListViewItem<TItem>) => {\n if (props.onItemSave) {\n await props.onItemSave(vi.raw)\n }\n commitEdit(vi)\n emit('item-saved', vi)\n}\n\nconst onCancelClick = (vi: ListViewItem<TItem>) => {\n cancelEdit(vi)\n}\n\nconst onCloseClick = (vi: ListViewItem<TItem>) => {\n closeEdit(vi)\n expandedKeys.value.delete(vi.key)\n emit('close', vi)\n}\n\nconst keyAtIndex = (idx: number): ListEditorKey | null => {\n const item = modelValue.value[idx]\n if (!item) return null\n return keyOf(item)\n}\n\nconst moveUp = (idx: number) => {\n if (idx <= 0) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, idx - 1)\n if (key !== null) markMoved(key)\n}\nconst moveDown = (idx: number) => {\n if (idx >= modelValue.value.length - 1) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, idx + 1)\n if (key !== null) markMoved(key)\n}\nconst moveTop = (idx: number) => {\n if (idx <= 0) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, 0)\n if (key !== null) markMoved(key)\n}\nconst moveBottom = (idx: number) => {\n if (idx >= modelValue.value.length - 1) return\n const key = keyAtIndex(idx)\n controller.moveItem(idx, modelValue.value.length - 1)\n if (key !== null) markMoved(key)\n}\n\n// Per-key actions cache: stable identity per row — see AListEditor for\n// rationale. Closures capture the stable key and resolve the current vi via\n// findVi at call time.\ntype ActionsBundle = {\n edit: () => void\n save: () => Promise<void> | void\n cancel: () => void\n close: () => void\n delete: () => Promise<void>\n addAfter: () => void\n toggleExpand: () => void\n moveUp: () => void\n moveDown: () => void\n moveTop: () => void\n moveBottom: () => void\n update: (next: TItem | Partial<TItem> | ((current: TItem) => TItem)) => void\n}\nconst actionsCache = new Map<ListEditorKey, ActionsBundle>()\nconst getActions = (key: ListEditorKey): ActionsBundle => {\n let actions = actionsCache.get(key)\n if (!actions) {\n actions = {\n edit: () => {\n const vi = findVi(key)\n if (vi) onEditClick(vi)\n },\n save: () => {\n const vi = findVi(key)\n if (vi) return onSaveClick(vi)\n },\n cancel: () => {\n const vi = findVi(key)\n if (vi) onCancelClick(vi)\n },\n close: () => {\n const vi = findVi(key)\n if (vi) onCloseClick(vi)\n },\n delete: async () => {\n const vi = findVi(key)\n if (vi) await onDeleteClick(vi)\n },\n addAfter: () => {\n const vi = findVi(key)\n if (vi) onRowAddAfterClick(vi)\n },\n toggleExpand: () => {\n const vi = findVi(key)\n if (vi) onExpandClick(vi)\n },\n moveUp: () => {\n const vi = findVi(key)\n if (vi) moveUp(vi.index)\n },\n moveDown: () => {\n const vi = findVi(key)\n if (vi) moveDown(vi.index)\n },\n moveTop: () => {\n const vi = findVi(key)\n if (vi) moveTop(vi.index)\n },\n moveBottom: () => {\n const vi = findVi(key)\n if (vi) moveBottom(vi.index)\n },\n update: (next) => controller.updateItem(key, next),\n }\n actionsCache.set(key, actions)\n }\n return actions\n}\nwatch(\n () => viewItemsDecorated.value,\n (now) => {\n if (actionsCache.size === 0) return\n const liveKeys = new Set(now.map((v) => v.key))\n for (const key of actionsCache.keys()) {\n if (!liveKeys.has(key)) actionsCache.delete(key)\n }\n }\n)\n\nconst buildSlotProps = (vi: DecoratedViewItem<TItem>) => ({\n item: vi,\n raw: vi.raw,\n index: vi.index,\n key: vi.key,\n readonly: props.readonly,\n disabled: props.disabled,\n expanded: vi.expanded,\n editing: vi.editing,\n dirty: vi.dirty,\n unsaved: vi.unsaved,\n reorderMode: reorderMode.value,\n moved: vi.moved,\n canMoveUp: vi.canMoveUp,\n canMoveDown: vi.canMoveDown,\n touch: isTouch.value,\n stateKeyPrefix: rowStateScope.prefixFor(vi.key),\n actions: getActions(vi.key),\n})\n\nconst toolbarSlotProps = computed(() => ({\n applying: applying.value,\n hasPendingChanges: totalPendingChanges.value,\n movedCount: totalPendingCount.value,\n error: applyError.value,\n actions: {\n apply: applyReorder,\n cancel: cancelReorderMode,\n },\n}))\n\nconst reorderToggleSlotProps = computed(() => ({\n mode: mode.value,\n disabled: !canEnterReorder.value,\n hasPendingChanges: totalHasPendingChanges.value,\n actions: {\n enterReorderMode,\n exitReorderMode: cancelReorderMode,\n },\n}))\n\n// Registers a named unsaved-changes section when the consumer passes a label.\nuseUnsavedSection(() =>\n props.unsavedSectionLabel && !props.disableUnsaved\n ? { label: props.unsavedSectionLabel, dirty: controller.hasUnsaved.value }\n : []\n)\n\n// Expose the controller handle (validateAll/getPayload/commit/etc. via\n// `useTemplateRef<ListEditorHandle<TItem>>`) plus the reorder-mode controls.\ndefineExpose<\n ListEditorHandle<TItem> & {\n enterReorderMode: () => void\n cancelReorderMode: () => void\n applyReorder: () => Promise<void>\n openRow: (key: ListEditorKey) => void\n openAll: () => void\n }\n>({\n ...controller,\n openRow,\n openAll,\n // Saving is separate from the editor's \"Apply\", so a consumer can commit while still in\n // reorder mode with an unapplied move. The reorder session (component-level `movedKeys` +\n // snapshot) is NOT controller state, so re-baseline it here too — otherwise the \"N pending\n // changes\" badge lingers after the save and a later Cancel would revert past it.\n commit: (savedItems?: TItem[]) => {\n controller.commit(savedItems)\n movedKeys.value = new Set()\n if (snapshot.value) snapshot.value = cloneDeep(modelValue.value) as TItem[]\n },\n // validateAll() also opens invalid rows so a blocked save surfaces WHICH rows\n // are wrong — their #item form mounts instead of a collapsed red rail (QA 85050\n // B4-17). The body is gated on `editing` (not `expanded`), so drive `beginEdit`.\n // Shared with AListEditor + ANestedSortableListEditor via the helper.\n validateAll: () => {\n // Cascade into embedded children — a single outer save reveals invalid rows red\n // at every nesting level (e.g. quiz question turning red must also red its answers).\n const selfValid = validateAllSelf()\n if (!childContributions) return selfValid\n let valid = selfValid\n for (const child of childContributions.values()) {\n if (!child.validateAll()) valid = false\n }\n return valid\n },\n enterReorderMode,\n cancelReorderMode,\n applyReorder,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n class=\"a-sortable-list-editor\"\n :class=\"[\n `a-sortable-list-editor--two-rows-${twoRows}`,\n `a-sortable-list-editor--mode-${mode}`,\n {\n 'a-sortable-list-editor--readonly': readonly,\n 'a-sortable-list-editor--disabled': disabled,\n 'a-sortable-list-editor--touch': isTouch,\n 'a-sortable-list-editor--drag-enabled': dragEnabled,\n 'a-sortable-list-editor--chips': chips,\n 'a-sortable-list-editor--embedded': embedded,\n 'a-sortable-list-editor--header-floating': !embedded && !chips && !headerHasContent && headerVisible,\n },\n ]\"\n >\n <div class=\"a-le-card\">\n <div\n v-if=\"headerVisible\"\n class=\"a-le-header\"\n >\n <slot\n name=\"header\"\n :title=\"title\"\n v-bind=\"reorderToggleSlotProps\"\n >\n <h3\n v-if=\"title\"\n class=\"a-le-title-heading\"\n >\n {{ title }}\n </h3>\n <span\n v-if=\"!reorderMode && unsavedCountVisible\"\n class=\"a-le-unsaved-count\"\n :data-unsaved-count=\"unsavedCount\"\n >\n {{ t('common.sortable.pendingChanges', { count: unsavedCount }) }}\n </span>\n <div class=\"a-le-header-actions\">\n <template v-if=\"reorderMode && !embedded\">\n <!-- Reorder-mode header: pending count + Cancel/Apply, sitting\n where the \"Reorder\" button lives in view mode. -->\n <slot\n name=\"reorder-toolbar\"\n v-bind=\"toolbarSlotProps\"\n >\n <LeStatus\n :class=\"{ 'a-le-toolbar-status--pending': totalPendingChanges }\"\n :has-pending-changes=\"totalPendingChanges\"\n :pending-count=\"totalPendingCount\"\n :error=\"applyError\"\n />\n <VBtn\n variant=\"text\"\n size=\"small\"\n :disabled=\"applying\"\n @click=\"cancelReorderMode\"\n >\n {{ t('common.sortable.reorderCancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"flat\"\n size=\"small\"\n prepend-icon=\"mdi-check\"\n :loading=\"applying\"\n :disabled=\"applying || !totalPendingChanges\"\n @click=\"applyReorder\"\n >\n {{ t('common.sortable.reorderApply') }}\n </VBtn>\n </slot>\n </template>\n <slot\n v-else-if=\"reorderToggleVisible\"\n name=\"reorder-toggle\"\n v-bind=\"reorderToggleSlotProps\"\n >\n <VBtn\n v-if=\"compactReorderButton\"\n variant=\"tonal\"\n color=\"primary\"\n icon\n size=\"x-small\"\n :disabled=\"!canEnterReorder\"\n @click=\"enterReorderMode\"\n >\n <VIcon\n icon=\"mdi-sort\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.reorder')\"\n />\n </VBtn>\n <VBtn\n v-else\n variant=\"tonal\"\n color=\"primary\"\n prepend-icon=\"mdi-sort\"\n size=\"small\"\n :disabled=\"!canEnterReorder\"\n @click=\"enterReorderMode\"\n >\n {{ t('common.sortable.reorder') }}\n </VBtn>\n </slot>\n </div>\n </slot>\n </div>\n\n <div\n v-if=\"loading\"\n class=\"a-le-state a-le-state--loading\"\n >\n <VProgressCircular\n indeterminate\n color=\"primary\"\n size=\"32\"\n />\n </div>\n\n <div\n v-else-if=\"error\"\n class=\"a-le-state a-le-state--error\"\n >\n <VAlert\n type=\"error\"\n variant=\"tonal\"\n density=\"compact\"\n border=\"start\"\n >\n {{ error }}\n </VAlert>\n </div>\n\n <div\n v-else-if=\"!reorderMode && $slots['view-body']\"\n class=\"a-le-view-body\"\n >\n <slot\n name=\"view-body\"\n :items=\"modelValue\"\n :mode=\"mode\"\n :actions=\"{ enterReorderMode }\"\n />\n </div>\n\n <div\n v-else-if=\"isEmpty\"\n class=\"a-le-state a-le-state--empty\"\n >\n <slot\n name=\"empty\"\n :readonly=\"readonly\"\n :disabled=\"disabled\"\n :actions=\"{ add: onAddClick }\"\n >\n <LeEmptyState\n :title=\"emptyTitleResolved\"\n :add-label=\"addLabelResolved\"\n :can-add=\"canAdd\"\n @add=\"onAddClick\"\n />\n </slot>\n </div>\n\n <div\n v-else\n ref=\"rowsContainer\"\n class=\"a-sortable-list-editor__rows\"\n >\n <div\n v-for=\"vi in viewItemsDecorated\"\n :key=\"String(vi.key)\"\n class=\"a-le-row-wrapper\"\n >\n <!-- Interstitial slots render as SIBLINGS of `.a-le-row` (inside this\n wrapper), so consumer content placed between rows never inherits the\n row's unsaved/editing/grabbed/validation tint. (QA 85050 BUG-04/05) -->\n <slot\n name=\"before-item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n\n <div\n :data-id=\"String(vi.key)\"\n role=\"listitem\"\n :tabindex=\"keyboardNav.rowTabindex(vi.key)\"\n class=\"a-le-row\"\n :class=\"{\n 'a-le-row--two-rows': twoRows === 'always',\n 'a-le-row--editing': vi.editing,\n 'a-le-row--expanded': vi.expanded,\n 'a-le-row--unsaved': vi.unsaved,\n 'a-le-row--reorder': reorderMode,\n 'a-le-row--grabbed': keyboardNav.isGrabbed(vi.key),\n 'a-le-row--clickable': isRowClickable(vi),\n [`a-le-row--validation-${vi.validationState}`]: vi.validationState !== null,\n }\"\n @keydown=\"keyboardNav.handleKeydown(vi.key, $event)\"\n >\n <div\n class=\"a-le-row-header\"\n @click=\"onRowClick(vi)\"\n >\n <LeDragHandle v-if=\"dragEnabled\" />\n\n <div class=\"a-le-row-main\">\n <slot\n name=\"item-compact\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <span class=\"a-le-title\">\n {{ resolveCompactText(vi.raw) }}\n </span>\n </slot>\n <LeUnsavedLabel\n v-if=\"vi.unsaved\"\n :dot-only=\"chips\"\n />\n </div>\n\n <div\n v-if=\"!chips && !reorderMode\"\n class=\"a-le-status\"\n >\n <slot\n name=\"item-status\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <span\n v-if=\"statusField && vi.raw[statusField] != null && vi.raw[statusField] !== ''\"\n class=\"a-le-status-badge\"\n >\n {{ vi.raw[statusField] }}\n </span>\n </slot>\n </div>\n\n <div class=\"a-le-actions\">\n <slot\n name=\"item-actions\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <template v-if=\"chips && canInteract\">\n <!-- Chips is the one layout that would otherwise swap the arrows out for the handle.\n Keep them whenever dragging is unavailable (covers `disable-drag`, which gating on\n `isTouch` did not) AND whenever a finger could be used at all — a hybrid gets both,\n so putting the mouse down never leaves the row unmovable. Every other layout here\n already keeps its arrows unconditionally in reorder mode. -->\n <template v-if=\"(!dragEnabled || hasCoarsePointer) && !disableReorder\">\n <VBtn\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n :disabled=\"!vi.canMoveUp\"\n class=\"a-le-action a-le-action--up\"\n @click.stop=\"moveUp(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-up\"\n size=\"14\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n :disabled=\"!vi.canMoveDown\"\n class=\"a-le-action a-le-action--down\"\n @click.stop=\"moveDown(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-down\"\n size=\"14\"\n />\n </VBtn>\n </template>\n <VBtn\n v-if=\"showDeleteButton\"\n icon\n size=\"x-small\"\n variant=\"text\"\n density=\"compact\"\n :active=\"false\"\n class=\"a-le-action a-le-action--chip-close\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <VIcon\n icon=\"mdi-close\"\n size=\"14\"\n />\n </VBtn>\n </template>\n <template v-else-if=\"reorderMode\">\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :disabled=\"!vi.canMoveUp\"\n class=\"mx-1 a-le-action a-le-action--up\"\n @click.stop=\"moveUp(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-up\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.moveUp')\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :disabled=\"!vi.canMoveDown\"\n class=\"mx-1 a-le-action a-le-action--down\"\n @click.stop=\"moveDown(vi.index)\"\n >\n <VIcon\n icon=\"mdi-arrow-down\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.moveDown')\"\n />\n </VBtn>\n <VBtn\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :active=\"false\"\n class=\"mx-1 a-le-action a-le-action--menu\"\n >\n <VIcon\n icon=\"mdi-dots-vertical\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.more')\"\n />\n <VMenu activator=\"parent\">\n <VList density=\"compact\">\n <VListItem\n :disabled=\"!vi.canMoveUp\"\n @click.stop=\"moveTop(vi.index)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-arrow-collapse-up\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToTop') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n :disabled=\"!vi.canMoveDown\"\n @click.stop=\"moveBottom(vi.index)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-arrow-collapse-down\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToBottom') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showMoveToPosition && viewItemsDecorated.length > 1\"\n @click.stop=\"openMoveToPosition(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-target\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.moveToPosition.action') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showAddAfterAction && canInteract\"\n @click=\"onRowAddAfterClick(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-plus\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.addAfter') }}\n </VListItemTitle>\n </VListItem>\n <VListItem\n v-if=\"showDeleteButton && canInteract\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <template #prepend>\n <VIcon icon=\"mdi-trash-can-outline\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.delete') }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </VBtn>\n </template>\n <template v-else>\n <VBtn\n v-if=\"showEditButton && canInteract\"\n icon\n size=\"small\"\n variant=\"tonal\"\n color=\"primary\"\n density=\"comfortable\"\n class=\"mx-1 a-le-action a-le-action--edit\"\n @click.stop=\"onEditClick(vi)\"\n >\n <VIcon\n icon=\"mdi-pencil-outline\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.edit')\"\n />\n </VBtn>\n <VBtn\n v-if=\"showDeleteButton && canInteract\"\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n class=\"mx-1 a-le-action a-le-action--delete\"\n @click.stop=\"onDeleteClick(vi)\"\n >\n <VIcon\n icon=\"mdi-trash-can-outline\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.delete')\"\n />\n </VBtn>\n <VBtn\n v-if=\"showAddAfterAction && canInteract\"\n icon\n size=\"small\"\n variant=\"text\"\n density=\"comfortable\"\n :active=\"false\"\n class=\"mx-1 a-le-action a-le-action--menu\"\n >\n <VIcon\n icon=\"mdi-dots-vertical\"\n size=\"18\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n :text=\"t('common.sortable.more')\"\n />\n <VMenu activator=\"parent\">\n <VList density=\"compact\">\n <VListItem @click=\"onRowAddAfterClick(vi)\">\n <template #prepend>\n <VIcon icon=\"mdi-plus\" />\n </template>\n <VListItemTitle>\n {{ t('common.sortable.addAfter') }}\n </VListItemTitle>\n </VListItem>\n </VList>\n </VMenu>\n </VBtn>\n </template>\n </slot>\n </div>\n </div>\n\n <template v-if=\"vi.editing && (allowEditInReorder || !reorderMode) && $slots.item\">\n <div class=\"a-le-row-body\">\n <div class=\"a-le-form\">\n <slot\n name=\"item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n <slot\n name=\"item-footer\"\n v-bind=\"buildSlotProps(vi)\"\n >\n <div\n v-if=\"showInlineSaveFooter && !reorderMode\"\n class=\"a-le-row-footer\"\n >\n <div class=\"a-le-row-footer-spacer\" />\n <VBtn\n variant=\"text\"\n :disabled=\"vi.loading\"\n @click.stop=\"onCancelClick(vi)\"\n >\n {{ t('common.button.cancel') }}\n </VBtn>\n <VBtn\n color=\"primary\"\n variant=\"flat\"\n prepend-icon=\"mdi-check\"\n :disabled=\"vi.loading\"\n @click.stop=\"onSaveClick(vi)\"\n >\n {{ t('common.button.save') }}\n </VBtn>\n </div>\n </slot>\n </template>\n\n <div\n v-else-if=\"$slots['item-readonly'] && (readonly || vi.expanded) && (allowEditInReorder || !reorderMode)\"\n class=\"a-le-row-body\"\n >\n <div class=\"a-le-form\">\n <slot\n name=\"item-readonly\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n </div>\n\n <slot\n name=\"after-item\"\n v-bind=\"buildSlotProps(vi)\"\n />\n </div>\n </div>\n\n <slot\n v-if=\"canAdd && !loading && !error && !isEmpty\"\n name=\"add-button\"\n :readonly=\"readonly\"\n :disabled=\"disabled\"\n :props=\"{ onClick: onAddClick }\"\n :actions=\"{ add: onAddClick }\"\n >\n <button\n type=\"button\"\n class=\"a-le-row-add\"\n @click=\"onAddClick\"\n >\n <VIcon\n icon=\"mdi-plus\"\n size=\"18\"\n />\n <span>{{ addLabelResolved }}</span>\n </button>\n </slot>\n </div>\n\n <LeMoveToPositionDialog\n v-model=\"moveToPositionDialogOpen\"\n :total=\"viewItemsDecorated.length\"\n :current-index=\"moveToPositionTarget?.index ?? 0\"\n :item-label=\"moveToPositionLabel\"\n @confirm=\"onMoveToPositionConfirm\"\n />\n\n <LeDeleteDialog\n v-model=\"deleteDialog\"\n :title=\"deleteConfirmTitleResolved\"\n :text=\"deleteConfirmTextResolved\"\n :confirm-label=\"t('common.sortable.delete')\"\n :cancel-label=\"t('common.button.cancel')\"\n :error=\"deleteError\"\n :in-flight=\"deleteInFlight\"\n @confirm=\"onDeleteDialogConfirm\"\n @cancel=\"onDeleteDialogCancel\"\n />\n\n <div\n class=\"a-le-sr-only\"\n aria-live=\"polite\"\n role=\"status\"\n >\n {{\n keyboardNav.grabbedKey.value !== null\n ? t('common.sortable.keyboardGrab.status', {\n n: keyboardNav.grabbedIndex.value + 1,\n total: keyboardNav.totalCount.value,\n })\n : ''\n }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n@use './styles/tokens';\n@use './styles/shared';\n\n// Variant-specific rules: reorder-mode trims, drag clone styling, chips\n// flex-wrap layout, validation rail.\n.a-sortable-list-editor {\n &__rows {\n display: flex;\n flex-direction: column;\n }\n\n // View-mode body slot — match the row's horizontal rhythm (~16 px) with a\n // vertical inset so content doesn't sit flush against the border.\n .a-le-view-body {\n padding: 12px 16px;\n }\n\n // Reorder mode trims row-header padding since the drag handle eats some of it.\n .a-le-row--reorder .a-le-row-header {\n padding-left: 12px;\n padding-right: 8px;\n gap: 8px;\n }\n\n // Drag rendering — SortableJS clone + ghost + chosen source.\n .a-le-row--ghost {\n opacity: 0.35;\n background: var(--le-primary-state);\n }\n\n .a-le-row--chosen {\n opacity: 0.5;\n }\n\n // Floating clone following the cursor — row-shaped card with elevation; action\n // column + status badge hidden (below) so the preview stays clean.\n .a-le-row--drag {\n background: var(--le-surface);\n border: 1px solid var(--le-border);\n border-radius: var(--le-radius);\n box-shadow: var(--le-elev-3);\n max-width: 420px;\n opacity: 0.96;\n pointer-events: none;\n }\n\n .a-le-row--drag .a-le-actions,\n .a-le-row--drag .a-le-status {\n display: none;\n }\n\n // Header-only-with-reorder variant — no title/header slot, so render a slim\n // band right-aligning just the Reorder button.\n &--header-floating .a-le-header {\n justify-content: flex-end;\n padding: 6px 8px;\n min-height: 0;\n }\n\n // Embedded variant — sits inside another editor's row. Drop card chrome,\n // tighten rows, lighten background so it reads as part of the parent's body.\n &--embedded .a-le-card {\n background: transparent;\n border: none;\n box-shadow: none;\n border-radius: 0;\n }\n\n &--embedded .a-le-header {\n padding: 4px 0 6px;\n min-height: auto;\n background: transparent;\n border: none;\n }\n\n &--embedded .a-le-title-heading {\n font-size: 13px;\n font-weight: 500;\n color: var(--le-on-surface-medium, rgb(0 0 0 / 70%));\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n &--embedded .a-le-row {\n background: var(--le-surface);\n border: 1px solid var(--le-border);\n border-radius: 6px;\n }\n\n // The inter-row gap lives on the wrapper (the real list item). `.a-le-row` is no\n // longer its wrapper's last child once `#after-item` renders, so the old\n // `.a-le-row:last-of-type` reset stopped clearing the trailing gap. (QA 85050 BUG-04/05)\n &--embedded .a-le-row-wrapper:not(:last-child) {\n margin-bottom: 4px;\n }\n\n &--embedded .a-le-row-add {\n min-height: var(--le-row-min-height);\n padding: 0 16px;\n background: transparent;\n border: 1px dashed var(--le-border);\n border-radius: 6px;\n color: var(--le-primary);\n margin-top: 4px;\n width: 100%;\n }\n\n &--embedded .a-le-row-add:hover {\n background: var(--le-primary-state);\n border-style: solid;\n }\n\n // Chips-layout overrides — `__rows` flex-wraps into pills, `row-header` gets\n // 8 px left padding (vs 12 px in AListEditor), `drag-handle` shrinks to the\n // pill height.\n &--chips &__rows {\n display: flex;\n\n // Reset the base column direction — chips flow inline and wrap.\n flex-flow: row wrap;\n gap: 6px;\n flex: 1 1 100%;\n }\n\n &--chips .a-le-row-header {\n padding: 2px 4px 2px 8px;\n gap: 4px;\n min-height: 28px;\n }\n\n &--chips .a-le-drag-handle {\n padding: 0;\n font-size: 16px;\n }\n}\n\n// Narrow-container / mobile layout — taller rows, always-visible actions,\n// status badge dropped for room.\n/* stylelint-disable selector-max-compound-selectors */\n@container le-shell (max-width: 768px) {\n .a-sortable-list-editor {\n --le-row-min-height: 48px;\n --le-row-pad-y: 10px;\n\n .a-le-row:not(.a-le-row--editing) .a-le-status {\n display: none;\n }\n\n .a-le-row .a-le-action--edit,\n .a-le-row .a-le-action--delete,\n .a-le-row .a-le-action--menu {\n opacity: 1;\n }\n }\n}\n/* stylelint-enable selector-max-compound-selectors */\n</style>\n","import type { UserAdminConfig } from '@/types/UserAdminConfig'\nimport { UserAdminConfigLayoutTypeDefault, UserAdminConfigTypeDefault } from '@/types/UserAdminConfig'\nimport { dateTimeNow } from '@/utils/datetime'\n\nexport function useUserAdminConfigFactory() {\n const createDefaultUserAdminConfig = (system: string): UserAdminConfig => {\n return {\n id: 0,\n user: 0,\n configType: UserAdminConfigTypeDefault,\n layoutType: UserAdminConfigLayoutTypeDefault,\n systemResource: '',\n customName: '',\n defaultConfig: false,\n data: [],\n position: 0,\n createdAt: dateTimeNow(),\n modifiedAt: dateTimeNow(),\n createdBy: null,\n modifiedBy: null,\n _resourceName: 'userAdminConfig',\n _system: system,\n }\n }\n\n return {\n createDefaultUserAdminConfig,\n }\n}\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n title?: string\n body?: string\n stayLabel?: string\n discardLabel?: string\n /**\n * Names of the dirty sections (from the guard's `dirtyLabels`). When\n * non-empty the dialog lists them instead of the generic body message.\n */\n dirtyLabels?: string[]\n}\n\nwithDefaults(defineProps<Props>(), {\n title: undefined,\n body: undefined,\n stayLabel: undefined,\n discardLabel: undefined,\n dirtyLabels: () => [],\n})\n\nconst emit = defineEmits<{\n resolve: [discard: boolean]\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n\nconst { t } = useI18n()\n\nconst onStay = () => {\n emit('resolve', false)\n}\n\nconst onDiscard = () => {\n emit('resolve', true)\n}\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"480\"\n persistent\n >\n <VCard>\n <VCardTitle>\n {{ title ?? t('common.sortable.unsavedChanges.title') }}\n </VCardTitle>\n <VCardText>\n <template v-if=\"body\">\n {{ body }}\n </template>\n <template v-else-if=\"dirtyLabels.length\">\n {{ t('common.sortable.unsavedChanges.sectionsIntro') }}\n <ul class=\"a-unsaved-sections\">\n <li\n v-for=\"(label, i) in dirtyLabels\"\n :key=\"i\"\n >\n {{ label }}\n </li>\n </ul>\n {{ t('common.sortable.unsavedChanges.leaveQuestion') }}\n </template>\n <template v-else>\n {{ t('common.sortable.unsavedChanges.body') }}\n </template>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n @click=\"onStay\"\n >\n {{ stayLabel ?? t('common.sortable.unsavedChanges.stay') }}\n </VBtn>\n <VBtn\n color=\"warning\"\n variant=\"flat\"\n @click=\"onDiscard\"\n >\n {{ discardLabel ?? t('common.sortable.unsavedChanges.discard') }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n\n<style scoped lang=\"scss\">\n.a-unsaved-sections {\n margin: 8px 0;\n padding-left: 20px;\n\n li {\n font-weight: 500;\n }\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useI18n } from 'vue-i18n'\n\nexport interface Props {\n title?: string\n body?: string\n stayLabel?: string\n discardLabel?: string\n /**\n * Names of the dirty sections (from the guard's `dirtyLabels`). When\n * non-empty the dialog lists them instead of the generic body message.\n */\n dirtyLabels?: string[]\n}\n\nwithDefaults(defineProps<Props>(), {\n title: undefined,\n body: undefined,\n stayLabel: undefined,\n discardLabel: undefined,\n dirtyLabels: () => [],\n})\n\nconst emit = defineEmits<{\n resolve: [discard: boolean]\n}>()\n\nconst open = defineModel<boolean>({ required: true })\n\nconst { t } = useI18n()\n\nconst onStay = () => {\n emit('resolve', false)\n}\n\nconst onDiscard = () => {\n emit('resolve', true)\n}\n</script>\n\n<template>\n <VDialog\n v-model=\"open\"\n max-width=\"480\"\n persistent\n >\n <VCard>\n <VCardTitle>\n {{ title ?? t('common.sortable.unsavedChanges.title') }}\n </VCardTitle>\n <VCardText>\n <template v-if=\"body\">\n {{ body }}\n </template>\n <template v-else-if=\"dirtyLabels.length\">\n {{ t('common.sortable.unsavedChanges.sectionsIntro') }}\n <ul class=\"a-unsaved-sections\">\n <li\n v-for=\"(label, i) in dirtyLabels\"\n :key=\"i\"\n >\n {{ label }}\n </li>\n </ul>\n {{ t('common.sortable.unsavedChanges.leaveQuestion') }}\n </template>\n <template v-else>\n {{ t('common.sortable.unsavedChanges.body') }}\n </template>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <VBtn\n variant=\"text\"\n @click=\"onStay\"\n >\n {{ stayLabel ?? t('common.sortable.unsavedChanges.stay') }}\n </VBtn>\n <VBtn\n color=\"warning\"\n variant=\"flat\"\n @click=\"onDiscard\"\n >\n {{ discardLabel ?? t('common.sortable.unsavedChanges.discard') }}\n </VBtn>\n </VCardActions>\n </VCard>\n </VDialog>\n</template>\n\n<style scoped lang=\"scss\">\n.a-unsaved-sections {\n margin: 8px 0;\n padding-left: 20px;\n\n li {\n font-weight: 500;\n }\n}\n</style>\n","import { computed, getCurrentInstance, onBeforeUnmount, ref, watch, type ComputedRef, type Ref } from 'vue'\nimport { onBeforeRouteLeave } from 'vue-router'\nimport {\n provideUnsavedSectionRegistry,\n type UnsavedSectionDescriptor,\n type UnsavedSectionSource,\n} from '@/labs/unsavedGuard/useUnsavedSection'\n\ntype UnsavedSource = Ref<boolean | Set<unknown> | unknown[] | null | undefined>\n\nexport interface UseUnsavedChangesGuardOptions {\n /**\n * Reactive sources that signal \"unsaved\" state. Each source's truthiness is\n * checked: a Set/array is \"dirty\" when non-empty, a boolean when true, null\n * or undefined as not dirty.\n */\n sources: UnsavedSource[]\n /**\n * Block route navigation via vue-router's onBeforeRouteLeave. Default true.\n * When omitted/false, the route guard is not registered.\n */\n guardRoute?: boolean | Ref<boolean>\n /**\n * Block window/tab unload via beforeunload. Default true.\n */\n guardWindowUnload?: boolean | Ref<boolean>\n /**\n * Optional Vuetify dialog v-model. When provided, attempts to close the\n * dialog while dirty are intercepted: dialog stays open until the user\n * confirms via the confirm dialog or via `acknowledge()`.\n */\n guardDialogModel?: Ref<boolean>\n /**\n * Named sections owned by the guard host component itself. Descendants use\n * `useUnsavedSection` instead — but a component can't `inject` its own\n * `provide`, so when the host *is* the section owner (e.g. a dialog), pass\n * the sections here.\n */\n ownSections?: UnsavedSectionSource\n}\n\nexport interface UseUnsavedChangesGuardApi {\n hasUnsavedChanges: ComputedRef<boolean>\n /**\n * Labels of the dirty sections registered by descendants via\n * `useUnsavedSection`. Bind to `AUnsavedConfirmDialog`'s `dirtyLabels` prop\n * so the dialog names *which* parts are unsaved. Empty when no descendant\n * registered a section (dialog falls back to the generic message).\n */\n dirtyLabels: ComputedRef<string[]>\n /**\n * v-model-bound to the confirm dialog. When the guard wants to ask the user\n * to confirm leaving, it sets this to true. The confirm dialog reads it.\n */\n promptOpen: Ref<boolean>\n /**\n * Resolves the confirm prompt with `discard=true` (proceed) or `false`\n * (stay). Called by the confirm dialog.\n */\n resolvePrompt: (discard: boolean) => void\n /**\n * Manually mark the most recent intent as acknowledged so the next\n * route/dialog/unload attempt proceeds without prompting. Useful right\n * before a programmatic navigation that the consumer has already\n * confirmed.\n *\n * The acknowledgement AUTO-EXPIRES after a few seconds if nothing consumes it\n * (see `ACKNOWLEDGE_TTL_MS`): a delete that acknowledges up-front but then FAILS\n * (throws, never navigates) must not leave the guard silently disarmed for the\n * next unrelated navigation. Consuming it (a real leave) clears the timer.\n */\n acknowledge: () => void\n /**\n * Releases what the guard registered imperatively — `beforeunload` listener, acknowledge timer,\n * dialog watcher — and settles an open prompt as \"stay\". Idempotent, and called automatically on\n * unmount; outside a component it is the only way to clean up. The route-leave guard is\n * lifecycle-bound and unaffected.\n */\n stop: () => void\n /**\n * Cancel a pending `acknowledge()` (disarm). Call from a delete's failure path\n * so a failed/aborted delete restores the guard immediately instead of waiting\n * for the TTL. No-op if nothing is acknowledged.\n */\n unacknowledge: () => void\n}\n\n// An acknowledgement is meant for an IMMINENT navigation (a delete's router.push after its HTTP\n// round-trip — tens to hundreds of ms). If none arrives within this window the delete almost\n// certainly failed, so the one-shot expires rather than arming an unrelated later navigation.\n// Generously longer than any real delete request so a legitimate slow-success never false-prompts.\nconst ACKNOWLEDGE_TTL_MS = 8000\n\nconst isTruthySource = (value: unknown): boolean => {\n if (value === null || value === undefined) return false\n if (typeof value === 'boolean') return value\n if (value instanceof Set) return value.size > 0\n if (Array.isArray(value)) return value.length > 0\n return Boolean(value)\n}\n\nconst resolveBool = (v: boolean | Ref<boolean> | undefined, fallback: boolean): boolean => {\n if (v === undefined) return fallback\n if (typeof v === 'boolean') return v\n return v.value\n}\n\nexport function useUnsavedChangesGuard(options: UseUnsavedChangesGuardOptions): UseUnsavedChangesGuardApi {\n // Provide a section registry so descendants can name their dirty sections\n // via `useUnsavedSection`. The dialog reads `dirtyLabels` from this.\n const sectionRegistry = provideUnsavedSectionRegistry()\n\n // The host component can't inject its own provide, so register its own\n // sections directly.\n if (options.ownSections) {\n const ownSections = options.ownSections\n const id = Symbol('unsaved.section.own')\n const normalized = computed<UnsavedSectionDescriptor[]>(() => {\n const resolved = ownSections()\n return Array.isArray(resolved) ? resolved : [resolved]\n })\n sectionRegistry.register(id, normalized)\n }\n\n const hasUnsavedChanges = computed<boolean>(\n () => options.sources.some((s) => isTruthySource(s.value)) || sectionRegistry.dirtyLabels.value.length > 0\n )\n\n const promptOpen = ref<boolean>(false)\n let pendingResolver: ((discard: boolean) => void) | null = null\n let acknowledgedOnce = false\n let acknowledgeTimer: ReturnType<typeof setTimeout> | null = null\n\n const clearAcknowledgeTimer = () => {\n if (acknowledgeTimer !== null) {\n clearTimeout(acknowledgeTimer)\n acknowledgeTimer = null\n }\n }\n\n const askToLeave = (): Promise<boolean> => {\n if (acknowledgedOnce) {\n acknowledgedOnce = false\n clearAcknowledgeTimer()\n return Promise.resolve(true)\n }\n return new Promise((resolve) => {\n pendingResolver = resolve\n promptOpen.value = true\n })\n }\n\n const resolvePrompt = (discard: boolean) => {\n promptOpen.value = false\n if (pendingResolver) {\n pendingResolver(discard)\n pendingResolver = null\n }\n }\n\n const acknowledge = () => {\n acknowledgedOnce = true\n // Auto-expire: if the imminent navigation never arrives (e.g. the delete threw), don't leave\n // the guard armed for an unrelated later leave. A real consume (askToLeave) clears this first.\n clearAcknowledgeTimer()\n acknowledgeTimer = setTimeout(() => {\n acknowledgedOnce = false\n acknowledgeTimer = null\n }, ACKNOWLEDGE_TTL_MS)\n }\n\n const unacknowledge = () => {\n acknowledgedOnce = false\n clearAcknowledgeTimer()\n }\n\n // Route guard — `onBeforeRouteLeave` only works inside a route component\n // (it reads the current vm context). Outside a component it's a no-op.\n if (resolveBool(options.guardRoute, true) && getCurrentInstance()) {\n try {\n onBeforeRouteLeave(async () => {\n if (!hasUnsavedChanges.value) return true\n const discard = await askToLeave()\n return discard\n })\n } catch {\n // Not in a route context — skip silently.\n }\n }\n\n // beforeunload — modern browsers strip custom messages but still display a\n // generic confirm. Setting `returnValue` is the canonical way to opt in.\n // Collected, not tied to onBeforeUnmount: outside a component that hook is a silent no-op.\n const disposers: Array<() => void> = [clearAcknowledgeTimer]\n let stopped = false\n\n if (resolveBool(options.guardWindowUnload, true)) {\n const onBeforeUnload = (e: BeforeUnloadEvent) => {\n if (!hasUnsavedChanges.value) return\n e.preventDefault()\n e.returnValue = ''\n }\n if (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', onBeforeUnload)\n disposers.push(() => window.removeEventListener('beforeunload', onBeforeUnload))\n }\n }\n\n // Dialog guard — when the parent dialog tries to close while dirty, intercept\n // and ask the user to confirm. The parent dialog model goes from false→true\n // (open) to true→false (closing); we re-open it while we await the prompt.\n if (options.guardDialogModel) {\n const dialogModel = options.guardDialogModel\n let suppressNext = false\n const stopDialogWatch = watch(dialogModel, async (now, prev) => {\n if (suppressNext) {\n suppressNext = false\n return\n }\n if (prev === true && now === false && hasUnsavedChanges.value) {\n // Re-open the dialog while we wait for the user's choice.\n suppressNext = true\n dialogModel.value = true\n const discard = await askToLeave()\n // A teardown mid-prompt must not fall through and mutate the caller's dialog model.\n if (stopped) return\n if (discard) {\n suppressNext = true\n dialogModel.value = false\n }\n }\n })\n disposers.push(stopDialogWatch)\n }\n\n const stop = () => {\n if (stopped) return\n stopped = true\n // An open prompt would leave whoever awaits askToLeave() pending forever; \"stay\" is safe.\n resolvePrompt(false)\n disposers.forEach((dispose) => dispose())\n }\n\n if (getCurrentInstance()) {\n onBeforeUnmount(stop)\n }\n\n return {\n hasUnsavedChanges,\n dirtyLabels: sectionRegistry.dirtyLabels,\n promptOpen,\n resolvePrompt,\n acknowledge,\n unacknowledge,\n stop,\n }\n}\n","<script lang=\"ts\" setup>\nimport ADialogToolbar from '@/components/ADialogToolbar.vue'\nimport { useI18n } from 'vue-i18n'\nimport { inject, ref, useTemplateRef, watch } from 'vue'\nimport AFormTextField from '@/components/form/AFormTextField.vue'\nimport ARow from '@/components/ARow.vue'\nimport AFormSwitch from '@/components/form/AFormSwitch.vue'\nimport ASortableListEditor from '@/labs/listEditor/ASortableListEditor.vue'\nimport type { ExposedListEditorHandle } from '@/labs/listEditor/composables/useListEditorController'\nimport type { AxiosInstance } from 'axios'\nimport type { IntegerId } from '@/types/common'\nimport { MAX_BOOKMARK_ITEMS, useFilterBookmarkStore } from '@/labs/filters/bookmarksStore'\nimport { useUserAdminConfigApi } from '@/labs/filters/userAdminConfig'\nimport { useAlerts } from '@/composables/system/alerts'\nimport { useUserAdminConfigFactory } from '@/model/factory/UserAdminConfigFactory'\nimport { type UserAdminConfig, UserAdminConfigLayoutType, UserAdminConfigType } from '@/types/UserAdminConfig'\nimport useVuelidate from '@vuelidate/core'\nimport { useValidate } from '@/validators/vuelidate/useValidate'\nimport { cloneDeep, isUndefined } from '@/utils/common'\nimport { DatatablePaginationKey, FilterConfigKey, FilterDataKey } from '@/labs/filters/filterInjectionKeys'\nimport { useFilterHelpers } from '@/labs/filters/filterFactory'\nimport AUnsavedConfirmDialog from '@/labs/unsavedGuard/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/labs/unsavedGuard/useUnsavedChangesGuard'\nimport { hasAnzuApiValidationErrorSpecific, isAnzuApiValidationError } from '@/model/error/AnzuApiValidationError'\nimport { isAnzuApiAxiosError } from '@/model/error/AnzuApiAxiosError'\nimport { HTTP_STATUS_NOT_FOUND } from '@/composables/statusCodes'\n\nconst props = withDefaults(\n defineProps<{\n client: () => AxiosInstance\n system: string\n subject: string\n user: IntegerId\n datatableHiddenColumns?: string[] | undefined\n }>(),\n {\n datatableHiddenColumns: undefined,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'onClose'): void\n}>()\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst pagination = inject(DatatablePaginationKey)\n\nif (isUndefined(pagination) || isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\n// The dialog is mounted behind the parent's `v-if`, so it had no model of its own -- and the guard\n// needs one to watch. Closing now runs through here: `requestClose` lets the guard ask first,\n// `forceClose` is for the paths that already are the confirmation.\nconst isOpen = ref(true)\n\n// The editor takes its clean baseline when it is created, so it waits for the first fetch. After\n// that it stays mounted whatever happens -- it is the only thing registering this tab's pending\n// work with the guard, and a reload that swapped it out would disarm the guard mid-edit.\nconst manageLoaded = ref(false)\nconst loadFailed = ref(false)\n\nconst guard = useUnsavedChangesGuard({\n sources: [],\n guardDialogModel: isOpen,\n guardRoute: false,\n guardWindowUnload: false,\n})\n\nwatch(isOpen, (open) => {\n if (!open) emit('onClose')\n})\n\nconst requestClose = () => {\n // Not while a write is out. The toolbar's X and the escape key reach this without going past\n // anything the write phase disables, and closing here would ask the user whether to discard work\n // that is already on its way to the server -- then write it anyway, whatever they answered.\n if (saveButtonLoading.value) return\n isOpen.value = false\n}\n\nconst forceClose = () => {\n guard.acknowledge()\n isOpen.value = false\n}\n\nconst activeTab = ref<'add' | 'manage'>('add')\nconst customName = ref('')\nconst storeDatatableHiddenColumns = ref(false)\nconst storeDatatableOrder = ref(false)\nconst saveButtonLoading = ref(false)\nconst listLoading = ref(false)\nconst errorCount = ref(false)\nconst itemsManage = ref<Array<UserAdminConfig>>([])\n\ninterface RowUpdate {\n update: (next: UserAdminConfig) => void\n}\n\nconst MAX_BOOKMARK_NAME_LENGTH = 100\n\n// The editor owns opening a row, saving it and cancelling out of it, so the rename no longer needs\n// its own held copy, its own vuelidate instance or its own confirm/cancel buttons. What is left is\n// the rule itself, which drives the editor's red rail and blocks its save.\nconst validateBookmarkName = (item: UserAdminConfig): boolean =>\n !!item.customName && item.customName.length <= MAX_BOOKMARK_NAME_LENGTH\n\nconst { required, maxLength } = useValidate()\nconst rulesCreate = {\n customName: {\n required,\n maxLength: maxLength(MAX_BOOKMARK_NAME_LENGTH),\n },\n}\nconst vCreate$ = useVuelidate(rulesCreate, { customName }, { $stopPropagation: true })\nconst filterBookmarkStore = useFilterBookmarkStore()\n\nconst {\n createUserAdminConfig,\n useFetchUserAdminConfigList,\n updateUserAdminConfigPositions,\n deleteUserAdminConfig,\n updateUserAdminConfig,\n} =\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n useUserAdminConfigApi(props.client, props.system)\nconst { t } = useI18n()\nconst { showErrorsDefault, showUnknownError, showValidationError, showWarningT } = useAlerts()\nconst { createDefaultUserAdminConfig } = useUserAdminConfigFactory()\n\nconst editor = useTemplateRef<ExposedListEditorHandle<UserAdminConfig>>('editor')\n\n// One save for the whole tab, which is how every other list editor in this codebase is used: the\n// editor holds the data and the form's button persists it. A per-row PUT looked tidier and was not\n// -- re-baselining the one saved row meant reloading the list, and the reload took the pending\n// reorder and any other open row's typed text with it.\n// A delete answered with \"not found\" says the row is already gone, which is what this was asking\n// for. That is how an attempt whose answer never made it back looks the second time around: without\n// reading it this way, every retry would stop on the same row and the dialog could never finish.\nconst isAlreadyGone = (e: unknown) => isAnzuApiAxiosError(e) && e.cause.response?.status === HTTP_STATUS_NOT_FOUND\n\nconst saveManage = async () => {\n // Not while the list is being refreshed: the order this would send is the one on screen, and the\n // answer already on its way is about to replace it. The button is disabled for the same reason --\n // this is the half of it that does not depend on anyone looking at the button.\n if (listLoading.value) return\n if (!editor.value?.validateAll()) return\n saveButtonLoading.value = true\n try {\n const changes = editor.value.getChanges()\n // Deletes first, then renames, then the order -- which is taken from `itemsManage`, and the\n // deleted rows have already left it.\n for (const item of changes.deleted) {\n try {\n await deleteUserAdminConfig(item.id)\n } catch (e) {\n if (!isAlreadyGone(e)) throw e\n }\n // Out of the cache in the same breath: the filter bar is already on screen reading it, and a\n // save that fails further down never gets to the refresh that would have done this.\n filterBookmarkStore.removeOne(bookmarkCacheKey(), item.id)\n // That row is gone for good. Dropping its pending deletion here is what makes a second press\n // of the save button safe after a later call in this batch failed: the renames it resends are\n // the same PUT with the same result, but a DELETE resent against a row that is already gone\n // would fail and stop the batch at the same place every time.\n editor.value.restoreDeleted(item.id)\n }\n for (const item of changes.updated) {\n await updateUserAdminConfig(item.id, cloneDeep(item))\n }\n // Deleting every row leaves nothing to order, and an empty list is not an order to send.\n if (itemsManage.value.length > 0) {\n await updateUserAdminConfigPositions(itemsManage.value.map((item) => item.id))\n }\n // Once, at the end: this is also what refreshes the store the filter bar reads its names from,\n // and what the editor re-baselines against.\n applyItems(await fetchItems())\n forceClose()\n } catch (e) {\n showErrorsDefault(e)\n // Nothing is refetched here and nothing is rolled back. What was written already looks the way\n // it looks on the server -- a deleted row is gone from both, a renamed one carries the new name\n // in both -- and what was not written is still the user's to correct and send again. Refetching\n // would take that unsent work with it without asking, which is the one thing this dialog must\n // not do. The store is told its copy is behind instead.\n filterBookmarkStore.markStale(bookmarkCacheKey())\n } finally {\n saveButtonLoading.value = false\n }\n}\n\nconst { serializeFilters } = useFilterHelpers(filterData, filterConfig)\n\nconst systemResource = props.system + '_' + props.subject\nconst bookmarkCacheKey = () => filterBookmarkStore.generateKey(UserAdminConfigLayoutType.Desktop, systemResource)\n\nconst addBookmark = async () => {\n saveButtonLoading.value = true\n errorCount.value = false\n const config = createDefaultUserAdminConfig(props.system)\n config.user = props.user\n config.configType = UserAdminConfigType.FilterBookmark\n config.layoutType = UserAdminConfigLayoutType.Desktop\n config.systemResource = systemResource\n config.customName = customName.value\n config.data = {\n filter: serializeFilters(filterData, pagination, false),\n datatableHiddenColumns:\n storeDatatableHiddenColumns.value && props.datatableHiddenColumns ? props.datatableHiddenColumns : undefined,\n sortBy: storeDatatableOrder.value && pagination.value.sortBy ? pagination.value.sortBy : undefined,\n }\n try {\n const { count, maxPosition } = await filterBookmarkStore.fetchBookmarkStats(\n {\n user: props.user,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList\n )\n if (count >= MAX_BOOKMARK_ITEMS) {\n errorCount.value = true\n saveButtonLoading.value = false\n return\n }\n // After the highest position in use, not after the number of rows. The manage tab renumbers\n // only the rows it sends, so a deletion saved there leaves a gap, and counting rows from then\n // on would put this bookmark on a position another one already holds.\n config.position = maxPosition + 1\n const res = await createUserAdminConfig(config)\n filterBookmarkStore.addOne(bookmarkCacheKey(), res)\n // Cleared because `requestClose` may not close: with work pending on the other tab the guard\n // asks, and \"stay\" would otherwise leave this bookmark's name in the field for a second click\n // to create it again. Empty, the `required` rule blocks that.\n customName.value = ''\n vCreate$.value.$reset()\n // The write is done, and `requestClose` refuses while one is out. The `finally` sets it again.\n saveButtonLoading.value = false\n // `requestClose`, not `forceClose`: adding a bookmark is a decision about THIS tab. It says\n // nothing about a reorder left pending on the other one, so the guard still gets to ask.\n requestClose()\n } catch (e) {\n if (\n isAnzuApiValidationError(e) &&\n hasAnzuApiValidationErrorSpecific(e, 'error_field_not_unique', 'cms.userAdminConfig.model.systemResource')\n ) {\n showWarningT('common.filter.bookmark.nameUniqueError')\n return\n }\n showErrorsDefault(e)\n } finally {\n saveButtonLoading.value = false\n }\n}\n\nconst onConfirm = () => {\n if (activeTab.value === 'add') {\n vCreate$.value.$touch()\n if (vCreate$.value.$invalid) {\n showValidationError()\n return\n }\n addBookmark()\n } else if (activeTab.value === 'manage') {\n // Not gated on the list being non-empty: deleting every row empties it while leaving the\n // deletions themselves pending, and this button is the only thing that sends them.\n saveManage()\n }\n}\n\n// Entering the manage tab starts a fetch, and the tabs can be switched faster than one comes back,\n// so two can be in flight at once. Only the newest one is allowed to land: without this an older\n// answer could overtake a newer one and put the list back to what it was two switches ago.\nlet fetchGeneration = 0\nlet fetchesInFlight = 0\n\nconst fetchItems = async (): Promise<UserAdminConfig[] | null> => {\n const generation = ++fetchGeneration\n // Counted, not a flag: an older fetch answering must not report the tab as settled while a newer\n // one is still out, or the editor takes edits again in the gap between the two.\n fetchesInFlight++\n listLoading.value = true\n loadFailed.value = false\n try {\n const items = await filterBookmarkStore.getBookmarks(\n {\n user: props.user,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList,\n true\n )\n if (generation !== fetchGeneration) return null\n // `null` is this request's own answer that it failed; the store's `error` flag is shared with\n // every other fetch it serves, this dialog's bookmark count among them.\n if (items === null) {\n loadFailed.value = true\n showUnknownError()\n return null\n }\n return items\n } catch (e) {\n // The same question as on the way out of the try: an answer that a newer one has overtaken does\n // not get to put the tab into an error state or raise an alert over it.\n if (generation !== fetchGeneration) return null\n loadFailed.value = true\n showErrorsDefault(e)\n return null\n } finally {\n fetchesInFlight--\n listLoading.value = fetchesInFlight > 0\n }\n}\n\n// The fetched rows are handed to the editor rather than left to reach it through `v-model`: that\n// way round is a render away, and a commit that ran before the rows arrived would pin the baseline\n// to the list from before the fetch -- every difference the fetch brought would then read as the\n// user's own unsaved edit. The editor is still to mount on the first load; it takes its own\n// baseline from `itemsManage` when it does.\nconst applyItems = (items: UserAdminConfig[] | null) => {\n if (!items) return\n itemsManage.value = items\n manageLoaded.value = true\n editor.value?.commit(items)\n}\n\nwatch(activeTab, async () => {\n errorCount.value = false\n if (activeTab.value !== 'manage') return\n // Entering the tab refreshes it -- a bookmark just added on the other tab is the near case -- but\n // never over work the user has not saved: the fetched order would replace the dragged one.\n if (editor.value?.hasUnsaved) return\n const items = await fetchItems()\n // Asked again on the way back: the fetch takes long enough for the user to have started dragging\n // in the meantime, and applying it then would be the same loss, just later.\n if (editor.value?.hasUnsaved) return\n applyItems(items)\n})\n</script>\n\n<template>\n <!-- `persistent` while a write is out: the escape key and a click outside go straight to the\n model, past everything the write phase disables. -->\n <VDialog\n v-model=\"isOpen\"\n :persistent=\"saveButtonLoading\"\n :width=\"500\"\n >\n <VCard>\n <ADialogToolbar @on-cancel=\"requestClose\">\n {{ t('common.filter.bookmark.title') }}\n </ADialogToolbar>\n <VCardText class=\"pt-0\">\n <VTabs\n v-model=\"activeTab\"\n fixed-tabs\n >\n <VTab\n value=\"add\"\n :disabled=\"saveButtonLoading\"\n >\n {{ t('common.filter.bookmark.add') }}\n </VTab>\n <VTab\n value=\"manage\"\n :disabled=\"saveButtonLoading\"\n >\n {{ t('common.filter.bookmark.manage') }}\n </VTab>\n </VTabs>\n <div\n v-if=\"activeTab === 'add'\"\n class=\"w-100 pt-4\"\n >\n <ARow :title=\"t('common.filter.bookmark.infoSave')\" />\n <ARow\n v-if=\"errorCount\"\n class=\"text-error\"\n :title=\"t('common.filter.bookmark.errorMax')\"\n />\n <ARow>\n <AFormTextField\n v-model=\"customName\"\n :label=\"t('common.filter.bookmark.name')\"\n required\n :disabled=\"saveButtonLoading\"\n :v=\"vCreate$.customName\"\n />\n </ARow>\n <ARow>\n <AFormSwitch\n v-model=\"storeDatatableHiddenColumns\"\n :disabled=\"saveButtonLoading\"\n :label=\"t('common.filter.bookmark.storeTableColumns')\"\n />\n </ARow>\n <ARow>\n <AFormSwitch\n v-model=\"storeDatatableOrder\"\n :disabled=\"saveButtonLoading\"\n :label=\"t('common.filter.bookmark.storeTableOrder')\"\n />\n </ARow>\n </div>\n <!-- `v-show`, not `v-if`: the guard sees this tab's pending work only through the section\n the editor registers, so unmounting it on a glance at the other tab would leave the\n dialog able to close on a dragged order without asking. The spinner is the editor's own\n `loading` for the same reason -- swapping it out on every reload would do the same. -->\n <div\n v-show=\"activeTab === 'manage'\"\n class=\"w-100 pt-4\"\n >\n <div\n v-if=\"!manageLoaded && !loadFailed\"\n class=\"d-flex w-100 align-center justify-center\"\n >\n <VProgressCircular indeterminate />\n </div>\n <!-- Nothing ever loaded: the editor's own empty state would claim there are no bookmarks,\n which is not what a failed fetch found out. -->\n <ARow\n v-else-if=\"!manageLoaded\"\n class=\"text-error\"\n :title=\"t('common.alert.unknownError')\"\n />\n <!-- Mounted once the first fetch has settled -- empty or not, so an empty list gets the\n editor's own empty state rather than a blank tab -- and never unmounted after that. -->\n <ASortableListEditor\n v-else\n ref=\"editor\"\n v-model=\"itemsManage\"\n :position=\"false\"\n :loading=\"listLoading || saveButtonLoading\"\n compact-field=\"customName\"\n :validate=\"validateBookmarkName\"\n :show-add-button=\"false\"\n :unsaved-section-label=\"t('common.filter.bookmark.unsavedSection')\"\n >\n <template #item=\"{ raw, actions }: { raw: UserAdminConfig; actions: RowUpdate }\">\n <AFormTextField\n :model-value=\"raw.customName\"\n hide-details=\"auto\"\n @update:model-value=\"actions.update({ ...raw, customName: String($event ?? '') })\"\n />\n </template>\n </ASortableListEditor>\n </div>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <!-- Nothing in here takes input while a write is out: the change set was read when the\n button was pressed, so anything typed after that would not be in it, and the close that\n follows a successful save would take it with it. -->\n <ABtnTertiary\n data-cy=\"button-cancel\"\n :disabled=\"saveButtonLoading\"\n @click.stop=\"requestClose\"\n >\n {{ t('common.button.cancel') }}\n </ABtnTertiary>\n <!-- Not while the list is being refreshed: the order this would send is the one on screen,\n which the answer on its way is about to replace. -->\n <ABtnPrimary\n data-cy=\"button-confirm\"\n :disabled=\"activeTab === 'manage' && listLoading\"\n :loading=\"saveButtonLoading\"\n @click.stop=\"onConfirm\"\n >\n {{ activeTab === 'add' ? t('common.button.add') : t('common.filter.bookmark.saveBookmarkOrder') }}\n </ABtnPrimary>\n </VCardActions>\n </VCard>\n </VDialog>\n\n <AUnsavedConfirmDialog\n v-model=\"guard.promptOpen.value\"\n :dirty-labels=\"guard.dirtyLabels.value\"\n @resolve=\"guard.resolvePrompt\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport ADialogToolbar from '@/components/ADialogToolbar.vue'\nimport { useI18n } from 'vue-i18n'\nimport { inject, ref, useTemplateRef, watch } from 'vue'\nimport AFormTextField from '@/components/form/AFormTextField.vue'\nimport ARow from '@/components/ARow.vue'\nimport AFormSwitch from '@/components/form/AFormSwitch.vue'\nimport ASortableListEditor from '@/labs/listEditor/ASortableListEditor.vue'\nimport type { ExposedListEditorHandle } from '@/labs/listEditor/composables/useListEditorController'\nimport type { AxiosInstance } from 'axios'\nimport type { IntegerId } from '@/types/common'\nimport { MAX_BOOKMARK_ITEMS, useFilterBookmarkStore } from '@/labs/filters/bookmarksStore'\nimport { useUserAdminConfigApi } from '@/labs/filters/userAdminConfig'\nimport { useAlerts } from '@/composables/system/alerts'\nimport { useUserAdminConfigFactory } from '@/model/factory/UserAdminConfigFactory'\nimport { type UserAdminConfig, UserAdminConfigLayoutType, UserAdminConfigType } from '@/types/UserAdminConfig'\nimport useVuelidate from '@vuelidate/core'\nimport { useValidate } from '@/validators/vuelidate/useValidate'\nimport { cloneDeep, isUndefined } from '@/utils/common'\nimport { DatatablePaginationKey, FilterConfigKey, FilterDataKey } from '@/labs/filters/filterInjectionKeys'\nimport { useFilterHelpers } from '@/labs/filters/filterFactory'\nimport AUnsavedConfirmDialog from '@/labs/unsavedGuard/AUnsavedConfirmDialog.vue'\nimport { useUnsavedChangesGuard } from '@/labs/unsavedGuard/useUnsavedChangesGuard'\nimport { hasAnzuApiValidationErrorSpecific, isAnzuApiValidationError } from '@/model/error/AnzuApiValidationError'\nimport { isAnzuApiAxiosError } from '@/model/error/AnzuApiAxiosError'\nimport { HTTP_STATUS_NOT_FOUND } from '@/composables/statusCodes'\n\nconst props = withDefaults(\n defineProps<{\n client: () => AxiosInstance\n system: string\n subject: string\n user: IntegerId\n datatableHiddenColumns?: string[] | undefined\n }>(),\n {\n datatableHiddenColumns: undefined,\n }\n)\n\nconst emit = defineEmits<{\n (e: 'onClose'): void\n}>()\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst pagination = inject(DatatablePaginationKey)\n\nif (isUndefined(pagination) || isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\n// The dialog is mounted behind the parent's `v-if`, so it had no model of its own -- and the guard\n// needs one to watch. Closing now runs through here: `requestClose` lets the guard ask first,\n// `forceClose` is for the paths that already are the confirmation.\nconst isOpen = ref(true)\n\n// The editor takes its clean baseline when it is created, so it waits for the first fetch. After\n// that it stays mounted whatever happens -- it is the only thing registering this tab's pending\n// work with the guard, and a reload that swapped it out would disarm the guard mid-edit.\nconst manageLoaded = ref(false)\nconst loadFailed = ref(false)\n\nconst guard = useUnsavedChangesGuard({\n sources: [],\n guardDialogModel: isOpen,\n guardRoute: false,\n guardWindowUnload: false,\n})\n\nwatch(isOpen, (open) => {\n if (!open) emit('onClose')\n})\n\nconst requestClose = () => {\n // Not while a write is out. The toolbar's X and the escape key reach this without going past\n // anything the write phase disables, and closing here would ask the user whether to discard work\n // that is already on its way to the server -- then write it anyway, whatever they answered.\n if (saveButtonLoading.value) return\n isOpen.value = false\n}\n\nconst forceClose = () => {\n guard.acknowledge()\n isOpen.value = false\n}\n\nconst activeTab = ref<'add' | 'manage'>('add')\nconst customName = ref('')\nconst storeDatatableHiddenColumns = ref(false)\nconst storeDatatableOrder = ref(false)\nconst saveButtonLoading = ref(false)\nconst listLoading = ref(false)\nconst errorCount = ref(false)\nconst itemsManage = ref<Array<UserAdminConfig>>([])\n\ninterface RowUpdate {\n update: (next: UserAdminConfig) => void\n}\n\nconst MAX_BOOKMARK_NAME_LENGTH = 100\n\n// The editor owns opening a row, saving it and cancelling out of it, so the rename no longer needs\n// its own held copy, its own vuelidate instance or its own confirm/cancel buttons. What is left is\n// the rule itself, which drives the editor's red rail and blocks its save.\nconst validateBookmarkName = (item: UserAdminConfig): boolean =>\n !!item.customName && item.customName.length <= MAX_BOOKMARK_NAME_LENGTH\n\nconst { required, maxLength } = useValidate()\nconst rulesCreate = {\n customName: {\n required,\n maxLength: maxLength(MAX_BOOKMARK_NAME_LENGTH),\n },\n}\nconst vCreate$ = useVuelidate(rulesCreate, { customName }, { $stopPropagation: true })\nconst filterBookmarkStore = useFilterBookmarkStore()\n\nconst {\n createUserAdminConfig,\n useFetchUserAdminConfigList,\n updateUserAdminConfigPositions,\n deleteUserAdminConfig,\n updateUserAdminConfig,\n} =\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n useUserAdminConfigApi(props.client, props.system)\nconst { t } = useI18n()\nconst { showErrorsDefault, showUnknownError, showValidationError, showWarningT } = useAlerts()\nconst { createDefaultUserAdminConfig } = useUserAdminConfigFactory()\n\nconst editor = useTemplateRef<ExposedListEditorHandle<UserAdminConfig>>('editor')\n\n// One save for the whole tab, which is how every other list editor in this codebase is used: the\n// editor holds the data and the form's button persists it. A per-row PUT looked tidier and was not\n// -- re-baselining the one saved row meant reloading the list, and the reload took the pending\n// reorder and any other open row's typed text with it.\n// A delete answered with \"not found\" says the row is already gone, which is what this was asking\n// for. That is how an attempt whose answer never made it back looks the second time around: without\n// reading it this way, every retry would stop on the same row and the dialog could never finish.\nconst isAlreadyGone = (e: unknown) => isAnzuApiAxiosError(e) && e.cause.response?.status === HTTP_STATUS_NOT_FOUND\n\nconst saveManage = async () => {\n // Not while the list is being refreshed: the order this would send is the one on screen, and the\n // answer already on its way is about to replace it. The button is disabled for the same reason --\n // this is the half of it that does not depend on anyone looking at the button.\n if (listLoading.value) return\n if (!editor.value?.validateAll()) return\n saveButtonLoading.value = true\n try {\n const changes = editor.value.getChanges()\n // Deletes first, then renames, then the order -- which is taken from `itemsManage`, and the\n // deleted rows have already left it.\n for (const item of changes.deleted) {\n try {\n await deleteUserAdminConfig(item.id)\n } catch (e) {\n if (!isAlreadyGone(e)) throw e\n }\n // Out of the cache in the same breath: the filter bar is already on screen reading it, and a\n // save that fails further down never gets to the refresh that would have done this.\n filterBookmarkStore.removeOne(bookmarkCacheKey(), item.id)\n // That row is gone for good. Dropping its pending deletion here is what makes a second press\n // of the save button safe after a later call in this batch failed: the renames it resends are\n // the same PUT with the same result, but a DELETE resent against a row that is already gone\n // would fail and stop the batch at the same place every time.\n editor.value.restoreDeleted(item.id)\n }\n for (const item of changes.updated) {\n await updateUserAdminConfig(item.id, cloneDeep(item))\n }\n // Deleting every row leaves nothing to order, and an empty list is not an order to send.\n if (itemsManage.value.length > 0) {\n await updateUserAdminConfigPositions(itemsManage.value.map((item) => item.id))\n }\n // Once, at the end: this is also what refreshes the store the filter bar reads its names from,\n // and what the editor re-baselines against.\n applyItems(await fetchItems())\n forceClose()\n } catch (e) {\n showErrorsDefault(e)\n // Nothing is refetched here and nothing is rolled back. What was written already looks the way\n // it looks on the server -- a deleted row is gone from both, a renamed one carries the new name\n // in both -- and what was not written is still the user's to correct and send again. Refetching\n // would take that unsent work with it without asking, which is the one thing this dialog must\n // not do. The store is told its copy is behind instead.\n filterBookmarkStore.markStale(bookmarkCacheKey())\n } finally {\n saveButtonLoading.value = false\n }\n}\n\nconst { serializeFilters } = useFilterHelpers(filterData, filterConfig)\n\nconst systemResource = props.system + '_' + props.subject\nconst bookmarkCacheKey = () => filterBookmarkStore.generateKey(UserAdminConfigLayoutType.Desktop, systemResource)\n\nconst addBookmark = async () => {\n saveButtonLoading.value = true\n errorCount.value = false\n const config = createDefaultUserAdminConfig(props.system)\n config.user = props.user\n config.configType = UserAdminConfigType.FilterBookmark\n config.layoutType = UserAdminConfigLayoutType.Desktop\n config.systemResource = systemResource\n config.customName = customName.value\n config.data = {\n filter: serializeFilters(filterData, pagination, false),\n datatableHiddenColumns:\n storeDatatableHiddenColumns.value && props.datatableHiddenColumns ? props.datatableHiddenColumns : undefined,\n sortBy: storeDatatableOrder.value && pagination.value.sortBy ? pagination.value.sortBy : undefined,\n }\n try {\n const { count, maxPosition } = await filterBookmarkStore.fetchBookmarkStats(\n {\n user: props.user,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList\n )\n if (count >= MAX_BOOKMARK_ITEMS) {\n errorCount.value = true\n saveButtonLoading.value = false\n return\n }\n // After the highest position in use, not after the number of rows. The manage tab renumbers\n // only the rows it sends, so a deletion saved there leaves a gap, and counting rows from then\n // on would put this bookmark on a position another one already holds.\n config.position = maxPosition + 1\n const res = await createUserAdminConfig(config)\n filterBookmarkStore.addOne(bookmarkCacheKey(), res)\n // Cleared because `requestClose` may not close: with work pending on the other tab the guard\n // asks, and \"stay\" would otherwise leave this bookmark's name in the field for a second click\n // to create it again. Empty, the `required` rule blocks that.\n customName.value = ''\n vCreate$.value.$reset()\n // The write is done, and `requestClose` refuses while one is out. The `finally` sets it again.\n saveButtonLoading.value = false\n // `requestClose`, not `forceClose`: adding a bookmark is a decision about THIS tab. It says\n // nothing about a reorder left pending on the other one, so the guard still gets to ask.\n requestClose()\n } catch (e) {\n if (\n isAnzuApiValidationError(e) &&\n hasAnzuApiValidationErrorSpecific(e, 'error_field_not_unique', 'cms.userAdminConfig.model.systemResource')\n ) {\n showWarningT('common.filter.bookmark.nameUniqueError')\n return\n }\n showErrorsDefault(e)\n } finally {\n saveButtonLoading.value = false\n }\n}\n\nconst onConfirm = () => {\n if (activeTab.value === 'add') {\n vCreate$.value.$touch()\n if (vCreate$.value.$invalid) {\n showValidationError()\n return\n }\n addBookmark()\n } else if (activeTab.value === 'manage') {\n // Not gated on the list being non-empty: deleting every row empties it while leaving the\n // deletions themselves pending, and this button is the only thing that sends them.\n saveManage()\n }\n}\n\n// Entering the manage tab starts a fetch, and the tabs can be switched faster than one comes back,\n// so two can be in flight at once. Only the newest one is allowed to land: without this an older\n// answer could overtake a newer one and put the list back to what it was two switches ago.\nlet fetchGeneration = 0\nlet fetchesInFlight = 0\n\nconst fetchItems = async (): Promise<UserAdminConfig[] | null> => {\n const generation = ++fetchGeneration\n // Counted, not a flag: an older fetch answering must not report the tab as settled while a newer\n // one is still out, or the editor takes edits again in the gap between the two.\n fetchesInFlight++\n listLoading.value = true\n loadFailed.value = false\n try {\n const items = await filterBookmarkStore.getBookmarks(\n {\n user: props.user,\n layoutType: UserAdminConfigLayoutType.Desktop,\n systemResource: systemResource,\n },\n useFetchUserAdminConfigList,\n true\n )\n if (generation !== fetchGeneration) return null\n // `null` is this request's own answer that it failed; the store's `error` flag is shared with\n // every other fetch it serves, this dialog's bookmark count among them.\n if (items === null) {\n loadFailed.value = true\n showUnknownError()\n return null\n }\n return items\n } catch (e) {\n // The same question as on the way out of the try: an answer that a newer one has overtaken does\n // not get to put the tab into an error state or raise an alert over it.\n if (generation !== fetchGeneration) return null\n loadFailed.value = true\n showErrorsDefault(e)\n return null\n } finally {\n fetchesInFlight--\n listLoading.value = fetchesInFlight > 0\n }\n}\n\n// The fetched rows are handed to the editor rather than left to reach it through `v-model`: that\n// way round is a render away, and a commit that ran before the rows arrived would pin the baseline\n// to the list from before the fetch -- every difference the fetch brought would then read as the\n// user's own unsaved edit. The editor is still to mount on the first load; it takes its own\n// baseline from `itemsManage` when it does.\nconst applyItems = (items: UserAdminConfig[] | null) => {\n if (!items) return\n itemsManage.value = items\n manageLoaded.value = true\n editor.value?.commit(items)\n}\n\nwatch(activeTab, async () => {\n errorCount.value = false\n if (activeTab.value !== 'manage') return\n // Entering the tab refreshes it -- a bookmark just added on the other tab is the near case -- but\n // never over work the user has not saved: the fetched order would replace the dragged one.\n if (editor.value?.hasUnsaved) return\n const items = await fetchItems()\n // Asked again on the way back: the fetch takes long enough for the user to have started dragging\n // in the meantime, and applying it then would be the same loss, just later.\n if (editor.value?.hasUnsaved) return\n applyItems(items)\n})\n</script>\n\n<template>\n <!-- `persistent` while a write is out: the escape key and a click outside go straight to the\n model, past everything the write phase disables. -->\n <VDialog\n v-model=\"isOpen\"\n :persistent=\"saveButtonLoading\"\n :width=\"500\"\n >\n <VCard>\n <ADialogToolbar @on-cancel=\"requestClose\">\n {{ t('common.filter.bookmark.title') }}\n </ADialogToolbar>\n <VCardText class=\"pt-0\">\n <VTabs\n v-model=\"activeTab\"\n fixed-tabs\n >\n <VTab\n value=\"add\"\n :disabled=\"saveButtonLoading\"\n >\n {{ t('common.filter.bookmark.add') }}\n </VTab>\n <VTab\n value=\"manage\"\n :disabled=\"saveButtonLoading\"\n >\n {{ t('common.filter.bookmark.manage') }}\n </VTab>\n </VTabs>\n <div\n v-if=\"activeTab === 'add'\"\n class=\"w-100 pt-4\"\n >\n <ARow :title=\"t('common.filter.bookmark.infoSave')\" />\n <ARow\n v-if=\"errorCount\"\n class=\"text-error\"\n :title=\"t('common.filter.bookmark.errorMax')\"\n />\n <ARow>\n <AFormTextField\n v-model=\"customName\"\n :label=\"t('common.filter.bookmark.name')\"\n required\n :disabled=\"saveButtonLoading\"\n :v=\"vCreate$.customName\"\n />\n </ARow>\n <ARow>\n <AFormSwitch\n v-model=\"storeDatatableHiddenColumns\"\n :disabled=\"saveButtonLoading\"\n :label=\"t('common.filter.bookmark.storeTableColumns')\"\n />\n </ARow>\n <ARow>\n <AFormSwitch\n v-model=\"storeDatatableOrder\"\n :disabled=\"saveButtonLoading\"\n :label=\"t('common.filter.bookmark.storeTableOrder')\"\n />\n </ARow>\n </div>\n <!-- `v-show`, not `v-if`: the guard sees this tab's pending work only through the section\n the editor registers, so unmounting it on a glance at the other tab would leave the\n dialog able to close on a dragged order without asking. The spinner is the editor's own\n `loading` for the same reason -- swapping it out on every reload would do the same. -->\n <div\n v-show=\"activeTab === 'manage'\"\n class=\"w-100 pt-4\"\n >\n <div\n v-if=\"!manageLoaded && !loadFailed\"\n class=\"d-flex w-100 align-center justify-center\"\n >\n <VProgressCircular indeterminate />\n </div>\n <!-- Nothing ever loaded: the editor's own empty state would claim there are no bookmarks,\n which is not what a failed fetch found out. -->\n <ARow\n v-else-if=\"!manageLoaded\"\n class=\"text-error\"\n :title=\"t('common.alert.unknownError')\"\n />\n <!-- Mounted once the first fetch has settled -- empty or not, so an empty list gets the\n editor's own empty state rather than a blank tab -- and never unmounted after that. -->\n <ASortableListEditor\n v-else\n ref=\"editor\"\n v-model=\"itemsManage\"\n :position=\"false\"\n :loading=\"listLoading || saveButtonLoading\"\n compact-field=\"customName\"\n :validate=\"validateBookmarkName\"\n :show-add-button=\"false\"\n :unsaved-section-label=\"t('common.filter.bookmark.unsavedSection')\"\n >\n <template #item=\"{ raw, actions }: { raw: UserAdminConfig; actions: RowUpdate }\">\n <AFormTextField\n :model-value=\"raw.customName\"\n hide-details=\"auto\"\n @update:model-value=\"actions.update({ ...raw, customName: String($event ?? '') })\"\n />\n </template>\n </ASortableListEditor>\n </div>\n </VCardText>\n <VCardActions>\n <VSpacer />\n <!-- Nothing in here takes input while a write is out: the change set was read when the\n button was pressed, so anything typed after that would not be in it, and the close that\n follows a successful save would take it with it. -->\n <ABtnTertiary\n data-cy=\"button-cancel\"\n :disabled=\"saveButtonLoading\"\n @click.stop=\"requestClose\"\n >\n {{ t('common.button.cancel') }}\n </ABtnTertiary>\n <!-- Not while the list is being refreshed: the order this would send is the one on screen,\n which the answer on its way is about to replace. -->\n <ABtnPrimary\n data-cy=\"button-confirm\"\n :disabled=\"activeTab === 'manage' && listLoading\"\n :loading=\"saveButtonLoading\"\n @click.stop=\"onConfirm\"\n >\n {{ activeTab === 'add' ? t('common.button.add') : t('common.filter.bookmark.saveBookmarkOrder') }}\n </ABtnPrimary>\n </VCardActions>\n </VCard>\n </VDialog>\n\n <AUnsavedConfirmDialog\n v-model=\"guard.promptOpen.value\"\n :dirty-labels=\"guard.dirtyLabels.value\"\n @resolve=\"guard.resolvePrompt\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\nimport FilterBookmarkDialog from '@/labs/filters/FilterBookmarkDialog.vue'\nimport type { AxiosInstance } from 'axios'\nimport type { IntegerId } from '@/types/common'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\n\nwithDefaults(\n defineProps<{\n client: () => AxiosInstance\n system: string\n subject: string\n user: IntegerId\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n datatableHiddenColumns?: string[] | undefined\n datatableSortBy?: DatatableSortBy\n }>(),\n {\n tooltipT: 'common.button.bookmarkFilter',\n buttonClass: 'ml-2',\n dataCy: 'filter-bookmark',\n datatableHiddenColumns: undefined,\n datatableSortBy: undefined,\n }\n)\n\nconst dialog = defineModel<boolean>('dialog', { default: false, required: false })\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n dialog.value = true\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis px-2\"\n min-width=\"36px\"\n variant=\"flat\"\n @click.stop=\"onClick\"\n >\n <VIcon\n color=\"grey-darken-1\"\n icon=\"mdi-bookmark-outline\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n <FilterBookmarkDialog\n v-if=\"dialog\"\n :client=\"client\"\n :system=\"system\"\n :user=\"user\"\n :subject=\"subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n @on-close=\"dialog = false\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\nimport FilterBookmarkDialog from '@/labs/filters/FilterBookmarkDialog.vue'\nimport type { AxiosInstance } from 'axios'\nimport type { IntegerId } from '@/types/common'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\n\nwithDefaults(\n defineProps<{\n client: () => AxiosInstance\n system: string\n subject: string\n user: IntegerId\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n datatableHiddenColumns?: string[] | undefined\n datatableSortBy?: DatatableSortBy\n }>(),\n {\n tooltipT: 'common.button.bookmarkFilter',\n buttonClass: 'ml-2',\n dataCy: 'filter-bookmark',\n datatableHiddenColumns: undefined,\n datatableSortBy: undefined,\n }\n)\n\nconst dialog = defineModel<boolean>('dialog', { default: false, required: false })\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n dialog.value = true\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n class=\"text-medium-emphasis px-2\"\n min-width=\"36px\"\n variant=\"flat\"\n @click.stop=\"onClick\"\n >\n <VIcon\n color=\"grey-darken-1\"\n icon=\"mdi-bookmark-outline\"\n />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n <FilterBookmarkDialog\n v-if=\"dialog\"\n :client=\"client\"\n :system=\"system\"\n :user=\"user\"\n :subject=\"subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n @on-close=\"dialog = false\"\n />\n</template>\n","<script lang=\"ts\" setup>\nimport AFilterSubmitButton from '@/components/buttons/filter/AFilterSubmitButton.vue'\nimport AFilterResetButton from '@/components/buttons/filter/AFilterResetButton.vue'\nimport { computed, inject, nextTick, provide, ref } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n SubjectSelectCloseSidebarKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isBoolean, isDefined, isUndefined } from '@/utils/common'\nimport { type FilterStoreIdentifier, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { datatableSlotName } from '@/components/datatable/datatable'\nimport FilterDetailItem from '@/labs/filters/FilterDetailItem.vue'\nimport FilterBookmarks from '@/labs/filters/FilterBookmarks.vue'\nimport type { IntegerIdNullable } from '@/types/common'\nimport type { AxiosInstance } from 'axios'\nimport AFilterBookmarkButton from '@/components/buttons/filter/AFilterBookmarkButton.vue'\n\nconst props = withDefaults(\n defineProps<{\n hideButtons?: boolean\n formName?: string\n disableFilterUrlSync?: boolean\n userId?: IntegerIdNullable | undefined\n client?: (() => AxiosInstance) | undefined\n store?: FilterStoreIdentifier | boolean // false to disable, FilterStoreIdentifier to custom store key\n }>(),\n {\n hideButtons: false,\n formName: 'search',\n disableFilterUrlSync: false,\n userId: undefined,\n client: undefined,\n store: true,\n }\n)\nconst emit = defineEmits<{\n (e: 'submit'): void\n (e: 'reset'): void\n (e: 'bookmarkLoadAfter'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: false,\n})\n\nconst closeSidebarOnMobile = inject(SubjectSelectCloseSidebarKey, () => {})\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nif (isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst identifier = ref<Partial<FilterStoreIdentifier>>({\n system: filterConfig.general.system,\n subject: filterConfig.general.subject,\n})\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isBoolean(props.store)) {\n identifier.value.system = props.store.system\n identifier.value.subject = props.store.subject\n} else if (false === props.store) {\n identifier.value.system = undefined\n identifier.value.subject = undefined\n}\n\nconst submitResetCounter = ref(0)\nprovide(FilterSubmitResetCounterKey, submitResetCounter)\nconst filterSelected = ref<Map<string, ValueObjectOption<string | number>[]>>(new Map())\nprovide(FilterSelectedKey, filterSelected)\n\nconst submitFilter = () => {\n submitResetCounter.value++\n nextTick(() => {\n emit('submit')\n closeSidebarOnMobile()\n })\n}\n\nconst { clearAll, clearAllFilterSelected } = useFilterClearHelpers()\n\nconst submitFilterBookmark = () => {\n nextTick(() => {\n submitResetCounter.value++\n emit('bookmarkLoadAfter')\n closeSidebarOnMobile()\n })\n}\n\nconst resetFilter = () => {\n clearAll(filterData, filterConfig)\n clearAllFilterSelected(filterData, filterConfig, filterSelected)\n nextTick(() => {\n submitResetCounter.value++\n emit('reset')\n closeSidebarOnMobile()\n })\n}\n\nconst touched = computed(() => {\n return filterConfig.touched\n})\n\nconst renderedFieldNames = computed(() => {\n return Object.entries(filterConfig.fields)\n .filter(([, field]) => !field.render.skip)\n .map(([fieldName]) => fieldName)\n})\n\ndefineExpose({\n submit: submitFilter,\n reset: resetFilter,\n})\n</script>\n\n<template>\n <VForm\n :name=\"formName\"\n @submit.prevent=\"submitFilter\"\n >\n <div class=\"subject-select-filter__content px-2 py-4\">\n <slot name=\"bookmarks\">\n <VRow density=\"compact\">\n <VCol v-if=\"store && userId && isDefined(client)\">\n <div class=\"d-flex flex-wrap align-center\">\n <FilterBookmarks\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n v-model:datatable-hidden-columns=\"datatableHiddenColumns\"\n :client=\"client\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :user-id=\"userId\"\n @submit=\"submitFilterBookmark\"\n />\n </div>\n </VCol>\n </VRow>\n </slot>\n <slot name=\"detail\">\n <VRow>\n <VCol\n v-for=\"fieldName in renderedFieldNames\"\n :key=\"fieldName\"\n :cols=\"filterConfig.fields[fieldName].render.xs || 12\"\n :sm=\"filterConfig.fields[fieldName].render.sm || 12\"\n :md=\"filterConfig.fields[fieldName].render.md || 12\"\n :lg=\"filterConfig.fields[fieldName].render.lg || 12\"\n :xl=\"filterConfig.fields[fieldName].render.xl || 12\"\n >\n <slot\n :name=\"datatableSlotName(fieldName)\"\n :item-config=\"filterConfig.fields[fieldName]\"\n >\n <FilterDetailItem :name=\"fieldName\" />\n </slot>\n </VCol>\n </VRow>\n </slot>\n </div>\n <div\n v-if=\"!hideButtons\"\n class=\"subject-select-filter__actions\"\n >\n <slot name=\"buttons\">\n <AFilterSubmitButton :touched=\"touched\" />\n <AFilterResetButton @reset=\"resetFilter\" />\n <AFilterBookmarkButton\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n :client=\"client\"\n :user=\"userId\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n />\n </slot>\n </div>\n </VForm>\n</template>\n\n<style lang=\"scss\">\n@use 'vuetify/tools' as *;\n\n.a-filter {\n &__container {\n width: 100%;\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport AFilterSubmitButton from '@/components/buttons/filter/AFilterSubmitButton.vue'\nimport AFilterResetButton from '@/components/buttons/filter/AFilterResetButton.vue'\nimport { computed, inject, nextTick, provide, ref } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n SubjectSelectCloseSidebarKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isBoolean, isDefined, isUndefined } from '@/utils/common'\nimport { type FilterStoreIdentifier, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { datatableSlotName } from '@/components/datatable/datatable'\nimport FilterDetailItem from '@/labs/filters/FilterDetailItem.vue'\nimport FilterBookmarks from '@/labs/filters/FilterBookmarks.vue'\nimport type { IntegerIdNullable } from '@/types/common'\nimport type { AxiosInstance } from 'axios'\nimport AFilterBookmarkButton from '@/components/buttons/filter/AFilterBookmarkButton.vue'\n\nconst props = withDefaults(\n defineProps<{\n hideButtons?: boolean\n formName?: string\n disableFilterUrlSync?: boolean\n userId?: IntegerIdNullable | undefined\n client?: (() => AxiosInstance) | undefined\n store?: FilterStoreIdentifier | boolean // false to disable, FilterStoreIdentifier to custom store key\n }>(),\n {\n hideButtons: false,\n formName: 'search',\n disableFilterUrlSync: false,\n userId: undefined,\n client: undefined,\n store: true,\n }\n)\nconst emit = defineEmits<{\n (e: 'submit'): void\n (e: 'reset'): void\n (e: 'bookmarkLoadAfter'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: false,\n})\n\nconst closeSidebarOnMobile = inject(SubjectSelectCloseSidebarKey, () => {})\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nif (isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst identifier = ref<Partial<FilterStoreIdentifier>>({\n system: filterConfig.general.system,\n subject: filterConfig.general.subject,\n})\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isBoolean(props.store)) {\n identifier.value.system = props.store.system\n identifier.value.subject = props.store.subject\n} else if (false === props.store) {\n identifier.value.system = undefined\n identifier.value.subject = undefined\n}\n\nconst submitResetCounter = ref(0)\nprovide(FilterSubmitResetCounterKey, submitResetCounter)\nconst filterSelected = ref<Map<string, ValueObjectOption<string | number>[]>>(new Map())\nprovide(FilterSelectedKey, filterSelected)\n\nconst submitFilter = () => {\n submitResetCounter.value++\n nextTick(() => {\n emit('submit')\n closeSidebarOnMobile()\n })\n}\n\nconst { clearAll, clearAllFilterSelected } = useFilterClearHelpers()\n\nconst submitFilterBookmark = () => {\n nextTick(() => {\n submitResetCounter.value++\n emit('bookmarkLoadAfter')\n closeSidebarOnMobile()\n })\n}\n\nconst resetFilter = () => {\n clearAll(filterData, filterConfig)\n clearAllFilterSelected(filterData, filterConfig, filterSelected)\n nextTick(() => {\n submitResetCounter.value++\n emit('reset')\n closeSidebarOnMobile()\n })\n}\n\nconst touched = computed(() => {\n return filterConfig.touched\n})\n\nconst renderedFieldNames = computed(() => {\n return Object.entries(filterConfig.fields)\n .filter(([, field]) => !field.render.skip)\n .map(([fieldName]) => fieldName)\n})\n\ndefineExpose({\n submit: submitFilter,\n reset: resetFilter,\n})\n</script>\n\n<template>\n <VForm\n :name=\"formName\"\n @submit.prevent=\"submitFilter\"\n >\n <div class=\"subject-select-filter__content px-2 py-4\">\n <slot name=\"bookmarks\">\n <VRow density=\"compact\">\n <VCol v-if=\"store && userId && isDefined(client)\">\n <div class=\"d-flex flex-wrap align-center\">\n <FilterBookmarks\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n v-model:datatable-hidden-columns=\"datatableHiddenColumns\"\n :client=\"client\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :user-id=\"userId\"\n @submit=\"submitFilterBookmark\"\n />\n </div>\n </VCol>\n </VRow>\n </slot>\n <slot name=\"detail\">\n <VRow>\n <VCol\n v-for=\"fieldName in renderedFieldNames\"\n :key=\"fieldName\"\n :cols=\"filterConfig.fields[fieldName].render.xs || 12\"\n :sm=\"filterConfig.fields[fieldName].render.sm || 12\"\n :md=\"filterConfig.fields[fieldName].render.md || 12\"\n :lg=\"filterConfig.fields[fieldName].render.lg || 12\"\n :xl=\"filterConfig.fields[fieldName].render.xl || 12\"\n >\n <slot\n :name=\"datatableSlotName(fieldName)\"\n :item-config=\"filterConfig.fields[fieldName]\"\n >\n <FilterDetailItem :name=\"fieldName\" />\n </slot>\n </VCol>\n </VRow>\n </slot>\n </div>\n <div\n v-if=\"!hideButtons\"\n class=\"subject-select-filter__actions\"\n >\n <slot name=\"buttons\">\n <AFilterSubmitButton :touched=\"touched\" />\n <AFilterResetButton @reset=\"resetFilter\" />\n <AFilterBookmarkButton\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n :client=\"client\"\n :user=\"userId\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n />\n </slot>\n </div>\n </VForm>\n</template>\n\n<style lang=\"scss\">\n@use 'vuetify/tools' as *;\n\n.a-filter {\n &__container {\n width: 100%;\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { useI18n } from 'vue-i18n'\nimport type { Pagination } from '@/labs/filters/pagination'\nimport { usePagination } from '@/labs/filters/pagination'\nimport type { DocId, IntegerId } from '@/types/common'\nimport { cloneDeep, isArray, isNull, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport { FilterInnerConfigKey, FilterInnerDataKey } from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype FetchItemsMinimalType = (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n) => Promise<any[]>\n\ntype UseCachedType = () => {\n fetch: any\n add: any\n addManualMinimal: any\n}\n\nconst props = withDefaults(\n defineProps<{\n modelValue: any\n label?: string | undefined\n required?: boolean\n multiple?: boolean\n clearable?: boolean\n v?: any\n errorMessage?: string\n hideLabel?: boolean\n fetchItemsMinimal: FetchItemsMinimalType\n filterByField?: string\n filterSortBy?: DatatableSortBy\n loading?: boolean\n useCached: UseCachedType\n itemTitle?: string\n itemValue?: string\n minSearchChars?: number\n minSearchText?: string | undefined\n }>(),\n {\n label: undefined,\n required: undefined,\n multiple: false,\n clearable: false,\n v: null,\n errorMessage: undefined,\n hideLabel: false,\n filterByField: 'name',\n filterSortBy: null,\n loading: false,\n itemTitle: 'name',\n itemValue: 'id',\n minSearchChars: 2,\n minSearchText: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'blur', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'focus', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'searchChange', data: string): void\n (e: 'searchChangeDebounced', data: string): void\n}>()\n\nconst search = defineModel<string>('search', { default: '', required: false })\nconst loadingLocal = defineModel<boolean>('loadingLocal', { default: false, required: false })\nconst fetchedItemsMinimal = defineModel<Map<IntegerId | DocId, any>>('fetchedItemsMinimal', {\n required: true,\n})\n\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (isUndefined(filterInnerConfig) || isUndefined(filterInnerData)) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerConfig.fields[props.filterByField]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerData[props.filterByField])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${props.filterByField}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { fetch, add, addManualMinimal } = props.useCached()\n\nconst noDataText = computed(() => {\n if (loadingLocal.value) {\n return '$vuetify.loading'\n }\n if (fetchedItemsMinimal.value.size === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nconst modelValue = computed({\n get() {\n return props.modelValue\n },\n set(newValue: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined) {\n emit('update:modelValue', cloneDeep<DocId | IntegerId | DocId[] | IntegerId[] | null | undefined>(newValue))\n },\n})\n\nconst { t } = useI18n()\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst isFocused = ref(false)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { pagination } = usePagination(\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isNull(props.filterSortBy) ? null : props.filterSortBy.key,\n props.filterSortBy?.order\n)\n\nconst onFocus = () => {\n isFocused.value = true\n emit('focus', modelValue.value)\n}\n\nconst onBlur = () => {\n isFocused.value = false\n props.v?.$touch()\n emit('blur', modelValue.value)\n}\n\nconst errorMessageComputed = computed(() => {\n if (!isUndefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return props.v.$errors.map((item: ErrorObject) => item.$message)\n return []\n})\n\nconst labelComputed = computed(() => {\n if (!isUndefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (!isUndefined(props.required)) return props.required\n return props.v?.required && props.v?.required.$params.type === 'required'\n})\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string | null) => {\n if (isNull(query) || query.length < props.minSearchChars) {\n fetchedItemsMinimal.value.clear()\n return\n }\n loadingLocal.value = true\n filterInnerData[props.filterByField] = query\n fetchedItemsMinimal.value.clear()\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n res.forEach((item: any) => {\n fetchedItemsMinimal.value.set(item[props.itemValue], item)\n })\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst allItems = computed<ValueObjectOption<DocId | IntegerId>[]>(() => {\n const final: Map<IntegerId | DocId, string> = new Map()\n const finalRaw: Map<IntegerId | DocId, any> = new Map()\n if (isArray(modelValue.value)) {\n modelValue.value.forEach((value: any) => {\n final.set(value, '')\n })\n } else if (modelValue.value) {\n final.set(modelValue.value, '')\n }\n fetchedItemsMinimal.value.forEach((value) => {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n })\n return Array.from(final, ([key, value]) => {\n return { value: key, title: value, raw: finalRaw.get(key) }\n })\n})\n\nconst tryToAddFromFetchedItems = (ids: Set<DocId | IntegerId>) => {\n return new Promise<boolean>((resolve) => {\n fetchedItemsMinimal.value.forEach((value, key) => {\n if (ids.has(key)) {\n addManualMinimal(cloneDeep(value))\n }\n })\n return resolve(true)\n })\n}\n\nconst onClickClear = () => {\n search.value = ''\n apiSearch('')\n if (props.multiple) {\n modelValue.value = []\n return\n }\n modelValue.value = null\n}\n\nwatchDebounced(\n search,\n (newValueBug, oldValueBug) => {\n // todo rollback fix when fixed on vuetify/vue use side\n const newValue = newValueBug as unknown as string\n const oldValue = oldValueBug as unknown as string | undefined\n if (newValue !== oldValue) {\n apiSearch(newValue)\n emit('searchChangeDebounced', newValue)\n }\n },\n { debounce: 300 }\n)\n\nwatch(search, (newValue, oldValue) => {\n if (newValue !== oldValue) {\n emit('searchChange', newValue)\n }\n})\n\nwatch(\n modelValue,\n async (newValue) => {\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n return\n }\n const values = isArray(newValue) ? newValue : [newValue]\n const idsToFetch = new Set(values)\n await tryToAddFromFetchedItems(idsToFetch)\n\n if (idsToFetch.size > 0) {\n add(Array.from(idsToFetch) as Array<DocId & IntegerId>)\n fetch()\n }\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"modelValue\"\n v-model:search=\"search\"\n chips\n :items=\"allItems\"\n no-filter\n :multiple=\"multiple\"\n :clearable=\"clearable\"\n :error-messages=\"errorMessageComputed\"\n :loading=\"loadingLocal\"\n :no-data-text=\"noDataText\"\n autocomplete=\"off\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @click:clear=\"onClickClear\"\n >\n <template #label>\n <span\n v-if=\"!hideLabel\"\n :key=\"requiredComputed + ''\"\n >\n {{ labelComputed }}\n <span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </span>\n </template>\n <template #append-item>\n <slot name=\"append-item\" />\n </template>\n <template\n v-if=\"!multiple\"\n #selection\n />\n <!-- @vue-skip -->\n <template #chip=\"{ props: chipProps, internalItem: chipItem }\">\n <slot\n name=\"chip\"\n :props=\"chipProps\"\n :item=\"chipItem\"\n >\n <VChip\n v-bind=\"chipProps\"\n :text=\"chipItem.title\"\n />\n </slot>\n </template>\n <!-- @vue-skip -->\n <template #item=\"{ props: itemProps, internalItem: itemItem }\">\n <slot\n name=\"item\"\n :props=\"itemProps\"\n :item=\"itemItem\"\n >\n <VListItem :props=\"itemProps\" />\n </slot>\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup>\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { useI18n } from 'vue-i18n'\nimport type { Pagination } from '@/labs/filters/pagination'\nimport { usePagination } from '@/labs/filters/pagination'\nimport type { DocId, IntegerId } from '@/types/common'\nimport { cloneDeep, isArray, isNull, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport { FilterInnerConfigKey, FilterInnerDataKey } from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype FetchItemsMinimalType = (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n) => Promise<any[]>\n\ntype UseCachedType = () => {\n fetch: any\n add: any\n addManualMinimal: any\n}\n\nconst props = withDefaults(\n defineProps<{\n modelValue: any\n label?: string | undefined\n required?: boolean\n multiple?: boolean\n clearable?: boolean\n v?: any\n errorMessage?: string\n hideLabel?: boolean\n fetchItemsMinimal: FetchItemsMinimalType\n filterByField?: string\n filterSortBy?: DatatableSortBy\n loading?: boolean\n useCached: UseCachedType\n itemTitle?: string\n itemValue?: string\n minSearchChars?: number\n minSearchText?: string | undefined\n }>(),\n {\n label: undefined,\n required: undefined,\n multiple: false,\n clearable: false,\n v: null,\n errorMessage: undefined,\n hideLabel: false,\n filterByField: 'name',\n filterSortBy: null,\n loading: false,\n itemTitle: 'name',\n itemValue: 'id',\n minSearchChars: 2,\n minSearchText: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'update:modelValue', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'blur', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'focus', data: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined): void\n (e: 'searchChange', data: string): void\n (e: 'searchChangeDebounced', data: string): void\n}>()\n\nconst search = defineModel<string>('search', { default: '', required: false })\nconst loadingLocal = defineModel<boolean>('loadingLocal', { default: false, required: false })\nconst fetchedItemsMinimal = defineModel<Map<IntegerId | DocId, any>>('fetchedItemsMinimal', {\n required: true,\n})\n\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (isUndefined(filterInnerConfig) || isUndefined(filterInnerData)) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n\nif (\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerConfig.fields[props.filterByField]) ||\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isUndefined(filterInnerData[props.filterByField])\n) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${props.filterByField}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { fetch, add, addManualMinimal } = props.useCached()\n\nconst noDataText = computed(() => {\n if (loadingLocal.value) {\n return '$vuetify.loading'\n }\n if (fetchedItemsMinimal.value.size === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nconst modelValue = computed({\n get() {\n return props.modelValue\n },\n set(newValue: DocId | IntegerId | DocId[] | IntegerId[] | null | undefined) {\n emit('update:modelValue', cloneDeep<DocId | IntegerId | DocId[] | IntegerId[] | null | undefined>(newValue))\n },\n})\n\nconst { t } = useI18n()\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst isFocused = ref(false)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst { pagination } = usePagination(\n // eslint-disable-next-line vue/no-setup-props-reactivity-loss\n isNull(props.filterSortBy) ? null : props.filterSortBy.key,\n props.filterSortBy?.order\n)\n\nconst onFocus = () => {\n isFocused.value = true\n emit('focus', modelValue.value)\n}\n\nconst onBlur = () => {\n isFocused.value = false\n props.v?.$touch()\n emit('blur', modelValue.value)\n}\n\nconst errorMessageComputed = computed(() => {\n if (!isUndefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return props.v.$errors.map((item: ErrorObject) => item.$message)\n return []\n})\n\nconst labelComputed = computed(() => {\n if (!isUndefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (!isUndefined(props.required)) return props.required\n return props.v?.required && props.v?.required.$params.type === 'required'\n})\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string | null) => {\n if (isNull(query) || query.length < props.minSearchChars) {\n fetchedItemsMinimal.value.clear()\n return\n }\n loadingLocal.value = true\n filterInnerData[props.filterByField] = query\n fetchedItemsMinimal.value.clear()\n try {\n const res = await props.fetchItemsMinimal(pagination, filterInnerData, filterInnerConfig)\n res.forEach((item: any) => {\n fetchedItemsMinimal.value.set(item[props.itemValue], item)\n })\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst allItems = computed<ValueObjectOption<DocId | IntegerId>[]>(() => {\n const final: Map<IntegerId | DocId, string> = new Map()\n const finalRaw: Map<IntegerId | DocId, any> = new Map()\n if (isArray(modelValue.value)) {\n modelValue.value.forEach((value: any) => {\n final.set(value, '')\n })\n } else if (modelValue.value) {\n final.set(modelValue.value, '')\n }\n fetchedItemsMinimal.value.forEach((value) => {\n final.set(value[props.itemValue], value[props.itemTitle])\n finalRaw.set(value[props.itemValue], cloneDeep(value))\n })\n return Array.from(final, ([key, value]) => {\n return { value: key, title: value, raw: finalRaw.get(key) }\n })\n})\n\nconst tryToAddFromFetchedItems = (ids: Set<DocId | IntegerId>) => {\n return new Promise<boolean>((resolve) => {\n fetchedItemsMinimal.value.forEach((value, key) => {\n if (ids.has(key)) {\n addManualMinimal(cloneDeep(value))\n }\n })\n return resolve(true)\n })\n}\n\nconst onClickClear = () => {\n search.value = ''\n apiSearch('')\n if (props.multiple) {\n modelValue.value = []\n return\n }\n modelValue.value = null\n}\n\nwatchDebounced(\n search,\n (newValueBug, oldValueBug) => {\n // todo rollback fix when fixed on vuetify/vue use side\n const newValue = newValueBug as unknown as string\n const oldValue = oldValueBug as unknown as string | undefined\n if (newValue !== oldValue) {\n apiSearch(newValue)\n emit('searchChangeDebounced', newValue)\n }\n },\n { debounce: 300 }\n)\n\nwatch(search, (newValue, oldValue) => {\n if (newValue !== oldValue) {\n emit('searchChange', newValue)\n }\n})\n\nwatch(\n modelValue,\n async (newValue) => {\n if (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0)) {\n return\n }\n const values = isArray(newValue) ? newValue : [newValue]\n const idsToFetch = new Set(values)\n await tryToAddFromFetchedItems(idsToFetch)\n\n if (idsToFetch.size > 0) {\n add(Array.from(idsToFetch) as Array<DocId & IntegerId>)\n fetch()\n }\n },\n { immediate: true }\n)\n</script>\n\n<template>\n <VAutocomplete\n v-model=\"modelValue\"\n v-model:search=\"search\"\n chips\n :items=\"allItems\"\n no-filter\n :multiple=\"multiple\"\n :clearable=\"clearable\"\n :error-messages=\"errorMessageComputed\"\n :loading=\"loadingLocal\"\n :no-data-text=\"noDataText\"\n autocomplete=\"off\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @click:clear=\"onClickClear\"\n >\n <template #label>\n <span\n v-if=\"!hideLabel\"\n :key=\"requiredComputed + ''\"\n >\n {{ labelComputed }}\n <span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </span>\n </template>\n <template #append-item>\n <slot name=\"append-item\" />\n </template>\n <template\n v-if=\"!multiple\"\n #selection\n />\n <!-- @vue-skip -->\n <template #chip=\"{ props: chipProps, internalItem: chipItem }\">\n <slot\n name=\"chip\"\n :props=\"chipProps\"\n :item=\"chipItem\"\n >\n <VChip\n v-bind=\"chipProps\"\n :text=\"chipItem.title\"\n />\n </slot>\n </template>\n <!-- @vue-skip -->\n <template #item=\"{ props: itemProps, internalItem: itemItem }\">\n <slot\n name=\"item\"\n :props=\"itemProps\"\n :item=\"itemItem\"\n >\n <VListItem :props=\"itemProps\" />\n </slot>\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup>\nimport { ref } from 'vue'\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\n\nwithDefaults(\n defineProps<{\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n tooltipT: 'common.button.advancedFilters',\n buttonClass: 'mt-1',\n dataCy: 'filter-advanced',\n }\n)\nconst emit = defineEmits<{\n (e: 'advancedFilter'): void\n}>()\n\nconst active = ref(false)\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n active.value = !active.value\n emit('advancedFilter')\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n icon\n size=\"x-small\"\n variant=\"text\"\n @click.stop=\"onClick\"\n >\n <VIcon icon=\"mdi-filter-variant\" />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { ref } from 'vue'\nimport { eventClickBlur } from '@/utils/event'\nimport { useI18n } from 'vue-i18n'\n\nwithDefaults(\n defineProps<{\n tooltipT?: string\n buttonClass?: string\n dataCy?: string\n }>(),\n {\n tooltipT: 'common.button.advancedFilters',\n buttonClass: 'mt-1',\n dataCy: 'filter-advanced',\n }\n)\nconst emit = defineEmits<{\n (e: 'advancedFilter'): void\n}>()\n\nconst active = ref(false)\n\nconst onClick = (event: Event) => {\n eventClickBlur(event)\n active.value = !active.value\n emit('advancedFilter')\n}\n\nconst { t } = useI18n()\n</script>\n\n<template>\n <VBtn\n :class=\"buttonClass\"\n :data-cy=\"dataCy\"\n icon\n size=\"x-small\"\n variant=\"text\"\n @click.stop=\"onClick\"\n >\n <VIcon icon=\"mdi-filter-variant\" />\n <VTooltip\n activator=\"parent\"\n location=\"bottom\"\n >\n {{ t(tooltipT) }}\n </VTooltip>\n </VBtn>\n</template>\n","<script lang=\"ts\" setup>\nimport { computed, inject } from 'vue'\nimport { FilterConfigKey, FilterDataKey, FilterSelectedKey } from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterSelected = inject(FilterSelectedKey)\n\nif (isUndefined(filterConfig) || isUndefined(filterData) || isUndefined(filterSelected)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst { t } = useI18n()\n\nconst getTitleFromConfig = (name: string) => {\n const titleT = filterConfig.fields?.[name]?.titleT\n if (titleT) return t(titleT)\n return name\n}\n\nconst selectedArray = computed(() => {\n const fieldOrder = Object.keys(filterConfig.fields)\n return Array.from(filterSelected.value)\n .filter(([key]) => filterConfig.fields?.[key]?.render?.selected !== false)\n .map(([key, valueArray]) => ({\n name: key,\n title: getTitleFromConfig(key),\n options: valueArray,\n }))\n .sort((a, b) => fieldOrder.indexOf(a.name) - fieldOrder.indexOf(b.name))\n})\n\nconst { clearOneFilterSelected, isClearable } = useFilterClearHelpers()\n\n/**\n * Clearing means \"back to the default\", so on a field already holding its default there is\n * nothing to clear and the close button would do nothing at all - it would drop the chip, write\n * the same value back, and the chip would come straight back. Only fields with a non-null default\n * can reach that state; an array is different, because closing one chip removes one option.\n */\nconst canClear = (name: string) => {\n if (!isClearable(name, filterConfig)) return false\n const config = filterConfig.fields[name]\n // A time interval is a pair sharing one chip, and clearing writes the default into both. Only\n // `until` may differ - the custom dialog opens prefilled, so shortening just the upper bound\n // leaves `from` at its default - and the button still has work to do then.\n if (config.type === 'timeInterval' && config.related) {\n const related = filterConfig.fields[config.related]\n if (filterData[config.related] !== related.default) return true\n }\n const value = filterData[name]\n if (isArray(value)) return true\n return value !== config.default\n}\n\nconst clickClose = (name: string, optionValue: number | string) => {\n clearOneFilterSelected(name, optionValue, filterData, filterConfig, filterSelected)\n filterConfig.touched = true\n}\n</script>\n\n<template>\n <div\n v-for=\"item in selectedArray\"\n :key=\"item.name\"\n class=\"a-selected-filters\"\n >\n <div class=\"a-selected-filters__label text-body-small\">{{ item.title }}:</div>\n <div\n v-for=\"option in item.options\"\n :key=\"option.value\"\n class=\"a-selected-filters__chips\"\n >\n <VChip\n v-if=\"canClear(item.name)\"\n closable\n size=\"small\"\n class=\"a-selected-filters__chip\"\n @click:close.stop=\"clickClose(item.name, option.value)\"\n >\n <template #close>\n <VIcon\n size=\"16\"\n icon=\"mdi-close-circle\"\n />\n </template>\n {{ option.title }}\n </VChip>\n <VChip\n v-else\n size=\"small\"\n class=\"a-selected-filters__chip\"\n >\n {{ option.title }}\n </VChip>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n.a-selected-filters {\n display: inline-flex;\n align-items: center;\n background: #f5f5f5;\n border-radius: 20px;\n padding: 4px 4px 4px 12px;\n margin: 0 4px 2px 0;\n gap: 8px;\n max-width: 100%;\n\n &__label {\n white-space: nowrap;\n }\n\n &__chips {\n display: flex;\n gap: 4px;\n flex-wrap: wrap;\n }\n\n &__chip {\n background: white;\n box-shadow: none;\n\n .v-chip__content {\n max-width: 40vw;\n }\n\n &:hover .v-chip__close {\n opacity: 0.8;\n }\n }\n\n .v-chip__close {\n opacity: 0.3;\n transition: opacity 0.2s;\n }\n}\n\n// Values above are hardcoded light, which renders white-on-white in dark theme.\n.v-theme--dark .a-selected-filters {\n background: rgb(var(--v-theme-on-surface), 0.08);\n\n .a-selected-filters__chip {\n background: rgb(var(--v-theme-on-surface), 0.16);\n color: rgb(var(--v-theme-on-surface));\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport { computed, inject } from 'vue'\nimport { FilterConfigKey, FilterDataKey, FilterSelectedKey } from '@/labs/filters/filterInjectionKeys'\nimport { isArray, isUndefined } from '@/utils/common'\nimport { useI18n } from 'vue-i18n'\nimport { useFilterClearHelpers } from '@/labs/filters/filterFactory'\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nconst filterSelected = inject(FilterSelectedKey)\n\nif (isUndefined(filterConfig) || isUndefined(filterData) || isUndefined(filterSelected)) {\n throw new Error('Incorrect provide/inject config.')\n}\n\nconst { t } = useI18n()\n\nconst getTitleFromConfig = (name: string) => {\n const titleT = filterConfig.fields?.[name]?.titleT\n if (titleT) return t(titleT)\n return name\n}\n\nconst selectedArray = computed(() => {\n const fieldOrder = Object.keys(filterConfig.fields)\n return Array.from(filterSelected.value)\n .filter(([key]) => filterConfig.fields?.[key]?.render?.selected !== false)\n .map(([key, valueArray]) => ({\n name: key,\n title: getTitleFromConfig(key),\n options: valueArray,\n }))\n .sort((a, b) => fieldOrder.indexOf(a.name) - fieldOrder.indexOf(b.name))\n})\n\nconst { clearOneFilterSelected, isClearable } = useFilterClearHelpers()\n\n/**\n * Clearing means \"back to the default\", so on a field already holding its default there is\n * nothing to clear and the close button would do nothing at all - it would drop the chip, write\n * the same value back, and the chip would come straight back. Only fields with a non-null default\n * can reach that state; an array is different, because closing one chip removes one option.\n */\nconst canClear = (name: string) => {\n if (!isClearable(name, filterConfig)) return false\n const config = filterConfig.fields[name]\n // A time interval is a pair sharing one chip, and clearing writes the default into both. Only\n // `until` may differ - the custom dialog opens prefilled, so shortening just the upper bound\n // leaves `from` at its default - and the button still has work to do then.\n if (config.type === 'timeInterval' && config.related) {\n const related = filterConfig.fields[config.related]\n if (filterData[config.related] !== related.default) return true\n }\n const value = filterData[name]\n if (isArray(value)) return true\n return value !== config.default\n}\n\nconst clickClose = (name: string, optionValue: number | string) => {\n clearOneFilterSelected(name, optionValue, filterData, filterConfig, filterSelected)\n filterConfig.touched = true\n}\n</script>\n\n<template>\n <div\n v-for=\"item in selectedArray\"\n :key=\"item.name\"\n class=\"a-selected-filters\"\n >\n <div class=\"a-selected-filters__label text-body-small\">{{ item.title }}:</div>\n <div\n v-for=\"option in item.options\"\n :key=\"option.value\"\n class=\"a-selected-filters__chips\"\n >\n <VChip\n v-if=\"canClear(item.name)\"\n closable\n size=\"small\"\n class=\"a-selected-filters__chip\"\n @click:close.stop=\"clickClose(item.name, option.value)\"\n >\n <template #close>\n <VIcon\n size=\"16\"\n icon=\"mdi-close-circle\"\n />\n </template>\n {{ option.title }}\n </VChip>\n <VChip\n v-else\n size=\"small\"\n class=\"a-selected-filters__chip\"\n >\n {{ option.title }}\n </VChip>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n.a-selected-filters {\n display: inline-flex;\n align-items: center;\n background: #f5f5f5;\n border-radius: 20px;\n padding: 4px 4px 4px 12px;\n margin: 0 4px 2px 0;\n gap: 8px;\n max-width: 100%;\n\n &__label {\n white-space: nowrap;\n }\n\n &__chips {\n display: flex;\n gap: 4px;\n flex-wrap: wrap;\n }\n\n &__chip {\n background: white;\n box-shadow: none;\n\n .v-chip__content {\n max-width: 40vw;\n }\n\n &:hover .v-chip__close {\n opacity: 0.8;\n }\n }\n\n .v-chip__close {\n opacity: 0.3;\n transition: opacity 0.2s;\n }\n}\n\n// Values above are hardcoded light, which renders white-on-white in dark theme.\n.v-theme--dark .a-selected-filters {\n background: rgb(var(--v-theme-on-surface), 0.08);\n\n .a-selected-filters__chip {\n background: rgb(var(--v-theme-on-surface), 0.16);\n color: rgb(var(--v-theme-on-surface));\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport AFilterAdvancedButton from '@/labs/filters/AFilterAdvancedButton.vue'\nimport AFilterSubmitButton from '@/components/buttons/filter/AFilterSubmitButton.vue'\nimport AFilterResetButton from '@/components/buttons/filter/AFilterResetButton.vue'\nimport { computed, inject, nextTick, provide, ref } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport FiltersSelected from '@/labs/filters/FiltersSelected.vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isBoolean, isDefined, isUndefined } from '@/utils/common'\nimport { type FilterStoreIdentifier, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { datatableSlotName } from '@/components/datatable/datatable'\nimport FilterDetailItem from '@/labs/filters/FilterDetailItem.vue'\nimport AFilterBookmarkButton from '@/components/buttons/filter/AFilterBookmarkButton.vue'\nimport FilterBookmarks from '@/labs/filters/FilterBookmarks.vue'\nimport type { IntegerIdNullable } from '@/types/common'\nimport { type AxiosInstance } from 'axios'\n\nconst props = withDefaults(\n defineProps<{\n enableTop?: boolean\n hideButtons?: boolean\n formName?: string\n userId?: IntegerIdNullable | undefined\n client?: (() => AxiosInstance) | undefined\n store?: FilterStoreIdentifier | boolean // false to disable, FilterStoreIdentifier to custom store key\n alwaysVisible?: boolean\n hideMore?: boolean\n }>(),\n {\n enableTop: false,\n hideButtons: false,\n formName: 'search',\n userId: undefined,\n client: undefined,\n store: true,\n alwaysVisible: false,\n hideMore: false,\n }\n)\nconst emit = defineEmits<{\n (e: 'submit'): void\n (e: 'reset'): void\n (e: 'bookmarkLoadAfter'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: false,\n})\nconst showDetail = defineModel<boolean>('showDetail', { default: false, required: false })\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nif (isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\nconst identifier = ref<Partial<FilterStoreIdentifier>>({\n system: filterConfig.general.system,\n subject: filterConfig.general.subject,\n})\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isBoolean(props.store)) {\n identifier.value.system = props.store.system\n identifier.value.subject = props.store.subject\n} else if (false === props.store) {\n identifier.value.system = undefined\n identifier.value.subject = undefined\n}\nconst submitResetCounter = ref(0)\nprovide(FilterSubmitResetCounterKey, submitResetCounter)\nconst filterSelected = ref<Map<string, ValueObjectOption<string | number>[]>>(new Map())\nprovide(FilterSelectedKey, filterSelected)\n\nconst submitFilter = () => {\n submitResetCounter.value++\n nextTick(() => {\n emit('submit')\n })\n}\n\nconst { clearAll, clearAllFilterSelected } = useFilterClearHelpers()\n\nconst submitFilterBookmark = () => {\n nextTick(() => {\n submitResetCounter.value++\n emit('bookmarkLoadAfter')\n })\n}\n\nconst resetFilter = () => {\n clearAll(filterData, filterConfig)\n clearAllFilterSelected(filterData, filterConfig, filterSelected)\n nextTick(() => {\n submitResetCounter.value++\n emit('reset')\n })\n}\n\nconst toggleFilterDetail = () => {\n showDetail.value = !showDetail.value\n}\n\nconst touched = computed(() => {\n return filterConfig.touched\n})\n\nconst renderedFieldNames = computed(() => {\n return Object.entries(filterConfig.fields)\n .filter(([, field]) => !field.render.skip)\n .map(([fieldName]) => fieldName)\n})\n\nif (props.alwaysVisible) {\n showDetail.value = true\n}\n\ndefineExpose({\n submit: submitFilter,\n reset: resetFilter,\n})\n</script>\n\n<template>\n <VForm\n :name=\"formName\"\n @submit.prevent=\"submitFilter\"\n >\n <VRow\n v-if=\"enableTop\"\n density=\"compact\"\n >\n <VCol>\n <slot name=\"top\" />\n </VCol>\n </VRow>\n <VRow density=\"compact\">\n <VCol v-if=\"store && userId && isDefined(client)\">\n <slot name=\"bookmarks\">\n <div class=\"d-flex flex-wrap align-center\">\n <FilterBookmarks\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n v-model:datatable-hidden-columns=\"datatableHiddenColumns\"\n :client=\"client\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :user-id=\"userId\"\n @submit=\"submitFilterBookmark\"\n />\n </div>\n </slot>\n </VCol>\n </VRow>\n <VRow\n v-if=\"!alwaysVisible\"\n density=\"compact\"\n >\n <VCol\n v-if=\"!hideMore\"\n cols=\"auto\"\n >\n <AFilterAdvancedButton\n :button-active=\"showDetail\"\n @advanced-filter=\"toggleFilterDetail\"\n />\n </VCol>\n <VCol>\n <div class=\"a-filter__container\">\n <div class=\"a-filter__search\">\n <slot name=\"search\" />\n </div>\n <FiltersSelected />\n </div>\n </VCol>\n <VCol\n v-if=\"!hideButtons\"\n class=\"text-right\"\n cols=\"auto\"\n >\n <slot name=\"buttons\">\n <AFilterSubmitButton :touched=\"touched\" />\n <AFilterResetButton @reset=\"resetFilter\" />\n <AFilterBookmarkButton\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n :client=\"client\"\n :user=\"userId\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n />\n </slot>\n </VCol>\n </VRow>\n <div v-if=\"!hideMore\">\n <component :is=\"alwaysVisible ? 'div' : 'VSlideYTransition'\">\n <div\n v-show=\"showDetail\"\n :class=\"{ 'mt-6 pa-4 system-border-a': !alwaysVisible }\"\n >\n <slot name=\"detail\">\n <VRow>\n <VCol\n v-for=\"fieldName in renderedFieldNames\"\n :key=\"fieldName\"\n :cols=\"filterConfig.fields[fieldName].render.xs || 12\"\n :sm=\"filterConfig.fields[fieldName].render.sm || 6\"\n :md=\"filterConfig.fields[fieldName].render.md || 4\"\n :lg=\"filterConfig.fields[fieldName].render.lg || 3\"\n :xl=\"filterConfig.fields[fieldName].render.xl || 2\"\n >\n <slot\n :name=\"datatableSlotName(fieldName)\"\n :item-config=\"filterConfig.fields[fieldName]\"\n >\n <FilterDetailItem :name=\"fieldName\" />\n </slot>\n </VCol>\n </VRow>\n </slot>\n </div>\n </component>\n </div>\n </VForm>\n</template>\n\n<style lang=\"scss\">\n@use 'vuetify/tools' as *;\n\n.a-filter {\n &__container {\n width: 100%;\n }\n\n &__search {\n display: inline-flex;\n vertical-align: middle;\n min-width: 100%;\n height: 34px;\n\n @include media-breakpoint-up(sm) {\n min-width: 50%;\n margin-right: 8px;\n }\n\n @include media-breakpoint-up(md) {\n min-width: 40%;\n }\n\n @include media-breakpoint-up(lg) {\n min-width: 30%;\n }\n }\n}\n</style>\n","<script lang=\"ts\" setup>\nimport AFilterAdvancedButton from '@/labs/filters/AFilterAdvancedButton.vue'\nimport AFilterSubmitButton from '@/components/buttons/filter/AFilterSubmitButton.vue'\nimport AFilterResetButton from '@/components/buttons/filter/AFilterResetButton.vue'\nimport { computed, inject, nextTick, provide, ref } from 'vue'\nimport {\n FilterConfigKey,\n FilterDataKey,\n FilterSelectedKey,\n FilterSubmitResetCounterKey,\n} from '@/labs/filters/filterInjectionKeys'\nimport FiltersSelected from '@/labs/filters/FiltersSelected.vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { isBoolean, isDefined, isUndefined } from '@/utils/common'\nimport { type FilterStoreIdentifier, useFilterClearHelpers } from '@/labs/filters/filterFactory'\nimport { datatableSlotName } from '@/components/datatable/datatable'\nimport FilterDetailItem from '@/labs/filters/FilterDetailItem.vue'\nimport AFilterBookmarkButton from '@/components/buttons/filter/AFilterBookmarkButton.vue'\nimport FilterBookmarks from '@/labs/filters/FilterBookmarks.vue'\nimport type { IntegerIdNullable } from '@/types/common'\nimport { type AxiosInstance } from 'axios'\n\nconst props = withDefaults(\n defineProps<{\n enableTop?: boolean\n hideButtons?: boolean\n formName?: string\n userId?: IntegerIdNullable | undefined\n client?: (() => AxiosInstance) | undefined\n store?: FilterStoreIdentifier | boolean // false to disable, FilterStoreIdentifier to custom store key\n alwaysVisible?: boolean\n hideMore?: boolean\n }>(),\n {\n enableTop: false,\n hideButtons: false,\n formName: 'search',\n userId: undefined,\n client: undefined,\n store: true,\n alwaysVisible: false,\n hideMore: false,\n }\n)\nconst emit = defineEmits<{\n (e: 'submit'): void\n (e: 'reset'): void\n (e: 'bookmarkLoadAfter'): void\n}>()\n\nconst datatableHiddenColumns = defineModel<string[] | undefined>('datatableHiddenColumns', {\n default: undefined,\n required: false,\n})\nconst showDetail = defineModel<boolean>('showDetail', { default: false, required: false })\n\nconst filterConfig = inject(FilterConfigKey)\nconst filterData = inject(FilterDataKey)\nif (isUndefined(filterConfig) || isUndefined(filterData)) {\n throw new Error('Incorrect provide/inject config.')\n}\nconst identifier = ref<Partial<FilterStoreIdentifier>>({\n system: filterConfig.general.system,\n subject: filterConfig.general.subject,\n})\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (!isBoolean(props.store)) {\n identifier.value.system = props.store.system\n identifier.value.subject = props.store.subject\n} else if (false === props.store) {\n identifier.value.system = undefined\n identifier.value.subject = undefined\n}\nconst submitResetCounter = ref(0)\nprovide(FilterSubmitResetCounterKey, submitResetCounter)\nconst filterSelected = ref<Map<string, ValueObjectOption<string | number>[]>>(new Map())\nprovide(FilterSelectedKey, filterSelected)\n\nconst submitFilter = () => {\n submitResetCounter.value++\n nextTick(() => {\n emit('submit')\n })\n}\n\nconst { clearAll, clearAllFilterSelected } = useFilterClearHelpers()\n\nconst submitFilterBookmark = () => {\n nextTick(() => {\n submitResetCounter.value++\n emit('bookmarkLoadAfter')\n })\n}\n\nconst resetFilter = () => {\n clearAll(filterData, filterConfig)\n clearAllFilterSelected(filterData, filterConfig, filterSelected)\n nextTick(() => {\n submitResetCounter.value++\n emit('reset')\n })\n}\n\nconst toggleFilterDetail = () => {\n showDetail.value = !showDetail.value\n}\n\nconst touched = computed(() => {\n return filterConfig.touched\n})\n\nconst renderedFieldNames = computed(() => {\n return Object.entries(filterConfig.fields)\n .filter(([, field]) => !field.render.skip)\n .map(([fieldName]) => fieldName)\n})\n\nif (props.alwaysVisible) {\n showDetail.value = true\n}\n\ndefineExpose({\n submit: submitFilter,\n reset: resetFilter,\n})\n</script>\n\n<template>\n <VForm\n :name=\"formName\"\n @submit.prevent=\"submitFilter\"\n >\n <VRow\n v-if=\"enableTop\"\n density=\"compact\"\n >\n <VCol>\n <slot name=\"top\" />\n </VCol>\n </VRow>\n <VRow density=\"compact\">\n <VCol v-if=\"store && userId && isDefined(client)\">\n <slot name=\"bookmarks\">\n <div class=\"d-flex flex-wrap align-center\">\n <FilterBookmarks\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n v-model:datatable-hidden-columns=\"datatableHiddenColumns\"\n :client=\"client\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :user-id=\"userId\"\n @submit=\"submitFilterBookmark\"\n />\n </div>\n </slot>\n </VCol>\n </VRow>\n <VRow\n v-if=\"!alwaysVisible\"\n density=\"compact\"\n >\n <VCol\n v-if=\"!hideMore\"\n cols=\"auto\"\n >\n <AFilterAdvancedButton\n :button-active=\"showDetail\"\n @advanced-filter=\"toggleFilterDetail\"\n />\n </VCol>\n <VCol>\n <div class=\"a-filter__container\">\n <div class=\"a-filter__search\">\n <slot name=\"search\" />\n </div>\n <FiltersSelected />\n </div>\n </VCol>\n <VCol\n v-if=\"!hideButtons\"\n class=\"text-right\"\n cols=\"auto\"\n >\n <slot name=\"buttons\">\n <AFilterSubmitButton :touched=\"touched\" />\n <AFilterResetButton @reset=\"resetFilter\" />\n <AFilterBookmarkButton\n v-if=\"identifier.system && identifier.subject && userId && isDefined(client)\"\n :client=\"client\"\n :user=\"userId\"\n :system=\"identifier.system\"\n :subject=\"identifier.subject\"\n :datatable-hidden-columns=\"datatableHiddenColumns\"\n />\n </slot>\n </VCol>\n </VRow>\n <div v-if=\"!hideMore\">\n <component :is=\"alwaysVisible ? 'div' : 'VSlideYTransition'\">\n <div\n v-show=\"showDetail\"\n :class=\"{ 'mt-6 pa-4 system-border-a': !alwaysVisible }\"\n >\n <slot name=\"detail\">\n <VRow>\n <VCol\n v-for=\"fieldName in renderedFieldNames\"\n :key=\"fieldName\"\n :cols=\"filterConfig.fields[fieldName].render.xs || 12\"\n :sm=\"filterConfig.fields[fieldName].render.sm || 6\"\n :md=\"filterConfig.fields[fieldName].render.md || 4\"\n :lg=\"filterConfig.fields[fieldName].render.lg || 3\"\n :xl=\"filterConfig.fields[fieldName].render.xl || 2\"\n >\n <slot\n :name=\"datatableSlotName(fieldName)\"\n :item-config=\"filterConfig.fields[fieldName]\"\n >\n <FilterDetailItem :name=\"fieldName\" />\n </slot>\n </VCol>\n </VRow>\n </slot>\n </div>\n </component>\n </div>\n </VForm>\n</template>\n\n<style lang=\"scss\">\n@use 'vuetify/tools' as *;\n\n.a-filter {\n &__container {\n width: 100%;\n }\n\n &__search {\n display: inline-flex;\n vertical-align: middle;\n min-width: 100%;\n height: 34px;\n\n @include media-breakpoint-up(sm) {\n min-width: 50%;\n margin-right: 8px;\n }\n\n @include media-breakpoint-up(md) {\n min-width: 40%;\n }\n\n @include media-breakpoint-up(lg) {\n min-width: 30%;\n }\n }\n}\n</style>\n","<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { cloneDeep, isArray, isDefined, isEmpty, isNull, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport { useI18n } from 'vue-i18n'\nimport type { DocId, IntegerId, IntegerIdNullable } from '@/types/common'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport { FilterInnerConfigKey, FilterInnerDataKey } from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype ModelValueType = T | T[] | null | undefined\n\nconst props = withDefaults(\n defineProps<{\n label?: string | undefined\n required?: boolean | undefined\n multiple?: boolean\n clearable?: boolean\n v?: any\n errorMessage?: string\n hideDetails?: boolean\n hideLabel?: boolean\n fetchItems: (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n ) => Promise<ValueObjectOption<T>[]>\n fetchItemsByIds: (ids: T[]) => Promise<ValueObjectOption<T>[]>\n filterByField: string\n filterSortBy?: DatatableSortBy\n loading?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean | undefined\n readonly?: boolean\n chips?: boolean\n closableChips?: boolean\n disableAutoSingleSelect?: boolean // auto select works only when modelValue is empty/null and prefetch is set to 'mounted'\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n minSearchChars?: number\n minSearchText?: string | undefined\n }>(),\n {\n label: undefined,\n required: undefined,\n multiple: false,\n clearable: false,\n v: null,\n errorMessage: undefined,\n hideDetails: false,\n hideLabel: false,\n filterSortBy: null,\n loading: false,\n collab: undefined,\n disabled: undefined,\n chips: false,\n closableChips: false,\n disableAutoSingleSelect: false,\n prefetch: false,\n minSearchChars: 2,\n minSearchText: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'searchChange', data: string): void\n (e: 'searchChangeDebounced', data: string): void\n (e: 'blur', data: ModelValueType): void\n (e: 'focus', data: ModelValueType): void\n (e: 'click:chipClose', data: ValueObjectOption<T>): void\n}>()\n\nconst SEARCH_DEBOUNCE_MS = 300\n\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (isUndefined(filterInnerConfig) || isUndefined(filterInnerData)) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterByFieldProp = props.filterByField\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterSortByProp = props.filterSortBy\n\nif (isUndefined(filterInnerConfig.fields[filterByFieldProp]) || isUndefined(filterInnerData[filterByFieldProp])) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${filterByFieldProp}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst modelValue = defineModel<ModelValueType>({\n required: true,\n set(newValue) {\n return isArray(newValue) ? cloneDeep(newValue) : newValue\n },\n})\n\nconst modelValueSelected = defineModel<ValueObjectOption<T> | ValueObjectOption<T>[] | null>('selected', {\n required: false,\n default: null,\n set(newValue) {\n return isArray(newValue) ? cloneDeep(newValue) : newValue\n },\n})\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst changeFieldData = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, changeCollabFieldData, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n changeFieldData.value = changeCollabFieldData\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst search = ref('')\nconst isFocused = ref(false)\nconst modelValueAutocomplete = ref<ValueObjectOption<T> | ValueObjectOption<T>[] | null>(null)\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onBlur = () => {\n isFocused.value = false\n emit('blur', modelValue.value)\n props.v?.$touch()\n releaseFieldLock.value(modelValue.value)\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return props.v.$errors.map((item: ErrorObject) => item.$message)\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n return props.v?.required && props.v?.required.$params.type === 'required'\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nconst { pagination } = usePagination(isNull(filterSortByProp) ? null : filterSortByProp.key, filterSortByProp?.order)\nconst fetchedItems = ref<ValueObjectOption<T>[]>([])\nconst selectedItemsCache = ref<ValueObjectOption<T>[]>([])\nconst isFirstLoad = ref(true)\nconst prefetchCompleted = ref(false)\n\nconst allItems = computed<ValueObjectOption<T>[]>(() => {\n const itemsMap = new Map<T, ValueObjectOption<T>>()\n const addToMap = (items: ValueObjectOption<T>[]) => {\n items.forEach((item) => {\n itemsMap.set(item.value, {\n value: item.value,\n title: item.title,\n subtitle: item.subtitle,\n } as ValueObjectOption<T>)\n })\n }\n\n addToMap(selectedItemsCache.value as ValueObjectOption<T>[])\n addToMap(fetchedItems.value as ValueObjectOption<T>[])\n\n return Array.from(itemsMap.values())\n})\n\nconst loadingLocal = ref(false)\nconst loadingComputed = computed(() => {\n if (loadingLocal.value) return true\n return props.loading\n})\n\nconst resetToEmptyState = (value: ModelValueType) => {\n selectedItemsCache.value = []\n modelValueSelected.value = isArray(value) ? [] : null\n modelValueAutocomplete.value = isArray(value) ? [] : null\n}\n\nconst updateSelected = (value: T[] | T) => {\n const findItem = (id: T): ValueObjectOption<T> =>\n allItems.value.find((obj) => obj.value === id) ?? ({ title: `${id}`, value: id } as ValueObjectOption<T>)\n return isArray(value) ? value.map(findItem) : findItem(value)\n}\n\nconst loadListItems = async (ids: T[] | T) => {\n loadingLocal.value = true\n\n try {\n const idsArray = isArray(ids) ? ids : [ids]\n selectedItemsCache.value = await props.fetchItemsByIds(idsArray)\n const selectedNewValue = updateSelected(ids)\n modelValueSelected.value = selectedNewValue\n modelValueAutocomplete.value = selectedNewValue\n return selectedItemsCache.value\n } catch (e) {\n // Mirror tryLoadModelValue: don't let a failed by-ids resolve become a generic global toast (QA 85050).\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst tryLoadModelValue = async (tryLoadValue: ModelValueType, prefetch = false) => {\n const idsToFetch = isArray(tryLoadValue) ? tryLoadValue : [tryLoadValue]\n loadingLocal.value = true\n\n try {\n const fetchedData = await props.fetchItemsByIds(idsToFetch as Array<IntegerId & DocId>)\n if (isArray(fetchedData) && fetchedData.length > 0) {\n selectedItemsCache.value = fetchedData\n if (props.multiple) {\n const values = fetchedData.map((item) => item.value)\n modelValue.value = values\n if (prefetch) {\n await tryAutoFetch('force', values)\n }\n loadingLocal.value = false\n return true\n }\n modelValue.value = fetchedData[0].value\n if (prefetch) {\n await tryAutoFetch('force', fetchedData[0].value)\n }\n loadingLocal.value = false\n return true\n }\n loadingLocal.value = false\n return false\n } catch (e) {\n showErrorsDefault(e)\n }\n}\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loadingLocal.value = true\n filterInnerData[filterByFieldProp] = query\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (error) {\n showErrorsDefault(error)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst tryAutoFetch = async (mode: 'focus' | 'hover' | 'mounted' | 'force', newValue: ModelValueType) => {\n if (loadingLocal.value) return\n if (mode !== 'force') {\n if (props.prefetch === false || props.prefetch !== mode || prefetchCompleted.value) return\n }\n\n loadingLocal.value = true\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) {\n fetchedItems.value = res\n if (\n !props.disableAutoSingleSelect &&\n mode === 'mounted' &&\n res.length === 1 &&\n (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0))\n ) {\n modelValue.value = props.multiple ? [res[0].value] : res[0].value\n }\n }\n prefetchCompleted.value = true\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst onFocus = async () => {\n isFocused.value = true\n acquireFieldLock.value()\n await tryAutoFetch('focus', modelValue.value)\n emit('focus', modelValue.value)\n}\n\nconst onMouseEnter = async () => {\n await tryAutoFetch('hover', modelValue.value)\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!props.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!props.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n if (props.multiple) {\n modelValue.value = []\n return\n }\n modelValue.value = null\n}\n\nconst onChipCloseClick = (closedItem: ValueObjectOption<T>) => {\n if (isArray(modelValue.value)) {\n modelValue.value = modelValue.value.filter((item) => item !== closedItem.value)\n return\n }\n if (closedItem.value === modelValue.value && props.clearable) {\n modelValue.value = null\n }\n}\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (newValue.length > 0 && newValue.length < props.minSearchChars) return\n if (newValue.length === 0 && props.prefetch === false) {\n fetchedItems.value = []\n return\n }\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n emit('searchChangeDebounced', newValue)\n },\n { debounce: SEARCH_DEBOUNCE_MS }\n)\n\nwatch(search, (newValue, oldValue) => {\n if (newValue !== oldValue) {\n emit('searchChange', newValue)\n }\n})\n\nconst onAutocompleteModelUpdate = (newValue: ValueObjectOption<T> | readonly ValueObjectOption<T>[] | null) => {\n const cloned = cloneDeep(newValue) as ValueObjectOption<T> | ValueObjectOption<T>[] | null\n modelValueSelected.value = cloned\n if (isNull(cloned) || isUndefined(cloned)) {\n modelValue.value = null\n return\n }\n if (isArray(cloned)) {\n modelValue.value = cloned.map((item) => item.value)\n return\n }\n modelValue.value = cloned.value\n}\n\nconst noDataText = computed(() => {\n if (loadingLocal.value) {\n return '$vuetify.loading'\n }\n if (fetchedItems.value.length === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nwatch(\n modelValue,\n async (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (isFirstLoad.value) {\n isFirstLoad.value = false\n await tryAutoFetch('mounted', newValue)\n }\n if (collabOptions.value.enabled && isFocused.value) {\n changeFieldData.value(newValue)\n }\n if (isEmpty(newValue)) {\n resetToEmptyState(newValue)\n return\n }\n await loadListItems(newValue as T[] | T)\n },\n { immediate: true }\n)\n\ndefineExpose({\n tryLoadModelValue,\n})\n</script>\n\n<template>\n <VAutocomplete\n :model-value=\"modelValueAutocomplete as any\"\n :items=\"allItems\"\n no-filter\n :multiple=\"multiple\"\n :clearable=\"clearable\"\n :error-messages=\"errorMessageComputed\"\n :chips=\"chips || multiple || closableChips\"\n :hide-details=\"hideDetails\"\n :loading=\"loadingComputed\"\n :disabled=\"disabledComputed\"\n :readonly=\"readonly\"\n :no-data-text=\"noDataText\"\n return-object\n autocomplete=\"off\"\n :hide-selected=\"closableChips\"\n :closable-chips=\"closableChips && !loadingComputed && !disabledComputed && !readonly\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onAutocompleteModelUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n :title=\"internalItem.raw.title\"\n :subtitle=\"internalItem.raw.subtitle\"\n />\n </template>\n <template #chip=\"{ props: chipProps, internalItem }\">\n <VChip\n :closable=\"chipProps.closable as boolean\"\n size=\"small\"\n :text=\"`${internalItem.title} (${internalItem.raw.subtitle})`\"\n :disabled=\"internalItem.props.disabled\"\n @click:close=\"onChipCloseClick(internalItem.raw)\"\n >\n {{ internalItem.raw.title }}\n <span\n v-if=\"internalItem.raw.subtitle\"\n class=\"font-italic pl-1\"\n >\n ({{ internalItem.raw.subtitle }})\n </span>\n </VChip>\n </template>\n <template #label>\n <span\n v-if=\"!hideLabel\"\n :key=\"requiredComputed + ''\"\n >\n {{ labelComputed }}\n <span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </span>\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append-inner\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n <template\n v-if=\"$slots.append\"\n #append\n >\n <slot name=\"append\" />\n </template>\n </VAutocomplete>\n</template>\n","<script lang=\"ts\" setup generic=\"T extends string | number\">\nimport { watchDebounced } from '@vueuse/core'\nimport { computed, getCurrentInstance, inject, type Ref, ref, watch } from 'vue'\nimport type { ValueObjectOption } from '@/types/ValueObject'\nimport { cloneDeep, isArray, isDefined, isEmpty, isNull, isUndefined } from '@/utils/common'\nimport { SubjectScopeSymbol, SystemScopeSymbol } from '@/components/injectionKeys'\nimport type { ErrorObject } from '@vuelidate/core'\nimport { stringSplitOnFirstOccurrence } from '@/utils/string'\nimport { useI18n } from 'vue-i18n'\nimport type { DocId, IntegerId, IntegerIdNullable } from '@/types/common'\nimport ACollabLockedByUser from '@/components/collab/components/ACollabLockedByUser.vue'\nimport type { CollabComponentConfig, CollabFieldData } from '@/components/collab/types/Collab'\nimport { useCollabField } from '@/components/collab/composables/collabField'\nimport { useCommonAdminCollabOptions } from '@/components/collab/composables/commonAdminCollabOptions'\nimport type { FilterConfig, FilterData } from '@/labs/filters/filterFactory'\nimport { FilterInnerConfigKey, FilterInnerDataKey } from '@/labs/filters/filterInjectionKeys'\nimport type { DatatableSortBy } from '@/composables/system/datatableColumns'\nimport { type Pagination, usePagination } from '@/labs/filters/pagination'\nimport { useAlerts } from '@/composables/system/alerts'\n\ntype ModelValueType = T | T[] | null | undefined\n\nconst props = withDefaults(\n defineProps<{\n label?: string | undefined\n required?: boolean | undefined\n multiple?: boolean\n clearable?: boolean\n v?: any\n errorMessage?: string\n hideDetails?: boolean\n hideLabel?: boolean\n fetchItems: (\n pagination: Ref<Pagination>,\n filterData: FilterData,\n filterConfig: FilterConfig\n ) => Promise<ValueObjectOption<T>[]>\n fetchItemsByIds: (ids: T[]) => Promise<ValueObjectOption<T>[]>\n filterByField: string\n filterSortBy?: DatatableSortBy\n loading?: boolean\n collab?: CollabComponentConfig\n disabled?: boolean | undefined\n readonly?: boolean\n chips?: boolean\n closableChips?: boolean\n disableAutoSingleSelect?: boolean // auto select works only when modelValue is empty/null and prefetch is set to 'mounted'\n prefetch?: 'hover' | 'focus' | 'mounted' | false\n minSearchChars?: number\n minSearchText?: string | undefined\n }>(),\n {\n label: undefined,\n required: undefined,\n multiple: false,\n clearable: false,\n v: null,\n errorMessage: undefined,\n hideDetails: false,\n hideLabel: false,\n filterSortBy: null,\n loading: false,\n collab: undefined,\n disabled: undefined,\n chips: false,\n closableChips: false,\n disableAutoSingleSelect: false,\n prefetch: false,\n minSearchChars: 2,\n minSearchText: undefined,\n }\n)\nconst emit = defineEmits<{\n (e: 'searchChange', data: string): void\n (e: 'searchChangeDebounced', data: string): void\n (e: 'blur', data: ModelValueType): void\n (e: 'focus', data: ModelValueType): void\n (e: 'click:chipClose', data: ValueObjectOption<T>): void\n}>()\n\nconst SEARCH_DEBOUNCE_MS = 300\n\nconst filterInnerConfig = inject(FilterInnerConfigKey)\nconst filterInnerData = inject(FilterInnerDataKey)\n\nconst componentName = getCurrentInstance()?.type.__name\n\nif (isUndefined(filterInnerConfig) || isUndefined(filterInnerData)) {\n throw new Error(`[${componentName}] Incorrect provide/inject config.`)\n}\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterByFieldProp = props.filterByField\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nconst filterSortByProp = props.filterSortBy\n\nif (isUndefined(filterInnerConfig.fields[filterByFieldProp]) || isUndefined(filterInnerData[filterByFieldProp])) {\n throw new Error(\n `[${componentName}] Incorrect filter inner config. ` +\n `FilterByField is '${filterByFieldProp}' and available options are ${Object.keys(filterInnerData).join(', ')}.`\n )\n}\n\nconst modelValue = defineModel<ModelValueType>({\n required: true,\n set(newValue) {\n return isArray(newValue) ? cloneDeep(newValue) : newValue\n },\n})\n\nconst modelValueSelected = defineModel<ValueObjectOption<T> | ValueObjectOption<T>[] | null>('selected', {\n required: false,\n default: null,\n set(newValue) {\n return isArray(newValue) ? cloneDeep(newValue) : newValue\n },\n})\n\n// Collaboration\nconst { collabOptions } = useCommonAdminCollabOptions()\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst releaseFieldLock = ref((data: CollabFieldData) => {})\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst changeFieldData = ref((data: CollabFieldData) => {})\nconst acquireFieldLock = ref(() => {})\nconst lockedByUserLocal = ref<IntegerIdNullable>(null)\n// eslint-disable-next-line vue/no-setup-props-reactivity-loss\nif (collabOptions.value.enabled && isDefined(props.collab)) {\n const { releaseCollabFieldLock, changeCollabFieldData, acquireCollabFieldLock, lockedByUser } = useCollabField(\n props.collab.room,\n props.collab.field\n )\n releaseFieldLock.value = releaseCollabFieldLock\n changeFieldData.value = changeCollabFieldData\n acquireFieldLock.value = acquireCollabFieldLock\n watch(\n lockedByUser,\n (newValue) => {\n lockedByUserLocal.value = newValue\n },\n { immediate: true }\n )\n}\n\nconst search = ref('')\nconst isFocused = ref(false)\nconst modelValueAutocomplete = ref<ValueObjectOption<T> | ValueObjectOption<T>[] | null>(null)\nconst apiRequestCounter = ref(0)\n\nconst { t } = useI18n()\n\nconst system = inject<string | undefined>(SystemScopeSymbol, undefined)\nconst subject = inject<string | undefined>(SubjectScopeSymbol, undefined)\n\nconst onBlur = () => {\n isFocused.value = false\n emit('blur', modelValue.value)\n props.v?.$touch()\n releaseFieldLock.value(modelValue.value)\n}\n\nconst errorMessageComputed = computed(() => {\n if (isDefined(props.errorMessage)) return [props.errorMessage]\n if (props.v?.$errors?.length) return props.v.$errors.map((item: ErrorObject) => item.$message)\n return []\n})\n\nconst labelComputed = computed(() => {\n if (isDefined(props.label)) return props.label\n if (isUndefined(system) || isUndefined(subject) || isUndefined(props.v?.$path)) return ''\n const { end: path } = stringSplitOnFirstOccurrence(props.v?.$path, '.')\n return t(system + '.' + subject + '.model.' + path)\n})\n\nconst requiredComputed = computed(() => {\n if (isDefined(props.required)) return props.required\n return props.v?.required && props.v?.required.$params.type === 'required'\n})\n\nconst disabledComputed = computed(() => {\n if (isDefined(props.disabled)) return props.disabled\n return !!lockedByUserLocal.value\n})\n\nconst { pagination } = usePagination(isNull(filterSortByProp) ? null : filterSortByProp.key, filterSortByProp?.order)\nconst fetchedItems = ref<ValueObjectOption<T>[]>([])\nconst selectedItemsCache = ref<ValueObjectOption<T>[]>([])\nconst isFirstLoad = ref(true)\nconst prefetchCompleted = ref(false)\n\nconst allItems = computed<ValueObjectOption<T>[]>(() => {\n const itemsMap = new Map<T, ValueObjectOption<T>>()\n const addToMap = (items: ValueObjectOption<T>[]) => {\n items.forEach((item) => {\n itemsMap.set(item.value, {\n value: item.value,\n title: item.title,\n subtitle: item.subtitle,\n } as ValueObjectOption<T>)\n })\n }\n\n addToMap(selectedItemsCache.value as ValueObjectOption<T>[])\n addToMap(fetchedItems.value as ValueObjectOption<T>[])\n\n return Array.from(itemsMap.values())\n})\n\nconst loadingLocal = ref(false)\nconst loadingComputed = computed(() => {\n if (loadingLocal.value) return true\n return props.loading\n})\n\nconst resetToEmptyState = (value: ModelValueType) => {\n selectedItemsCache.value = []\n modelValueSelected.value = isArray(value) ? [] : null\n modelValueAutocomplete.value = isArray(value) ? [] : null\n}\n\nconst updateSelected = (value: T[] | T) => {\n const findItem = (id: T): ValueObjectOption<T> =>\n allItems.value.find((obj) => obj.value === id) ?? ({ title: `${id}`, value: id } as ValueObjectOption<T>)\n return isArray(value) ? value.map(findItem) : findItem(value)\n}\n\nconst loadListItems = async (ids: T[] | T) => {\n loadingLocal.value = true\n\n try {\n const idsArray = isArray(ids) ? ids : [ids]\n selectedItemsCache.value = await props.fetchItemsByIds(idsArray)\n const selectedNewValue = updateSelected(ids)\n modelValueSelected.value = selectedNewValue\n modelValueAutocomplete.value = selectedNewValue\n return selectedItemsCache.value\n } catch (e) {\n // Mirror tryLoadModelValue: don't let a failed by-ids resolve become a generic global toast (QA 85050).\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst tryLoadModelValue = async (tryLoadValue: ModelValueType, prefetch = false) => {\n const idsToFetch = isArray(tryLoadValue) ? tryLoadValue : [tryLoadValue]\n loadingLocal.value = true\n\n try {\n const fetchedData = await props.fetchItemsByIds(idsToFetch as Array<IntegerId & DocId>)\n if (isArray(fetchedData) && fetchedData.length > 0) {\n selectedItemsCache.value = fetchedData\n if (props.multiple) {\n const values = fetchedData.map((item) => item.value)\n modelValue.value = values\n if (prefetch) {\n await tryAutoFetch('force', values)\n }\n loadingLocal.value = false\n return true\n }\n modelValue.value = fetchedData[0].value\n if (prefetch) {\n await tryAutoFetch('force', fetchedData[0].value)\n }\n loadingLocal.value = false\n return true\n }\n loadingLocal.value = false\n return false\n } catch (e) {\n showErrorsDefault(e)\n }\n}\n\nconst { showErrorsDefault } = useAlerts()\n\nconst apiSearch = async (query: string, requestCounter: number) => {\n loadingLocal.value = true\n filterInnerData[filterByFieldProp] = query\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (requestCounter === apiRequestCounter.value) fetchedItems.value = res\n } catch (error) {\n showErrorsDefault(error)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst tryAutoFetch = async (mode: 'focus' | 'hover' | 'mounted' | 'force', newValue: ModelValueType) => {\n if (loadingLocal.value) return\n if (mode !== 'force') {\n if (props.prefetch === false || props.prefetch !== mode || prefetchCompleted.value) return\n }\n\n loadingLocal.value = true\n try {\n const res = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n if (apiRequestCounter.value === 0) {\n fetchedItems.value = res\n if (\n !props.disableAutoSingleSelect &&\n mode === 'mounted' &&\n res.length === 1 &&\n (isNull(newValue) || isUndefined(newValue) || (isArray(newValue) && newValue.length === 0))\n ) {\n modelValue.value = props.multiple ? [res[0].value] : res[0].value\n }\n }\n prefetchCompleted.value = true\n } catch (e) {\n showErrorsDefault(e)\n } finally {\n loadingLocal.value = false\n }\n}\n\nconst onFocus = async () => {\n isFocused.value = true\n acquireFieldLock.value()\n await tryAutoFetch('focus', modelValue.value)\n emit('focus', modelValue.value)\n}\n\nconst onMouseEnter = async () => {\n await tryAutoFetch('hover', modelValue.value)\n}\n\nconst singleItemSelectedTitle = computed(() => {\n if (!props.multiple && selectedItemsCache.value[0]) {\n return selectedItemsCache.value[0].title\n }\n return undefined\n})\n\nconst onSearchUpdate = (query: string) => {\n if (!props.multiple && !isFocused.value && query.length === 0) return // vuetify fix\n if (singleItemSelectedTitle.value === query) return\n search.value = query\n}\n\nconst onClickClear = async () => {\n try {\n fetchedItems.value = await props.fetchItems(pagination, filterInnerData, filterInnerConfig)\n } catch (e) {\n showErrorsDefault(e)\n }\n if (props.multiple) {\n modelValue.value = []\n return\n }\n modelValue.value = null\n}\n\nconst onChipCloseClick = (closedItem: ValueObjectOption<T>) => {\n if (isArray(modelValue.value)) {\n modelValue.value = modelValue.value.filter((item) => item !== closedItem.value)\n return\n }\n if (closedItem.value === modelValue.value && props.clearable) {\n modelValue.value = null\n }\n}\n\nwatchDebounced(\n search,\n (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (newValue.length > 0 && newValue.length < props.minSearchChars) return\n if (newValue.length === 0 && props.prefetch === false) {\n fetchedItems.value = []\n return\n }\n apiRequestCounter.value++\n apiSearch(newValue, apiRequestCounter.value)\n emit('searchChangeDebounced', newValue)\n },\n { debounce: SEARCH_DEBOUNCE_MS }\n)\n\nwatch(search, (newValue, oldValue) => {\n if (newValue !== oldValue) {\n emit('searchChange', newValue)\n }\n})\n\nconst onAutocompleteModelUpdate = (newValue: ValueObjectOption<T> | readonly ValueObjectOption<T>[] | null) => {\n const cloned = cloneDeep(newValue) as ValueObjectOption<T> | ValueObjectOption<T>[] | null\n modelValueSelected.value = cloned\n if (isNull(cloned) || isUndefined(cloned)) {\n modelValue.value = null\n return\n }\n if (isArray(cloned)) {\n modelValue.value = cloned.map((item) => item.value)\n return\n }\n modelValue.value = cloned.value\n}\n\nconst noDataText = computed(() => {\n if (loadingLocal.value) {\n return '$vuetify.loading'\n }\n if (fetchedItems.value.length === 0 && search.value.length < props.minSearchChars) {\n return isUndefined(props.minSearchText)\n ? t('common.filter.filterMinChars', { min: props.minSearchChars })\n : props.minSearchText\n }\n return undefined\n})\n\nwatch(\n modelValue,\n async (newValue, oldValue) => {\n if (newValue === oldValue) return\n if (isFirstLoad.value) {\n isFirstLoad.value = false\n await tryAutoFetch('mounted', newValue)\n }\n if (collabOptions.value.enabled && isFocused.value) {\n changeFieldData.value(newValue)\n }\n if (isEmpty(newValue)) {\n resetToEmptyState(newValue)\n return\n }\n await loadListItems(newValue as T[] | T)\n },\n { immediate: true }\n)\n\ndefineExpose({\n tryLoadModelValue,\n})\n</script>\n\n<template>\n <VAutocomplete\n :model-value=\"modelValueAutocomplete as any\"\n :items=\"allItems\"\n no-filter\n :multiple=\"multiple\"\n :clearable=\"clearable\"\n :error-messages=\"errorMessageComputed\"\n :chips=\"chips || multiple || closableChips\"\n :hide-details=\"hideDetails\"\n :loading=\"loadingComputed\"\n :disabled=\"disabledComputed\"\n :readonly=\"readonly\"\n :no-data-text=\"noDataText\"\n return-object\n autocomplete=\"off\"\n :hide-selected=\"closableChips\"\n :closable-chips=\"closableChips && !loadingComputed && !disabledComputed && !readonly\"\n @update:search=\"onSearchUpdate\"\n @update:model-value=\"onAutocompleteModelUpdate\"\n @blur=\"onBlur\"\n @focus=\"onFocus\"\n @mouseenter=\"onMouseEnter\"\n @click:clear=\"onClickClear\"\n >\n <template #item=\"{ props: itemProps, internalItem }\">\n <VListItem\n v-bind=\"itemProps\"\n :title=\"internalItem.raw.title\"\n :subtitle=\"internalItem.raw.subtitle\"\n />\n </template>\n <template #chip=\"{ props: chipProps, internalItem }\">\n <VChip\n :closable=\"chipProps.closable as boolean\"\n size=\"small\"\n :text=\"`${internalItem.title} (${internalItem.raw.subtitle})`\"\n :disabled=\"internalItem.props.disabled\"\n @click:close=\"onChipCloseClick(internalItem.raw)\"\n >\n {{ internalItem.raw.title }}\n <span\n v-if=\"internalItem.raw.subtitle\"\n class=\"font-italic pl-1\"\n >\n ({{ internalItem.raw.subtitle }})\n </span>\n </VChip>\n </template>\n <template #label>\n <span\n v-if=\"!hideLabel\"\n :key=\"requiredComputed + ''\"\n >\n {{ labelComputed }}\n <span\n v-if=\"requiredComputed\"\n class=\"required\"\n />\n </span>\n </template>\n <template\n v-if=\"lockedByUserLocal\"\n #append-inner\n >\n <slot\n name=\"locked\"\n :user-id=\"lockedByUserLocal\"\n >\n <ACollabLockedByUser\n v-if=\"collab\"\n :id=\"lockedByUserLocal\"\n :users=\"collab.cachedUsers\"\n />\n </slot>\n </template>\n <template\n v-if=\"$slots.append\"\n #append\n >\n <slot name=\"append\" />\n </template>\n </VAutocomplete>\n</template>\n"],"x_google_ignoreList":[28,41,42,43,128,129],"mappings":"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"}
|