@conduction/nextcloud-vue 2.144.0 → 2.145.0

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.
Files changed (85) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +1 -0
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  6. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +55 -2
  7. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
  10. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +16 -0
  11. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  12. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -1
  13. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  14. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +1 -1
  15. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +1 -1
  16. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -1
  17. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +3 -3
  18. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -1
  19. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
  20. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +2 -2
  21. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  22. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  23. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +6 -3
  24. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  25. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  26. package/dist/esm/components/CnMailTab/CnMailTab.vue.js +1 -1
  27. package/dist/esm/components/CnMailTab/CnMailTab.vue2.js.map +1 -1
  28. package/dist/esm/components/CnMailTab/CnMailTab.vue3.js +2 -2
  29. package/dist/esm/components/CnMailTab/CnMailTab.vue3.js.map +1 -1
  30. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue.js +1 -1
  31. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue2.js.map +1 -1
  32. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue3.js.map +1 -1
  33. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  34. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +73 -12
  35. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  36. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +165 -126
  37. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  38. package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
  39. package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js +14 -0
  40. package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
  41. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +2 -1
  42. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
  43. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
  44. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +13 -8
  45. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  46. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  47. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue.js +1 -1
  48. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +10 -2
  49. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  50. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  51. package/dist/esm/composables/indexSources.js +35 -9
  52. package/dist/esm/composables/indexSources.js.map +1 -1
  53. package/dist/esm/l10n/nl.json.js +2 -0
  54. package/dist/esm/l10n/nl.json.js.map +1 -1
  55. package/dist/esm/library-style.js +1 -1
  56. package/dist/esm/nextcloud-vue.css +742 -326
  57. package/dist/esm/utils/builtInFormatters.js +18 -1
  58. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  59. package/dist/esm/utils/localHeaderRows.js +95 -0
  60. package/dist/esm/utils/localHeaderRows.js.map +1 -0
  61. package/dist/nextcloud-vue.cjs.js +514 -179
  62. package/dist/nextcloud-vue.cjs.js.map +2 -2
  63. package/dist/nextcloud-vue.css +742 -326
  64. package/l10n/nl.json +2 -0
  65. package/package.json +1 -1
  66. package/src/components/CnActionDialog/CnActionDialog.vue +8 -1
  67. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +55 -2
  68. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +18 -0
  69. package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +2 -1
  70. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +2 -2
  71. package/src/components/CnIndexPage/CnIndexPage.vue +6 -3
  72. package/src/components/CnMailTab/CnMailTab.vue +6 -4
  73. package/src/components/CnNotificationMatrix/CnNotificationMatrix.vue +4 -1
  74. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +131 -20
  75. package/src/components/CnSettingsField/CnSettingsField.vue +15 -0
  76. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +13 -8
  77. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +10 -2
  78. package/src/composables/indexSources.js +35 -9
  79. package/src/css/dialog.css +18 -9
  80. package/src/css/look-board-detail.css +219 -23
  81. package/src/css/look-board-index.css +38 -4
  82. package/src/css/look-board.css +138 -8
  83. package/src/css/table.css +8 -1
  84. package/src/utils/builtInFormatters.js +17 -0
  85. package/src/utils/localHeaderRows.js +91 -0
@@ -1 +1 @@
1
- {"version":3,"file":"CnWorkspaceFilterWidget.vue2.js","sources":["../../../../src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-workspace-filter-widget\"\n\t\t:class=\"{\n\t\t\t'cn-workspace-filter-widget--start': isStart,\n\t\t\t'cn-workspace-filter-widget--chips': style === 'chips',\n\t\t\t'cn-workspace-filter-widget--bar': isBar,\n\t\t\t'cn-workspace-filter-widget--inline': content.inline === true,\n\t\t\t'cn-workspace-filter-widget--end': content.align === 'end',\n\t\t}\"\n\t\tdata-testid=\"cn-workspace-filter-widget\">\n\t\t<!-- The start card (`layout: \"start\"`): a title and one line of\n\t\t guidance beside the control, as the \"Contact starten\" card. -->\n\t\t<div v-if=\"isStart && (title || description)\" class=\"cn-workspace-filter-widget__text\">\n\t\t\t<h3 v-if=\"title\" class=\"cn-workspace-filter-widget__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h3>\n\t\t\t<p v-if=\"description\" class=\"cn-workspace-filter-widget__description\">\n\t\t\t\t{{ description }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- A bar (`layout: \"bar\"`): its `controls` side by side in one row,\n\t\t each a workspace filter of its own (chips, a switch, a select). -->\n\t\t<template v-if=\"isBar\">\n\t\t\t<CnWorkspaceFilterWidget\n\t\t\t\tv-for=\"(control, index) in barControls\"\n\t\t\t\t:key=\"index\"\n\t\t\t\t:content=\"control\"\n\t\t\t\t@change=\"$emit('change', $event)\" />\n\t\t</template>\n\n\t\t<!-- An input with a load button (`style: \"input\"`): the value goes to\n\t\t the workspace only when it is loaded, and only when it is valid. -->\n\t\t<form\n\t\t\tv-if=\"!isBar && style === 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__form\"\n\t\t\tnovalidate\n\t\t\tdata-testid=\"cn-workspace-filter-form\"\n\t\t\t@submit.prevent=\"submitInput\">\n\t\t\t<div class=\"cn-workspace-filter-widget__field\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-workspace-filter-widget__field-label\">{{ tr(label) }}</label>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tv-model=\"draft\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t:inputmode=\"inputType === 'year' ? 'numeric' : 'text'\"\n\t\t\t\t\t:aria-invalid=\"inputError ? 'true' : 'false'\"\n\t\t\t\t\t:aria-describedby=\"inputError ? `${inputId}-error` : undefined\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input\">\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"inputError\"\n\t\t\t\t\t:id=\"`${inputId}-error`\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input-error\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input-error\">\n\t\t\t\t\t{{ inputError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\" variant=\"primary\" data-testid=\"cn-workspace-filter-submit\">\n\t\t\t\t{{ tr(content.submitLabel || '') || loadLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"exportTableId\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__export\"\n\t\t\t\tdata-testid=\"cn-workspace-filter-export\"\n\t\t\t\t@click=\"exportTable\">\n\t\t\t\t{{ tr(content.exportTable.label || '') || exportLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<p v-if=\"!isBar && label && style !== 'chips' && style !== 'toggle' && style !== 'input'\" class=\"cn-workspace-filter-widget__label\">\n\t\t\t{{ tr(label) }}\n\t\t</p>\n\n\t\t<!-- An object picker (`objectSource`): searches OpenRegister on the\n\t\t server, so it reaches every object, not a fetched page. -->\n\t\t<CnResourceSelect\n\t\t\tv-if=\"!isBar && style !== 'input' && objectSource\"\n\t\t\tclass=\"cn-workspace-filter-widget__control\"\n\t\t\t:register=\"objectSource.register\"\n\t\t\t:schema=\"objectSource.schema\"\n\t\t\t:labelField=\"objectSource.labelField || 'title'\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? '' : String(selected)\"\n\t\t\t:placeholder=\"tr(objectSource.placeholder || '')\"\n\t\t\t:ariaLabelCombobox=\"tr(objectSource.ariaLabel || '') || title || label || writeKey\"\n\t\t\t:preload=\"objectSource.preload !== false\"\n\t\t\t:clearable=\"Boolean(content.allLabel)\"\n\t\t\t:allowCreate=\"false\"\n\t\t\tdata-testid=\"cn-workspace-filter-object\"\n\t\t\t@update:modelValue=\"applySelection($event || '')\" />\n\n\t\t<div v-else-if=\"loading && style !== 'input'\" class=\"cn-workspace-filter-widget__status\">\n\t\t\t{{ loadingLabel }}\n\t\t</div>\n\n\t\t<!-- Chips style (screens-page-lenses): one compact segmented group,\n\t\t a count after each label, arrow keys move the choice. -->\n\t\t<CnSegmentedControl\n\t\t\tv-else-if=\"style === 'chips'\"\n\t\t\tclass=\"cn-workspace-filter-widget__chips\"\n\t\t\tsize=\"compact\"\n\t\t\t:options=\"chipOptions\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? null : String(selected)\"\n\t\t\t:ariaLabel=\"tr(label) || writeKey\"\n\t\t\tdata-testid=\"cn-workspace-filter-chips\"\n\t\t\t@update:modelValue=\"applySelection\" />\n\n\t\t<!-- Toggle style (screens-page-controls): a switch that writes\n\t\t `onValue` / `offValue` (true / false) to the key. -->\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-else-if=\"style === 'toggle'\"\n\t\t\tclass=\"cn-workspace-filter-widget__toggle\"\n\t\t\ttype=\"switch\"\n\t\t\t:modelValue=\"toggleOn\"\n\t\t\tdata-testid=\"cn-workspace-filter-toggle\"\n\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t{{ tr(label) }}\n\t\t</NcCheckboxRadioSwitch>\n\n\t\t<!-- Select style -->\n\t\t<NcSelect\n\t\t\tv-else-if=\"style === 'select'\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"selectOptions\"\n\t\t\t:clearable=\"false\"\n\t\t\t:inputLabel=\"content.inline ? '' : (tr(label) || writeKey)\"\n\t\t\t:labelOutside=\"content.inline === true\"\n\t\t\t:ariaLabelCombobox=\"tr(label) || writeKey\"\n\t\t\tlabel=\"label\"\n\t\t\tdata-testid=\"cn-workspace-filter-select\"\n\t\t\t@update:modelValue=\"onSelect\" />\n\n\t\t<!-- Radio-list style (default) -->\n\t\t<ul v-else-if=\"!isBar && style !== 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__list\"\n\t\t\trole=\"radiogroup\"\n\t\t\t:aria-label=\"tr(label) || writeKey\">\n\t\t\t<li\n\t\t\t\tv-for=\"option in selectOptions\"\n\t\t\t\t:key=\"String(option.value)\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__item\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"radioGroupName\"\n\t\t\t\t\t:modelValue=\"isActive(option) ? String(option.value) : ''\"\n\t\t\t\t\t:value=\"String(option.value)\"\n\t\t\t\t\t:data-testid=\"`cn-workspace-filter-option-${option.value}`\"\n\t\t\t\t\t@update:modelValue=\"onRadioPick(option)\">\n\t\t\t\t\t<span class=\"cn-workspace-filter-widget__option-label\">{{ option.label }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"showCounts && option.count !== undefined && option.count !== null\"\n\t\t\t\t\t\tclass=\"cn-workspace-filter-widget__count\">{{ option.count }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<component\n\t\t\t:is=\"startLink.to ? 'router-link' : 'a'\"\n\t\t\tv-if=\"startLink\"\n\t\t\t:to=\"startLink.to || undefined\"\n\t\t\t:href=\"startLink.href || undefined\"\n\t\t\tclass=\"cn-workspace-filter-widget__link\"\n\t\t\tdata-testid=\"cn-workspace-filter-link\">\n\t\t\t{{ startLink.label }}\n\t\t</component>\n\t</div>\n</template>\n\n<script>\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fetchListTotal } from '../../utils/fetchFilterCounts.js'\nimport { quarterKey } from '../../utils/periodOptions.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnWorkspaceFilterWidget — a dashboard choice-list that writes the selected\n * value into the page workspace context so sibling widgets refetch (#91\n * Wave 3, the `workspace-filter` widget).\n *\n * Options come from ONE of three sources (checked in order):\n * 1. static `options[]` — each `{ value, label, count? }`.\n * 2. an OpenRegister `source` — `{ register, schema, groupBy, filter? }`,\n * fetched from OR's `/grouped` facet so each distinct value becomes an\n * option with its object `count`.\n * 3. an `endpointSource` — `{ url, params?, responsePath? }` returning an\n * array of `{ value, label, count? }` (or `{ id, name }` / bare strings,\n * normalised).\n *\n * The chosen value is written to the workspace context key named by `writes`\n * (`\"@workspace.<key>\"` or a bare `\"<key>\"`). CnDashboardPage provides\n * `cnWorkspaceContext`; every sibling widget whose declarative source\n * interpolates `@workspace.<key>` re-resolves its tokens and refetches when\n * the selection changes — the pipelinq WerkplekQueueFilter contract.\n *\n * An optional leading \"All\" option (`allLabel`) clears the key (writes the\n * empty string), so an optional `@workspace.<key>?` token drops and siblings\n * show the unfiltered set.\n *\n * ```js\n * content: {\n * label: 'Queue',\n * writes: '@workspace.queue',\n * style: 'radio', // 'radio' (default) | 'select' | 'chips'\n * allLabel: 'All',\n * showCounts: true,\n * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },\n * }\n * ```\n */\nexport default {\n\tname: 'CnWorkspaceFilterWidget',\n\n\tcomponents: { CnResourceSelect, CnSegmentedControl, NcButton, NcSelect, NcCheckboxRadioSwitch },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context. CnDashboardPage provides a `ref({})`;\n\t\t * Vue 2.7's Options-API inject AUTO-UNWRAPS it, so this is the plain\n\t\t * reactive bag (the raw-ref `{ value }` shape is also handled on write).\n\t\t * Null on pages without one (the widget then just emits `@change`).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** Host translate function, for the start card's texts. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob.\n\t\t *\n\t\t * Start card keys (abstract-start-card): `layout: \"start\"` draws\n\t\t * `title` and `description` beside the control, and `link`\n\t\t * (`{ label, route? | href? }`) after it. `objectSource`\n\t\t * (`{ register, schema, labelField?, placeholder?, ariaLabel?, preload? }`)\n\t\t * makes the control an OpenRegister object picker that searches on the\n\t\t * server and writes the picked object's id; without a selection and\n\t\t * without `allLabel` it selects the first object.\n\t\t *\n\t\t * Chips (screens-page-lenses): `style: \"chips\"` draws the options as one\n\t\t * compact segmented group with a count after each label. An option's\n\t\t * `countFrom` (`{ register, schema, filter? }`, or a list of them that\n\t\t * are added up) counts that list; a static `count` is used otherwise.\n\t\t * `urlKey` keeps the choice in the address (`?<urlKey>=<value>`), and\n\t\t * the address wins over `default` on load.\n\t\t *\n\t\t * Page controls (screens-page-controls): `style: \"toggle\"` is a switch\n\t\t * that writes `onValue` / `offValue` (true / false); `layout: \"bar\"`\n\t\t * with `controls` draws several controls side by side in one row, and\n\t\t * `align: \"end\"` pushes a control to the right edge.\n\t\t *\n\t\t * Input (workspace-filter-input): `style: \"input\"` draws a labelled text\n\t\t * field and a load button (`submitLabel`). The value is written only\n\t\t * when it is loaded and only when valid: `inputType: \"quarter\"` reads\n\t\t * `YYYY-Qn` and `\"year\"` reads `YYYY`, both seeded with the current one;\n\t\t * any other input takes a `pattern` (a regular expression) if given.\n\t\t * `exportTable: { exportId, label? }` adds a button beside the load\n\t\t * button that asks the object table with that `exportId` for its rows\n\t\t * as CSV (DqTermijnen \"CSV exporteren\").\n\t\t *\n\t\t * @type {{label?: string, submitLabel?: string, exportTable?: {exportId: string, label?: string}, inputType?: string, pattern?: string, controls?: Array<object>, onValue?: unknown, offValue?: unknown, align?: string, urlKey?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, objectSource?: object, default?: (string|number), layout?: string, title?: string, description?: string, link?: object}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['change'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The input's text before it is loaded (`style: \"input\"`). */\n\t\t\tdraft: '',\n\t\t\t/** Why the input's text was refused, or ''. */\n\t\t\tinputError: '',\n\t\t\t/** Fetched options (from source / endpointSource); static options use content.options directly. */\n\t\t\tfetchedOptions: null,\n\t\t\t/** True while options are being fetched. */\n\t\t\tloading: false,\n\t\t\t/** The currently-selected value (mirrors the workspace key). */\n\t\t\tselected: undefined,\n\t\t\t/** Counted totals of the options that ask (`countFrom`), by option position. */\n\t\t\toptionCounts: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Section label. */\n\t\tlabel() {\n\t\t\treturn this.content.label || ''\n\t\t},\n\n\t\t/** Whether the widget draws the start card. */\n\t\tisStart() {\n\t\t\treturn this.content.layout === 'start'\n\t\t},\n\n\t\t/** The start card's title, translated. */\n\t\ttitle() {\n\t\t\treturn this.tr(this.content.title || '')\n\t\t},\n\n\t\t/** The start card's guidance line, translated. */\n\t\tdescription() {\n\t\t\treturn this.tr(this.content.description || '')\n\t\t},\n\n\t\t/**\n\t\t * The link after the control, or null.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t */\n\t\tstartLink() {\n\t\t\tconst link = this.content.link\n\t\t\tif (!link || typeof link !== 'object' || !link.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route && typeof link.route === 'object' && link.route.name) {\n\t\t\t\treturn { label: this.tr(link.label), to: link.route }\n\t\t\t}\n\t\t\tif (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\treturn { label: this.tr(link.label), href: link.href }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The object picker declaration, or null.\n\t\t *\n\t\t * @return {{register: string, schema: string, labelField?: string}|null}\n\t\t */\n\t\tobjectSource() {\n\t\t\tconst src = this.content.objectSource\n\t\t\treturn src && typeof src === 'object' && src.register && src.schema ? src : null\n\t\t},\n\n\t\t/** Choice style: 'chips', 'select' or 'radio' (default). */\n\t\tstyle() {\n\t\t\treturn ['select', 'chips', 'toggle', 'input'].includes(this.content.style) ? this.content.style : 'radio'\n\t\t},\n\n\t\t/**\n\t\t * The chips: each option with its label translated and its count,\n\t\t * the static one or the counted one.\n\t\t *\n\t\t * @return {Array<{value: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tchipOptions() {\n\t\t\treturn this.displayOptions.map((option, index) => {\n\t\t\t\tconst counted = this.optionCounts[index]\n\t\t\t\tconst count = counted !== undefined && counted !== null ? counted : option.count\n\t\t\t\tconst chip = { value: String(option.value), label: this.tr(option.label) }\n\t\t\t\tif (this.showCounts && Number.isFinite(count)) {\n\t\t\t\t\tchip.count = count\n\t\t\t\t}\n\t\t\t\treturn chip\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is a bar of controls (`layout: \"bar\"`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-bar-holds-the-pages-controls-in-one-row\n\t\t */\n\t\tisBar() {\n\t\t\treturn this.content.layout === 'bar' && Array.isArray(this.content.controls)\n\t\t},\n\n\t\t/**\n\t\t * The bar's controls, each an inline workspace filter of its own.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tbarControls() {\n\t\t\treturn this.content.controls\n\t\t\t\t.filter((control) => control && typeof control === 'object')\n\t\t\t\t.map((control) => ({ ...control, inline: true }))\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when on. */\n\t\tonValue() {\n\t\t\treturn this.content.onValue !== undefined ? this.content.onValue : true\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when off. */\n\t\toffValue() {\n\t\t\treturn this.content.offValue !== undefined ? this.content.offValue : false\n\t\t},\n\n\t\t/** @return {boolean} Whether the switch is on. */\n\t\ttoggleOn() {\n\t\t\treturn this.selected !== undefined && String(this.selected) === String(this.onValue)\n\t\t},\n\n\t\t/**\n\t\t * The address key that carries the choice (`urlKey`), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\turlKey() {\n\t\t\treturn typeof this.content.urlKey === 'string' ? this.content.urlKey : ''\n\t\t},\n\n\t\t/** Whether to render per-option counts. */\n\t\tshowCounts() {\n\t\t\treturn this.content.showCounts !== false\n\t\t},\n\n\t\t/**\n\t\t * What an input reads: `quarter`, `year` or `text`.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tinputType() {\n\t\t\treturn ['quarter', 'year'].includes(this.content.inputType) ? this.content.inputType : 'text'\n\t\t},\n\n\t\t/**\n\t\t * The form an input's text must have, or null for any.\n\t\t *\n\t\t * @return {RegExp|null}\n\t\t */\n\t\tinputPattern() {\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn /^\\d{4}-Q[1-4]$/\n\t\t\t}\n\t\t\tif (this.inputType === 'year') {\n\t\t\t\treturn /^\\d{4}$/\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.content.pattern ? new RegExp(this.content.pattern) : null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/** The input's id, unique per key. */\n\t\tinputId() {\n\t\t\treturn `cn-wsf-input-${this.writeKey || 'value'}`\n\t\t},\n\n\t\t/** The load button's label when the content names none. */\n\t\tloadLabel() {\n\t\t\treturn t('nextcloud-vue', 'Load')\n\t\t},\n\n\t\t/** @return {string} The library label of the table export button. */\n\t\texportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Export CSV')\n\t\t},\n\n\t\t/** @return {string} The `exportId` of the table the input exports, or ''. */\n\t\texportTableId() {\n\t\t\tconst target = this.content && this.content.exportTable\n\t\t\treturn target && typeof target.exportId === 'string' ? target.exportId : ''\n\t\t},\n\n\t\t/** The bare workspace key the selection writes (strips a `@workspace.` / `@page.` prefix). */\n\t\twriteKey() {\n\t\t\tconst w = this.content.writes || ''\n\t\t\treturn String(w).replace(/^@(workspace|page)\\./, '')\n\t\t},\n\n\t\t/** A stable radiogroup name so the radios are mutually exclusive. */\n\t\tradioGroupName() {\n\t\t\treturn `cn-wsf-${this.writeKey || 'filter'}`\n\t\t},\n\n\t\t/** The option list actually rendered — the optional \"All\" entry prepended. */\n\t\tdisplayOptions() {\n\t\t\tconst base = this.normalisedOptions\n\t\t\tif (this.content.allLabel) {\n\t\t\t\treturn [{ value: '', label: this.content.allLabel }, ...base]\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Normalised `{ value, label, count? }` options from whichever source is configured. */\n\t\tnormalisedOptions() {\n\t\t\tconst raw = this.fetchedOptions !== null\n\t\t\t\t? this.fetchedOptions\n\t\t\t\t: (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\treturn raw.map((o) => this.normaliseOption(o)).filter((o) => o.value !== undefined && o.value !== null)\n\t\t},\n\n\t\t/**\n\t\t * The options a select or the radio list draws, each label run through\n\t\t * the host's translate (the chips did already; the bar's sort select\n\t\t * showed its English keys beside a translated switch).\n\t\t *\n\t\t * @return {Array<{value: unknown, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-workspace-filter-translate/specs/workspace-filter/spec.md#requirement-every-workspace-filter-style-translates-its-texts\n\t\t */\n\t\tselectOptions() {\n\t\t\treturn this.displayOptions.map((option) => ({ ...option, label: this.tr(option.label) }))\n\t\t},\n\n\t\t/** The selected option object (for NcSelect). */\n\t\tselectedOption() {\n\t\t\treturn this.selectOptions.find((o) => String(o.value) === String(this.selected)) || null\n\t\t},\n\n\t\t/**\n\t\t * The reactive workspace value for this key — watched so an external\n\t\t * write (another widget) syncs the local selection.\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\tworkspaceValue() {\n\t\t\treturn this.readWorkspace()\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** Re-fetch options when a dynamic source changes. */\n\t\tcontent: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Track external workspace changes (another widget writing the same key).\n\t\t *\n\t\t * @param {unknown} val The new workspace value for this key.\n\t\t */\n\t\tworkspaceValue(val) {\n\t\t\tif (val !== undefined) {\n\t\t\t\tthis.selected = val\n\t\t\t}\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Seed the selection: existing workspace value → content.default → the\n\t\t// \"All\" clear option (empty) when present, else the first option once\n\t\t// loaded (handled in loadOptions).\n\t\tconst fromAddress = this.readAddress()\n\t\tconst existing = this.readWorkspace()\n\t\tif (this.style === 'input') {\n\t\t\tconst seed = existing !== undefined && existing !== null && existing !== '' ? String(existing) : this.inputDefault()\n\t\t\tthis.draft = seed\n\t\t\tthis.selected = seed\n\t\t\tif (seed !== '' && seed !== existing) {\n\t\t\t\tthis.writeWorkspace(seed)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (fromAddress !== undefined) {\n\t\t\tthis.selected = fromAddress\n\t\t\tthis.writeWorkspace(fromAddress)\n\t\t} else if (existing !== undefined) {\n\t\t\tthis.selected = existing\n\t\t} else if (this.content.default !== undefined) {\n\t\t\tthis.selected = this.content.default\n\t\t\tthis.writeWorkspace(this.content.default)\n\t\t} else if (this.style === 'toggle') {\n\t\t\t// A switch starts off, and says so, so a condition on its key holds.\n\t\t\tthis.selected = this.offValue\n\t\t\tthis.writeWorkspace(this.offValue)\n\t\t}\n\t\tthis.loadOptions()\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = () => this.loadCounts()\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tthis.loadCounts()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The choice named in the address (`?<urlKey>=…`), when it is one of\n\t\t * the options; undefined otherwise.\n\t\t *\n\t\t * @return {string|undefined}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\treadAddress() {\n\t\t\tif (!this.urlKey || !this.$route || !this.$route.query) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst raw = this.$route.query[this.urlKey]\n\t\t\tif (this.style === 'toggle') {\n\t\t\t\tif (raw === undefined) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t\treturn [this.onValue, this.offValue].find((value) => String(value) === String(raw))\n\t\t\t}\n\t\t\tconst known = this.displayOptions.some((option) => String(option.value) === String(raw))\n\t\t\treturn known ? String(raw) : undefined\n\t\t},\n\n\t\t/**\n\t\t * Write the choice to the address, replacing the history entry and\n\t\t * keeping the other query keys.\n\t\t *\n\t\t * @param {unknown} value The chosen value.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\twriteAddress(value) {\n\t\t\tif (!this.urlKey || !this.$router || !this.$route) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst query = this.$route.query || {}\n\t\t\tif (String(query[this.urlKey]) === String(value)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst result = this.$router.replace({ query: { ...query, [this.urlKey]: String(value) } })\n\t\t\tif (result && typeof result.catch === 'function') {\n\t\t\t\tresult.catch(() => {})\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Count the lists behind the options that ask (`countFrom`: a list\n\t\t * `{ register, schema, filter? }`, or several that are added up). One\n\t\t * list request each; an option whose count failed shows none.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tasync loadCounts() {\n\t\t\tconst options = this.displayOptions\n\t\t\tconst seq = (this.countSeq = (this.countSeq || 0) + 1)\n\t\t\tconst ctx = { workspace: this.readWorkspaceBag() }\n\t\t\tawait Promise.all(options.map(async (option, index) => {\n\t\t\t\tconst raw = (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\t\t\t.find((candidate) => candidate && typeof candidate === 'object' && String(candidate.value ?? candidate.id) === String(option.value))\n\t\t\t\tconst from = raw ? raw.countFrom : null\n\t\t\t\tconst lists = (Array.isArray(from) ? from : [from]).filter((list) => list && typeof list === 'object' && list.register && list.schema)\n\t\t\t\tif (lists.length === 0) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet total\n\t\t\t\ttry {\n\t\t\t\t\tconst parts = await Promise.all(lists.map((list) => fetchListTotal(list.register, list.schema, list.filter || {}, ctx)))\n\t\t\t\t\tif (parts.some((part) => part === null)) {\n\t\t\t\t\t\tthrow new Error('no total')\n\t\t\t\t\t}\n\t\t\t\t\ttotal = parts.reduce((sum, part) => sum + part, 0)\n\t\t\t\t} catch {\n\t\t\t\t\ttotal = null\n\t\t\t\t}\n\t\t\t\tif (seq === this.countSeq) {\n\t\t\t\t\tthis.optionCounts = { ...this.optionCounts, [index]: total }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Normalise a raw option into `{ value, label, count? }`. Accepts\n\t\t * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR\n\t\t * facet), or a bare string/number.\n\t\t *\n\t\t * @param {unknown} o The raw option.\n\t\t * @return {{value: unknown, label: string, count?: number}}\n\t\t */\n\t\tnormaliseOption(o) {\n\t\t\tif (o === null || o === undefined) {\n\t\t\t\treturn { value: undefined, label: '' }\n\t\t\t}\n\t\t\tif (typeof o !== 'object') {\n\t\t\t\treturn { value: o, label: String(o) }\n\t\t\t}\n\t\t\tconst value = o.value !== undefined ? o.value : (o.id !== undefined ? o.id : o.key)\n\t\t\tconst label = o.label !== undefined ? o.label : (o.name !== undefined ? o.name : String(value))\n\t\t\tconst out = { value, label: String(label) }\n\t\t\tif (o.count !== undefined) {\n\t\t\t\tout.count = o.count\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Load options for the active source (static content.options need no\n\t\t * fetch). Seeds the first option as the selection when nothing is set\n\t\t * and no \"All\" clear option exists.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tif (this.objectSource) {\n\t\t\t\tawait this.seedFirstObject()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.content.endpointSource && this.content.endpointSource.url) {\n\t\t\t\tawait this.loadFromEndpoint()\n\t\t\t} else if (this.content.source && this.content.source.schema) {\n\t\t\t\tawait this.loadFromOrSource()\n\t\t\t} else {\n\t\t\t\tthis.fetchedOptions = null\n\t\t\t}\n\t\t\t// Default selection: when nothing is selected and there's no \"All\"\n\t\t\t// clear affordance, adopt the first option so siblings have a value.\n\t\t\tif ((this.selected === undefined || this.selected === '') && !this.content.allLabel) {\n\t\t\t\tconst first = this.normalisedOptions[0]\n\t\t\t\tif (first && this.readWorkspace() === undefined && this.content.default === undefined) {\n\t\t\t\t\tthis.selected = first.value\n\t\t\t\t\tthis.writeWorkspace(first.value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The object picker's default: with nothing selected, no `default` and\n\t\t * no `allLabel`, select the first object the source lists, so the page\n\t\t * always has one in focus. Fail-safe: a failed read selects nothing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync seedFirstObject() {\n\t\t\tif ((this.selected !== undefined && this.selected !== '') || this.content.allLabel || this.content.default !== undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst src = this.objectSource\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: src.register, schema: src.schema })\n\t\t\t\tconst res = await axios.get(url, { params: { _limit: 1 } })\n\t\t\t\tconst data = res && res.data\n\t\t\t\tconst rows = Array.isArray(data) ? data : ((data && data.results) || [])\n\t\t\t\tconst first = rows[0]\n\t\t\t\tconst id = first && (first.id || (first['@self'] && first['@self'].id))\n\t\t\t\tif (id && (this.selected === undefined || this.selected === '') && this.readWorkspace() === undefined) {\n\t\t\t\t\tthis.selected = String(id)\n\t\t\t\t\tthis.writeWorkspace(String(id))\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Nothing selected: the siblings wait for a pick.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an `endpointSource` (array of options at\n\t\t * responsePath). Fail-safe: a failed fetch leaves an empty list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromEndpoint() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst payload = await fetchEndpointSource(this.content.endpointSource, {\n\t\t\t\t\tworkspace: this.readWorkspaceBag(),\n\t\t\t\t})\n\t\t\t\tthis.fetchedOptions = Array.isArray(payload) ? payload : []\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an OpenRegister `/grouped` facet — each distinct\n\t\t * `groupBy` value becomes an option with its object count. Fail-safe.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromOrSource() {\n\t\t\tconst src = this.content.source\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/grouped',\n\t\t\t\t\t{ register: src.register, schema: src.schema },\n\t\t\t\t)\n\t\t\t\tconst params = { groupBy: src.groupBy, metric: 'count' }\n\t\t\t\tconst filter = resolveFilterTokens(src.filter || {}, { workspace: this.readWorkspaceBag() })\n\t\t\t\tfor (const [k, v] of Object.entries(filter)) {\n\t\t\t\t\tif (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[`filter[${k}]`] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tconst groups = (res && res.data && res.data.groups) || []\n\t\t\t\tthis.fetchedOptions = groups\n\t\t\t\t\t.filter((g) => g.key !== null && g.key !== undefined && g.key !== '')\n\t\t\t\t\t.map((g) => ({ value: g.key, label: String(g.key), count: Number(g.value) || 0 }))\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an option is the active selection.\n\t\t *\n\t\t * @param {object} option The option.\n\t\t * @return {boolean}\n\t\t */\n\t\tisActive(option) {\n\t\t\treturn String(option.value) === String(this.selected ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Radio-list pick handler.\n\t\t *\n\t\t * @param {object} option The picked option.\n\t\t * @return {void}\n\t\t */\n\t\tonRadioPick(option) {\n\t\t\tthis.applySelection(option.value)\n\t\t},\n\n\t\t/**\n\t\t * Switch handler: write `onValue` or `offValue`.\n\t\t *\n\t\t * @param {boolean} on Whether the switch is on.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-toggle-and-a-select-are-page-controls\n\t\t */\n\t\tonToggle(on) {\n\t\t\tthis.applySelection(on ? this.onValue : this.offValue)\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler.\n\t\t *\n\t\t * @param {object|null} option The picked option object.\n\t\t * @return {void}\n\t\t */\n\t\tonSelect(option) {\n\t\t\tthis.applySelection(option ? option.value : '')\n\t\t},\n\n\t\t/**\n\t\t * Apply a new selection: mirror it locally, write it into the workspace\n\t\t * context (so sibling widgets refetch), and emit `@change`.\n\t\t *\n\t\t * @param {unknown} value The new value.\n\t\t * @return {void}\n\t\t */\n\t\t/**\n\t\t * The value an input starts with: `content.default`, else the current\n\t\t * quarter or year for those types, else empty.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tinputDefault() {\n\t\t\tif (this.content.default !== undefined && this.content.default !== null) {\n\t\t\t\treturn String(this.content.default)\n\t\t\t}\n\t\t\tconst today = new Date()\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(today)\n\t\t\t}\n\t\t\treturn this.inputType === 'year' ? String(today.getFullYear()) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask the table named by `exportTable.exportId` for its rows as CSV.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-export-table/specs/workspace-filter-export-table/spec.md#requirement-a-workspace-filter-input-can-export-the-table-it-loads\n\t\t */\n\t\texportTable() {\n\t\t\temit('cn:widget:export', { exportId: this.exportTableId })\n\t\t},\n\n\t\t/**\n\t\t * Load the input's text into the workspace, or say why it is refused.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tsubmitInput() {\n\t\t\tconst value = String(this.draft || '').trim()\n\t\t\tconst pattern = this.inputPattern\n\t\t\tif (value === '' || (pattern && !pattern.test(value))) {\n\t\t\t\tthis.inputError = this.inputType === 'quarter'\n\t\t\t\t\t? t('nextcloud-vue', 'Enter a quarter as YYYY-Qn, for example 2026-Q3.')\n\t\t\t\t\t: (this.inputType === 'year' ? t('nextcloud-vue', 'Enter a year as four digits, for example 2026.') : t('nextcloud-vue', 'This value has the wrong form.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.inputError = ''\n\t\t\tthis.applySelection(value)\n\t\t},\n\n\t\tapplySelection(value) {\n\t\t\tthis.selected = value\n\t\t\tthis.writeWorkspace(value)\n\t\t\tthis.writeAddress(value)\n\t\t\t/**\n\t\t\t * @event change Emitted when the selection changes. Payload: `{ key, value }`.\n\t\t\t */\n\t\t\tthis.$emit('change', { key: this.writeKey, value })\n\t\t},\n\n\t\t/**\n\t\t * The unwrapped workspace bag (or `{}`).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\treadWorkspaceBag() {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn ('value' in holder) ? (holder.value || {}) : holder\n\t\t},\n\n\t\t/**\n\t\t * Read the current workspace value for this widget's key (undefined\n\t\t * when unset).\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\treadWorkspace() {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst bag = this.readWorkspaceBag()\n\t\t\treturn bag[this.writeKey]\n\t\t},\n\n\t\t/**\n\t\t * Write a value into the reactive workspace bag under this widget's key\n\t\t * (the CnInteractionFormWidget write pattern — replace-in-place for the\n\t\t * unwrapped bag, `.value` for the raw-ref shape).\n\t\t *\n\t\t * @param {unknown} value The value to write.\n\t\t * @return {void}\n\t\t */\n\t\twriteWorkspace(value) {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [this.writeKey]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[this.writeKey] = value\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-workspace-filter-widget__form {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 12px 16px;\n}\n\n.cn-workspace-filter-widget__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-workspace-filter-widget__field-label {\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__input {\n\tbox-sizing: border-box;\n\tmin-height: var(--default-clickable-area, 34px);\n\tmargin: 0;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-workspace-filter-widget__input[aria-invalid='true'] {\n\tborder-color: var(--color-error);\n}\n\n.cn-workspace-filter-widget__input-error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n\n.cn-workspace-filter-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\twidth: 100%;\n}\n\n.cn-workspace-filter-widget__label {\n\tmargin: 0;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-workspace-filter-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* The chips: the compact segmented group, left, in the card the grid draws. */\n.cn-workspace-filter-widget--chips {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n}\n\n/* A bar: its controls in one row, an `align: \"end\"` control pushed right. */\n.cn-workspace-filter-widget--bar {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px 16px;\n}\n\n/* An inline control sits in a bar: label left of the control, width to its content. */\n.cn-workspace-filter-widget--inline {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\twidth: auto;\n}\n\n.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__label {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--end {\n\tmargin-inline-start: auto;\n}\n\n.cn-workspace-filter-widget--end ~ .cn-workspace-filter-widget--end {\n\tmargin-inline-start: 0;\n}\n\n.cn-workspace-filter-widget__toggle {\n\tfont-weight: 600;\n}\n\n/* The start card: text left, control (and link) right, as PqDashboard's \"Contact starten\". */\n.cn-workspace-filter-widget--start {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 16px 24px;\n}\n\n.cn-workspace-filter-widget__text {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n}\n\n.cn-workspace-filter-widget__title {\n\tmargin: 0 0 4px;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__description {\n\tmargin: 0;\n\tmax-width: 420px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--start .cn-workspace-filter-widget__control,\n.cn-workspace-filter-widget--start > .v-select {\n\tflex: 0 1 480px;\n\tmin-width: 240px;\n}\n\n.cn-workspace-filter-widget__link {\n\tfont-weight: 600;\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n\twhite-space: nowrap;\n}\n\n.cn-workspace-filter-widget__count {\n\tmargin-inline-start: 6px;\n\tpadding: 0 6px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n/* On a phone the bar's controls take a row each (the chips already wrap), and\n a switch and a select are 44px touch targets. */\n@media (max-width: 640px) {\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--inline {\n\t\tflex: 1 1 100%;\n\t}\n\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--end {\n\t\tmargin-inline-start: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__toggle {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.v-select) {\n\t\tflex: 1 1 auto;\n\t\tmin-width: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.vs__dropdown-toggle) {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["CnResourceSelect","CnSegmentedControl","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnWorkspaceFilterWidget.vue2.js","sources":["../../../../src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-workspace-filter-widget\"\n\t\t:class=\"{\n\t\t\t'cn-workspace-filter-widget--start': isStart,\n\t\t\t'cn-workspace-filter-widget--chips': style === 'chips',\n\t\t\t'cn-workspace-filter-widget--bar': isBar,\n\t\t\t'cn-workspace-filter-widget--inline': content.inline === true,\n\t\t\t'cn-workspace-filter-widget--end': content.align === 'end',\n\t\t}\"\n\t\tdata-testid=\"cn-workspace-filter-widget\">\n\t\t<!-- The start card (`layout: \"start\"`): a title and one line of\n\t\t guidance beside the control, as the \"Contact starten\" card. -->\n\t\t<div v-if=\"isStart && (title || description)\" class=\"cn-workspace-filter-widget__text\">\n\t\t\t<h3 v-if=\"title\" class=\"cn-workspace-filter-widget__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h3>\n\t\t\t<p v-if=\"description\" class=\"cn-workspace-filter-widget__description\">\n\t\t\t\t{{ description }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- A bar (`layout: \"bar\"`): its `controls` side by side in one row,\n\t\t each a workspace filter of its own (chips, a switch, a select). -->\n\t\t<template v-if=\"isBar\">\n\t\t\t<CnWorkspaceFilterWidget\n\t\t\t\tv-for=\"(control, index) in barControls\"\n\t\t\t\t:key=\"index\"\n\t\t\t\t:content=\"control\"\n\t\t\t\t@change=\"$emit('change', $event)\" />\n\t\t</template>\n\n\t\t<!-- An input with a load button (`style: \"input\"`): the value goes to\n\t\t the workspace only when it is loaded, and only when it is valid. -->\n\t\t<form\n\t\t\tv-if=\"!isBar && style === 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__form\"\n\t\t\tnovalidate\n\t\t\tdata-testid=\"cn-workspace-filter-form\"\n\t\t\t@submit.prevent=\"submitInput\">\n\t\t\t<div class=\"cn-workspace-filter-widget__field\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-workspace-filter-widget__field-label\">{{ tr(label) }}</label>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tv-model=\"draft\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t:inputmode=\"inputType === 'year' ? 'numeric' : 'text'\"\n\t\t\t\t\t:aria-invalid=\"inputError ? 'true' : 'false'\"\n\t\t\t\t\t:aria-describedby=\"inputError ? `${inputId}-error` : undefined\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input\">\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"inputError\"\n\t\t\t\t\t:id=\"`${inputId}-error`\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input-error\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input-error\">\n\t\t\t\t\t{{ inputError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\" variant=\"primary\" data-testid=\"cn-workspace-filter-submit\">\n\t\t\t\t{{ tr(content.submitLabel || '') || loadLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"exportTableId\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__export\"\n\t\t\t\tdata-testid=\"cn-workspace-filter-export\"\n\t\t\t\t@click=\"exportTable\">\n\t\t\t\t{{ tr(content.exportTable.label || '') || exportLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<p v-if=\"!isBar && label && style !== 'chips' && style !== 'toggle' && style !== 'input'\" class=\"cn-workspace-filter-widget__label\">\n\t\t\t{{ tr(label) }}\n\t\t</p>\n\n\t\t<!-- An object picker (`objectSource`): searches OpenRegister on the\n\t\t server, so it reaches every object, not a fetched page. -->\n\t\t<CnResourceSelect\n\t\t\tv-if=\"!isBar && style !== 'input' && objectSource\"\n\t\t\tclass=\"cn-workspace-filter-widget__control\"\n\t\t\t:register=\"objectSource.register\"\n\t\t\t:schema=\"objectSource.schema\"\n\t\t\t:labelField=\"objectSource.labelField || 'title'\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? '' : String(selected)\"\n\t\t\t:placeholder=\"tr(objectSource.placeholder || '')\"\n\t\t\t:ariaLabelCombobox=\"tr(objectSource.ariaLabel || '') || title || label || writeKey\"\n\t\t\t:preload=\"objectSource.preload !== false\"\n\t\t\t:clearable=\"Boolean(content.allLabel)\"\n\t\t\t:allowCreate=\"false\"\n\t\t\tdata-testid=\"cn-workspace-filter-object\"\n\t\t\t@update:modelValue=\"applySelection($event || '')\" />\n\n\t\t<div v-else-if=\"loading && style !== 'input'\" class=\"cn-workspace-filter-widget__status\">\n\t\t\t{{ loadingLabel }}\n\t\t</div>\n\n\t\t<!-- Chips style (screens-page-lenses): one compact segmented group,\n\t\t a count after each label, arrow keys move the choice. -->\n\t\t<CnSegmentedControl\n\t\t\tv-else-if=\"style === 'chips'\"\n\t\t\tclass=\"cn-workspace-filter-widget__chips\"\n\t\t\tsize=\"compact\"\n\t\t\t:options=\"chipOptions\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? null : String(selected)\"\n\t\t\t:ariaLabel=\"tr(label) || writeKey\"\n\t\t\tdata-testid=\"cn-workspace-filter-chips\"\n\t\t\t@update:modelValue=\"applySelection\" />\n\n\t\t<!-- Toggle style (screens-page-controls): a switch that writes\n\t\t `onValue` / `offValue` (true / false) to the key. -->\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-else-if=\"style === 'toggle'\"\n\t\t\tclass=\"cn-workspace-filter-widget__toggle\"\n\t\t\ttype=\"switch\"\n\t\t\t:modelValue=\"toggleOn\"\n\t\t\tdata-testid=\"cn-workspace-filter-toggle\"\n\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t{{ tr(label) }}\n\t\t</NcCheckboxRadioSwitch>\n\n\t\t<!-- Select style -->\n\t\t<NcSelect\n\t\t\tv-else-if=\"style === 'select'\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"selectOptions\"\n\t\t\t:clearable=\"false\"\n\t\t\t:inputLabel=\"content.inline ? '' : (tr(label) || writeKey)\"\n\t\t\t:labelOutside=\"content.inline === true\"\n\t\t\t:ariaLabelCombobox=\"tr(label) || writeKey\"\n\t\t\tlabel=\"label\"\n\t\t\tdata-testid=\"cn-workspace-filter-select\"\n\t\t\t@update:modelValue=\"onSelect\" />\n\n\t\t<!-- Radio-list style (default) -->\n\t\t<ul v-else-if=\"!isBar && style !== 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__list\"\n\t\t\trole=\"radiogroup\"\n\t\t\t:aria-label=\"tr(label) || writeKey\">\n\t\t\t<li\n\t\t\t\tv-for=\"option in selectOptions\"\n\t\t\t\t:key=\"String(option.value)\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__item\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"radioGroupName\"\n\t\t\t\t\t:modelValue=\"isActive(option) ? String(option.value) : ''\"\n\t\t\t\t\t:value=\"String(option.value)\"\n\t\t\t\t\t:data-testid=\"`cn-workspace-filter-option-${option.value}`\"\n\t\t\t\t\t@update:modelValue=\"onRadioPick(option)\">\n\t\t\t\t\t<span class=\"cn-workspace-filter-widget__option-label\">{{ option.label }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"showCounts && option.count !== undefined && option.count !== null\"\n\t\t\t\t\t\tclass=\"cn-workspace-filter-widget__count\">{{ option.count }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<component\n\t\t\t:is=\"startLink.to ? 'router-link' : 'a'\"\n\t\t\tv-if=\"startLink\"\n\t\t\t:to=\"startLink.to || undefined\"\n\t\t\t:href=\"startLink.href || undefined\"\n\t\t\tclass=\"cn-workspace-filter-widget__link\"\n\t\t\tdata-testid=\"cn-workspace-filter-link\">\n\t\t\t{{ startLink.label }}\n\t\t</component>\n\t</div>\n</template>\n\n<script>\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fetchListTotal } from '../../utils/fetchFilterCounts.js'\nimport { quarterKey } from '../../utils/periodOptions.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnWorkspaceFilterWidget — a dashboard choice-list that writes the selected\n * value into the page workspace context so sibling widgets refetch (#91\n * Wave 3, the `workspace-filter` widget).\n *\n * Options come from ONE of three sources (checked in order):\n * 1. static `options[]` — each `{ value, label, count? }`.\n * 2. an OpenRegister `source` — `{ register, schema, groupBy, filter? }`,\n * fetched from OR's `/grouped` facet so each distinct value becomes an\n * option with its object `count`.\n * 3. an `endpointSource` — `{ url, params?, responsePath? }` returning an\n * array of `{ value, label, count? }` (or `{ id, name }` / bare strings,\n * normalised).\n *\n * The chosen value is written to the workspace context key named by `writes`\n * (`\"@workspace.<key>\"` or a bare `\"<key>\"`). CnDashboardPage provides\n * `cnWorkspaceContext`; every sibling widget whose declarative source\n * interpolates `@workspace.<key>` re-resolves its tokens and refetches when\n * the selection changes — the pipelinq WerkplekQueueFilter contract.\n *\n * An optional leading \"All\" option (`allLabel`) clears the key (writes the\n * empty string), so an optional `@workspace.<key>?` token drops and siblings\n * show the unfiltered set.\n *\n * ```js\n * content: {\n * label: 'Queue',\n * writes: '@workspace.queue',\n * style: 'radio', // 'radio' (default) | 'select' | 'chips'\n * allLabel: 'All',\n * showCounts: true,\n * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },\n * }\n * ```\n */\nexport default {\n\tname: 'CnWorkspaceFilterWidget',\n\n\tcomponents: { CnResourceSelect, CnSegmentedControl, NcButton, NcSelect, NcCheckboxRadioSwitch },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context. CnDashboardPage provides a `ref({})`;\n\t\t * Vue 2.7's Options-API inject AUTO-UNWRAPS it, so this is the plain\n\t\t * reactive bag (the raw-ref `{ value }` shape is also handled on write).\n\t\t * Null on pages without one (the widget then just emits `@change`).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** Host translate function, for the start card's texts. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob.\n\t\t *\n\t\t * Start card keys (abstract-start-card): `layout: \"start\"` draws\n\t\t * `title` and `description` beside the control, and `link`\n\t\t * (`{ label, route? | href? }`) after it. `objectSource`\n\t\t * (`{ register, schema, labelField?, placeholder?, ariaLabel?, preload? }`)\n\t\t * makes the control an OpenRegister object picker that searches on the\n\t\t * server and writes the picked object's id; without a selection and\n\t\t * without `allLabel` it selects the first object.\n\t\t *\n\t\t * Chips (screens-page-lenses): `style: \"chips\"` draws the options as one\n\t\t * compact segmented group with a count after each label. An option's\n\t\t * `countFrom` (`{ register, schema, filter? }`, or a list of them that\n\t\t * are added up) counts that list; a static `count` is used otherwise.\n\t\t * `urlKey` keeps the choice in the address (`?<urlKey>=<value>`), and\n\t\t * the address wins over `default` on load.\n\t\t *\n\t\t * Page controls (screens-page-controls): `style: \"toggle\"` is a switch\n\t\t * that writes `onValue` / `offValue` (true / false); `layout: \"bar\"`\n\t\t * with `controls` draws several controls side by side in one row, and\n\t\t * `align: \"end\"` pushes a control to the right edge.\n\t\t *\n\t\t * Input (workspace-filter-input): `style: \"input\"` draws a labelled text\n\t\t * field and a load button (`submitLabel`). The value is written only\n\t\t * when it is loaded and only when valid: `inputType: \"quarter\"` reads\n\t\t * `YYYY-Qn` and `\"year\"` reads `YYYY`, both seeded with the current one;\n\t\t * any other input takes a `pattern` (a regular expression) if given.\n\t\t * `exportTable: { exportId, label? }` adds a button beside the load\n\t\t * button that asks the object table with that `exportId` for its rows\n\t\t * as CSV (DqTermijnen \"CSV exporteren\").\n\t\t *\n\t\t * @type {{label?: string, submitLabel?: string, exportTable?: {exportId: string, label?: string}, inputType?: string, pattern?: string, controls?: Array<object>, onValue?: unknown, offValue?: unknown, align?: string, urlKey?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, objectSource?: object, default?: (string|number), layout?: string, title?: string, description?: string, link?: object}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['change'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The input's text before it is loaded (`style: \"input\"`). */\n\t\t\tdraft: '',\n\t\t\t/** Why the input's text was refused, or ''. */\n\t\t\tinputError: '',\n\t\t\t/** Fetched options (from source / endpointSource); static options use content.options directly. */\n\t\t\tfetchedOptions: null,\n\t\t\t/** True while options are being fetched. */\n\t\t\tloading: false,\n\t\t\t/** The currently-selected value (mirrors the workspace key). */\n\t\t\tselected: undefined,\n\t\t\t/** Counted totals of the options that ask (`countFrom`), by option position. */\n\t\t\toptionCounts: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Section label. */\n\t\tlabel() {\n\t\t\treturn this.content.label || ''\n\t\t},\n\n\t\t/** Whether the widget draws the start card. */\n\t\tisStart() {\n\t\t\treturn this.content.layout === 'start'\n\t\t},\n\n\t\t/** The start card's title, translated. */\n\t\ttitle() {\n\t\t\treturn this.tr(this.content.title || '')\n\t\t},\n\n\t\t/** The start card's guidance line, translated. */\n\t\tdescription() {\n\t\t\treturn this.tr(this.content.description || '')\n\t\t},\n\n\t\t/**\n\t\t * The link after the control, or null.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t */\n\t\tstartLink() {\n\t\t\tconst link = this.content.link\n\t\t\tif (!link || typeof link !== 'object' || !link.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route && typeof link.route === 'object' && link.route.name) {\n\t\t\t\treturn { label: this.tr(link.label), to: link.route }\n\t\t\t}\n\t\t\tif (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\treturn { label: this.tr(link.label), href: link.href }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The object picker declaration, or null.\n\t\t *\n\t\t * @return {{register: string, schema: string, labelField?: string}|null}\n\t\t */\n\t\tobjectSource() {\n\t\t\tconst src = this.content.objectSource\n\t\t\treturn src && typeof src === 'object' && src.register && src.schema ? src : null\n\t\t},\n\n\t\t/** Choice style: 'chips', 'select' or 'radio' (default). */\n\t\tstyle() {\n\t\t\treturn ['select', 'chips', 'toggle', 'input'].includes(this.content.style) ? this.content.style : 'radio'\n\t\t},\n\n\t\t/**\n\t\t * The chips: each option with its label translated and its count,\n\t\t * the static one or the counted one.\n\t\t *\n\t\t * @return {Array<{value: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tchipOptions() {\n\t\t\treturn this.displayOptions.map((option, index) => {\n\t\t\t\tconst counted = this.optionCounts[index]\n\t\t\t\tconst count = counted !== undefined && counted !== null ? counted : option.count\n\t\t\t\tconst chip = { value: String(option.value), label: this.tr(option.label) }\n\t\t\t\tif (this.showCounts && Number.isFinite(count)) {\n\t\t\t\t\tchip.count = count\n\t\t\t\t}\n\t\t\t\treturn chip\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is a bar of controls (`layout: \"bar\"`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-bar-holds-the-pages-controls-in-one-row\n\t\t */\n\t\tisBar() {\n\t\t\treturn this.content.layout === 'bar' && Array.isArray(this.content.controls)\n\t\t},\n\n\t\t/**\n\t\t * The bar's controls, each an inline workspace filter of its own.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tbarControls() {\n\t\t\treturn this.content.controls\n\t\t\t\t.filter((control) => control && typeof control === 'object')\n\t\t\t\t.map((control) => ({ ...control, inline: true }))\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when on. */\n\t\tonValue() {\n\t\t\treturn this.content.onValue !== undefined ? this.content.onValue : true\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when off. */\n\t\toffValue() {\n\t\t\treturn this.content.offValue !== undefined ? this.content.offValue : false\n\t\t},\n\n\t\t/** @return {boolean} Whether the switch is on. */\n\t\ttoggleOn() {\n\t\t\treturn this.selected !== undefined && String(this.selected) === String(this.onValue)\n\t\t},\n\n\t\t/**\n\t\t * The address key that carries the choice (`urlKey`), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\turlKey() {\n\t\t\treturn typeof this.content.urlKey === 'string' ? this.content.urlKey : ''\n\t\t},\n\n\t\t/** Whether to render per-option counts. */\n\t\tshowCounts() {\n\t\t\treturn this.content.showCounts !== false\n\t\t},\n\n\t\t/**\n\t\t * What an input reads: `quarter`, `year` or `text`.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tinputType() {\n\t\t\treturn ['quarter', 'year'].includes(this.content.inputType) ? this.content.inputType : 'text'\n\t\t},\n\n\t\t/**\n\t\t * The form an input's text must have, or null for any.\n\t\t *\n\t\t * @return {RegExp|null}\n\t\t */\n\t\tinputPattern() {\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn /^\\d{4}-Q[1-4]$/\n\t\t\t}\n\t\t\tif (this.inputType === 'year') {\n\t\t\t\treturn /^\\d{4}$/\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.content.pattern ? new RegExp(this.content.pattern) : null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/** The input's id, unique per key. */\n\t\tinputId() {\n\t\t\treturn `cn-wsf-input-${this.writeKey || 'value'}`\n\t\t},\n\n\t\t/** The load button's label when the content names none. */\n\t\tloadLabel() {\n\t\t\treturn t('nextcloud-vue', 'Load')\n\t\t},\n\n\t\t/** @return {string} The library label of the table export button. */\n\t\texportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Export CSV')\n\t\t},\n\n\t\t/** @return {string} The `exportId` of the table the input exports, or ''. */\n\t\texportTableId() {\n\t\t\tconst target = this.content && this.content.exportTable\n\t\t\treturn target && typeof target.exportId === 'string' ? target.exportId : ''\n\t\t},\n\n\t\t/** The bare workspace key the selection writes (strips a `@workspace.` / `@page.` prefix). */\n\t\twriteKey() {\n\t\t\tconst w = this.content.writes || ''\n\t\t\treturn String(w).replace(/^@(workspace|page)\\./, '')\n\t\t},\n\n\t\t/** A stable radiogroup name so the radios are mutually exclusive. */\n\t\tradioGroupName() {\n\t\t\treturn `cn-wsf-${this.writeKey || 'filter'}`\n\t\t},\n\n\t\t/** The option list actually rendered — the optional \"All\" entry prepended. */\n\t\tdisplayOptions() {\n\t\t\tconst base = this.normalisedOptions\n\t\t\tif (this.content.allLabel) {\n\t\t\t\treturn [{ value: '', label: this.content.allLabel }, ...base]\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Normalised `{ value, label, count? }` options from whichever source is configured. */\n\t\tnormalisedOptions() {\n\t\t\tconst raw = this.fetchedOptions !== null\n\t\t\t\t? this.fetchedOptions\n\t\t\t\t: (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\treturn raw.map((o) => this.normaliseOption(o)).filter((o) => o.value !== undefined && o.value !== null)\n\t\t},\n\n\t\t/**\n\t\t * The options a select or the radio list draws, each label run through\n\t\t * the host's translate (the chips did already; the bar's sort select\n\t\t * showed its English keys beside a translated switch).\n\t\t *\n\t\t * @return {Array<{value: unknown, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-workspace-filter-translate/specs/workspace-filter/spec.md#requirement-every-workspace-filter-style-translates-its-texts\n\t\t */\n\t\tselectOptions() {\n\t\t\treturn this.displayOptions.map((option) => ({ ...option, label: this.tr(option.label) }))\n\t\t},\n\n\t\t/** The selected option object (for NcSelect). */\n\t\tselectedOption() {\n\t\t\treturn this.selectOptions.find((o) => String(o.value) === String(this.selected)) || null\n\t\t},\n\n\t\t/**\n\t\t * The reactive workspace value for this key — watched so an external\n\t\t * write (another widget) syncs the local selection.\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\tworkspaceValue() {\n\t\t\treturn this.readWorkspace()\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** Re-fetch options when a dynamic source changes. */\n\t\tcontent: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Track external workspace changes (another widget writing the same key).\n\t\t *\n\t\t * @param {unknown} val The new workspace value for this key.\n\t\t */\n\t\tworkspaceValue(val) {\n\t\t\tif (val !== undefined) {\n\t\t\t\tthis.selected = val\n\t\t\t}\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Seed the selection: existing workspace value → content.default → the\n\t\t// \"All\" clear option (empty) when present, else the first option once\n\t\t// loaded (handled in loadOptions).\n\t\tconst fromAddress = this.readAddress()\n\t\tconst existing = this.readWorkspace()\n\t\tif (this.style === 'input') {\n\t\t\tconst seed = existing !== undefined && existing !== null && existing !== '' ? String(existing) : this.inputDefault()\n\t\t\tthis.draft = seed\n\t\t\tthis.selected = seed\n\t\t\tif (seed !== '' && seed !== existing) {\n\t\t\t\tthis.writeWorkspace(seed)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (fromAddress !== undefined) {\n\t\t\tthis.selected = fromAddress\n\t\t\tthis.writeWorkspace(fromAddress)\n\t\t} else if (existing !== undefined) {\n\t\t\tthis.selected = existing\n\t\t} else if (this.content.default !== undefined) {\n\t\t\tthis.selected = this.content.default\n\t\t\tthis.writeWorkspace(this.content.default)\n\t\t} else if (this.style === 'toggle') {\n\t\t\t// A switch starts off, and says so, so a condition on its key holds.\n\t\t\tthis.selected = this.offValue\n\t\t\tthis.writeWorkspace(this.offValue)\n\t\t}\n\t\tthis.loadOptions()\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = () => this.loadCounts()\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tthis.loadCounts()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The choice named in the address (`?<urlKey>=…`), when it is one of\n\t\t * the options; undefined otherwise.\n\t\t *\n\t\t * @return {string|undefined}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\treadAddress() {\n\t\t\tif (!this.urlKey || !this.$route || !this.$route.query) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst raw = this.$route.query[this.urlKey]\n\t\t\tif (this.style === 'toggle') {\n\t\t\t\tif (raw === undefined) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t\treturn [this.onValue, this.offValue].find((value) => String(value) === String(raw))\n\t\t\t}\n\t\t\tconst known = this.displayOptions.some((option) => String(option.value) === String(raw))\n\t\t\treturn known ? String(raw) : undefined\n\t\t},\n\n\t\t/**\n\t\t * Write the choice to the address, replacing the history entry and\n\t\t * keeping the other query keys.\n\t\t *\n\t\t * @param {unknown} value The chosen value.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\twriteAddress(value) {\n\t\t\tif (!this.urlKey || !this.$router || !this.$route) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst query = this.$route.query || {}\n\t\t\tif (String(query[this.urlKey]) === String(value)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst result = this.$router.replace({ query: { ...query, [this.urlKey]: String(value) } })\n\t\t\tif (result && typeof result.catch === 'function') {\n\t\t\t\tresult.catch(() => {})\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Count the lists behind the options that ask (`countFrom`: a list\n\t\t * `{ register, schema, filter? }`, or several that are added up). One\n\t\t * list request each; an option whose count failed shows none.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tasync loadCounts() {\n\t\t\tconst options = this.displayOptions\n\t\t\tconst seq = (this.countSeq = (this.countSeq || 0) + 1)\n\t\t\tconst ctx = { workspace: this.readWorkspaceBag() }\n\t\t\tawait Promise.all(options.map(async (option, index) => {\n\t\t\t\tconst raw = (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\t\t\t.find((candidate) => candidate && typeof candidate === 'object' && String(candidate.value ?? candidate.id) === String(option.value))\n\t\t\t\tconst from = raw ? raw.countFrom : null\n\t\t\t\tconst lists = (Array.isArray(from) ? from : [from]).filter((list) => list && typeof list === 'object' && list.register && list.schema)\n\t\t\t\tif (lists.length === 0) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet total\n\t\t\t\ttry {\n\t\t\t\t\tconst parts = await Promise.all(lists.map((list) => fetchListTotal(list.register, list.schema, list.filter || {}, ctx)))\n\t\t\t\t\tif (parts.some((part) => part === null)) {\n\t\t\t\t\t\tthrow new Error('no total')\n\t\t\t\t\t}\n\t\t\t\t\ttotal = parts.reduce((sum, part) => sum + part, 0)\n\t\t\t\t} catch {\n\t\t\t\t\ttotal = null\n\t\t\t\t}\n\t\t\t\tif (seq === this.countSeq) {\n\t\t\t\t\tthis.optionCounts = { ...this.optionCounts, [index]: total }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Normalise a raw option into `{ value, label, count? }`. Accepts\n\t\t * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR\n\t\t * facet), or a bare string/number.\n\t\t *\n\t\t * @param {unknown} o The raw option.\n\t\t * @return {{value: unknown, label: string, count?: number}}\n\t\t */\n\t\tnormaliseOption(o) {\n\t\t\tif (o === null || o === undefined) {\n\t\t\t\treturn { value: undefined, label: '' }\n\t\t\t}\n\t\t\tif (typeof o !== 'object') {\n\t\t\t\treturn { value: o, label: String(o) }\n\t\t\t}\n\t\t\tconst value = o.value !== undefined ? o.value : (o.id !== undefined ? o.id : o.key)\n\t\t\tconst label = o.label !== undefined ? o.label : (o.name !== undefined ? o.name : String(value))\n\t\t\tconst out = { value, label: String(label) }\n\t\t\tif (o.count !== undefined) {\n\t\t\t\tout.count = o.count\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Load options for the active source (static content.options need no\n\t\t * fetch). Seeds the first option as the selection when nothing is set\n\t\t * and no \"All\" clear option exists.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tif (this.objectSource) {\n\t\t\t\tawait this.seedFirstObject()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.content.endpointSource && this.content.endpointSource.url) {\n\t\t\t\tawait this.loadFromEndpoint()\n\t\t\t} else if (this.content.source && this.content.source.schema) {\n\t\t\t\tawait this.loadFromOrSource()\n\t\t\t} else {\n\t\t\t\tthis.fetchedOptions = null\n\t\t\t}\n\t\t\t// Default selection: when nothing is selected and there's no \"All\"\n\t\t\t// clear affordance, adopt the first option so siblings have a value.\n\t\t\tif ((this.selected === undefined || this.selected === '') && !this.content.allLabel) {\n\t\t\t\tconst first = this.normalisedOptions[0]\n\t\t\t\tif (first && this.readWorkspace() === undefined && this.content.default === undefined) {\n\t\t\t\t\tthis.selected = first.value\n\t\t\t\t\tthis.writeWorkspace(first.value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The object picker's default: with nothing selected, no `default` and\n\t\t * no `allLabel`, select the first object the source lists, so the page\n\t\t * always has one in focus. Fail-safe: a failed read selects nothing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync seedFirstObject() {\n\t\t\tif ((this.selected !== undefined && this.selected !== '') || this.content.allLabel || this.content.default !== undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst src = this.objectSource\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: src.register, schema: src.schema })\n\t\t\t\tconst res = await axios.get(url, { params: { _limit: 1 } })\n\t\t\t\tconst data = res && res.data\n\t\t\t\tconst rows = Array.isArray(data) ? data : ((data && data.results) || [])\n\t\t\t\tconst first = rows[0]\n\t\t\t\tconst id = first && (first.id || (first['@self'] && first['@self'].id))\n\t\t\t\tif (id && (this.selected === undefined || this.selected === '') && this.readWorkspace() === undefined) {\n\t\t\t\t\tthis.selected = String(id)\n\t\t\t\t\tthis.writeWorkspace(String(id))\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Nothing selected: the siblings wait for a pick.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an `endpointSource` (array of options at\n\t\t * responsePath). Fail-safe: a failed fetch leaves an empty list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromEndpoint() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst payload = await fetchEndpointSource(this.content.endpointSource, {\n\t\t\t\t\tworkspace: this.readWorkspaceBag(),\n\t\t\t\t})\n\t\t\t\tthis.fetchedOptions = Array.isArray(payload) ? payload : []\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an OpenRegister `/grouped` facet — each distinct\n\t\t * `groupBy` value becomes an option with its object count. Fail-safe.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromOrSource() {\n\t\t\tconst src = this.content.source\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/grouped',\n\t\t\t\t\t{ register: src.register, schema: src.schema },\n\t\t\t\t)\n\t\t\t\tconst params = { groupBy: src.groupBy, metric: 'count' }\n\t\t\t\tconst filter = resolveFilterTokens(src.filter || {}, { workspace: this.readWorkspaceBag() })\n\t\t\t\tfor (const [k, v] of Object.entries(filter)) {\n\t\t\t\t\tif (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[`filter[${k}]`] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tconst groups = (res && res.data && res.data.groups) || []\n\t\t\t\tthis.fetchedOptions = groups\n\t\t\t\t\t.filter((g) => g.key !== null && g.key !== undefined && g.key !== '')\n\t\t\t\t\t.map((g) => ({ value: g.key, label: String(g.key), count: Number(g.value) || 0 }))\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an option is the active selection.\n\t\t *\n\t\t * @param {object} option The option.\n\t\t * @return {boolean}\n\t\t */\n\t\tisActive(option) {\n\t\t\treturn String(option.value) === String(this.selected ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Radio-list pick handler.\n\t\t *\n\t\t * @param {object} option The picked option.\n\t\t * @return {void}\n\t\t */\n\t\tonRadioPick(option) {\n\t\t\tthis.applySelection(option.value)\n\t\t},\n\n\t\t/**\n\t\t * Switch handler: write `onValue` or `offValue`.\n\t\t *\n\t\t * @param {boolean} on Whether the switch is on.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-toggle-and-a-select-are-page-controls\n\t\t */\n\t\tonToggle(on) {\n\t\t\tthis.applySelection(on ? this.onValue : this.offValue)\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler.\n\t\t *\n\t\t * @param {object|null} option The picked option object.\n\t\t * @return {void}\n\t\t */\n\t\tonSelect(option) {\n\t\t\tthis.applySelection(option ? option.value : '')\n\t\t},\n\n\t\t/**\n\t\t * Apply a new selection: mirror it locally, write it into the workspace\n\t\t * context (so sibling widgets refetch), and emit `@change`.\n\t\t *\n\t\t * @param {unknown} value The new value.\n\t\t * @return {void}\n\t\t */\n\t\t/**\n\t\t * The value an input starts with: `content.default`, else the current\n\t\t * quarter or year for those types, else empty. For a quarter or year\n\t\t * input, `default: \"previous\"` is the last complete one (DqTermijnen\n\t\t * opens on the last complete quarter).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tinputDefault() {\n\t\t\tconst today = new Date()\n\t\t\tif (this.content.default === 'previous' && this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(new Date(today.getFullYear(), today.getMonth() - 3, 1))\n\t\t\t}\n\t\t\tif (this.content.default === 'previous' && this.inputType === 'year') {\n\t\t\t\treturn String(today.getFullYear() - 1)\n\t\t\t}\n\t\t\tif (this.content.default !== undefined && this.content.default !== null) {\n\t\t\t\treturn String(this.content.default)\n\t\t\t}\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(today)\n\t\t\t}\n\t\t\treturn this.inputType === 'year' ? String(today.getFullYear()) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask the table named by `exportTable.exportId` for its rows as CSV.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-export-table/specs/workspace-filter-export-table/spec.md#requirement-a-workspace-filter-input-can-export-the-table-it-loads\n\t\t */\n\t\texportTable() {\n\t\t\temit('cn:widget:export', { exportId: this.exportTableId })\n\t\t},\n\n\t\t/**\n\t\t * Load the input's text into the workspace, or say why it is refused.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tsubmitInput() {\n\t\t\tconst value = String(this.draft || '').trim()\n\t\t\tconst pattern = this.inputPattern\n\t\t\tif (value === '' || (pattern && !pattern.test(value))) {\n\t\t\t\tthis.inputError = this.inputType === 'quarter'\n\t\t\t\t\t? t('nextcloud-vue', 'Enter a quarter as YYYY-Qn, for example 2026-Q3.')\n\t\t\t\t\t: (this.inputType === 'year' ? t('nextcloud-vue', 'Enter a year as four digits, for example 2026.') : t('nextcloud-vue', 'This value has the wrong form.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.inputError = ''\n\t\t\tthis.applySelection(value)\n\t\t},\n\n\t\tapplySelection(value) {\n\t\t\tthis.selected = value\n\t\t\tthis.writeWorkspace(value)\n\t\t\tthis.writeAddress(value)\n\t\t\t/**\n\t\t\t * @event change Emitted when the selection changes. Payload: `{ key, value }`.\n\t\t\t */\n\t\t\tthis.$emit('change', { key: this.writeKey, value })\n\t\t},\n\n\t\t/**\n\t\t * The unwrapped workspace bag (or `{}`).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\treadWorkspaceBag() {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn ('value' in holder) ? (holder.value || {}) : holder\n\t\t},\n\n\t\t/**\n\t\t * Read the current workspace value for this widget's key (undefined\n\t\t * when unset).\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\treadWorkspace() {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst bag = this.readWorkspaceBag()\n\t\t\treturn bag[this.writeKey]\n\t\t},\n\n\t\t/**\n\t\t * Write a value into the reactive workspace bag under this widget's key\n\t\t * (the CnInteractionFormWidget write pattern — replace-in-place for the\n\t\t * unwrapped bag, `.value` for the raw-ref shape).\n\t\t *\n\t\t * @param {unknown} value The value to write.\n\t\t * @return {void}\n\t\t */\n\t\twriteWorkspace(value) {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [this.writeKey]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[this.writeKey] = value\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-workspace-filter-widget__form {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 12px 16px;\n}\n\n.cn-workspace-filter-widget__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-workspace-filter-widget__field-label {\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__input {\n\tbox-sizing: border-box;\n\tmin-height: var(--default-clickable-area, 34px);\n\tmargin: 0;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-workspace-filter-widget__input[aria-invalid='true'] {\n\tborder-color: var(--color-error);\n}\n\n.cn-workspace-filter-widget__input-error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n\n.cn-workspace-filter-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\twidth: 100%;\n}\n\n.cn-workspace-filter-widget__label {\n\tmargin: 0;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-workspace-filter-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* The chips: the compact segmented group, left, in the card the grid draws. */\n.cn-workspace-filter-widget--chips {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n}\n\n/* A bar: its controls in one row, an `align: \"end\"` control pushed right. */\n.cn-workspace-filter-widget--bar {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px 16px;\n}\n\n/* An inline control sits in a bar: label left of the control, width to its content. */\n.cn-workspace-filter-widget--inline {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\twidth: auto;\n}\n\n.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__label {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--end {\n\tmargin-inline-start: auto;\n}\n\n.cn-workspace-filter-widget--end ~ .cn-workspace-filter-widget--end {\n\tmargin-inline-start: 0;\n}\n\n.cn-workspace-filter-widget__toggle {\n\tfont-weight: 600;\n}\n\n/* The start card: text left, control (and link) right, as PqDashboard's \"Contact starten\". */\n.cn-workspace-filter-widget--start {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 16px 24px;\n}\n\n.cn-workspace-filter-widget__text {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n}\n\n.cn-workspace-filter-widget__title {\n\tmargin: 0 0 4px;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__description {\n\tmargin: 0;\n\tmax-width: 420px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--start .cn-workspace-filter-widget__control,\n.cn-workspace-filter-widget--start > .v-select {\n\tflex: 0 1 480px;\n\tmin-width: 240px;\n}\n\n.cn-workspace-filter-widget__link {\n\tfont-weight: 600;\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n\twhite-space: nowrap;\n}\n\n.cn-workspace-filter-widget__count {\n\tmargin-inline-start: 6px;\n\tpadding: 0 6px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n/* On a phone the bar's controls take a row each (the chips already wrap), and\n a switch and a select are 44px touch targets. */\n@media (max-width: 640px) {\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--inline {\n\t\tflex: 1 1 100%;\n\t}\n\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--end {\n\t\tmargin-inline-start: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__toggle {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.v-select) {\n\t\tflex: 1 1 auto;\n\t\tmin-width: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.vs__dropdown-toggle) {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["CnResourceSelect","CnSegmentedControl","t"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"CnWorkspaceFilterWidget.vue3.js","sources":["../../../../src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue?vue&type=template&id=59cf3a24&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-workspace-filter-widget\"\n\t\t:class=\"{\n\t\t\t'cn-workspace-filter-widget--start': isStart,\n\t\t\t'cn-workspace-filter-widget--chips': style === 'chips',\n\t\t\t'cn-workspace-filter-widget--bar': isBar,\n\t\t\t'cn-workspace-filter-widget--inline': content.inline === true,\n\t\t\t'cn-workspace-filter-widget--end': content.align === 'end',\n\t\t}\"\n\t\tdata-testid=\"cn-workspace-filter-widget\">\n\t\t<!-- The start card (`layout: \"start\"`): a title and one line of\n\t\t guidance beside the control, as the \"Contact starten\" card. -->\n\t\t<div v-if=\"isStart && (title || description)\" class=\"cn-workspace-filter-widget__text\">\n\t\t\t<h3 v-if=\"title\" class=\"cn-workspace-filter-widget__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h3>\n\t\t\t<p v-if=\"description\" class=\"cn-workspace-filter-widget__description\">\n\t\t\t\t{{ description }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- A bar (`layout: \"bar\"`): its `controls` side by side in one row,\n\t\t each a workspace filter of its own (chips, a switch, a select). -->\n\t\t<template v-if=\"isBar\">\n\t\t\t<CnWorkspaceFilterWidget\n\t\t\t\tv-for=\"(control, index) in barControls\"\n\t\t\t\t:key=\"index\"\n\t\t\t\t:content=\"control\"\n\t\t\t\t@change=\"$emit('change', $event)\" />\n\t\t</template>\n\n\t\t<!-- An input with a load button (`style: \"input\"`): the value goes to\n\t\t the workspace only when it is loaded, and only when it is valid. -->\n\t\t<form\n\t\t\tv-if=\"!isBar && style === 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__form\"\n\t\t\tnovalidate\n\t\t\tdata-testid=\"cn-workspace-filter-form\"\n\t\t\t@submit.prevent=\"submitInput\">\n\t\t\t<div class=\"cn-workspace-filter-widget__field\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-workspace-filter-widget__field-label\">{{ tr(label) }}</label>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tv-model=\"draft\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t:inputmode=\"inputType === 'year' ? 'numeric' : 'text'\"\n\t\t\t\t\t:aria-invalid=\"inputError ? 'true' : 'false'\"\n\t\t\t\t\t:aria-describedby=\"inputError ? `${inputId}-error` : undefined\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input\">\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"inputError\"\n\t\t\t\t\t:id=\"`${inputId}-error`\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input-error\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input-error\">\n\t\t\t\t\t{{ inputError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\" variant=\"primary\" data-testid=\"cn-workspace-filter-submit\">\n\t\t\t\t{{ tr(content.submitLabel || '') || loadLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"exportTableId\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__export\"\n\t\t\t\tdata-testid=\"cn-workspace-filter-export\"\n\t\t\t\t@click=\"exportTable\">\n\t\t\t\t{{ tr(content.exportTable.label || '') || exportLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<p v-if=\"!isBar && label && style !== 'chips' && style !== 'toggle' && style !== 'input'\" class=\"cn-workspace-filter-widget__label\">\n\t\t\t{{ tr(label) }}\n\t\t</p>\n\n\t\t<!-- An object picker (`objectSource`): searches OpenRegister on the\n\t\t server, so it reaches every object, not a fetched page. -->\n\t\t<CnResourceSelect\n\t\t\tv-if=\"!isBar && style !== 'input' && objectSource\"\n\t\t\tclass=\"cn-workspace-filter-widget__control\"\n\t\t\t:register=\"objectSource.register\"\n\t\t\t:schema=\"objectSource.schema\"\n\t\t\t:labelField=\"objectSource.labelField || 'title'\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? '' : String(selected)\"\n\t\t\t:placeholder=\"tr(objectSource.placeholder || '')\"\n\t\t\t:ariaLabelCombobox=\"tr(objectSource.ariaLabel || '') || title || label || writeKey\"\n\t\t\t:preload=\"objectSource.preload !== false\"\n\t\t\t:clearable=\"Boolean(content.allLabel)\"\n\t\t\t:allowCreate=\"false\"\n\t\t\tdata-testid=\"cn-workspace-filter-object\"\n\t\t\t@update:modelValue=\"applySelection($event || '')\" />\n\n\t\t<div v-else-if=\"loading && style !== 'input'\" class=\"cn-workspace-filter-widget__status\">\n\t\t\t{{ loadingLabel }}\n\t\t</div>\n\n\t\t<!-- Chips style (screens-page-lenses): one compact segmented group,\n\t\t a count after each label, arrow keys move the choice. -->\n\t\t<CnSegmentedControl\n\t\t\tv-else-if=\"style === 'chips'\"\n\t\t\tclass=\"cn-workspace-filter-widget__chips\"\n\t\t\tsize=\"compact\"\n\t\t\t:options=\"chipOptions\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? null : String(selected)\"\n\t\t\t:ariaLabel=\"tr(label) || writeKey\"\n\t\t\tdata-testid=\"cn-workspace-filter-chips\"\n\t\t\t@update:modelValue=\"applySelection\" />\n\n\t\t<!-- Toggle style (screens-page-controls): a switch that writes\n\t\t `onValue` / `offValue` (true / false) to the key. -->\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-else-if=\"style === 'toggle'\"\n\t\t\tclass=\"cn-workspace-filter-widget__toggle\"\n\t\t\ttype=\"switch\"\n\t\t\t:modelValue=\"toggleOn\"\n\t\t\tdata-testid=\"cn-workspace-filter-toggle\"\n\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t{{ tr(label) }}\n\t\t</NcCheckboxRadioSwitch>\n\n\t\t<!-- Select style -->\n\t\t<NcSelect\n\t\t\tv-else-if=\"style === 'select'\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"selectOptions\"\n\t\t\t:clearable=\"false\"\n\t\t\t:inputLabel=\"content.inline ? '' : (tr(label) || writeKey)\"\n\t\t\t:labelOutside=\"content.inline === true\"\n\t\t\t:ariaLabelCombobox=\"tr(label) || writeKey\"\n\t\t\tlabel=\"label\"\n\t\t\tdata-testid=\"cn-workspace-filter-select\"\n\t\t\t@update:modelValue=\"onSelect\" />\n\n\t\t<!-- Radio-list style (default) -->\n\t\t<ul v-else-if=\"!isBar && style !== 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__list\"\n\t\t\trole=\"radiogroup\"\n\t\t\t:aria-label=\"tr(label) || writeKey\">\n\t\t\t<li\n\t\t\t\tv-for=\"option in selectOptions\"\n\t\t\t\t:key=\"String(option.value)\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__item\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"radioGroupName\"\n\t\t\t\t\t:modelValue=\"isActive(option) ? String(option.value) : ''\"\n\t\t\t\t\t:value=\"String(option.value)\"\n\t\t\t\t\t:data-testid=\"`cn-workspace-filter-option-${option.value}`\"\n\t\t\t\t\t@update:modelValue=\"onRadioPick(option)\">\n\t\t\t\t\t<span class=\"cn-workspace-filter-widget__option-label\">{{ option.label }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"showCounts && option.count !== undefined && option.count !== null\"\n\t\t\t\t\t\tclass=\"cn-workspace-filter-widget__count\">{{ option.count }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<component\n\t\t\t:is=\"startLink.to ? 'router-link' : 'a'\"\n\t\t\tv-if=\"startLink\"\n\t\t\t:to=\"startLink.to || undefined\"\n\t\t\t:href=\"startLink.href || undefined\"\n\t\t\tclass=\"cn-workspace-filter-widget__link\"\n\t\t\tdata-testid=\"cn-workspace-filter-link\">\n\t\t\t{{ startLink.label }}\n\t\t</component>\n\t</div>\n</template>\n\n<script>\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fetchListTotal } from '../../utils/fetchFilterCounts.js'\nimport { quarterKey } from '../../utils/periodOptions.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnWorkspaceFilterWidget — a dashboard choice-list that writes the selected\n * value into the page workspace context so sibling widgets refetch (#91\n * Wave 3, the `workspace-filter` widget).\n *\n * Options come from ONE of three sources (checked in order):\n * 1. static `options[]` — each `{ value, label, count? }`.\n * 2. an OpenRegister `source` — `{ register, schema, groupBy, filter? }`,\n * fetched from OR's `/grouped` facet so each distinct value becomes an\n * option with its object `count`.\n * 3. an `endpointSource` — `{ url, params?, responsePath? }` returning an\n * array of `{ value, label, count? }` (or `{ id, name }` / bare strings,\n * normalised).\n *\n * The chosen value is written to the workspace context key named by `writes`\n * (`\"@workspace.<key>\"` or a bare `\"<key>\"`). CnDashboardPage provides\n * `cnWorkspaceContext`; every sibling widget whose declarative source\n * interpolates `@workspace.<key>` re-resolves its tokens and refetches when\n * the selection changes — the pipelinq WerkplekQueueFilter contract.\n *\n * An optional leading \"All\" option (`allLabel`) clears the key (writes the\n * empty string), so an optional `@workspace.<key>?` token drops and siblings\n * show the unfiltered set.\n *\n * ```js\n * content: {\n * label: 'Queue',\n * writes: '@workspace.queue',\n * style: 'radio', // 'radio' (default) | 'select' | 'chips'\n * allLabel: 'All',\n * showCounts: true,\n * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },\n * }\n * ```\n */\nexport default {\n\tname: 'CnWorkspaceFilterWidget',\n\n\tcomponents: { CnResourceSelect, CnSegmentedControl, NcButton, NcSelect, NcCheckboxRadioSwitch },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context. CnDashboardPage provides a `ref({})`;\n\t\t * Vue 2.7's Options-API inject AUTO-UNWRAPS it, so this is the plain\n\t\t * reactive bag (the raw-ref `{ value }` shape is also handled on write).\n\t\t * Null on pages without one (the widget then just emits `@change`).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** Host translate function, for the start card's texts. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob.\n\t\t *\n\t\t * Start card keys (abstract-start-card): `layout: \"start\"` draws\n\t\t * `title` and `description` beside the control, and `link`\n\t\t * (`{ label, route? | href? }`) after it. `objectSource`\n\t\t * (`{ register, schema, labelField?, placeholder?, ariaLabel?, preload? }`)\n\t\t * makes the control an OpenRegister object picker that searches on the\n\t\t * server and writes the picked object's id; without a selection and\n\t\t * without `allLabel` it selects the first object.\n\t\t *\n\t\t * Chips (screens-page-lenses): `style: \"chips\"` draws the options as one\n\t\t * compact segmented group with a count after each label. An option's\n\t\t * `countFrom` (`{ register, schema, filter? }`, or a list of them that\n\t\t * are added up) counts that list; a static `count` is used otherwise.\n\t\t * `urlKey` keeps the choice in the address (`?<urlKey>=<value>`), and\n\t\t * the address wins over `default` on load.\n\t\t *\n\t\t * Page controls (screens-page-controls): `style: \"toggle\"` is a switch\n\t\t * that writes `onValue` / `offValue` (true / false); `layout: \"bar\"`\n\t\t * with `controls` draws several controls side by side in one row, and\n\t\t * `align: \"end\"` pushes a control to the right edge.\n\t\t *\n\t\t * Input (workspace-filter-input): `style: \"input\"` draws a labelled text\n\t\t * field and a load button (`submitLabel`). The value is written only\n\t\t * when it is loaded and only when valid: `inputType: \"quarter\"` reads\n\t\t * `YYYY-Qn` and `\"year\"` reads `YYYY`, both seeded with the current one;\n\t\t * any other input takes a `pattern` (a regular expression) if given.\n\t\t * `exportTable: { exportId, label? }` adds a button beside the load\n\t\t * button that asks the object table with that `exportId` for its rows\n\t\t * as CSV (DqTermijnen \"CSV exporteren\").\n\t\t *\n\t\t * @type {{label?: string, submitLabel?: string, exportTable?: {exportId: string, label?: string}, inputType?: string, pattern?: string, controls?: Array<object>, onValue?: unknown, offValue?: unknown, align?: string, urlKey?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, objectSource?: object, default?: (string|number), layout?: string, title?: string, description?: string, link?: object}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['change'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The input's text before it is loaded (`style: \"input\"`). */\n\t\t\tdraft: '',\n\t\t\t/** Why the input's text was refused, or ''. */\n\t\t\tinputError: '',\n\t\t\t/** Fetched options (from source / endpointSource); static options use content.options directly. */\n\t\t\tfetchedOptions: null,\n\t\t\t/** True while options are being fetched. */\n\t\t\tloading: false,\n\t\t\t/** The currently-selected value (mirrors the workspace key). */\n\t\t\tselected: undefined,\n\t\t\t/** Counted totals of the options that ask (`countFrom`), by option position. */\n\t\t\toptionCounts: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Section label. */\n\t\tlabel() {\n\t\t\treturn this.content.label || ''\n\t\t},\n\n\t\t/** Whether the widget draws the start card. */\n\t\tisStart() {\n\t\t\treturn this.content.layout === 'start'\n\t\t},\n\n\t\t/** The start card's title, translated. */\n\t\ttitle() {\n\t\t\treturn this.tr(this.content.title || '')\n\t\t},\n\n\t\t/** The start card's guidance line, translated. */\n\t\tdescription() {\n\t\t\treturn this.tr(this.content.description || '')\n\t\t},\n\n\t\t/**\n\t\t * The link after the control, or null.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t */\n\t\tstartLink() {\n\t\t\tconst link = this.content.link\n\t\t\tif (!link || typeof link !== 'object' || !link.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route && typeof link.route === 'object' && link.route.name) {\n\t\t\t\treturn { label: this.tr(link.label), to: link.route }\n\t\t\t}\n\t\t\tif (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\treturn { label: this.tr(link.label), href: link.href }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The object picker declaration, or null.\n\t\t *\n\t\t * @return {{register: string, schema: string, labelField?: string}|null}\n\t\t */\n\t\tobjectSource() {\n\t\t\tconst src = this.content.objectSource\n\t\t\treturn src && typeof src === 'object' && src.register && src.schema ? src : null\n\t\t},\n\n\t\t/** Choice style: 'chips', 'select' or 'radio' (default). */\n\t\tstyle() {\n\t\t\treturn ['select', 'chips', 'toggle', 'input'].includes(this.content.style) ? this.content.style : 'radio'\n\t\t},\n\n\t\t/**\n\t\t * The chips: each option with its label translated and its count,\n\t\t * the static one or the counted one.\n\t\t *\n\t\t * @return {Array<{value: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tchipOptions() {\n\t\t\treturn this.displayOptions.map((option, index) => {\n\t\t\t\tconst counted = this.optionCounts[index]\n\t\t\t\tconst count = counted !== undefined && counted !== null ? counted : option.count\n\t\t\t\tconst chip = { value: String(option.value), label: this.tr(option.label) }\n\t\t\t\tif (this.showCounts && Number.isFinite(count)) {\n\t\t\t\t\tchip.count = count\n\t\t\t\t}\n\t\t\t\treturn chip\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is a bar of controls (`layout: \"bar\"`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-bar-holds-the-pages-controls-in-one-row\n\t\t */\n\t\tisBar() {\n\t\t\treturn this.content.layout === 'bar' && Array.isArray(this.content.controls)\n\t\t},\n\n\t\t/**\n\t\t * The bar's controls, each an inline workspace filter of its own.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tbarControls() {\n\t\t\treturn this.content.controls\n\t\t\t\t.filter((control) => control && typeof control === 'object')\n\t\t\t\t.map((control) => ({ ...control, inline: true }))\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when on. */\n\t\tonValue() {\n\t\t\treturn this.content.onValue !== undefined ? this.content.onValue : true\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when off. */\n\t\toffValue() {\n\t\t\treturn this.content.offValue !== undefined ? this.content.offValue : false\n\t\t},\n\n\t\t/** @return {boolean} Whether the switch is on. */\n\t\ttoggleOn() {\n\t\t\treturn this.selected !== undefined && String(this.selected) === String(this.onValue)\n\t\t},\n\n\t\t/**\n\t\t * The address key that carries the choice (`urlKey`), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\turlKey() {\n\t\t\treturn typeof this.content.urlKey === 'string' ? this.content.urlKey : ''\n\t\t},\n\n\t\t/** Whether to render per-option counts. */\n\t\tshowCounts() {\n\t\t\treturn this.content.showCounts !== false\n\t\t},\n\n\t\t/**\n\t\t * What an input reads: `quarter`, `year` or `text`.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tinputType() {\n\t\t\treturn ['quarter', 'year'].includes(this.content.inputType) ? this.content.inputType : 'text'\n\t\t},\n\n\t\t/**\n\t\t * The form an input's text must have, or null for any.\n\t\t *\n\t\t * @return {RegExp|null}\n\t\t */\n\t\tinputPattern() {\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn /^\\d{4}-Q[1-4]$/\n\t\t\t}\n\t\t\tif (this.inputType === 'year') {\n\t\t\t\treturn /^\\d{4}$/\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.content.pattern ? new RegExp(this.content.pattern) : null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/** The input's id, unique per key. */\n\t\tinputId() {\n\t\t\treturn `cn-wsf-input-${this.writeKey || 'value'}`\n\t\t},\n\n\t\t/** The load button's label when the content names none. */\n\t\tloadLabel() {\n\t\t\treturn t('nextcloud-vue', 'Load')\n\t\t},\n\n\t\t/** @return {string} The library label of the table export button. */\n\t\texportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Export CSV')\n\t\t},\n\n\t\t/** @return {string} The `exportId` of the table the input exports, or ''. */\n\t\texportTableId() {\n\t\t\tconst target = this.content && this.content.exportTable\n\t\t\treturn target && typeof target.exportId === 'string' ? target.exportId : ''\n\t\t},\n\n\t\t/** The bare workspace key the selection writes (strips a `@workspace.` / `@page.` prefix). */\n\t\twriteKey() {\n\t\t\tconst w = this.content.writes || ''\n\t\t\treturn String(w).replace(/^@(workspace|page)\\./, '')\n\t\t},\n\n\t\t/** A stable radiogroup name so the radios are mutually exclusive. */\n\t\tradioGroupName() {\n\t\t\treturn `cn-wsf-${this.writeKey || 'filter'}`\n\t\t},\n\n\t\t/** The option list actually rendered — the optional \"All\" entry prepended. */\n\t\tdisplayOptions() {\n\t\t\tconst base = this.normalisedOptions\n\t\t\tif (this.content.allLabel) {\n\t\t\t\treturn [{ value: '', label: this.content.allLabel }, ...base]\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Normalised `{ value, label, count? }` options from whichever source is configured. */\n\t\tnormalisedOptions() {\n\t\t\tconst raw = this.fetchedOptions !== null\n\t\t\t\t? this.fetchedOptions\n\t\t\t\t: (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\treturn raw.map((o) => this.normaliseOption(o)).filter((o) => o.value !== undefined && o.value !== null)\n\t\t},\n\n\t\t/**\n\t\t * The options a select or the radio list draws, each label run through\n\t\t * the host's translate (the chips did already; the bar's sort select\n\t\t * showed its English keys beside a translated switch).\n\t\t *\n\t\t * @return {Array<{value: unknown, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-workspace-filter-translate/specs/workspace-filter/spec.md#requirement-every-workspace-filter-style-translates-its-texts\n\t\t */\n\t\tselectOptions() {\n\t\t\treturn this.displayOptions.map((option) => ({ ...option, label: this.tr(option.label) }))\n\t\t},\n\n\t\t/** The selected option object (for NcSelect). */\n\t\tselectedOption() {\n\t\t\treturn this.selectOptions.find((o) => String(o.value) === String(this.selected)) || null\n\t\t},\n\n\t\t/**\n\t\t * The reactive workspace value for this key — watched so an external\n\t\t * write (another widget) syncs the local selection.\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\tworkspaceValue() {\n\t\t\treturn this.readWorkspace()\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** Re-fetch options when a dynamic source changes. */\n\t\tcontent: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Track external workspace changes (another widget writing the same key).\n\t\t *\n\t\t * @param {unknown} val The new workspace value for this key.\n\t\t */\n\t\tworkspaceValue(val) {\n\t\t\tif (val !== undefined) {\n\t\t\t\tthis.selected = val\n\t\t\t}\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Seed the selection: existing workspace value → content.default → the\n\t\t// \"All\" clear option (empty) when present, else the first option once\n\t\t// loaded (handled in loadOptions).\n\t\tconst fromAddress = this.readAddress()\n\t\tconst existing = this.readWorkspace()\n\t\tif (this.style === 'input') {\n\t\t\tconst seed = existing !== undefined && existing !== null && existing !== '' ? String(existing) : this.inputDefault()\n\t\t\tthis.draft = seed\n\t\t\tthis.selected = seed\n\t\t\tif (seed !== '' && seed !== existing) {\n\t\t\t\tthis.writeWorkspace(seed)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (fromAddress !== undefined) {\n\t\t\tthis.selected = fromAddress\n\t\t\tthis.writeWorkspace(fromAddress)\n\t\t} else if (existing !== undefined) {\n\t\t\tthis.selected = existing\n\t\t} else if (this.content.default !== undefined) {\n\t\t\tthis.selected = this.content.default\n\t\t\tthis.writeWorkspace(this.content.default)\n\t\t} else if (this.style === 'toggle') {\n\t\t\t// A switch starts off, and says so, so a condition on its key holds.\n\t\t\tthis.selected = this.offValue\n\t\t\tthis.writeWorkspace(this.offValue)\n\t\t}\n\t\tthis.loadOptions()\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = () => this.loadCounts()\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tthis.loadCounts()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The choice named in the address (`?<urlKey>=…`), when it is one of\n\t\t * the options; undefined otherwise.\n\t\t *\n\t\t * @return {string|undefined}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\treadAddress() {\n\t\t\tif (!this.urlKey || !this.$route || !this.$route.query) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst raw = this.$route.query[this.urlKey]\n\t\t\tif (this.style === 'toggle') {\n\t\t\t\tif (raw === undefined) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t\treturn [this.onValue, this.offValue].find((value) => String(value) === String(raw))\n\t\t\t}\n\t\t\tconst known = this.displayOptions.some((option) => String(option.value) === String(raw))\n\t\t\treturn known ? String(raw) : undefined\n\t\t},\n\n\t\t/**\n\t\t * Write the choice to the address, replacing the history entry and\n\t\t * keeping the other query keys.\n\t\t *\n\t\t * @param {unknown} value The chosen value.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\twriteAddress(value) {\n\t\t\tif (!this.urlKey || !this.$router || !this.$route) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst query = this.$route.query || {}\n\t\t\tif (String(query[this.urlKey]) === String(value)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst result = this.$router.replace({ query: { ...query, [this.urlKey]: String(value) } })\n\t\t\tif (result && typeof result.catch === 'function') {\n\t\t\t\tresult.catch(() => {})\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Count the lists behind the options that ask (`countFrom`: a list\n\t\t * `{ register, schema, filter? }`, or several that are added up). One\n\t\t * list request each; an option whose count failed shows none.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tasync loadCounts() {\n\t\t\tconst options = this.displayOptions\n\t\t\tconst seq = (this.countSeq = (this.countSeq || 0) + 1)\n\t\t\tconst ctx = { workspace: this.readWorkspaceBag() }\n\t\t\tawait Promise.all(options.map(async (option, index) => {\n\t\t\t\tconst raw = (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\t\t\t.find((candidate) => candidate && typeof candidate === 'object' && String(candidate.value ?? candidate.id) === String(option.value))\n\t\t\t\tconst from = raw ? raw.countFrom : null\n\t\t\t\tconst lists = (Array.isArray(from) ? from : [from]).filter((list) => list && typeof list === 'object' && list.register && list.schema)\n\t\t\t\tif (lists.length === 0) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet total\n\t\t\t\ttry {\n\t\t\t\t\tconst parts = await Promise.all(lists.map((list) => fetchListTotal(list.register, list.schema, list.filter || {}, ctx)))\n\t\t\t\t\tif (parts.some((part) => part === null)) {\n\t\t\t\t\t\tthrow new Error('no total')\n\t\t\t\t\t}\n\t\t\t\t\ttotal = parts.reduce((sum, part) => sum + part, 0)\n\t\t\t\t} catch {\n\t\t\t\t\ttotal = null\n\t\t\t\t}\n\t\t\t\tif (seq === this.countSeq) {\n\t\t\t\t\tthis.optionCounts = { ...this.optionCounts, [index]: total }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Normalise a raw option into `{ value, label, count? }`. Accepts\n\t\t * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR\n\t\t * facet), or a bare string/number.\n\t\t *\n\t\t * @param {unknown} o The raw option.\n\t\t * @return {{value: unknown, label: string, count?: number}}\n\t\t */\n\t\tnormaliseOption(o) {\n\t\t\tif (o === null || o === undefined) {\n\t\t\t\treturn { value: undefined, label: '' }\n\t\t\t}\n\t\t\tif (typeof o !== 'object') {\n\t\t\t\treturn { value: o, label: String(o) }\n\t\t\t}\n\t\t\tconst value = o.value !== undefined ? o.value : (o.id !== undefined ? o.id : o.key)\n\t\t\tconst label = o.label !== undefined ? o.label : (o.name !== undefined ? o.name : String(value))\n\t\t\tconst out = { value, label: String(label) }\n\t\t\tif (o.count !== undefined) {\n\t\t\t\tout.count = o.count\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Load options for the active source (static content.options need no\n\t\t * fetch). Seeds the first option as the selection when nothing is set\n\t\t * and no \"All\" clear option exists.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tif (this.objectSource) {\n\t\t\t\tawait this.seedFirstObject()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.content.endpointSource && this.content.endpointSource.url) {\n\t\t\t\tawait this.loadFromEndpoint()\n\t\t\t} else if (this.content.source && this.content.source.schema) {\n\t\t\t\tawait this.loadFromOrSource()\n\t\t\t} else {\n\t\t\t\tthis.fetchedOptions = null\n\t\t\t}\n\t\t\t// Default selection: when nothing is selected and there's no \"All\"\n\t\t\t// clear affordance, adopt the first option so siblings have a value.\n\t\t\tif ((this.selected === undefined || this.selected === '') && !this.content.allLabel) {\n\t\t\t\tconst first = this.normalisedOptions[0]\n\t\t\t\tif (first && this.readWorkspace() === undefined && this.content.default === undefined) {\n\t\t\t\t\tthis.selected = first.value\n\t\t\t\t\tthis.writeWorkspace(first.value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The object picker's default: with nothing selected, no `default` and\n\t\t * no `allLabel`, select the first object the source lists, so the page\n\t\t * always has one in focus. Fail-safe: a failed read selects nothing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync seedFirstObject() {\n\t\t\tif ((this.selected !== undefined && this.selected !== '') || this.content.allLabel || this.content.default !== undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst src = this.objectSource\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: src.register, schema: src.schema })\n\t\t\t\tconst res = await axios.get(url, { params: { _limit: 1 } })\n\t\t\t\tconst data = res && res.data\n\t\t\t\tconst rows = Array.isArray(data) ? data : ((data && data.results) || [])\n\t\t\t\tconst first = rows[0]\n\t\t\t\tconst id = first && (first.id || (first['@self'] && first['@self'].id))\n\t\t\t\tif (id && (this.selected === undefined || this.selected === '') && this.readWorkspace() === undefined) {\n\t\t\t\t\tthis.selected = String(id)\n\t\t\t\t\tthis.writeWorkspace(String(id))\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Nothing selected: the siblings wait for a pick.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an `endpointSource` (array of options at\n\t\t * responsePath). Fail-safe: a failed fetch leaves an empty list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromEndpoint() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst payload = await fetchEndpointSource(this.content.endpointSource, {\n\t\t\t\t\tworkspace: this.readWorkspaceBag(),\n\t\t\t\t})\n\t\t\t\tthis.fetchedOptions = Array.isArray(payload) ? payload : []\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an OpenRegister `/grouped` facet — each distinct\n\t\t * `groupBy` value becomes an option with its object count. Fail-safe.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromOrSource() {\n\t\t\tconst src = this.content.source\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/grouped',\n\t\t\t\t\t{ register: src.register, schema: src.schema },\n\t\t\t\t)\n\t\t\t\tconst params = { groupBy: src.groupBy, metric: 'count' }\n\t\t\t\tconst filter = resolveFilterTokens(src.filter || {}, { workspace: this.readWorkspaceBag() })\n\t\t\t\tfor (const [k, v] of Object.entries(filter)) {\n\t\t\t\t\tif (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[`filter[${k}]`] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tconst groups = (res && res.data && res.data.groups) || []\n\t\t\t\tthis.fetchedOptions = groups\n\t\t\t\t\t.filter((g) => g.key !== null && g.key !== undefined && g.key !== '')\n\t\t\t\t\t.map((g) => ({ value: g.key, label: String(g.key), count: Number(g.value) || 0 }))\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an option is the active selection.\n\t\t *\n\t\t * @param {object} option The option.\n\t\t * @return {boolean}\n\t\t */\n\t\tisActive(option) {\n\t\t\treturn String(option.value) === String(this.selected ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Radio-list pick handler.\n\t\t *\n\t\t * @param {object} option The picked option.\n\t\t * @return {void}\n\t\t */\n\t\tonRadioPick(option) {\n\t\t\tthis.applySelection(option.value)\n\t\t},\n\n\t\t/**\n\t\t * Switch handler: write `onValue` or `offValue`.\n\t\t *\n\t\t * @param {boolean} on Whether the switch is on.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-toggle-and-a-select-are-page-controls\n\t\t */\n\t\tonToggle(on) {\n\t\t\tthis.applySelection(on ? this.onValue : this.offValue)\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler.\n\t\t *\n\t\t * @param {object|null} option The picked option object.\n\t\t * @return {void}\n\t\t */\n\t\tonSelect(option) {\n\t\t\tthis.applySelection(option ? option.value : '')\n\t\t},\n\n\t\t/**\n\t\t * Apply a new selection: mirror it locally, write it into the workspace\n\t\t * context (so sibling widgets refetch), and emit `@change`.\n\t\t *\n\t\t * @param {unknown} value The new value.\n\t\t * @return {void}\n\t\t */\n\t\t/**\n\t\t * The value an input starts with: `content.default`, else the current\n\t\t * quarter or year for those types, else empty.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tinputDefault() {\n\t\t\tif (this.content.default !== undefined && this.content.default !== null) {\n\t\t\t\treturn String(this.content.default)\n\t\t\t}\n\t\t\tconst today = new Date()\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(today)\n\t\t\t}\n\t\t\treturn this.inputType === 'year' ? String(today.getFullYear()) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask the table named by `exportTable.exportId` for its rows as CSV.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-export-table/specs/workspace-filter-export-table/spec.md#requirement-a-workspace-filter-input-can-export-the-table-it-loads\n\t\t */\n\t\texportTable() {\n\t\t\temit('cn:widget:export', { exportId: this.exportTableId })\n\t\t},\n\n\t\t/**\n\t\t * Load the input's text into the workspace, or say why it is refused.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tsubmitInput() {\n\t\t\tconst value = String(this.draft || '').trim()\n\t\t\tconst pattern = this.inputPattern\n\t\t\tif (value === '' || (pattern && !pattern.test(value))) {\n\t\t\t\tthis.inputError = this.inputType === 'quarter'\n\t\t\t\t\t? t('nextcloud-vue', 'Enter a quarter as YYYY-Qn, for example 2026-Q3.')\n\t\t\t\t\t: (this.inputType === 'year' ? t('nextcloud-vue', 'Enter a year as four digits, for example 2026.') : t('nextcloud-vue', 'This value has the wrong form.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.inputError = ''\n\t\t\tthis.applySelection(value)\n\t\t},\n\n\t\tapplySelection(value) {\n\t\t\tthis.selected = value\n\t\t\tthis.writeWorkspace(value)\n\t\t\tthis.writeAddress(value)\n\t\t\t/**\n\t\t\t * @event change Emitted when the selection changes. Payload: `{ key, value }`.\n\t\t\t */\n\t\t\tthis.$emit('change', { key: this.writeKey, value })\n\t\t},\n\n\t\t/**\n\t\t * The unwrapped workspace bag (or `{}`).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\treadWorkspaceBag() {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn ('value' in holder) ? (holder.value || {}) : holder\n\t\t},\n\n\t\t/**\n\t\t * Read the current workspace value for this widget's key (undefined\n\t\t * when unset).\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\treadWorkspace() {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst bag = this.readWorkspaceBag()\n\t\t\treturn bag[this.writeKey]\n\t\t},\n\n\t\t/**\n\t\t * Write a value into the reactive workspace bag under this widget's key\n\t\t * (the CnInteractionFormWidget write pattern — replace-in-place for the\n\t\t * unwrapped bag, `.value` for the raw-ref shape).\n\t\t *\n\t\t * @param {unknown} value The value to write.\n\t\t * @return {void}\n\t\t */\n\t\twriteWorkspace(value) {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [this.writeKey]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[this.writeKey] = value\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-workspace-filter-widget__form {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 12px 16px;\n}\n\n.cn-workspace-filter-widget__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-workspace-filter-widget__field-label {\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__input {\n\tbox-sizing: border-box;\n\tmin-height: var(--default-clickable-area, 34px);\n\tmargin: 0;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-workspace-filter-widget__input[aria-invalid='true'] {\n\tborder-color: var(--color-error);\n}\n\n.cn-workspace-filter-widget__input-error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n\n.cn-workspace-filter-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\twidth: 100%;\n}\n\n.cn-workspace-filter-widget__label {\n\tmargin: 0;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-workspace-filter-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* The chips: the compact segmented group, left, in the card the grid draws. */\n.cn-workspace-filter-widget--chips {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n}\n\n/* A bar: its controls in one row, an `align: \"end\"` control pushed right. */\n.cn-workspace-filter-widget--bar {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px 16px;\n}\n\n/* An inline control sits in a bar: label left of the control, width to its content. */\n.cn-workspace-filter-widget--inline {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\twidth: auto;\n}\n\n.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__label {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--end {\n\tmargin-inline-start: auto;\n}\n\n.cn-workspace-filter-widget--end ~ .cn-workspace-filter-widget--end {\n\tmargin-inline-start: 0;\n}\n\n.cn-workspace-filter-widget__toggle {\n\tfont-weight: 600;\n}\n\n/* The start card: text left, control (and link) right, as PqDashboard's \"Contact starten\". */\n.cn-workspace-filter-widget--start {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 16px 24px;\n}\n\n.cn-workspace-filter-widget__text {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n}\n\n.cn-workspace-filter-widget__title {\n\tmargin: 0 0 4px;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__description {\n\tmargin: 0;\n\tmax-width: 420px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--start .cn-workspace-filter-widget__control,\n.cn-workspace-filter-widget--start > .v-select {\n\tflex: 0 1 480px;\n\tmin-width: 240px;\n}\n\n.cn-workspace-filter-widget__link {\n\tfont-weight: 600;\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n\twhite-space: nowrap;\n}\n\n.cn-workspace-filter-widget__count {\n\tmargin-inline-start: 6px;\n\tpadding: 0 6px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n/* On a phone the bar's controls take a row each (the chips already wrap), and\n a switch and a select are 44px touch targets. */\n@media (max-width: 640px) {\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--inline {\n\t\tflex: 1 1 100%;\n\t}\n\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--end {\n\t\tmargin-inline-start: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__toggle {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.v-select) {\n\t\tflex: 1 1 auto;\n\t\tmin-width: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.vs__dropdown-toggle) {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["_createElementBlock","_openBlock","_toDisplayString","_Fragment","_createBlock","_createElementVNode","_createTextVNode","_renderList"],"mappings":"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"}
1
+ {"version":3,"file":"CnWorkspaceFilterWidget.vue3.js","sources":["../../../../src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue?vue&type=template&id=476982f2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-workspace-filter-widget\"\n\t\t:class=\"{\n\t\t\t'cn-workspace-filter-widget--start': isStart,\n\t\t\t'cn-workspace-filter-widget--chips': style === 'chips',\n\t\t\t'cn-workspace-filter-widget--bar': isBar,\n\t\t\t'cn-workspace-filter-widget--inline': content.inline === true,\n\t\t\t'cn-workspace-filter-widget--end': content.align === 'end',\n\t\t}\"\n\t\tdata-testid=\"cn-workspace-filter-widget\">\n\t\t<!-- The start card (`layout: \"start\"`): a title and one line of\n\t\t guidance beside the control, as the \"Contact starten\" card. -->\n\t\t<div v-if=\"isStart && (title || description)\" class=\"cn-workspace-filter-widget__text\">\n\t\t\t<h3 v-if=\"title\" class=\"cn-workspace-filter-widget__title\">\n\t\t\t\t{{ title }}\n\t\t\t</h3>\n\t\t\t<p v-if=\"description\" class=\"cn-workspace-filter-widget__description\">\n\t\t\t\t{{ description }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- A bar (`layout: \"bar\"`): its `controls` side by side in one row,\n\t\t each a workspace filter of its own (chips, a switch, a select). -->\n\t\t<template v-if=\"isBar\">\n\t\t\t<CnWorkspaceFilterWidget\n\t\t\t\tv-for=\"(control, index) in barControls\"\n\t\t\t\t:key=\"index\"\n\t\t\t\t:content=\"control\"\n\t\t\t\t@change=\"$emit('change', $event)\" />\n\t\t</template>\n\n\t\t<!-- An input with a load button (`style: \"input\"`): the value goes to\n\t\t the workspace only when it is loaded, and only when it is valid. -->\n\t\t<form\n\t\t\tv-if=\"!isBar && style === 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__form\"\n\t\t\tnovalidate\n\t\t\tdata-testid=\"cn-workspace-filter-form\"\n\t\t\t@submit.prevent=\"submitInput\">\n\t\t\t<div class=\"cn-workspace-filter-widget__field\">\n\t\t\t\t<label :for=\"inputId\" class=\"cn-workspace-filter-widget__field-label\">{{ tr(label) }}</label>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tv-model=\"draft\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t:inputmode=\"inputType === 'year' ? 'numeric' : 'text'\"\n\t\t\t\t\t:aria-invalid=\"inputError ? 'true' : 'false'\"\n\t\t\t\t\t:aria-describedby=\"inputError ? `${inputId}-error` : undefined\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input\">\n\t\t\t\t<p\n\t\t\t\t\tv-if=\"inputError\"\n\t\t\t\t\t:id=\"`${inputId}-error`\"\n\t\t\t\t\tclass=\"cn-workspace-filter-widget__input-error\"\n\t\t\t\t\tdata-testid=\"cn-workspace-filter-input-error\">\n\t\t\t\t\t{{ inputError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\" variant=\"primary\" data-testid=\"cn-workspace-filter-submit\">\n\t\t\t\t{{ tr(content.submitLabel || '') || loadLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"exportTableId\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__export\"\n\t\t\t\tdata-testid=\"cn-workspace-filter-export\"\n\t\t\t\t@click=\"exportTable\">\n\t\t\t\t{{ tr(content.exportTable.label || '') || exportLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<p v-if=\"!isBar && label && style !== 'chips' && style !== 'toggle' && style !== 'input'\" class=\"cn-workspace-filter-widget__label\">\n\t\t\t{{ tr(label) }}\n\t\t</p>\n\n\t\t<!-- An object picker (`objectSource`): searches OpenRegister on the\n\t\t server, so it reaches every object, not a fetched page. -->\n\t\t<CnResourceSelect\n\t\t\tv-if=\"!isBar && style !== 'input' && objectSource\"\n\t\t\tclass=\"cn-workspace-filter-widget__control\"\n\t\t\t:register=\"objectSource.register\"\n\t\t\t:schema=\"objectSource.schema\"\n\t\t\t:labelField=\"objectSource.labelField || 'title'\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? '' : String(selected)\"\n\t\t\t:placeholder=\"tr(objectSource.placeholder || '')\"\n\t\t\t:ariaLabelCombobox=\"tr(objectSource.ariaLabel || '') || title || label || writeKey\"\n\t\t\t:preload=\"objectSource.preload !== false\"\n\t\t\t:clearable=\"Boolean(content.allLabel)\"\n\t\t\t:allowCreate=\"false\"\n\t\t\tdata-testid=\"cn-workspace-filter-object\"\n\t\t\t@update:modelValue=\"applySelection($event || '')\" />\n\n\t\t<div v-else-if=\"loading && style !== 'input'\" class=\"cn-workspace-filter-widget__status\">\n\t\t\t{{ loadingLabel }}\n\t\t</div>\n\n\t\t<!-- Chips style (screens-page-lenses): one compact segmented group,\n\t\t a count after each label, arrow keys move the choice. -->\n\t\t<CnSegmentedControl\n\t\t\tv-else-if=\"style === 'chips'\"\n\t\t\tclass=\"cn-workspace-filter-widget__chips\"\n\t\t\tsize=\"compact\"\n\t\t\t:options=\"chipOptions\"\n\t\t\t:modelValue=\"selected === undefined || selected === null ? null : String(selected)\"\n\t\t\t:ariaLabel=\"tr(label) || writeKey\"\n\t\t\tdata-testid=\"cn-workspace-filter-chips\"\n\t\t\t@update:modelValue=\"applySelection\" />\n\n\t\t<!-- Toggle style (screens-page-controls): a switch that writes\n\t\t `onValue` / `offValue` (true / false) to the key. -->\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-else-if=\"style === 'toggle'\"\n\t\t\tclass=\"cn-workspace-filter-widget__toggle\"\n\t\t\ttype=\"switch\"\n\t\t\t:modelValue=\"toggleOn\"\n\t\t\tdata-testid=\"cn-workspace-filter-toggle\"\n\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t{{ tr(label) }}\n\t\t</NcCheckboxRadioSwitch>\n\n\t\t<!-- Select style -->\n\t\t<NcSelect\n\t\t\tv-else-if=\"style === 'select'\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"selectOptions\"\n\t\t\t:clearable=\"false\"\n\t\t\t:inputLabel=\"content.inline ? '' : (tr(label) || writeKey)\"\n\t\t\t:labelOutside=\"content.inline === true\"\n\t\t\t:ariaLabelCombobox=\"tr(label) || writeKey\"\n\t\t\tlabel=\"label\"\n\t\t\tdata-testid=\"cn-workspace-filter-select\"\n\t\t\t@update:modelValue=\"onSelect\" />\n\n\t\t<!-- Radio-list style (default) -->\n\t\t<ul v-else-if=\"!isBar && style !== 'input'\"\n\t\t\tclass=\"cn-workspace-filter-widget__list\"\n\t\t\trole=\"radiogroup\"\n\t\t\t:aria-label=\"tr(label) || writeKey\">\n\t\t\t<li\n\t\t\t\tv-for=\"option in selectOptions\"\n\t\t\t\t:key=\"String(option.value)\"\n\t\t\t\tclass=\"cn-workspace-filter-widget__item\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"radioGroupName\"\n\t\t\t\t\t:modelValue=\"isActive(option) ? String(option.value) : ''\"\n\t\t\t\t\t:value=\"String(option.value)\"\n\t\t\t\t\t:data-testid=\"`cn-workspace-filter-option-${option.value}`\"\n\t\t\t\t\t@update:modelValue=\"onRadioPick(option)\">\n\t\t\t\t\t<span class=\"cn-workspace-filter-widget__option-label\">{{ option.label }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"showCounts && option.count !== undefined && option.count !== null\"\n\t\t\t\t\t\tclass=\"cn-workspace-filter-widget__count\">{{ option.count }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<component\n\t\t\t:is=\"startLink.to ? 'router-link' : 'a'\"\n\t\t\tv-if=\"startLink\"\n\t\t\t:to=\"startLink.to || undefined\"\n\t\t\t:href=\"startLink.href || undefined\"\n\t\t\tclass=\"cn-workspace-filter-widget__link\"\n\t\t\tdata-testid=\"cn-workspace-filter-link\">\n\t\t\t{{ startLink.label }}\n\t\t</component>\n\t</div>\n</template>\n\n<script>\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport CnSegmentedControl from '../CnSegmentedControl/CnSegmentedControl.vue'\nimport { fetchEndpointSource } from '../../composables/useEndpointSource.js'\nimport { fetchListTotal } from '../../utils/fetchFilterCounts.js'\nimport { quarterKey } from '../../utils/periodOptions.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\n\n/**\n * CnWorkspaceFilterWidget — a dashboard choice-list that writes the selected\n * value into the page workspace context so sibling widgets refetch (#91\n * Wave 3, the `workspace-filter` widget).\n *\n * Options come from ONE of three sources (checked in order):\n * 1. static `options[]` — each `{ value, label, count? }`.\n * 2. an OpenRegister `source` — `{ register, schema, groupBy, filter? }`,\n * fetched from OR's `/grouped` facet so each distinct value becomes an\n * option with its object `count`.\n * 3. an `endpointSource` — `{ url, params?, responsePath? }` returning an\n * array of `{ value, label, count? }` (or `{ id, name }` / bare strings,\n * normalised).\n *\n * The chosen value is written to the workspace context key named by `writes`\n * (`\"@workspace.<key>\"` or a bare `\"<key>\"`). CnDashboardPage provides\n * `cnWorkspaceContext`; every sibling widget whose declarative source\n * interpolates `@workspace.<key>` re-resolves its tokens and refetches when\n * the selection changes — the pipelinq WerkplekQueueFilter contract.\n *\n * An optional leading \"All\" option (`allLabel`) clears the key (writes the\n * empty string), so an optional `@workspace.<key>?` token drops and siblings\n * show the unfiltered set.\n *\n * ```js\n * content: {\n * label: 'Queue',\n * writes: '@workspace.queue',\n * style: 'radio', // 'radio' (default) | 'select' | 'chips'\n * allLabel: 'All',\n * showCounts: true,\n * source: { register: 'pipelinq', schema: 'werkitem', groupBy: 'queue' },\n * }\n * ```\n */\nexport default {\n\tname: 'CnWorkspaceFilterWidget',\n\n\tcomponents: { CnResourceSelect, CnSegmentedControl, NcButton, NcSelect, NcCheckboxRadioSwitch },\n\n\tinject: {\n\t\t/**\n\t\t * Page-level workspace context. CnDashboardPage provides a `ref({})`;\n\t\t * Vue 2.7's Options-API inject AUTO-UNWRAPS it, so this is the plain\n\t\t * reactive bag (the raw-ref `{ value }` shape is also handled on write).\n\t\t * Null on pages without one (the widget then just emits `@change`).\n\t\t */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** Host translate function, for the start card's texts. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted configuration blob.\n\t\t *\n\t\t * Start card keys (abstract-start-card): `layout: \"start\"` draws\n\t\t * `title` and `description` beside the control, and `link`\n\t\t * (`{ label, route? | href? }`) after it. `objectSource`\n\t\t * (`{ register, schema, labelField?, placeholder?, ariaLabel?, preload? }`)\n\t\t * makes the control an OpenRegister object picker that searches on the\n\t\t * server and writes the picked object's id; without a selection and\n\t\t * without `allLabel` it selects the first object.\n\t\t *\n\t\t * Chips (screens-page-lenses): `style: \"chips\"` draws the options as one\n\t\t * compact segmented group with a count after each label. An option's\n\t\t * `countFrom` (`{ register, schema, filter? }`, or a list of them that\n\t\t * are added up) counts that list; a static `count` is used otherwise.\n\t\t * `urlKey` keeps the choice in the address (`?<urlKey>=<value>`), and\n\t\t * the address wins over `default` on load.\n\t\t *\n\t\t * Page controls (screens-page-controls): `style: \"toggle\"` is a switch\n\t\t * that writes `onValue` / `offValue` (true / false); `layout: \"bar\"`\n\t\t * with `controls` draws several controls side by side in one row, and\n\t\t * `align: \"end\"` pushes a control to the right edge.\n\t\t *\n\t\t * Input (workspace-filter-input): `style: \"input\"` draws a labelled text\n\t\t * field and a load button (`submitLabel`). The value is written only\n\t\t * when it is loaded and only when valid: `inputType: \"quarter\"` reads\n\t\t * `YYYY-Qn` and `\"year\"` reads `YYYY`, both seeded with the current one;\n\t\t * any other input takes a `pattern` (a regular expression) if given.\n\t\t * `exportTable: { exportId, label? }` adds a button beside the load\n\t\t * button that asks the object table with that `exportId` for its rows\n\t\t * as CSV (DqTermijnen \"CSV exporteren\").\n\t\t *\n\t\t * @type {{label?: string, submitLabel?: string, exportTable?: {exportId: string, label?: string}, inputType?: string, pattern?: string, controls?: Array<object>, onValue?: unknown, offValue?: unknown, align?: string, urlKey?: string, writes?: string, style?: string, allLabel?: string, showCounts?: boolean, options?: Array, source?: object, endpointSource?: object, objectSource?: object, default?: (string|number), layout?: string, title?: string, description?: string, link?: object}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['change'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The input's text before it is loaded (`style: \"input\"`). */\n\t\t\tdraft: '',\n\t\t\t/** Why the input's text was refused, or ''. */\n\t\t\tinputError: '',\n\t\t\t/** Fetched options (from source / endpointSource); static options use content.options directly. */\n\t\t\tfetchedOptions: null,\n\t\t\t/** True while options are being fetched. */\n\t\t\tloading: false,\n\t\t\t/** The currently-selected value (mirrors the workspace key). */\n\t\t\tselected: undefined,\n\t\t\t/** Counted totals of the options that ask (`countFrom`), by option position. */\n\t\t\toptionCounts: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Section label. */\n\t\tlabel() {\n\t\t\treturn this.content.label || ''\n\t\t},\n\n\t\t/** Whether the widget draws the start card. */\n\t\tisStart() {\n\t\t\treturn this.content.layout === 'start'\n\t\t},\n\n\t\t/** The start card's title, translated. */\n\t\ttitle() {\n\t\t\treturn this.tr(this.content.title || '')\n\t\t},\n\n\t\t/** The start card's guidance line, translated. */\n\t\tdescription() {\n\t\t\treturn this.tr(this.content.description || '')\n\t\t},\n\n\t\t/**\n\t\t * The link after the control, or null.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t */\n\t\tstartLink() {\n\t\t\tconst link = this.content.link\n\t\t\tif (!link || typeof link !== 'object' || !link.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route && typeof link.route === 'object' && link.route.name) {\n\t\t\t\treturn { label: this.tr(link.label), to: link.route }\n\t\t\t}\n\t\t\tif (typeof link.href === 'string' && link.href !== '') {\n\t\t\t\treturn { label: this.tr(link.label), href: link.href }\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * The object picker declaration, or null.\n\t\t *\n\t\t * @return {{register: string, schema: string, labelField?: string}|null}\n\t\t */\n\t\tobjectSource() {\n\t\t\tconst src = this.content.objectSource\n\t\t\treturn src && typeof src === 'object' && src.register && src.schema ? src : null\n\t\t},\n\n\t\t/** Choice style: 'chips', 'select' or 'radio' (default). */\n\t\tstyle() {\n\t\t\treturn ['select', 'chips', 'toggle', 'input'].includes(this.content.style) ? this.content.style : 'radio'\n\t\t},\n\n\t\t/**\n\t\t * The chips: each option with its label translated and its count,\n\t\t * the static one or the counted one.\n\t\t *\n\t\t * @return {Array<{value: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tchipOptions() {\n\t\t\treturn this.displayOptions.map((option, index) => {\n\t\t\t\tconst counted = this.optionCounts[index]\n\t\t\t\tconst count = counted !== undefined && counted !== null ? counted : option.count\n\t\t\t\tconst chip = { value: String(option.value), label: this.tr(option.label) }\n\t\t\t\tif (this.showCounts && Number.isFinite(count)) {\n\t\t\t\t\tchip.count = count\n\t\t\t\t}\n\t\t\t\treturn chip\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget is a bar of controls (`layout: \"bar\"`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-bar-holds-the-pages-controls-in-one-row\n\t\t */\n\t\tisBar() {\n\t\t\treturn this.content.layout === 'bar' && Array.isArray(this.content.controls)\n\t\t},\n\n\t\t/**\n\t\t * The bar's controls, each an inline workspace filter of its own.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tbarControls() {\n\t\t\treturn this.content.controls\n\t\t\t\t.filter((control) => control && typeof control === 'object')\n\t\t\t\t.map((control) => ({ ...control, inline: true }))\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when on. */\n\t\tonValue() {\n\t\t\treturn this.content.onValue !== undefined ? this.content.onValue : true\n\t\t},\n\n\t\t/** @return {unknown} The value a switch writes when off. */\n\t\toffValue() {\n\t\t\treturn this.content.offValue !== undefined ? this.content.offValue : false\n\t\t},\n\n\t\t/** @return {boolean} Whether the switch is on. */\n\t\ttoggleOn() {\n\t\t\treturn this.selected !== undefined && String(this.selected) === String(this.onValue)\n\t\t},\n\n\t\t/**\n\t\t * The address key that carries the choice (`urlKey`), or ''.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\turlKey() {\n\t\t\treturn typeof this.content.urlKey === 'string' ? this.content.urlKey : ''\n\t\t},\n\n\t\t/** Whether to render per-option counts. */\n\t\tshowCounts() {\n\t\t\treturn this.content.showCounts !== false\n\t\t},\n\n\t\t/**\n\t\t * What an input reads: `quarter`, `year` or `text`.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tinputType() {\n\t\t\treturn ['quarter', 'year'].includes(this.content.inputType) ? this.content.inputType : 'text'\n\t\t},\n\n\t\t/**\n\t\t * The form an input's text must have, or null for any.\n\t\t *\n\t\t * @return {RegExp|null}\n\t\t */\n\t\tinputPattern() {\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn /^\\d{4}-Q[1-4]$/\n\t\t\t}\n\t\t\tif (this.inputType === 'year') {\n\t\t\t\treturn /^\\d{4}$/\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn this.content.pattern ? new RegExp(this.content.pattern) : null\n\t\t\t} catch {\n\t\t\t\treturn null\n\t\t\t}\n\t\t},\n\n\t\t/** The input's id, unique per key. */\n\t\tinputId() {\n\t\t\treturn `cn-wsf-input-${this.writeKey || 'value'}`\n\t\t},\n\n\t\t/** The load button's label when the content names none. */\n\t\tloadLabel() {\n\t\t\treturn t('nextcloud-vue', 'Load')\n\t\t},\n\n\t\t/** @return {string} The library label of the table export button. */\n\t\texportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Export CSV')\n\t\t},\n\n\t\t/** @return {string} The `exportId` of the table the input exports, or ''. */\n\t\texportTableId() {\n\t\t\tconst target = this.content && this.content.exportTable\n\t\t\treturn target && typeof target.exportId === 'string' ? target.exportId : ''\n\t\t},\n\n\t\t/** The bare workspace key the selection writes (strips a `@workspace.` / `@page.` prefix). */\n\t\twriteKey() {\n\t\t\tconst w = this.content.writes || ''\n\t\t\treturn String(w).replace(/^@(workspace|page)\\./, '')\n\t\t},\n\n\t\t/** A stable radiogroup name so the radios are mutually exclusive. */\n\t\tradioGroupName() {\n\t\t\treturn `cn-wsf-${this.writeKey || 'filter'}`\n\t\t},\n\n\t\t/** The option list actually rendered — the optional \"All\" entry prepended. */\n\t\tdisplayOptions() {\n\t\t\tconst base = this.normalisedOptions\n\t\t\tif (this.content.allLabel) {\n\t\t\t\treturn [{ value: '', label: this.content.allLabel }, ...base]\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Normalised `{ value, label, count? }` options from whichever source is configured. */\n\t\tnormalisedOptions() {\n\t\t\tconst raw = this.fetchedOptions !== null\n\t\t\t\t? this.fetchedOptions\n\t\t\t\t: (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\treturn raw.map((o) => this.normaliseOption(o)).filter((o) => o.value !== undefined && o.value !== null)\n\t\t},\n\n\t\t/**\n\t\t * The options a select or the radio list draws, each label run through\n\t\t * the host's translate (the chips did already; the bar's sort select\n\t\t * showed its English keys beside a translated switch).\n\t\t *\n\t\t * @return {Array<{value: unknown, label: string, count?: number}>}\n\t\t * @spec openspec/changes/screens-workspace-filter-translate/specs/workspace-filter/spec.md#requirement-every-workspace-filter-style-translates-its-texts\n\t\t */\n\t\tselectOptions() {\n\t\t\treturn this.displayOptions.map((option) => ({ ...option, label: this.tr(option.label) }))\n\t\t},\n\n\t\t/** The selected option object (for NcSelect). */\n\t\tselectedOption() {\n\t\t\treturn this.selectOptions.find((o) => String(o.value) === String(this.selected)) || null\n\t\t},\n\n\t\t/**\n\t\t * The reactive workspace value for this key — watched so an external\n\t\t * write (another widget) syncs the local selection.\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\tworkspaceValue() {\n\t\t\treturn this.readWorkspace()\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** Re-fetch options when a dynamic source changes. */\n\t\tcontent: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Track external workspace changes (another widget writing the same key).\n\t\t *\n\t\t * @param {unknown} val The new workspace value for this key.\n\t\t */\n\t\tworkspaceValue(val) {\n\t\t\tif (val !== undefined) {\n\t\t\t\tthis.selected = val\n\t\t\t}\n\t\t},\n\t},\n\n\tcreated() {\n\t\t// Seed the selection: existing workspace value → content.default → the\n\t\t// \"All\" clear option (empty) when present, else the first option once\n\t\t// loaded (handled in loadOptions).\n\t\tconst fromAddress = this.readAddress()\n\t\tconst existing = this.readWorkspace()\n\t\tif (this.style === 'input') {\n\t\t\tconst seed = existing !== undefined && existing !== null && existing !== '' ? String(existing) : this.inputDefault()\n\t\t\tthis.draft = seed\n\t\t\tthis.selected = seed\n\t\t\tif (seed !== '' && seed !== existing) {\n\t\t\t\tthis.writeWorkspace(seed)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tif (fromAddress !== undefined) {\n\t\t\tthis.selected = fromAddress\n\t\t\tthis.writeWorkspace(fromAddress)\n\t\t} else if (existing !== undefined) {\n\t\t\tthis.selected = existing\n\t\t} else if (this.content.default !== undefined) {\n\t\t\tthis.selected = this.content.default\n\t\t\tthis.writeWorkspace(this.content.default)\n\t\t} else if (this.style === 'toggle') {\n\t\t\t// A switch starts off, and says so, so a condition on its key holds.\n\t\t\tthis.selected = this.offValue\n\t\t\tthis.writeWorkspace(this.offValue)\n\t\t}\n\t\tthis.loadOptions()\n\t},\n\n\tmounted() {\n\t\tthis.onPageRefresh = () => this.loadCounts()\n\t\tsubscribe('cn:page:refresh', this.onPageRefresh)\n\t\tthis.loadCounts()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe('cn:page:refresh', this.onPageRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * The choice named in the address (`?<urlKey>=…`), when it is one of\n\t\t * the options; undefined otherwise.\n\t\t *\n\t\t * @return {string|undefined}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\treadAddress() {\n\t\t\tif (!this.urlKey || !this.$route || !this.$route.query) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst raw = this.$route.query[this.urlKey]\n\t\t\tif (this.style === 'toggle') {\n\t\t\t\tif (raw === undefined) {\n\t\t\t\t\treturn undefined\n\t\t\t\t}\n\t\t\t\treturn [this.onValue, this.offValue].find((value) => String(value) === String(raw))\n\t\t\t}\n\t\t\tconst known = this.displayOptions.some((option) => String(option.value) === String(raw))\n\t\t\treturn known ? String(raw) : undefined\n\t\t},\n\n\t\t/**\n\t\t * Write the choice to the address, replacing the history entry and\n\t\t * keeping the other query keys.\n\t\t *\n\t\t * @param {unknown} value The chosen value.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-the-choice-is-in-the-address\n\t\t */\n\t\twriteAddress(value) {\n\t\t\tif (!this.urlKey || !this.$router || !this.$route) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst query = this.$route.query || {}\n\t\t\tif (String(query[this.urlKey]) === String(value)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst result = this.$router.replace({ query: { ...query, [this.urlKey]: String(value) } })\n\t\t\tif (result && typeof result.catch === 'function') {\n\t\t\t\tresult.catch(() => {})\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Count the lists behind the options that ask (`countFrom`: a list\n\t\t * `{ register, schema, filter? }`, or several that are added up). One\n\t\t * list request each; an option whose count failed shows none.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/screens-page-lenses/specs/page-lenses/spec.md#requirement-a-workspace-filter-can-draw-chips-with-counts\n\t\t */\n\t\tasync loadCounts() {\n\t\t\tconst options = this.displayOptions\n\t\t\tconst seq = (this.countSeq = (this.countSeq || 0) + 1)\n\t\t\tconst ctx = { workspace: this.readWorkspaceBag() }\n\t\t\tawait Promise.all(options.map(async (option, index) => {\n\t\t\t\tconst raw = (Array.isArray(this.content.options) ? this.content.options : [])\n\t\t\t\t\t.find((candidate) => candidate && typeof candidate === 'object' && String(candidate.value ?? candidate.id) === String(option.value))\n\t\t\t\tconst from = raw ? raw.countFrom : null\n\t\t\t\tconst lists = (Array.isArray(from) ? from : [from]).filter((list) => list && typeof list === 'object' && list.register && list.schema)\n\t\t\t\tif (lists.length === 0) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tlet total\n\t\t\t\ttry {\n\t\t\t\t\tconst parts = await Promise.all(lists.map((list) => fetchListTotal(list.register, list.schema, list.filter || {}, ctx)))\n\t\t\t\t\tif (parts.some((part) => part === null)) {\n\t\t\t\t\t\tthrow new Error('no total')\n\t\t\t\t\t}\n\t\t\t\t\ttotal = parts.reduce((sum, part) => sum + part, 0)\n\t\t\t\t} catch {\n\t\t\t\t\ttotal = null\n\t\t\t\t}\n\t\t\t\tif (seq === this.countSeq) {\n\t\t\t\t\tthis.optionCounts = { ...this.optionCounts, [index]: total }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Normalise a raw option into `{ value, label, count? }`. Accepts\n\t\t * `{ value, label, count }`, `{ id, name }`, `{ key, count }` (OR\n\t\t * facet), or a bare string/number.\n\t\t *\n\t\t * @param {unknown} o The raw option.\n\t\t * @return {{value: unknown, label: string, count?: number}}\n\t\t */\n\t\tnormaliseOption(o) {\n\t\t\tif (o === null || o === undefined) {\n\t\t\t\treturn { value: undefined, label: '' }\n\t\t\t}\n\t\t\tif (typeof o !== 'object') {\n\t\t\t\treturn { value: o, label: String(o) }\n\t\t\t}\n\t\t\tconst value = o.value !== undefined ? o.value : (o.id !== undefined ? o.id : o.key)\n\t\t\tconst label = o.label !== undefined ? o.label : (o.name !== undefined ? o.name : String(value))\n\t\t\tconst out = { value, label: String(label) }\n\t\t\tif (o.count !== undefined) {\n\t\t\t\tout.count = o.count\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Load options for the active source (static content.options need no\n\t\t * fetch). Seeds the first option as the selection when nothing is set\n\t\t * and no \"All\" clear option exists.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tif (this.objectSource) {\n\t\t\t\tawait this.seedFirstObject()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.content.endpointSource && this.content.endpointSource.url) {\n\t\t\t\tawait this.loadFromEndpoint()\n\t\t\t} else if (this.content.source && this.content.source.schema) {\n\t\t\t\tawait this.loadFromOrSource()\n\t\t\t} else {\n\t\t\t\tthis.fetchedOptions = null\n\t\t\t}\n\t\t\t// Default selection: when nothing is selected and there's no \"All\"\n\t\t\t// clear affordance, adopt the first option so siblings have a value.\n\t\t\tif ((this.selected === undefined || this.selected === '') && !this.content.allLabel) {\n\t\t\t\tconst first = this.normalisedOptions[0]\n\t\t\t\tif (first && this.readWorkspace() === undefined && this.content.default === undefined) {\n\t\t\t\t\tthis.selected = first.value\n\t\t\t\t\tthis.writeWorkspace(first.value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string}\n\t\t */\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The object picker's default: with nothing selected, no `default` and\n\t\t * no `allLabel`, select the first object the source lists, so the page\n\t\t * always has one in focus. Fail-safe: a failed read selects nothing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync seedFirstObject() {\n\t\t\tif ((this.selected !== undefined && this.selected !== '') || this.content.allLabel || this.content.default !== undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst src = this.objectSource\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: src.register, schema: src.schema })\n\t\t\t\tconst res = await axios.get(url, { params: { _limit: 1 } })\n\t\t\t\tconst data = res && res.data\n\t\t\t\tconst rows = Array.isArray(data) ? data : ((data && data.results) || [])\n\t\t\t\tconst first = rows[0]\n\t\t\t\tconst id = first && (first.id || (first['@self'] && first['@self'].id))\n\t\t\t\tif (id && (this.selected === undefined || this.selected === '') && this.readWorkspace() === undefined) {\n\t\t\t\t\tthis.selected = String(id)\n\t\t\t\t\tthis.writeWorkspace(String(id))\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Nothing selected: the siblings wait for a pick.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an `endpointSource` (array of options at\n\t\t * responsePath). Fail-safe: a failed fetch leaves an empty list.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromEndpoint() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst payload = await fetchEndpointSource(this.content.endpointSource, {\n\t\t\t\t\tworkspace: this.readWorkspaceBag(),\n\t\t\t\t})\n\t\t\t\tthis.fetchedOptions = Array.isArray(payload) ? payload : []\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch options from an OpenRegister `/grouped` facet — each distinct\n\t\t * `groupBy` value becomes an option with its object count. Fail-safe.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadFromOrSource() {\n\t\t\tconst src = this.content.source\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/aggregations/{register}/{schema}/grouped',\n\t\t\t\t\t{ register: src.register, schema: src.schema },\n\t\t\t\t)\n\t\t\t\tconst params = { groupBy: src.groupBy, metric: 'count' }\n\t\t\t\tconst filter = resolveFilterTokens(src.filter || {}, { workspace: this.readWorkspaceBag() })\n\t\t\t\tfor (const [k, v] of Object.entries(filter)) {\n\t\t\t\t\tif (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[`filter[${k}]`] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tconst groups = (res && res.data && res.data.groups) || []\n\t\t\t\tthis.fetchedOptions = groups\n\t\t\t\t\t.filter((g) => g.key !== null && g.key !== undefined && g.key !== '')\n\t\t\t\t\t.map((g) => ({ value: g.key, label: String(g.key), count: Number(g.value) || 0 }))\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an option is the active selection.\n\t\t *\n\t\t * @param {object} option The option.\n\t\t * @return {boolean}\n\t\t */\n\t\tisActive(option) {\n\t\t\treturn String(option.value) === String(this.selected ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Radio-list pick handler.\n\t\t *\n\t\t * @param {object} option The picked option.\n\t\t * @return {void}\n\t\t */\n\t\tonRadioPick(option) {\n\t\t\tthis.applySelection(option.value)\n\t\t},\n\n\t\t/**\n\t\t * Switch handler: write `onValue` or `offValue`.\n\t\t *\n\t\t * @param {boolean} on Whether the switch is on.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-page-controls/specs/page-controls/spec.md#requirement-a-toggle-and-a-select-are-page-controls\n\t\t */\n\t\tonToggle(on) {\n\t\t\tthis.applySelection(on ? this.onValue : this.offValue)\n\t\t},\n\n\t\t/**\n\t\t * NcSelect input handler.\n\t\t *\n\t\t * @param {object|null} option The picked option object.\n\t\t * @return {void}\n\t\t */\n\t\tonSelect(option) {\n\t\t\tthis.applySelection(option ? option.value : '')\n\t\t},\n\n\t\t/**\n\t\t * Apply a new selection: mirror it locally, write it into the workspace\n\t\t * context (so sibling widgets refetch), and emit `@change`.\n\t\t *\n\t\t * @param {unknown} value The new value.\n\t\t * @return {void}\n\t\t */\n\t\t/**\n\t\t * The value an input starts with: `content.default`, else the current\n\t\t * quarter or year for those types, else empty. For a quarter or year\n\t\t * input, `default: \"previous\"` is the last complete one (DqTermijnen\n\t\t * opens on the last complete quarter).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tinputDefault() {\n\t\t\tconst today = new Date()\n\t\t\tif (this.content.default === 'previous' && this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(new Date(today.getFullYear(), today.getMonth() - 3, 1))\n\t\t\t}\n\t\t\tif (this.content.default === 'previous' && this.inputType === 'year') {\n\t\t\t\treturn String(today.getFullYear() - 1)\n\t\t\t}\n\t\t\tif (this.content.default !== undefined && this.content.default !== null) {\n\t\t\t\treturn String(this.content.default)\n\t\t\t}\n\t\t\tif (this.inputType === 'quarter') {\n\t\t\t\treturn quarterKey(today)\n\t\t\t}\n\t\t\treturn this.inputType === 'year' ? String(today.getFullYear()) : ''\n\t\t},\n\n\t\t/**\n\t\t * Ask the table named by `exportTable.exportId` for its rows as CSV.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-export-table/specs/workspace-filter-export-table/spec.md#requirement-a-workspace-filter-input-can-export-the-table-it-loads\n\t\t */\n\t\texportTable() {\n\t\t\temit('cn:widget:export', { exportId: this.exportTableId })\n\t\t},\n\n\t\t/**\n\t\t * Load the input's text into the workspace, or say why it is refused.\n\t\t *\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workspace-filter-input/specs/workspace-filter-input/spec.md#requirement-a-workspace-filter-can-be-an-input-loaded-by-a-button\n\t\t */\n\t\tsubmitInput() {\n\t\t\tconst value = String(this.draft || '').trim()\n\t\t\tconst pattern = this.inputPattern\n\t\t\tif (value === '' || (pattern && !pattern.test(value))) {\n\t\t\t\tthis.inputError = this.inputType === 'quarter'\n\t\t\t\t\t? t('nextcloud-vue', 'Enter a quarter as YYYY-Qn, for example 2026-Q3.')\n\t\t\t\t\t: (this.inputType === 'year' ? t('nextcloud-vue', 'Enter a year as four digits, for example 2026.') : t('nextcloud-vue', 'This value has the wrong form.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.inputError = ''\n\t\t\tthis.applySelection(value)\n\t\t},\n\n\t\tapplySelection(value) {\n\t\t\tthis.selected = value\n\t\t\tthis.writeWorkspace(value)\n\t\t\tthis.writeAddress(value)\n\t\t\t/**\n\t\t\t * @event change Emitted when the selection changes. Payload: `{ key, value }`.\n\t\t\t */\n\t\t\tthis.$emit('change', { key: this.writeKey, value })\n\t\t},\n\n\t\t/**\n\t\t * The unwrapped workspace bag (or `{}`).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\treadWorkspaceBag() {\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn ('value' in holder) ? (holder.value || {}) : holder\n\t\t},\n\n\t\t/**\n\t\t * Read the current workspace value for this widget's key (undefined\n\t\t * when unset).\n\t\t *\n\t\t * @return {unknown}\n\t\t */\n\t\treadWorkspace() {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst bag = this.readWorkspaceBag()\n\t\t\treturn bag[this.writeKey]\n\t\t},\n\n\t\t/**\n\t\t * Write a value into the reactive workspace bag under this widget's key\n\t\t * (the CnInteractionFormWidget write pattern — replace-in-place for the\n\t\t * unwrapped bag, `.value` for the raw-ref shape).\n\t\t *\n\t\t * @param {unknown} value The value to write.\n\t\t * @return {void}\n\t\t */\n\t\twriteWorkspace(value) {\n\t\t\tif (!this.writeKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst holder = this.cnWorkspaceContext\n\t\t\tif (!holder || typeof holder !== 'object') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif ('value' in holder) {\n\t\t\t\tholder.value = { ...(holder.value || {}), [this.writeKey]: value }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tholder[this.writeKey] = value\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-workspace-filter-widget__form {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 12px 16px;\n}\n\n.cn-workspace-filter-widget__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-workspace-filter-widget__field-label {\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__input {\n\tbox-sizing: border-box;\n\tmin-height: var(--default-clickable-area, 34px);\n\tmargin: 0;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-workspace-filter-widget__input[aria-invalid='true'] {\n\tborder-color: var(--color-error);\n}\n\n.cn-workspace-filter-widget__input-error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n\n.cn-workspace-filter-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\twidth: 100%;\n}\n\n.cn-workspace-filter-widget__label {\n\tmargin: 0;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__status {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-workspace-filter-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n/* The chips: the compact segmented group, left, in the card the grid draws. */\n.cn-workspace-filter-widget--chips {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n}\n\n/* A bar: its controls in one row, an `align: \"end\"` control pushed right. */\n.cn-workspace-filter-widget--bar {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px 16px;\n}\n\n/* An inline control sits in a bar: label left of the control, width to its content. */\n.cn-workspace-filter-widget--inline {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n\twidth: auto;\n}\n\n.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__label {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--end {\n\tmargin-inline-start: auto;\n}\n\n.cn-workspace-filter-widget--end ~ .cn-workspace-filter-widget--end {\n\tmargin-inline-start: 0;\n}\n\n.cn-workspace-filter-widget__toggle {\n\tfont-weight: 600;\n}\n\n/* The start card: text left, control (and link) right, as PqDashboard's \"Contact starten\". */\n.cn-workspace-filter-widget--start {\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 16px 24px;\n}\n\n.cn-workspace-filter-widget__text {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n}\n\n.cn-workspace-filter-widget__title {\n\tmargin: 0 0 4px;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tcolor: var(--color-main-text);\n}\n\n.cn-workspace-filter-widget__description {\n\tmargin: 0;\n\tmax-width: 420px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-workspace-filter-widget--start .cn-workspace-filter-widget__control,\n.cn-workspace-filter-widget--start > .v-select {\n\tflex: 0 1 480px;\n\tmin-width: 240px;\n}\n\n.cn-workspace-filter-widget__link {\n\tfont-weight: 600;\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n\twhite-space: nowrap;\n}\n\n.cn-workspace-filter-widget__count {\n\tmargin-inline-start: 6px;\n\tpadding: 0 6px;\n\tborder-radius: 999px;\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n}\n\n/* On a phone the bar's controls take a row each (the chips already wrap), and\n a switch and a select are 44px touch targets. */\n@media (max-width: 640px) {\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--inline {\n\t\tflex: 1 1 100%;\n\t}\n\n\t.cn-workspace-filter-widget--bar > .cn-workspace-filter-widget--end {\n\t\tmargin-inline-start: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline .cn-workspace-filter-widget__toggle {\n\t\tmin-height: 44px;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.v-select) {\n\t\tflex: 1 1 auto;\n\t\tmin-width: 0;\n\t}\n\n\t.cn-workspace-filter-widget--inline :deep(.vs__dropdown-toggle) {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["_createElementBlock","_openBlock","_toDisplayString","_Fragment","_createBlock","_createElementVNode","_createTextVNode","_renderList"],"mappings":"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"}