@conduction/nextcloud-vue 2.65.0 → 2.66.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.
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +99 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +438 -383
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +9 -3
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +1 -1
- package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +78 -21
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +129 -96
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js +3 -1
- package/dist/esm/components/CnFkResolveCell/CnFkResolveCell.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +144 -4
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +63 -7
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +2 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +11 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +2 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/mixins/pageViews.js +400 -0
- package/dist/esm/mixins/pageViews.js.map +1 -0
- package/dist/esm/nextcloud-vue.css +18 -0
- package/dist/esm/utils/actionsDispatcher.js +11 -2
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/columnFilters.js +27 -3
- package/dist/esm/utils/columnFilters.js.map +1 -1
- package/dist/esm/utils/schema.js +40 -2
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1521 -596
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +18 -0
- package/l10n/en.json +3 -0
- package/l10n/nl.json +3 -0
- package/package.json +1 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +165 -8
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
- package/src/components/CnDetailPage/CnDetailPage.vue +94 -5
- package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +67 -8
- package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
- package/src/css/detail-page.css +5 -0
- package/src/mixins/pageViews.js +396 -0
- package/src/schemas/app-manifest-v2.schema.json +29 -1
- package/src/utils/actionsDispatcher.js +11 -2
- package/src/utils/columnFilters.js +29 -2
- package/src/utils/schema.js +40 -2
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -7,7 +7,7 @@ let popoverSeq = 0;
|
|
|
7
7
|
*
|
|
8
8
|
* Renders the control that fits the column: a checkbox list for an enum, yes,
|
|
9
9
|
* no or any for a boolean, from and to for a number or a date, a searchable
|
|
10
|
-
* list of referenced objects for a reference, and
|
|
10
|
+
* list of referenced objects for a reference, and a contains box for text.
|
|
11
11
|
* Real inputs throughout, so every control works from the keyboard. Escape
|
|
12
12
|
* closes it and the host returns focus to the filter button.
|
|
13
13
|
*
|
|
@@ -141,8 +141,14 @@ var script = {
|
|
|
141
141
|
return translate('nextcloud-vue', 'To')
|
|
142
142
|
},
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
/**
|
|
145
|
+
* Label of the text box: the text filter matches on contains.
|
|
146
|
+
*
|
|
147
|
+
* @return {string}
|
|
148
|
+
* @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains
|
|
149
|
+
*/
|
|
150
|
+
containsLabel() {
|
|
151
|
+
return translate('nextcloud-vue', 'Contains')
|
|
146
152
|
},
|
|
147
153
|
|
|
148
154
|
clearLabel() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnColumnFilterPopover.vue2.js","sources":["../../../../src/components/CnDataTable/CnColumnFilterPopover.vue"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<Teleport to=\"body\" :disabled=\"!teleport\">\n\t\t<div\n\t\t\tref=\"panel\"\n\t\t\tclass=\"cn-column-filter\"\n\t\t\trole=\"dialog\"\n\t\t\t:aria-labelledby=\"headingId\"\n\t\t\t:style=\"panelStyle\"\n\t\t\tdata-testid=\"cn-column-filter\"\n\t\t\t@keydown.esc.stop.prevent=\"close\"\n\t\t\t@keydown.enter=\"onEnter\">\n\t\t\t<p :id=\"headingId\" class=\"cn-column-filter__heading\">\n\t\t\t\t{{ headingText }}\n\t\t\t</p>\n\n\t\t\t<!-- enum and reference: a checkbox list of real inputs -->\n\t\t\t<template v-if=\"def.kind === 'enum' || def.kind === 'reference'\">\n\t\t\t\t<label v-if=\"def.kind === 'reference'\" class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ searchLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\ttype=\"search\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-search\"\n\t\t\t\t\t\t@input=\"onSearchInput\">\n\t\t\t\t</label>\n\t\t\t\t<p v-if=\"def.kind === 'reference' && referenceLoading\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ loadingLabel }}\n\t\t\t\t</p>\n\t\t\t\t<p v-else-if=\"def.kind === 'reference' && referenceError\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ referenceError }}\n\t\t\t\t</p>\n\t\t\t\t<fieldset class=\"cn-column-filter__options\">\n\t\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t\t{{ headingText }}\n\t\t\t\t\t</legend>\n\t\t\t\t\t<label\n\t\t\t\t\t\tv-for=\"option in listOptions\"\n\t\t\t\t\t\t:key=\"option.value\"\n\t\t\t\t\t\tclass=\"cn-column-filter__option\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t\t:checked=\"draft.values.includes(option.value)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t\t@change=\"toggleValue(option.value)\">\n\t\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<p v-if=\"listOptions.length === 0 && !referenceLoading\" class=\"cn-column-filter__hint\">\n\t\t\t\t\t\t{{ noOptionsLabel }}\n\t\t\t\t\t</p>\n\t\t\t\t</fieldset>\n\t\t\t</template>\n\n\t\t\t<!-- boolean: yes, no, any -->\n\t\t\t<fieldset v-else-if=\"def.kind === 'boolean'\" class=\"cn-column-filter__options\">\n\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t{{ headingText }}\n\t\t\t\t</legend>\n\t\t\t\t<label v-for=\"option in booleanOptions\" :key=\"option.value\" class=\"cn-column-filter__option\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t:name=\"headingId + '-bool'\"\n\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t:checked=\"draft.value === option.value\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t@change=\"draft.value = option.value\">\n\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t</label>\n\t\t\t</fieldset>\n\n\t\t\t<!-- number and date: from and to -->\n\t\t\t<div v-else-if=\"def.kind === 'number' || def.kind === 'date'\" class=\"cn-column-filter__range\">\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ fromLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.from\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-from\">\n\t\t\t\t</label>\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ toLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.to\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-to\">\n\t\t\t\t</label>\n\t\t\t</div>\n\n\t\t\t<!-- string: equals -->\n\t\t\t<label v-else class=\"cn-column-filter__field\">\n\t\t\t\t<span class=\"cn-column-filter__label\">{{ equalsLabel }}</span>\n\t\t\t\t<input\n\t\t\t\t\tv-model=\"draft.value\"\n\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-text\">\n\t\t\t</label>\n\n\t\t\t<div class=\"cn-column-filter__actions\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-clear\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t{{ clearLabel }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button cn-column-filter__button--primary\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-apply\"\n\t\t\t\t\t@click=\"apply\">\n\t\t\t\t\t{{ applyLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t</Teleport>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\n\nlet popoverSeq = 0\n\n/**\n * CnColumnFilterPopover — the small panel a table header's filter button opens.\n *\n * Renders the control that fits the column: a checkbox list for an enum, yes,\n * no or any for a boolean, from and to for a number or a date, a searchable\n * list of referenced objects for a reference, and an equals box for text.\n * Real inputs throughout, so every control works from the keyboard. Escape\n * closes it and the host returns focus to the filter button.\n *\n * Internal to CnDataTable. It emits a state object; CnDataTable turns that\n * into query parameters with `columnFilterParams`.\n *\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport default {\n\tname: 'CnColumnFilterPopover',\n\n\tprops: {\n\t\t/** The filter definition from `columnFilterDef`. */\n\t\tdef: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** The column's current state from `columnFilterState`. */\n\t\tstate: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The translated column label. */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The filter button's bounding rect, to place the panel under it. */\n\t\tanchorRect: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Register slug a reference column's objects live in, when the column names none. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Render into `<body>`, so a scrolling table cannot clip the panel. */\n\t\tteleport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['apply', 'close'],\n\n\tdata() {\n\t\tpopoverSeq += 1\n\t\tconst s = this.state || {}\n\t\treturn {\n\t\t\theadingId: 'cn-column-filter-' + popoverSeq,\n\t\t\tdraft: {\n\t\t\t\tvalues: Array.isArray(s.values) ? [...s.values] : [],\n\t\t\t\tvalue: s.value !== undefined && s.value !== null ? String(s.value) : '',\n\t\t\t\tfrom: s.from || '',\n\t\t\t\tto: s.to || '',\n\t\t\t},\n\n\t\t\tquery: '',\n\t\t\treferenceOptions: [],\n\t\t\treferenceLabels: {},\n\t\t\treferenceLoading: false,\n\t\t\treferenceError: '',\n\t\t\tsearchTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\theadingText() {\n\t\t\treturn t('nextcloud-vue', 'Filter {column}', { column: this.label })\n\t\t},\n\n\t\t/**\n\t\t * The options a list filter shows. For a reference, the search results\n\t\t * plus any picked object that is not among them, so a selection never\n\t\t * disappears from view.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tlistOptions() {\n\t\t\tif (this.def.kind !== 'reference') {\n\t\t\t\treturn this.def.options || []\n\t\t\t}\n\t\t\tconst shown = new Set(this.referenceOptions.map((o) => o.value))\n\t\t\tconst picked = this.draft.values\n\t\t\t\t.filter((v) => !shown.has(v))\n\t\t\t\t.map((v) => ({ value: v, label: this.referenceLabels[v] || v }))\n\t\t\treturn [...picked, ...this.referenceOptions]\n\t\t},\n\n\t\tbooleanOptions() {\n\t\t\treturn [\n\t\t\t\t{ value: '', label: t('nextcloud-vue', 'Any') },\n\t\t\t\t{ value: 'true', label: t('nextcloud-vue', 'Yes') },\n\t\t\t\t{ value: 'false', label: t('nextcloud-vue', 'No') },\n\t\t\t]\n\t\t},\n\n\t\tpanelStyle() {\n\t\t\tif (!this.teleport || !this.anchorRect) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst width = 280\n\t\t\tconst viewport = typeof window !== 'undefined' ? window.innerWidth : 1024\n\t\t\tconst left = Math.max(8, Math.min(this.anchorRect.left, viewport - width - 8))\n\t\t\treturn { position: 'fixed', top: `${this.anchorRect.bottom + 4}px`, left: `${left}px`, width: `${width}px` }\n\t\t},\n\n\t\tsearchLabel() {\n\t\t\treturn t('nextcloud-vue', 'Search')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\tnoOptionsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing to choose from here.')\n\t\t},\n\n\t\tfromLabel() {\n\t\t\treturn t('nextcloud-vue', 'From')\n\t\t},\n\n\t\ttoLabel() {\n\t\t\treturn t('nextcloud-vue', 'To')\n\t\t},\n\n\t\tequalsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Equals')\n\t\t},\n\n\t\tclearLabel() {\n\t\t\treturn t('nextcloud-vue', 'Clear')\n\t\t},\n\n\t\tapplyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Apply')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tdocument.addEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tif (this.def.kind === 'reference') {\n\t\t\tthis.loadReferenceOptions('')\n\t\t}\n\t\tthis.$nextTick(() => {\n\t\t\tconst first = this.$refs.panel && this.$refs.panel.querySelector('input, button')\n\t\t\tif (first && typeof first.focus === 'function') {\n\t\t\t\tfirst.focus()\n\t\t\t}\n\t\t})\n\t},\n\n\tbeforeUnmount() {\n\t\tdocument.removeEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\ttoggleValue(value) {\n\t\t\tthis.draft.values = this.draft.values.includes(value)\n\t\t\t\t? this.draft.values.filter((v) => v !== value)\n\t\t\t\t: [...this.draft.values, value]\n\t\t},\n\n\t\t/**\n\t\t * The state this panel applies, in the shape `columnFilterParams` reads.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tdraftState() {\n\t\t\tif (this.def.kind === 'enum' || this.def.kind === 'reference') {\n\t\t\t\treturn { values: [...this.draft.values] }\n\t\t\t}\n\t\t\tif (this.def.kind === 'number' || this.def.kind === 'date') {\n\t\t\t\treturn { from: this.draft.from, to: this.draft.to }\n\t\t\t}\n\t\t\treturn { value: this.draft.value }\n\t\t},\n\n\t\tapply() {\n\t\t\t/**\n\t\t\t * @event apply The person applied the filter.\n\t\t\t * @type {object} The column filter state.\n\t\t\t */\n\t\t\tthis.$emit('apply', this.draftState())\n\t\t},\n\n\t\tclear() {\n\t\t\tthis.$emit('apply', this.def.kind === 'enum' || this.def.kind === 'reference'\n\t\t\t\t? { values: [] }\n\t\t\t\t: (this.def.kind === 'number' || this.def.kind === 'date') ? { from: '', to: '' } : { value: '' })\n\t\t},\n\n\t\tclose() {\n\t\t\t/**\n\t\t\t * @event close The panel should close without applying.\n\t\t\t */\n\t\t\tthis.$emit('close')\n\t\t},\n\n\t\tonEnter(event) {\n\t\t\t// Enter in a text, number or date box applies, like a form submit.\n\t\t\t// On a checkbox or a button it keeps its own meaning.\n\t\t\tconst target = event && event.target\n\t\t\tif (target && target.tagName === 'INPUT' && ['text', 'number', 'date', 'search'].includes(target.type)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.apply()\n\t\t\t}\n\t\t},\n\n\t\tonOutsideMouseDown(event) {\n\t\t\tconst panel = this.$refs.panel\n\t\t\tif (panel && event && event.target && !panel.contains(event.target)) {\n\t\t\t\tthis.close()\n\t\t\t}\n\t\t},\n\n\t\tonSearchInput() {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.loadReferenceOptions(this.query), 250)\n\t\t},\n\n\t\t/**\n\t\t * Search the referenced objects. The value is the object's uuid,\n\t\t * because that is what the server filters a reference on.\n\t\t *\n\t\t * @param {string} search The search term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferenceOptions(search) {\n\t\t\tconst ref = this.def.reference || {}\n\t\t\tconst register = ref.register || this.register\n\t\t\tif (!register || !ref.schema) {\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'This column cannot list its objects.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.referenceLoading = true\n\t\t\tthis.referenceError = ''\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}', {\n\t\t\t\t\tregister,\n\t\t\t\t\tschema: String(ref.schema),\n\t\t\t\t})\n\t\t\t\tconst params = { _limit: 50 }\n\t\t\t\tif (search) {\n\t\t\t\t\tparams._search = search\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst rows = (response && response.data && (response.data.results || response.data)) || []\n\t\t\t\tconst list = Array.isArray(rows) ? rows : []\n\t\t\t\tconst options = list\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst self = (row && row['@self']) || {}\n\t\t\t\t\t\tconst value = String(self.id || self.uuid || row.id || row.uuid || '')\n\t\t\t\t\t\tconst label = String((ref.labelField && row[ref.labelField]) || row.name || row.title || self.name || value)\n\t\t\t\t\t\treturn { value, label }\n\t\t\t\t\t})\n\t\t\t\t\t.filter((o) => o.value !== '')\n\t\t\t\tthis.referenceOptions = options\n\t\t\t\tthis.referenceLabels = { ...this.referenceLabels, ...Object.fromEntries(options.map((o) => [o.value, o.label])) }\n\t\t\t} catch {\n\t\t\t\tthis.referenceOptions = []\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'The list could not load.')\n\t\t\t} finally {\n\t\t\t\tthis.referenceLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-column-filter {\n\tz-index: 10000;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tpadding: 12px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n\tfont-weight: normal;\n\ttext-align: start;\n}\n\n.cn-column-filter__heading {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-column-filter__options {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n}\n\n.cn-column-filter__option {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 32px;\n\tcursor: pointer;\n}\n\n.cn-column-filter__range {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-column-filter__field {\n\tdisplay: flex;\n\tflex: 1 1 0;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-column-filter__label {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__input {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tmargin: 0;\n}\n\n.cn-column-filter__hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n.cn-column-filter__button {\n\tmin-height: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n}\n\n.cn-column-filter__button--primary {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-column-filter__button:focus-visible,\n.cn-column-filter__input:focus-visible,\n.cn-column-filter__option input:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-column-filter__sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["t"],"mappings":";;AA8HA,IAAI,UAAS,GAAI,EAAA;;AAEjB;AACC;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,uBAAuB;;AAE7B,CAAA,KAAK,EAAE;AACN;EACA,GAAG,EAAE;GACJ,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,OAAO,EAAE,CAAC;GACnB;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;AAED;AACA,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;AAGD,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;EACD;;CAED,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;;AAEzB,CAAA,IAAI,GAAG;EACN,UAAW,IAAG,EAAA;AACd,EAAA,MAAM,CAAE,GAAE,IAAI,CAAC,KAAM,IAAG,GAAC;AACzB,EAAA,OAAO;AACN,GAAA,SAAS,EAAE,mBAAoB,GAAE,UAAU;AAC3C,GAAA,KAAK,EAAE;IACN,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA,GAAI,EAAE;IACpD,KAAK,EAAE,CAAC,CAAC,KAAM,KAAI,SAAU,IAAG,CAAC,CAAC,KAAM,KAAI,IAAG,GAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAA,GAAI,EAAE;AACvE,IAAA,IAAI,EAAE,CAAC,CAAC,IAAG,IAAK,EAAE;IAClB,EAAE,EAAE,CAAC,CAAC,EAAG,IAAG,EAAE;IACd;;AAED,GAAA,KAAK,EAAE,EAAE;AACT,GAAA,gBAAgB,EAAE,EAAE;AACpB,GAAA,eAAe,EAAE,EAAE;GACnB,gBAAgB,EAAE,KAAK;AACvB,GAAA,cAAc,EAAE,EAAE;AAClB,GAAA,WAAW,EAAE,IAAI;AAClB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;EACT,WAAW,GAAG;GACb,OAAOA,SAAC,CAAC,eAAe,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,KAAI,EAAG,CAAA;GACnE;;AAED;;;AAGC;AACA;AACA;;EAED,WAAW,GAAG;AACb,GAAA,IAAI,IAAI,CAAC,GAAG,CAAC,IAAK,KAAI,WAAW,EAAE;IAClC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAM,IAAK,EAAC;AAC7B,IAAA;GACA,MAAM,KAAM,GAAE,IAAI,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAA;GAC/D,MAAM,MAAO,GAAE,IAAI,CAAC,KAAK,CAAC,MAAK;KAC7B,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;KAC3B,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,KAAK,CAAE,EAAC,CAAC,EAAA;AAChE,GAAA,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAA;GAC3C;;AAED,EAAA,cAAc,GAAG;AAChB,GAAA,OAAO;AACN,IAAA,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,KAAK,GAAG;AAC/C,IAAA,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,KAAK,GAAG;AACnD,IAAA,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,IAAI,GAAG;AACpD,IAAA;GACA;;EAED,UAAU,GAAG;AACZ,GAAA,IAAI,CAAC,IAAI,CAAC,QAAS,IAAG,CAAC,IAAI,CAAC,UAAU,EAAE;AACvC,IAAA,OAAO,EAAC;AACT,IAAA;GACA,MAAM,KAAI,GAAI,IAAE;AAChB,GAAA,MAAM,QAAO,GAAI,OAAO,MAAO,KAAI,WAAY,GAAE,MAAM,CAAC,UAAW,GAAE,KAAG;AACxE,GAAA,MAAM,IAAG,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,QAAS,GAAE,KAAM,GAAE,CAAC,CAAC,EAAA;GAC7E,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,MAAK,GAAI,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAE,EAAA;GAC3G;;EAED,WAAW,GAAG;AACb,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAA;GAClC;;AAED,EAAA,YAAY,GAAG;AACd,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,UAAU,CAAA;GACpC;;AAED,EAAA,cAAc,GAAG;GAChB,OAAOA,SAAC,CAAC,eAAe,EAAE,8BAA8B,CAAA;GACxD;;EAED,SAAS,GAAG;AACX,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,MAAM,CAAA;GAChC;;AAED,EAAA,OAAO,GAAG;GACT,OAAOA,SAAC,CAAC,eAAe,EAAE,IAAI,CAAA;GAC9B;;EAED,WAAW,GAAG;AACb,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAA;GAClC;;EAED,UAAU,GAAG;AACZ,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA;GACjC;;EAED,UAAU,GAAG;AACZ,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAA;GACjC;EACD;;AAED,CAAA,OAAO,GAAG;AACT,EAAA,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAA;AACpE,EAAA,IAAI,IAAI,CAAC,GAAG,CAAC,IAAK,KAAI,WAAW,EAAE;GAClC,IAAI,CAAC,oBAAoB,CAAC,EAAE,EAAA;AAC7B,GAAA;AACA,EAAA,IAAI,CAAC,SAAS,CAAC,MAAM;AACpB,GAAA,MAAM,KAAI,GAAI,IAAI,CAAC,KAAK,CAAC,KAAI,IAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,eAAe,EAAA;AAChF,GAAA,IAAI,KAAM,IAAG,OAAO,KAAK,CAAC,KAAM,KAAI,UAAU,EAAE;IAC/C,KAAK,CAAC,KAAK,GAAC;AACb,IAAA;GACA,EAAA;EACD;;AAED,CAAA,aAAa,GAAG;AACf,EAAA,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,EAAA;EACvE,YAAY,CAAC,IAAI,CAAC,WAAW,EAAA;EAC7B;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,WAAW,CAAC,KAAK,EAAE;GAClB,IAAI,CAAC,KAAK,CAAC,MAAO,GAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAA;AACnD,MAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAA,KAAM,KAAK,CAAA;MAC3C,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAA;GAC/B;;AAED;;AAEC;AACA;;EAED,UAAU,GAAG;GACZ,IAAI,IAAI,CAAC,GAAG,CAAC,IAAG,KAAM,MAAK,IAAK,IAAI,CAAC,GAAG,CAAC,IAAK,KAAI,WAAW,EAAE;AAC9D,IAAA,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE,EAAA;AACzC,IAAA;GACA,IAAI,IAAI,CAAC,GAAG,CAAC,IAAK,KAAI,YAAY,IAAI,CAAC,GAAG,CAAC,IAAG,KAAM,MAAM,EAAE;AAC3D,IAAA,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAG,EAAA;AACnD,IAAA;GACA,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAM,EAAA;GACjC;;AAED,EAAA,KAAK,GAAG;AACP;AACC;AACA;;AAED,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,EAAA;GACrC;;AAED,EAAA,KAAK,GAAG;AACP,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,UAAU,IAAI,CAAC,GAAG,CAAC,IAAG,KAAM,WAAU;MACzE,EAAE,MAAM,EAAE,EAAG,EAAA;AACf,MAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAK,KAAI,QAAO,IAAK,IAAI,CAAC,GAAG,CAAC,IAAG,KAAM,MAAM,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAC,KAAM,EAAE,KAAK,EAAE,IAAI,EAAA;GAClG;;AAED,EAAA,KAAK,GAAG;AACP;;;AAGA,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAA;GAClB;;AAED,EAAA,OAAO,CAAC,KAAK,EAAE;;AAEd;AACA,GAAA,MAAM,MAAK,GAAI,KAAI,IAAK,KAAK,CAAC,OAAK;AACnC,GAAA,IAAI,MAAO,IAAG,MAAM,CAAC,OAAM,KAAM,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AACvG,IAAA,KAAK,CAAC,cAAc,GAAC;IACrB,IAAI,CAAC,KAAK,GAAC;AACZ,IAAA;GACA;;EAED,kBAAkB,CAAC,KAAK,EAAE;GACzB,MAAM,KAAM,GAAE,IAAI,CAAC,KAAK,CAAC,MAAI;GAC7B,IAAI,KAAI,IAAK,KAAM,IAAG,KAAK,CAAC,MAAO,IAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;IACpE,IAAI,CAAC,KAAK,GAAC;AACZ,IAAA;GACA;;AAED,EAAA,aAAa,GAAG;GACf,YAAY,CAAC,IAAI,CAAC,WAAW,EAAA;AAC7B,GAAA,IAAI,CAAC,WAAY,GAAE,UAAU,CAAC,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAA;GAC9E;;AAED;;;AAGC;AACA;;;AAGD,EAAA,MAAM,oBAAoB,CAAC,MAAM,EAAE;AAClC,GAAA,MAAM,GAAI,GAAE,IAAI,CAAC,GAAG,CAAC,SAAQ,IAAK,GAAC;AACnC,GAAA,MAAM,QAAS,GAAE,GAAG,CAAC,QAAS,IAAG,IAAI,CAAC,SAAO;GAC7C,IAAI,CAAC,QAAS,IAAG,CAAC,GAAG,CAAC,MAAM,EAAE;AAC7B,IAAA,IAAI,CAAC,cAAa,GAAIA,SAAC,CAAC,eAAe,EAAE,sCAAsC,EAAA;IAC/E,MAAK;AACN,IAAA;GACA,IAAI,CAAC,gBAAiB,GAAE,KAAG;AAC3B,GAAA,IAAI,CAAC,cAAa,GAAI,GAAC;AACvB,GAAA,IAAI;IACH,MAAM,CAAC,EAAE,OAAO,EAAE,KAAI,EAAG,EAAE,EAAE,WAAU,EAAG,CAAE,GAAE,MAAM,OAAO,CAAC,GAAG,CAAC;KAC/D,OAAO,kBAAkB,CAAC;KAC1B,OAAO,mBAAmB,CAAC;KAC3B,EAAA;AACD,IAAA,MAAM,GAAE,GAAI,WAAW,CAAC,oDAAoD,EAAE;AAC7E,KAAA,QAAQ;KACR,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC;KAC1B,EAAA;IACD,MAAM,MAAK,GAAI,EAAE,MAAM,EAAE,EAAG,GAAA;IAC5B,IAAI,MAAM,EAAE;AACX,KAAA,MAAM,CAAC,OAAQ,GAAE,OAAK;AACvB,KAAA;AACA,IAAA,MAAM,QAAS,GAAE,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAA;AAChD,IAAA,MAAM,IAAG,GAAI,CAAC,QAAO,IAAK,QAAQ,CAAC,IAAG,KAAM,QAAQ,CAAC,IAAI,CAAC,OAAQ,IAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,GAAC;AACzF,IAAA,MAAM,IAAK,GAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAA,GAAI,IAAG,GAAI,GAAC;AAC3C,IAAA,MAAM,OAAM,GAAI,IAAG;MACjB,GAAG,CAAC,CAAC,GAAG,KAAK;AACb,MAAA,MAAM,IAAG,GAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,GAAC;MACvC,MAAM,KAAI,GAAI,MAAM,CAAC,IAAI,CAAC,EAAC,IAAK,IAAI,CAAC,IAAG,IAAK,GAAG,CAAC,EAAC,IAAK,GAAG,CAAC,IAAK,IAAG,EAAE,EAAA;MACrE,MAAM,KAAM,GAAE,MAAM,CAAC,CAAC,GAAG,CAAC,cAAc,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,IAAG,IAAK,GAAG,CAAC,KAAM,IAAG,IAAI,CAAC,QAAQ,KAAK,EAAA;AAC3G,MAAA,OAAO,EAAE,KAAK,EAAE,KAAM,EAAA;MACtB,CAAA;MACA,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,EAAA;IAC9B,IAAI,CAAC,gBAAe,GAAI,QAAM;IAC9B,IAAI,CAAC,eAAgB,GAAE,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,GAAA;AACjH,IAAA,CAAE,MAAM;IACP,IAAI,CAAC,gBAAiB,GAAE,GAAC;IACzB,IAAI,CAAC,cAAe,GAAEA,SAAC,CAAC,eAAe,EAAE,0BAA0B,EAAA;AACpE,IAAA,SAAU;IACT,IAAI,CAAC,mBAAmB,MAAI;AAC7B,IAAA;GACA;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnColumnFilterPopover.vue2.js","sources":["../../../../src/components/CnDataTable/CnColumnFilterPopover.vue"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<Teleport to=\"body\" :disabled=\"!teleport\">\n\t\t<div\n\t\t\tref=\"panel\"\n\t\t\tclass=\"cn-column-filter\"\n\t\t\trole=\"dialog\"\n\t\t\t:aria-labelledby=\"headingId\"\n\t\t\t:style=\"panelStyle\"\n\t\t\tdata-testid=\"cn-column-filter\"\n\t\t\t@keydown.esc.stop.prevent=\"close\"\n\t\t\t@keydown.enter=\"onEnter\">\n\t\t\t<p :id=\"headingId\" class=\"cn-column-filter__heading\">\n\t\t\t\t{{ headingText }}\n\t\t\t</p>\n\n\t\t\t<!-- enum and reference: a checkbox list of real inputs -->\n\t\t\t<template v-if=\"def.kind === 'enum' || def.kind === 'reference'\">\n\t\t\t\t<label v-if=\"def.kind === 'reference'\" class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ searchLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\ttype=\"search\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-search\"\n\t\t\t\t\t\t@input=\"onSearchInput\">\n\t\t\t\t</label>\n\t\t\t\t<p v-if=\"def.kind === 'reference' && referenceLoading\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ loadingLabel }}\n\t\t\t\t</p>\n\t\t\t\t<p v-else-if=\"def.kind === 'reference' && referenceError\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ referenceError }}\n\t\t\t\t</p>\n\t\t\t\t<fieldset class=\"cn-column-filter__options\">\n\t\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t\t{{ headingText }}\n\t\t\t\t\t</legend>\n\t\t\t\t\t<label\n\t\t\t\t\t\tv-for=\"option in listOptions\"\n\t\t\t\t\t\t:key=\"option.value\"\n\t\t\t\t\t\tclass=\"cn-column-filter__option\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t\t:checked=\"draft.values.includes(option.value)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t\t@change=\"toggleValue(option.value)\">\n\t\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<p v-if=\"listOptions.length === 0 && !referenceLoading\" class=\"cn-column-filter__hint\">\n\t\t\t\t\t\t{{ noOptionsLabel }}\n\t\t\t\t\t</p>\n\t\t\t\t</fieldset>\n\t\t\t</template>\n\n\t\t\t<!-- boolean: yes, no, any -->\n\t\t\t<fieldset v-else-if=\"def.kind === 'boolean'\" class=\"cn-column-filter__options\">\n\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t{{ headingText }}\n\t\t\t\t</legend>\n\t\t\t\t<label v-for=\"option in booleanOptions\" :key=\"option.value\" class=\"cn-column-filter__option\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t:name=\"headingId + '-bool'\"\n\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t:checked=\"draft.value === option.value\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t@change=\"draft.value = option.value\">\n\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t</label>\n\t\t\t</fieldset>\n\n\t\t\t<!-- number and date: from and to -->\n\t\t\t<div v-else-if=\"def.kind === 'number' || def.kind === 'date'\" class=\"cn-column-filter__range\">\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ fromLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.from\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-from\">\n\t\t\t\t</label>\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ toLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.to\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-to\">\n\t\t\t\t</label>\n\t\t\t</div>\n\n\t\t\t<!-- string: contains (OpenRegister `[like]`, case-insensitive) -->\n\t\t\t<label v-else class=\"cn-column-filter__field\">\n\t\t\t\t<span class=\"cn-column-filter__label\">{{ containsLabel }}</span>\n\t\t\t\t<input\n\t\t\t\t\tv-model=\"draft.value\"\n\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-text\">\n\t\t\t</label>\n\n\t\t\t<div class=\"cn-column-filter__actions\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-clear\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t{{ clearLabel }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button cn-column-filter__button--primary\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-apply\"\n\t\t\t\t\t@click=\"apply\">\n\t\t\t\t\t{{ applyLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t</Teleport>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\n\nlet popoverSeq = 0\n\n/**\n * CnColumnFilterPopover — the small panel a table header's filter button opens.\n *\n * Renders the control that fits the column: a checkbox list for an enum, yes,\n * no or any for a boolean, from and to for a number or a date, a searchable\n * list of referenced objects for a reference, and a contains box for text.\n * Real inputs throughout, so every control works from the keyboard. Escape\n * closes it and the host returns focus to the filter button.\n *\n * Internal to CnDataTable. It emits a state object; CnDataTable turns that\n * into query parameters with `columnFilterParams`.\n *\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport default {\n\tname: 'CnColumnFilterPopover',\n\n\tprops: {\n\t\t/** The filter definition from `columnFilterDef`. */\n\t\tdef: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** The column's current state from `columnFilterState`. */\n\t\tstate: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The translated column label. */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The filter button's bounding rect, to place the panel under it. */\n\t\tanchorRect: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Register slug a reference column's objects live in, when the column names none. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Render into `<body>`, so a scrolling table cannot clip the panel. */\n\t\tteleport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['apply', 'close'],\n\n\tdata() {\n\t\tpopoverSeq += 1\n\t\tconst s = this.state || {}\n\t\treturn {\n\t\t\theadingId: 'cn-column-filter-' + popoverSeq,\n\t\t\tdraft: {\n\t\t\t\tvalues: Array.isArray(s.values) ? [...s.values] : [],\n\t\t\t\tvalue: s.value !== undefined && s.value !== null ? String(s.value) : '',\n\t\t\t\tfrom: s.from || '',\n\t\t\t\tto: s.to || '',\n\t\t\t},\n\n\t\t\tquery: '',\n\t\t\treferenceOptions: [],\n\t\t\treferenceLabels: {},\n\t\t\treferenceLoading: false,\n\t\t\treferenceError: '',\n\t\t\tsearchTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\theadingText() {\n\t\t\treturn t('nextcloud-vue', 'Filter {column}', { column: this.label })\n\t\t},\n\n\t\t/**\n\t\t * The options a list filter shows. For a reference, the search results\n\t\t * plus any picked object that is not among them, so a selection never\n\t\t * disappears from view.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tlistOptions() {\n\t\t\tif (this.def.kind !== 'reference') {\n\t\t\t\treturn this.def.options || []\n\t\t\t}\n\t\t\tconst shown = new Set(this.referenceOptions.map((o) => o.value))\n\t\t\tconst picked = this.draft.values\n\t\t\t\t.filter((v) => !shown.has(v))\n\t\t\t\t.map((v) => ({ value: v, label: this.referenceLabels[v] || v }))\n\t\t\treturn [...picked, ...this.referenceOptions]\n\t\t},\n\n\t\tbooleanOptions() {\n\t\t\treturn [\n\t\t\t\t{ value: '', label: t('nextcloud-vue', 'Any') },\n\t\t\t\t{ value: 'true', label: t('nextcloud-vue', 'Yes') },\n\t\t\t\t{ value: 'false', label: t('nextcloud-vue', 'No') },\n\t\t\t]\n\t\t},\n\n\t\tpanelStyle() {\n\t\t\tif (!this.teleport || !this.anchorRect) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst width = 280\n\t\t\tconst viewport = typeof window !== 'undefined' ? window.innerWidth : 1024\n\t\t\tconst left = Math.max(8, Math.min(this.anchorRect.left, viewport - width - 8))\n\t\t\treturn { position: 'fixed', top: `${this.anchorRect.bottom + 4}px`, left: `${left}px`, width: `${width}px` }\n\t\t},\n\n\t\tsearchLabel() {\n\t\t\treturn t('nextcloud-vue', 'Search')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\tnoOptionsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing to choose from here.')\n\t\t},\n\n\t\tfromLabel() {\n\t\t\treturn t('nextcloud-vue', 'From')\n\t\t},\n\n\t\ttoLabel() {\n\t\t\treturn t('nextcloud-vue', 'To')\n\t\t},\n\n\t\t/**\n\t\t * Label of the text box: the text filter matches on contains.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains\n\t\t */\n\t\tcontainsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Contains')\n\t\t},\n\n\t\tclearLabel() {\n\t\t\treturn t('nextcloud-vue', 'Clear')\n\t\t},\n\n\t\tapplyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Apply')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tdocument.addEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tif (this.def.kind === 'reference') {\n\t\t\tthis.loadReferenceOptions('')\n\t\t}\n\t\tthis.$nextTick(() => {\n\t\t\tconst first = this.$refs.panel && this.$refs.panel.querySelector('input, button')\n\t\t\tif (first && typeof first.focus === 'function') {\n\t\t\t\tfirst.focus()\n\t\t\t}\n\t\t})\n\t},\n\n\tbeforeUnmount() {\n\t\tdocument.removeEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\ttoggleValue(value) {\n\t\t\tthis.draft.values = this.draft.values.includes(value)\n\t\t\t\t? this.draft.values.filter((v) => v !== value)\n\t\t\t\t: [...this.draft.values, value]\n\t\t},\n\n\t\t/**\n\t\t * The state this panel applies, in the shape `columnFilterParams` reads.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tdraftState() {\n\t\t\tif (this.def.kind === 'enum' || this.def.kind === 'reference') {\n\t\t\t\treturn { values: [...this.draft.values] }\n\t\t\t}\n\t\t\tif (this.def.kind === 'number' || this.def.kind === 'date') {\n\t\t\t\treturn { from: this.draft.from, to: this.draft.to }\n\t\t\t}\n\t\t\treturn { value: this.draft.value }\n\t\t},\n\n\t\tapply() {\n\t\t\t/**\n\t\t\t * @event apply The person applied the filter.\n\t\t\t * @type {object} The column filter state.\n\t\t\t */\n\t\t\tthis.$emit('apply', this.draftState())\n\t\t},\n\n\t\tclear() {\n\t\t\tthis.$emit('apply', this.def.kind === 'enum' || this.def.kind === 'reference'\n\t\t\t\t? { values: [] }\n\t\t\t\t: (this.def.kind === 'number' || this.def.kind === 'date') ? { from: '', to: '' } : { value: '' })\n\t\t},\n\n\t\tclose() {\n\t\t\t/**\n\t\t\t * @event close The panel should close without applying.\n\t\t\t */\n\t\t\tthis.$emit('close')\n\t\t},\n\n\t\tonEnter(event) {\n\t\t\t// Enter in a text, number or date box applies, like a form submit.\n\t\t\t// On a checkbox or a button it keeps its own meaning.\n\t\t\tconst target = event && event.target\n\t\t\tif (target && target.tagName === 'INPUT' && ['text', 'number', 'date', 'search'].includes(target.type)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.apply()\n\t\t\t}\n\t\t},\n\n\t\tonOutsideMouseDown(event) {\n\t\t\tconst panel = this.$refs.panel\n\t\t\tif (panel && event && event.target && !panel.contains(event.target)) {\n\t\t\t\tthis.close()\n\t\t\t}\n\t\t},\n\n\t\tonSearchInput() {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.loadReferenceOptions(this.query), 250)\n\t\t},\n\n\t\t/**\n\t\t * Search the referenced objects. The value is the object's uuid,\n\t\t * because that is what the server filters a reference on.\n\t\t *\n\t\t * @param {string} search The search term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferenceOptions(search) {\n\t\t\tconst ref = this.def.reference || {}\n\t\t\tconst register = ref.register || this.register\n\t\t\tif (!register || !ref.schema) {\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'This column cannot list its objects.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.referenceLoading = true\n\t\t\tthis.referenceError = ''\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}', {\n\t\t\t\t\tregister,\n\t\t\t\t\tschema: String(ref.schema),\n\t\t\t\t})\n\t\t\t\tconst params = { _limit: 50 }\n\t\t\t\tif (search) {\n\t\t\t\t\tparams._search = search\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst rows = (response && response.data && (response.data.results || response.data)) || []\n\t\t\t\tconst list = Array.isArray(rows) ? rows : []\n\t\t\t\tconst options = list\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst self = (row && row['@self']) || {}\n\t\t\t\t\t\tconst value = String(self.id || self.uuid || row.id || row.uuid || '')\n\t\t\t\t\t\tconst label = String((ref.labelField && row[ref.labelField]) || row.name || row.title || self.name || value)\n\t\t\t\t\t\treturn { value, label }\n\t\t\t\t\t})\n\t\t\t\t\t.filter((o) => o.value !== '')\n\t\t\t\tthis.referenceOptions = options\n\t\t\t\tthis.referenceLabels = { ...this.referenceLabels, ...Object.fromEntries(options.map((o) => [o.value, o.label])) }\n\t\t\t} catch {\n\t\t\t\tthis.referenceOptions = []\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'The list could not load.')\n\t\t\t} finally {\n\t\t\t\tthis.referenceLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-column-filter {\n\tz-index: 10000;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tpadding: 12px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n\tfont-weight: normal;\n\ttext-align: start;\n}\n\n.cn-column-filter__heading {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-column-filter__options {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n}\n\n.cn-column-filter__option {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 32px;\n\tcursor: pointer;\n}\n\n.cn-column-filter__range {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-column-filter__field {\n\tdisplay: flex;\n\tflex: 1 1 0;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-column-filter__label {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__input {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tmargin: 0;\n}\n\n.cn-column-filter__hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n.cn-column-filter__button {\n\tmin-height: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n}\n\n.cn-column-filter__button--primary {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-column-filter__button:focus-visible,\n.cn-column-filter__input:focus-visible,\n.cn-column-filter__option input:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-column-filter__sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
@@ -157,7 +157,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
157
157
|
])
|
|
158
158
|
]))
|
|
159
159
|
: (openBlock(), createElementBlock("label", _hoisted_21, [
|
|
160
|
-
createElementVNode("span", _hoisted_22, toDisplayString($options.
|
|
160
|
+
createElementVNode("span", _hoisted_22, toDisplayString($options.containsLabel), 1 /* TEXT */),
|
|
161
161
|
withDirectives(createElementVNode("input", {
|
|
162
162
|
"onUpdate:modelValue": _cache[4] || (_cache[4] = $event => (($data.draft.value) = $event)),
|
|
163
163
|
class: "cn-column-filter__input",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnColumnFilterPopover.vue3.js","sources":["../../../../src/components/CnDataTable/CnColumnFilterPopover.vue?vue&type=template&id=2cb54356&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<Teleport to=\"body\" :disabled=\"!teleport\">\n\t\t<div\n\t\t\tref=\"panel\"\n\t\t\tclass=\"cn-column-filter\"\n\t\t\trole=\"dialog\"\n\t\t\t:aria-labelledby=\"headingId\"\n\t\t\t:style=\"panelStyle\"\n\t\t\tdata-testid=\"cn-column-filter\"\n\t\t\t@keydown.esc.stop.prevent=\"close\"\n\t\t\t@keydown.enter=\"onEnter\">\n\t\t\t<p :id=\"headingId\" class=\"cn-column-filter__heading\">\n\t\t\t\t{{ headingText }}\n\t\t\t</p>\n\n\t\t\t<!-- enum and reference: a checkbox list of real inputs -->\n\t\t\t<template v-if=\"def.kind === 'enum' || def.kind === 'reference'\">\n\t\t\t\t<label v-if=\"def.kind === 'reference'\" class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ searchLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\ttype=\"search\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-search\"\n\t\t\t\t\t\t@input=\"onSearchInput\">\n\t\t\t\t</label>\n\t\t\t\t<p v-if=\"def.kind === 'reference' && referenceLoading\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ loadingLabel }}\n\t\t\t\t</p>\n\t\t\t\t<p v-else-if=\"def.kind === 'reference' && referenceError\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ referenceError }}\n\t\t\t\t</p>\n\t\t\t\t<fieldset class=\"cn-column-filter__options\">\n\t\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t\t{{ headingText }}\n\t\t\t\t\t</legend>\n\t\t\t\t\t<label\n\t\t\t\t\t\tv-for=\"option in listOptions\"\n\t\t\t\t\t\t:key=\"option.value\"\n\t\t\t\t\t\tclass=\"cn-column-filter__option\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t\t:checked=\"draft.values.includes(option.value)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t\t@change=\"toggleValue(option.value)\">\n\t\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<p v-if=\"listOptions.length === 0 && !referenceLoading\" class=\"cn-column-filter__hint\">\n\t\t\t\t\t\t{{ noOptionsLabel }}\n\t\t\t\t\t</p>\n\t\t\t\t</fieldset>\n\t\t\t</template>\n\n\t\t\t<!-- boolean: yes, no, any -->\n\t\t\t<fieldset v-else-if=\"def.kind === 'boolean'\" class=\"cn-column-filter__options\">\n\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t{{ headingText }}\n\t\t\t\t</legend>\n\t\t\t\t<label v-for=\"option in booleanOptions\" :key=\"option.value\" class=\"cn-column-filter__option\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t:name=\"headingId + '-bool'\"\n\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t:checked=\"draft.value === option.value\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t@change=\"draft.value = option.value\">\n\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t</label>\n\t\t\t</fieldset>\n\n\t\t\t<!-- number and date: from and to -->\n\t\t\t<div v-else-if=\"def.kind === 'number' || def.kind === 'date'\" class=\"cn-column-filter__range\">\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ fromLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.from\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-from\">\n\t\t\t\t</label>\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ toLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.to\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-to\">\n\t\t\t\t</label>\n\t\t\t</div>\n\n\t\t\t<!-- string: equals -->\n\t\t\t<label v-else class=\"cn-column-filter__field\">\n\t\t\t\t<span class=\"cn-column-filter__label\">{{ equalsLabel }}</span>\n\t\t\t\t<input\n\t\t\t\t\tv-model=\"draft.value\"\n\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-text\">\n\t\t\t</label>\n\n\t\t\t<div class=\"cn-column-filter__actions\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-clear\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t{{ clearLabel }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button cn-column-filter__button--primary\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-apply\"\n\t\t\t\t\t@click=\"apply\">\n\t\t\t\t\t{{ applyLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t</Teleport>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\n\nlet popoverSeq = 0\n\n/**\n * CnColumnFilterPopover — the small panel a table header's filter button opens.\n *\n * Renders the control that fits the column: a checkbox list for an enum, yes,\n * no or any for a boolean, from and to for a number or a date, a searchable\n * list of referenced objects for a reference, and an equals box for text.\n * Real inputs throughout, so every control works from the keyboard. Escape\n * closes it and the host returns focus to the filter button.\n *\n * Internal to CnDataTable. It emits a state object; CnDataTable turns that\n * into query parameters with `columnFilterParams`.\n *\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport default {\n\tname: 'CnColumnFilterPopover',\n\n\tprops: {\n\t\t/** The filter definition from `columnFilterDef`. */\n\t\tdef: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** The column's current state from `columnFilterState`. */\n\t\tstate: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The translated column label. */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The filter button's bounding rect, to place the panel under it. */\n\t\tanchorRect: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Register slug a reference column's objects live in, when the column names none. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Render into `<body>`, so a scrolling table cannot clip the panel. */\n\t\tteleport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['apply', 'close'],\n\n\tdata() {\n\t\tpopoverSeq += 1\n\t\tconst s = this.state || {}\n\t\treturn {\n\t\t\theadingId: 'cn-column-filter-' + popoverSeq,\n\t\t\tdraft: {\n\t\t\t\tvalues: Array.isArray(s.values) ? [...s.values] : [],\n\t\t\t\tvalue: s.value !== undefined && s.value !== null ? String(s.value) : '',\n\t\t\t\tfrom: s.from || '',\n\t\t\t\tto: s.to || '',\n\t\t\t},\n\n\t\t\tquery: '',\n\t\t\treferenceOptions: [],\n\t\t\treferenceLabels: {},\n\t\t\treferenceLoading: false,\n\t\t\treferenceError: '',\n\t\t\tsearchTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\theadingText() {\n\t\t\treturn t('nextcloud-vue', 'Filter {column}', { column: this.label })\n\t\t},\n\n\t\t/**\n\t\t * The options a list filter shows. For a reference, the search results\n\t\t * plus any picked object that is not among them, so a selection never\n\t\t * disappears from view.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tlistOptions() {\n\t\t\tif (this.def.kind !== 'reference') {\n\t\t\t\treturn this.def.options || []\n\t\t\t}\n\t\t\tconst shown = new Set(this.referenceOptions.map((o) => o.value))\n\t\t\tconst picked = this.draft.values\n\t\t\t\t.filter((v) => !shown.has(v))\n\t\t\t\t.map((v) => ({ value: v, label: this.referenceLabels[v] || v }))\n\t\t\treturn [...picked, ...this.referenceOptions]\n\t\t},\n\n\t\tbooleanOptions() {\n\t\t\treturn [\n\t\t\t\t{ value: '', label: t('nextcloud-vue', 'Any') },\n\t\t\t\t{ value: 'true', label: t('nextcloud-vue', 'Yes') },\n\t\t\t\t{ value: 'false', label: t('nextcloud-vue', 'No') },\n\t\t\t]\n\t\t},\n\n\t\tpanelStyle() {\n\t\t\tif (!this.teleport || !this.anchorRect) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst width = 280\n\t\t\tconst viewport = typeof window !== 'undefined' ? window.innerWidth : 1024\n\t\t\tconst left = Math.max(8, Math.min(this.anchorRect.left, viewport - width - 8))\n\t\t\treturn { position: 'fixed', top: `${this.anchorRect.bottom + 4}px`, left: `${left}px`, width: `${width}px` }\n\t\t},\n\n\t\tsearchLabel() {\n\t\t\treturn t('nextcloud-vue', 'Search')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\tnoOptionsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing to choose from here.')\n\t\t},\n\n\t\tfromLabel() {\n\t\t\treturn t('nextcloud-vue', 'From')\n\t\t},\n\n\t\ttoLabel() {\n\t\t\treturn t('nextcloud-vue', 'To')\n\t\t},\n\n\t\tequalsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Equals')\n\t\t},\n\n\t\tclearLabel() {\n\t\t\treturn t('nextcloud-vue', 'Clear')\n\t\t},\n\n\t\tapplyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Apply')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tdocument.addEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tif (this.def.kind === 'reference') {\n\t\t\tthis.loadReferenceOptions('')\n\t\t}\n\t\tthis.$nextTick(() => {\n\t\t\tconst first = this.$refs.panel && this.$refs.panel.querySelector('input, button')\n\t\t\tif (first && typeof first.focus === 'function') {\n\t\t\t\tfirst.focus()\n\t\t\t}\n\t\t})\n\t},\n\n\tbeforeUnmount() {\n\t\tdocument.removeEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\ttoggleValue(value) {\n\t\t\tthis.draft.values = this.draft.values.includes(value)\n\t\t\t\t? this.draft.values.filter((v) => v !== value)\n\t\t\t\t: [...this.draft.values, value]\n\t\t},\n\n\t\t/**\n\t\t * The state this panel applies, in the shape `columnFilterParams` reads.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tdraftState() {\n\t\t\tif (this.def.kind === 'enum' || this.def.kind === 'reference') {\n\t\t\t\treturn { values: [...this.draft.values] }\n\t\t\t}\n\t\t\tif (this.def.kind === 'number' || this.def.kind === 'date') {\n\t\t\t\treturn { from: this.draft.from, to: this.draft.to }\n\t\t\t}\n\t\t\treturn { value: this.draft.value }\n\t\t},\n\n\t\tapply() {\n\t\t\t/**\n\t\t\t * @event apply The person applied the filter.\n\t\t\t * @type {object} The column filter state.\n\t\t\t */\n\t\t\tthis.$emit('apply', this.draftState())\n\t\t},\n\n\t\tclear() {\n\t\t\tthis.$emit('apply', this.def.kind === 'enum' || this.def.kind === 'reference'\n\t\t\t\t? { values: [] }\n\t\t\t\t: (this.def.kind === 'number' || this.def.kind === 'date') ? { from: '', to: '' } : { value: '' })\n\t\t},\n\n\t\tclose() {\n\t\t\t/**\n\t\t\t * @event close The panel should close without applying.\n\t\t\t */\n\t\t\tthis.$emit('close')\n\t\t},\n\n\t\tonEnter(event) {\n\t\t\t// Enter in a text, number or date box applies, like a form submit.\n\t\t\t// On a checkbox or a button it keeps its own meaning.\n\t\t\tconst target = event && event.target\n\t\t\tif (target && target.tagName === 'INPUT' && ['text', 'number', 'date', 'search'].includes(target.type)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.apply()\n\t\t\t}\n\t\t},\n\n\t\tonOutsideMouseDown(event) {\n\t\t\tconst panel = this.$refs.panel\n\t\t\tif (panel && event && event.target && !panel.contains(event.target)) {\n\t\t\t\tthis.close()\n\t\t\t}\n\t\t},\n\n\t\tonSearchInput() {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.loadReferenceOptions(this.query), 250)\n\t\t},\n\n\t\t/**\n\t\t * Search the referenced objects. The value is the object's uuid,\n\t\t * because that is what the server filters a reference on.\n\t\t *\n\t\t * @param {string} search The search term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferenceOptions(search) {\n\t\t\tconst ref = this.def.reference || {}\n\t\t\tconst register = ref.register || this.register\n\t\t\tif (!register || !ref.schema) {\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'This column cannot list its objects.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.referenceLoading = true\n\t\t\tthis.referenceError = ''\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}', {\n\t\t\t\t\tregister,\n\t\t\t\t\tschema: String(ref.schema),\n\t\t\t\t})\n\t\t\t\tconst params = { _limit: 50 }\n\t\t\t\tif (search) {\n\t\t\t\t\tparams._search = search\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst rows = (response && response.data && (response.data.results || response.data)) || []\n\t\t\t\tconst list = Array.isArray(rows) ? rows : []\n\t\t\t\tconst options = list\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst self = (row && row['@self']) || {}\n\t\t\t\t\t\tconst value = String(self.id || self.uuid || row.id || row.uuid || '')\n\t\t\t\t\t\tconst label = String((ref.labelField && row[ref.labelField]) || row.name || row.title || self.name || value)\n\t\t\t\t\t\treturn { value, label }\n\t\t\t\t\t})\n\t\t\t\t\t.filter((o) => o.value !== '')\n\t\t\t\tthis.referenceOptions = options\n\t\t\t\tthis.referenceLabels = { ...this.referenceLabels, ...Object.fromEntries(options.map((o) => [o.value, o.label])) }\n\t\t\t} catch {\n\t\t\t\tthis.referenceOptions = []\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'The list could not load.')\n\t\t\t} finally {\n\t\t\t\tthis.referenceLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-column-filter {\n\tz-index: 10000;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tpadding: 12px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n\tfont-weight: normal;\n\ttext-align: start;\n}\n\n.cn-column-filter__heading {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-column-filter__options {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n}\n\n.cn-column-filter__option {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 32px;\n\tcursor: pointer;\n}\n\n.cn-column-filter__range {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-column-filter__field {\n\tdisplay: flex;\n\tflex: 1 1 0;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-column-filter__label {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__input {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tmargin: 0;\n}\n\n.cn-column-filter__hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n.cn-column-filter__button {\n\tmin-height: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n}\n\n.cn-column-filter__button--primary {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-column-filter__button:focus-visible,\n.cn-column-filter__input:focus-visible,\n.cn-column-filter__option input:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-column-filter__sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_createElementVNode","_Fragment","_toDisplayString","_createElementBlock","_renderList","_openBlock","_vModelDynamic","_vModelText"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnColumnFilterPopover.vue3.js","sources":["../../../../src/components/CnDataTable/CnColumnFilterPopover.vue?vue&type=template&id=2cb54356&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<Teleport to=\"body\" :disabled=\"!teleport\">\n\t\t<div\n\t\t\tref=\"panel\"\n\t\t\tclass=\"cn-column-filter\"\n\t\t\trole=\"dialog\"\n\t\t\t:aria-labelledby=\"headingId\"\n\t\t\t:style=\"panelStyle\"\n\t\t\tdata-testid=\"cn-column-filter\"\n\t\t\t@keydown.esc.stop.prevent=\"close\"\n\t\t\t@keydown.enter=\"onEnter\">\n\t\t\t<p :id=\"headingId\" class=\"cn-column-filter__heading\">\n\t\t\t\t{{ headingText }}\n\t\t\t</p>\n\n\t\t\t<!-- enum and reference: a checkbox list of real inputs -->\n\t\t\t<template v-if=\"def.kind === 'enum' || def.kind === 'reference'\">\n\t\t\t\t<label v-if=\"def.kind === 'reference'\" class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ searchLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"query\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\ttype=\"search\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-search\"\n\t\t\t\t\t\t@input=\"onSearchInput\">\n\t\t\t\t</label>\n\t\t\t\t<p v-if=\"def.kind === 'reference' && referenceLoading\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ loadingLabel }}\n\t\t\t\t</p>\n\t\t\t\t<p v-else-if=\"def.kind === 'reference' && referenceError\" class=\"cn-column-filter__hint\" role=\"status\">\n\t\t\t\t\t{{ referenceError }}\n\t\t\t\t</p>\n\t\t\t\t<fieldset class=\"cn-column-filter__options\">\n\t\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t\t{{ headingText }}\n\t\t\t\t\t</legend>\n\t\t\t\t\t<label\n\t\t\t\t\t\tv-for=\"option in listOptions\"\n\t\t\t\t\t\t:key=\"option.value\"\n\t\t\t\t\t\tclass=\"cn-column-filter__option\">\n\t\t\t\t\t\t<input\n\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t\t:checked=\"draft.values.includes(option.value)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t\t@change=\"toggleValue(option.value)\">\n\t\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t\t</label>\n\t\t\t\t\t<p v-if=\"listOptions.length === 0 && !referenceLoading\" class=\"cn-column-filter__hint\">\n\t\t\t\t\t\t{{ noOptionsLabel }}\n\t\t\t\t\t</p>\n\t\t\t\t</fieldset>\n\t\t\t</template>\n\n\t\t\t<!-- boolean: yes, no, any -->\n\t\t\t<fieldset v-else-if=\"def.kind === 'boolean'\" class=\"cn-column-filter__options\">\n\t\t\t\t<legend class=\"cn-column-filter__sr-only\">\n\t\t\t\t\t{{ headingText }}\n\t\t\t\t</legend>\n\t\t\t\t<label v-for=\"option in booleanOptions\" :key=\"option.value\" class=\"cn-column-filter__option\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t:name=\"headingId + '-bool'\"\n\t\t\t\t\t\t:value=\"option.value\"\n\t\t\t\t\t\t:checked=\"draft.value === option.value\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-option\"\n\t\t\t\t\t\t@change=\"draft.value = option.value\">\n\t\t\t\t\t<span>{{ option.label }}</span>\n\t\t\t\t</label>\n\t\t\t</fieldset>\n\n\t\t\t<!-- number and date: from and to -->\n\t\t\t<div v-else-if=\"def.kind === 'number' || def.kind === 'date'\" class=\"cn-column-filter__range\">\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ fromLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.from\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-from\">\n\t\t\t\t</label>\n\t\t\t\t<label class=\"cn-column-filter__field\">\n\t\t\t\t\t<span class=\"cn-column-filter__label\">{{ toLabel }}</span>\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-model=\"draft.to\"\n\t\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\t\t:type=\"def.kind === 'date' ? 'date' : 'number'\"\n\t\t\t\t\t\tdata-testid=\"cn-column-filter-to\">\n\t\t\t\t</label>\n\t\t\t</div>\n\n\t\t\t<!-- string: contains (OpenRegister `[like]`, case-insensitive) -->\n\t\t\t<label v-else class=\"cn-column-filter__field\">\n\t\t\t\t<span class=\"cn-column-filter__label\">{{ containsLabel }}</span>\n\t\t\t\t<input\n\t\t\t\t\tv-model=\"draft.value\"\n\t\t\t\t\tclass=\"cn-column-filter__input\"\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-text\">\n\t\t\t</label>\n\n\t\t\t<div class=\"cn-column-filter__actions\">\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-clear\"\n\t\t\t\t\t@click=\"clear\">\n\t\t\t\t\t{{ clearLabel }}\n\t\t\t\t</button>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"cn-column-filter__button cn-column-filter__button--primary\"\n\t\t\t\t\tdata-testid=\"cn-column-filter-apply\"\n\t\t\t\t\t@click=\"apply\">\n\t\t\t\t\t{{ applyLabel }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t</div>\n\t</Teleport>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\n\nlet popoverSeq = 0\n\n/**\n * CnColumnFilterPopover — the small panel a table header's filter button opens.\n *\n * Renders the control that fits the column: a checkbox list for an enum, yes,\n * no or any for a boolean, from and to for a number or a date, a searchable\n * list of referenced objects for a reference, and a contains box for text.\n * Real inputs throughout, so every control works from the keyboard. Escape\n * closes it and the host returns focus to the filter button.\n *\n * Internal to CnDataTable. It emits a state object; CnDataTable turns that\n * into query parameters with `columnFilterParams`.\n *\n * @spec openspec/changes/table-header-sort-and-filter/specs/cn-data-table/spec.md#requirement-every-backed-column-filters-from-its-header\n */\nexport default {\n\tname: 'CnColumnFilterPopover',\n\n\tprops: {\n\t\t/** The filter definition from `columnFilterDef`. */\n\t\tdef: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** The column's current state from `columnFilterState`. */\n\t\tstate: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The translated column label. */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The filter button's bounding rect, to place the panel under it. */\n\t\tanchorRect: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Register slug a reference column's objects live in, when the column names none. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Render into `<body>`, so a scrolling table cannot clip the panel. */\n\t\tteleport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['apply', 'close'],\n\n\tdata() {\n\t\tpopoverSeq += 1\n\t\tconst s = this.state || {}\n\t\treturn {\n\t\t\theadingId: 'cn-column-filter-' + popoverSeq,\n\t\t\tdraft: {\n\t\t\t\tvalues: Array.isArray(s.values) ? [...s.values] : [],\n\t\t\t\tvalue: s.value !== undefined && s.value !== null ? String(s.value) : '',\n\t\t\t\tfrom: s.from || '',\n\t\t\t\tto: s.to || '',\n\t\t\t},\n\n\t\t\tquery: '',\n\t\t\treferenceOptions: [],\n\t\t\treferenceLabels: {},\n\t\t\treferenceLoading: false,\n\t\t\treferenceError: '',\n\t\t\tsearchTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\theadingText() {\n\t\t\treturn t('nextcloud-vue', 'Filter {column}', { column: this.label })\n\t\t},\n\n\t\t/**\n\t\t * The options a list filter shows. For a reference, the search results\n\t\t * plus any picked object that is not among them, so a selection never\n\t\t * disappears from view.\n\t\t *\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\tlistOptions() {\n\t\t\tif (this.def.kind !== 'reference') {\n\t\t\t\treturn this.def.options || []\n\t\t\t}\n\t\t\tconst shown = new Set(this.referenceOptions.map((o) => o.value))\n\t\t\tconst picked = this.draft.values\n\t\t\t\t.filter((v) => !shown.has(v))\n\t\t\t\t.map((v) => ({ value: v, label: this.referenceLabels[v] || v }))\n\t\t\treturn [...picked, ...this.referenceOptions]\n\t\t},\n\n\t\tbooleanOptions() {\n\t\t\treturn [\n\t\t\t\t{ value: '', label: t('nextcloud-vue', 'Any') },\n\t\t\t\t{ value: 'true', label: t('nextcloud-vue', 'Yes') },\n\t\t\t\t{ value: 'false', label: t('nextcloud-vue', 'No') },\n\t\t\t]\n\t\t},\n\n\t\tpanelStyle() {\n\t\t\tif (!this.teleport || !this.anchorRect) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst width = 280\n\t\t\tconst viewport = typeof window !== 'undefined' ? window.innerWidth : 1024\n\t\t\tconst left = Math.max(8, Math.min(this.anchorRect.left, viewport - width - 8))\n\t\t\treturn { position: 'fixed', top: `${this.anchorRect.bottom + 4}px`, left: `${left}px`, width: `${width}px` }\n\t\t},\n\n\t\tsearchLabel() {\n\t\t\treturn t('nextcloud-vue', 'Search')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\tnoOptionsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing to choose from here.')\n\t\t},\n\n\t\tfromLabel() {\n\t\t\treturn t('nextcloud-vue', 'From')\n\t\t},\n\n\t\ttoLabel() {\n\t\t\treturn t('nextcloud-vue', 'To')\n\t\t},\n\n\t\t/**\n\t\t * Label of the text box: the text filter matches on contains.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/header-filter-contains/specs/cn-data-table/spec.md#requirement-a-text-header-filter-matches-on-contains\n\t\t */\n\t\tcontainsLabel() {\n\t\t\treturn t('nextcloud-vue', 'Contains')\n\t\t},\n\n\t\tclearLabel() {\n\t\t\treturn t('nextcloud-vue', 'Clear')\n\t\t},\n\n\t\tapplyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Apply')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tdocument.addEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tif (this.def.kind === 'reference') {\n\t\t\tthis.loadReferenceOptions('')\n\t\t}\n\t\tthis.$nextTick(() => {\n\t\t\tconst first = this.$refs.panel && this.$refs.panel.querySelector('input, button')\n\t\t\tif (first && typeof first.focus === 'function') {\n\t\t\t\tfirst.focus()\n\t\t\t}\n\t\t})\n\t},\n\n\tbeforeUnmount() {\n\t\tdocument.removeEventListener('mousedown', this.onOutsideMouseDown, true)\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\ttoggleValue(value) {\n\t\t\tthis.draft.values = this.draft.values.includes(value)\n\t\t\t\t? this.draft.values.filter((v) => v !== value)\n\t\t\t\t: [...this.draft.values, value]\n\t\t},\n\n\t\t/**\n\t\t * The state this panel applies, in the shape `columnFilterParams` reads.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tdraftState() {\n\t\t\tif (this.def.kind === 'enum' || this.def.kind === 'reference') {\n\t\t\t\treturn { values: [...this.draft.values] }\n\t\t\t}\n\t\t\tif (this.def.kind === 'number' || this.def.kind === 'date') {\n\t\t\t\treturn { from: this.draft.from, to: this.draft.to }\n\t\t\t}\n\t\t\treturn { value: this.draft.value }\n\t\t},\n\n\t\tapply() {\n\t\t\t/**\n\t\t\t * @event apply The person applied the filter.\n\t\t\t * @type {object} The column filter state.\n\t\t\t */\n\t\t\tthis.$emit('apply', this.draftState())\n\t\t},\n\n\t\tclear() {\n\t\t\tthis.$emit('apply', this.def.kind === 'enum' || this.def.kind === 'reference'\n\t\t\t\t? { values: [] }\n\t\t\t\t: (this.def.kind === 'number' || this.def.kind === 'date') ? { from: '', to: '' } : { value: '' })\n\t\t},\n\n\t\tclose() {\n\t\t\t/**\n\t\t\t * @event close The panel should close without applying.\n\t\t\t */\n\t\t\tthis.$emit('close')\n\t\t},\n\n\t\tonEnter(event) {\n\t\t\t// Enter in a text, number or date box applies, like a form submit.\n\t\t\t// On a checkbox or a button it keeps its own meaning.\n\t\t\tconst target = event && event.target\n\t\t\tif (target && target.tagName === 'INPUT' && ['text', 'number', 'date', 'search'].includes(target.type)) {\n\t\t\t\tevent.preventDefault()\n\t\t\t\tthis.apply()\n\t\t\t}\n\t\t},\n\n\t\tonOutsideMouseDown(event) {\n\t\t\tconst panel = this.$refs.panel\n\t\t\tif (panel && event && event.target && !panel.contains(event.target)) {\n\t\t\t\tthis.close()\n\t\t\t}\n\t\t},\n\n\t\tonSearchInput() {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.loadReferenceOptions(this.query), 250)\n\t\t},\n\n\t\t/**\n\t\t * Search the referenced objects. The value is the object's uuid,\n\t\t * because that is what the server filters a reference on.\n\t\t *\n\t\t * @param {string} search The search term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferenceOptions(search) {\n\t\t\tconst ref = this.def.reference || {}\n\t\t\tconst register = ref.register || this.register\n\t\t\tif (!register || !ref.schema) {\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'This column cannot list its objects.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.referenceLoading = true\n\t\t\tthis.referenceError = ''\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}', {\n\t\t\t\t\tregister,\n\t\t\t\t\tschema: String(ref.schema),\n\t\t\t\t})\n\t\t\t\tconst params = { _limit: 50 }\n\t\t\t\tif (search) {\n\t\t\t\t\tparams._search = search\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst rows = (response && response.data && (response.data.results || response.data)) || []\n\t\t\t\tconst list = Array.isArray(rows) ? rows : []\n\t\t\t\tconst options = list\n\t\t\t\t\t.map((row) => {\n\t\t\t\t\t\tconst self = (row && row['@self']) || {}\n\t\t\t\t\t\tconst value = String(self.id || self.uuid || row.id || row.uuid || '')\n\t\t\t\t\t\tconst label = String((ref.labelField && row[ref.labelField]) || row.name || row.title || self.name || value)\n\t\t\t\t\t\treturn { value, label }\n\t\t\t\t\t})\n\t\t\t\t\t.filter((o) => o.value !== '')\n\t\t\t\tthis.referenceOptions = options\n\t\t\t\tthis.referenceLabels = { ...this.referenceLabels, ...Object.fromEntries(options.map((o) => [o.value, o.label])) }\n\t\t\t} catch {\n\t\t\t\tthis.referenceOptions = []\n\t\t\t\tthis.referenceError = t('nextcloud-vue', 'The list could not load.')\n\t\t\t} finally {\n\t\t\t\tthis.referenceLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-column-filter {\n\tz-index: 10000;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tbox-sizing: border-box;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tpadding: 12px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbox-shadow: 0 2px 8px var(--color-box-shadow);\n\tfont-weight: normal;\n\ttext-align: start;\n}\n\n.cn-column-filter__heading {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-column-filter__options {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n}\n\n.cn-column-filter__option {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 32px;\n\tcursor: pointer;\n}\n\n.cn-column-filter__range {\n\tdisplay: flex;\n\tgap: 8px;\n}\n\n.cn-column-filter__field {\n\tdisplay: flex;\n\tflex: 1 1 0;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-column-filter__label {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__input {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\tmargin: 0;\n}\n\n.cn-column-filter__hint {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-column-filter__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n.cn-column-filter__button {\n\tmin-height: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tcursor: pointer;\n}\n\n.cn-column-filter__button--primary {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n}\n\n.cn-column-filter__button:focus-visible,\n.cn-column-filter__input:focus-visible,\n.cn-column-filter__option input:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-column-filter__sr-only {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["_createElementVNode","_Fragment","_toDisplayString","_createElementBlock","_renderList","_openBlock","_vModelDynamic","_vModelText"],"mappings":"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"}
|
|
@@ -13,25 +13,28 @@ import InformationOutline from 'vue-material-design-icons/InformationOutline.vue
|
|
|
13
13
|
import Pencil from 'vue-material-design-icons/Pencil.vue';
|
|
14
14
|
import Plus from 'vue-material-design-icons/Plus.vue';
|
|
15
15
|
import Refresh from 'vue-material-design-icons/Refresh.vue';
|
|
16
|
-
import
|
|
17
|
-
import __sfc_main$
|
|
16
|
+
import ViewDashboardOutline from 'vue-material-design-icons/ViewDashboardOutline.vue';
|
|
17
|
+
import __sfc_main$i from '../../dialogs/CnRelationLinkModal.vue.js';
|
|
18
|
+
import __sfc_main$h from '../../dialogs/CnWidgetStyleEditorModal.vue.js';
|
|
18
19
|
import __sfc_main$1 from '../CnActionsMenu/CnActionsMenu.vue.js';
|
|
19
|
-
import __sfc_main$
|
|
20
|
+
import __sfc_main$f from '../CnBodySections/CnBodySections.vue.js';
|
|
20
21
|
import __sfc_main$2 from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
|
|
21
22
|
import __sfc_main$7 from '../CnDashboardGrid/CnDashboardGrid.vue.js';
|
|
22
23
|
import __sfc_main$5 from '../CnDetailWidgetHost/CnDetailWidgetHost.vue.js';
|
|
23
24
|
import __sfc_main$6 from '../CnFormDialog/CnFormDialog.vue.js';
|
|
24
|
-
import __sfc_main$
|
|
25
|
+
import __sfc_main$9 from '../CnLifecycleActions/CnLifecycleActions.vue.js';
|
|
25
26
|
import __sfc_main$3 from '../CnLockedBanner/CnLockedBanner.vue.js';
|
|
26
27
|
import __sfc_main$4 from '../CnNextStepCard/CnNextStepCard.vue.js';
|
|
27
|
-
import __sfc_main$
|
|
28
|
-
import __sfc_main$
|
|
29
|
-
import __sfc_main$
|
|
28
|
+
import __sfc_main$e from '../CnRelatedCollections/CnRelatedCollections.vue.js';
|
|
29
|
+
import __sfc_main$8 from '../CnSegmentedControl/CnSegmentedControl.vue.js';
|
|
30
|
+
import __sfc_main$d from '../CnSummaryAggregates/CnSummaryAggregates.vue.js';
|
|
31
|
+
import __sfc_main$g from '../CnTranslatedBadge/CnTranslatedBadge.vue.js';
|
|
30
32
|
import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js';
|
|
31
33
|
import { useObjectLock } from '../../composables/useObjectLock.js';
|
|
32
34
|
import { useObjectPresence } from '../../composables/useObjectPresence.js';
|
|
33
35
|
import { useObjectSubscription } from '../../composables/useObjectSubscription.js';
|
|
34
36
|
import { gridLayout } from '../../mixins/gridLayout.js';
|
|
37
|
+
import { pageViews } from '../../mixins/pageViews.js';
|
|
35
38
|
import { isAppInstalled } from '../../utils/appInstalled.js';
|
|
36
39
|
import { compactLayoutRows } from '../../utils/dashboardPlacement.js';
|
|
37
40
|
import { defaultDetailGrid } from '../../utils/defaultDetailGrid.js';
|
|
@@ -39,10 +42,10 @@ import { stageOf, normalisePinnedAction, stageEntry, MAX_QUICK_ACTIONS, groupMen
|
|
|
39
42
|
import { cnGridCellStyle, hasGridRow } from '../../utils/grid.js';
|
|
40
43
|
import { slotRenders } from '../../utils/slotContent.js';
|
|
41
44
|
import { isDataWidgetDef, isRelatedWidgetDef, isGeoWidgetDef, isContentOnlyWidgetDef, isCardWidgetDef, widgetContentOf, resolveRegistryRenderer, widgetTitleOf } from '../../utils/widgetDispatch.js';
|
|
42
|
-
import __sfc_main$
|
|
43
|
-
import __sfc_main$
|
|
45
|
+
import __sfc_main$a from '../CnActionButtons/CnActionButtons.vue.js';
|
|
46
|
+
import __sfc_main$b from '../CnBreadcrumbs/CnBreadcrumbs.vue.js';
|
|
44
47
|
import __sfc_main from '../CnIcon/CnIcon.vue.js';
|
|
45
|
-
import __sfc_main$
|
|
48
|
+
import __sfc_main$c from '../CnStatusBadge/CnStatusBadge.vue.js';
|
|
46
49
|
import { getWidgetTypeEntry } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
|
|
47
50
|
import '../CnWidgetGrid/registerDashboardWidgets.js';
|
|
48
51
|
import { useObjectStore } from '../../store/useObjectStore.js';
|
|
@@ -186,22 +189,24 @@ var script = {
|
|
|
186
189
|
CnDetailWidgetHost: __sfc_main$5,
|
|
187
190
|
CnFormDialog: __sfc_main$6,
|
|
188
191
|
CnDashboardGrid: __sfc_main$7,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
192
|
+
CnSegmentedControl: __sfc_main$8,
|
|
193
|
+
ViewDashboardOutline,
|
|
194
|
+
CnLifecycleActions: __sfc_main$9,
|
|
195
|
+
CnActionButtons: __sfc_main$a,
|
|
196
|
+
CnBreadcrumbs: __sfc_main$b,
|
|
197
|
+
CnStatusBadge: __sfc_main$c,
|
|
198
|
+
CnSummaryAggregates: __sfc_main$d,
|
|
199
|
+
CnRelatedCollections: __sfc_main$e,
|
|
200
|
+
CnBodySections: __sfc_main$f,
|
|
201
|
+
CnTranslatedBadge: __sfc_main$g,
|
|
202
|
+
CnWidgetStyleEditorModal: __sfc_main$h,
|
|
203
|
+
CnRelationLinkModal: __sfc_main$i,
|
|
199
204
|
Cog,
|
|
200
205
|
Plus,
|
|
201
206
|
Pencil,
|
|
202
207
|
},
|
|
203
208
|
|
|
204
|
-
mixins: [gridLayout],
|
|
209
|
+
mixins: [gridLayout, pageViews],
|
|
205
210
|
|
|
206
211
|
inject: {
|
|
207
212
|
/**
|
|
@@ -2421,6 +2426,7 @@ var script = {
|
|
|
2421
2426
|
&& this.currentObject
|
|
2422
2427
|
&& !this.hasDefaultSlotContent
|
|
2423
2428
|
&& !this.hasGridLayout
|
|
2429
|
+
&& !this.hasViews
|
|
2424
2430
|
},
|
|
2425
2431
|
|
|
2426
2432
|
/**
|
|
@@ -2500,6 +2506,55 @@ var script = {
|
|
|
2500
2506
|
return this.bodyGridLayout.length > 0
|
|
2501
2507
|
},
|
|
2502
2508
|
|
|
2509
|
+
/**
|
|
2510
|
+
* The chosen view's layout as the grid draws it: items that draw
|
|
2511
|
+
* nothing leave and their rows close, as for the body grid.
|
|
2512
|
+
*
|
|
2513
|
+
* @return {Array<object>}
|
|
2514
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
|
|
2515
|
+
*/
|
|
2516
|
+
viewDisplayLayout() {
|
|
2517
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- reading the flag IS the effect, as in bodyGridLayout
|
|
2518
|
+
this.editingBody;
|
|
2519
|
+
return this.activeView ? this.closeDroppedRows(this.activeView.layout) : []
|
|
2520
|
+
},
|
|
2521
|
+
|
|
2522
|
+
/**
|
|
2523
|
+
* Whether the chosen view has nothing to draw.
|
|
2524
|
+
*
|
|
2525
|
+
* @return {boolean}
|
|
2526
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-view-with-nothing-to-draw-says-so
|
|
2527
|
+
*/
|
|
2528
|
+
viewIsEmpty() {
|
|
2529
|
+
return this.hasViews && this.viewDisplayLayout.length === 0
|
|
2530
|
+
},
|
|
2531
|
+
|
|
2532
|
+
/**
|
|
2533
|
+
* The grids the body draws: the body grid when it has items, then the
|
|
2534
|
+
* chosen view's grid in the region the view switch controls (left out
|
|
2535
|
+
* when the view is empty; the empty state takes the region then).
|
|
2536
|
+
*
|
|
2537
|
+
* @return {Array<{key: string, view: boolean, layout: Array<object>, attrs: object}>}
|
|
2538
|
+
* @spec openspec/changes/view-switch-containers/specs/view-switch-containers/spec.md#requirement-a-page-declares-views-that-each-hold-a-widget-grid
|
|
2539
|
+
*/
|
|
2540
|
+
bodyGridSections() {
|
|
2541
|
+
const sections = this.hasBodyGrid ? [{ key: 'body', view: false, layout: this.bodyGridLayout, attrs: {} }] : [];
|
|
2542
|
+
if (this.hasViews && !this.viewIsEmpty) {
|
|
2543
|
+
sections.push({
|
|
2544
|
+
key: `view-${this.activeViewId}`,
|
|
2545
|
+
view: true,
|
|
2546
|
+
layout: this.viewDisplayLayout,
|
|
2547
|
+
attrs: {
|
|
2548
|
+
id: this.viewRegionId,
|
|
2549
|
+
role: 'region',
|
|
2550
|
+
'aria-label': this.activeView.label,
|
|
2551
|
+
'data-testid': 'cn-detail-page-view-region',
|
|
2552
|
+
},
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
return sections
|
|
2556
|
+
},
|
|
2557
|
+
|
|
2503
2558
|
/**
|
|
2504
2559
|
* Whether the sidebar is rendered externally (via objectSidebarState inject)
|
|
2505
2560
|
* rather than inline. When external, CnDetailPage only manages state —
|
|
@@ -3721,6 +3776,8 @@ var script = {
|
|
|
3721
3776
|
*/
|
|
3722
3777
|
findWidget(item) {
|
|
3723
3778
|
return this.bodyGridWidgets.find((w) => w.id === item.widgetId)
|
|
3779
|
+
|| this.findViewWidget(item.widgetId)
|
|
3780
|
+
|| undefined
|
|
3724
3781
|
},
|
|
3725
3782
|
|
|
3726
3783
|
/**
|