@conduction/nextcloud-vue 2.56.0-beta.11 → 2.56.0-beta.13
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/CnAppNav/CnAppNav.vue2.js +253 -10
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +139 -46
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +87 -0
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +26 -24
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +154 -4
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +555 -480
- 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/CnDataTable/CnDataTable.vue2.js +37 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +12 -4
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +187 -19
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +215 -135
- 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 +157 -7
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +23 -5
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +5 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.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/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
- package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +74 -5
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +15 -8
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +5 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +5 -1
- 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 +513 -81
- package/dist/esm/store/useObjectStore.js +118 -33
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +25 -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/schemaRefSlug.js +19 -3
- package/dist/esm/utils/schemaRefSlug.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 +8858 -6566
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +513 -81
- package/l10n/en.json +5 -0
- package/l10n/nl.json +5 -0
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +441 -14
- package/src/components/CnAppRoot/CnAppRoot.md +4 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +94 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
- package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +237 -12
- package/src/components/CnDataTable/CnColumnFilterPopover.vue +11 -5
- package/src/components/CnDataTable/CnDataTable.vue +45 -1
- package/src/components/CnDetailPage/CnDetailPage.md +8 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +263 -7
- package/src/components/CnFkResolveCell/CnFkResolveCell.vue +3 -1
- package/src/components/CnFormDialog/CnFormDialog.vue +144 -4
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +206 -9
- package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
- package/src/components/CnSegmentedControl/CnSegmentedControl.md +1 -1
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +12 -0
- package/src/components/CnStagesWidget/CnStagesWidget.vue +189 -2
- package/src/components/CnStagesWidget/stagesModel.js +5 -2
- package/src/components/CnStatWidget/CnStatWidget.vue +89 -7
- package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
- package/src/css/detail-page.css +37 -4
- package/src/css/kpi-card.css +71 -1
- package/src/css/table.css +18 -6
- package/src/mixins/pageViews.js +396 -0
- package/src/schemas/app-manifest-v2.schema.json +162 -3
- package/src/store/useObjectStore.js +118 -33
- package/src/utils/actionsDispatcher.js +25 -2
- package/src/utils/columnFilters.js +29 -2
- package/src/utils/schema.js +40 -2
- package/src/utils/schemaRefSlug.js +19 -3
- 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":"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"}
|
|
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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"}
|
|
@@ -107,7 +107,13 @@ var script = {
|
|
|
107
107
|
* reader is looking. `columnsFromSchema` fills it from the JSON Schema property
|
|
108
108
|
* description automatically, so schema-driven tables get it for free.
|
|
109
109
|
*
|
|
110
|
-
*
|
|
110
|
+
* `secondary` draws a second, muted line under the cell's value: a field
|
|
111
|
+
* key (`"number"`), a template with `{field}` placeholders
|
|
112
|
+
* (`"{number} · {requester}"`, dotted paths allowed), or a function of
|
|
113
|
+
* the row. Empty fields leave their placeholder blank; a line that
|
|
114
|
+
* resolves to nothing is not drawn.
|
|
115
|
+
*
|
|
116
|
+
* @type {Array<{key: string, label: string, description: string, sortable: boolean, width: string, class: string, cellClass: string, secondary: (string|((row: object) => string))}|string>}
|
|
111
117
|
*/
|
|
112
118
|
columns: {
|
|
113
119
|
type: Array,
|
|
@@ -1078,6 +1084,36 @@ var script = {
|
|
|
1078
1084
|
* @param {object} col The column definition.
|
|
1079
1085
|
* @return {unknown} The value handed to the slot / CnCellRenderer.
|
|
1080
1086
|
*/
|
|
1087
|
+
/**
|
|
1088
|
+
* The secondary line of a cell, from `col.secondary`: a function is
|
|
1089
|
+
* called with the row; a string with `{field}` placeholders is a
|
|
1090
|
+
* template filled from the row (dotted paths allowed); any other
|
|
1091
|
+
* string is a field key. Returns '' when there is nothing to draw.
|
|
1092
|
+
*
|
|
1093
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-table-column-carries-a-secondary-line
|
|
1094
|
+
* @param {object} row The row.
|
|
1095
|
+
* @param {object} col The column definition.
|
|
1096
|
+
* @return {string} The secondary text, or ''.
|
|
1097
|
+
*/
|
|
1098
|
+
secondaryValue(row, col) {
|
|
1099
|
+
const spec = col?.secondary;
|
|
1100
|
+
if (typeof spec === 'function') {
|
|
1101
|
+
const out = spec(row);
|
|
1102
|
+
return out === null || out === undefined ? '' : String(out)
|
|
1103
|
+
}
|
|
1104
|
+
if (typeof spec !== 'string' || spec === '') {
|
|
1105
|
+
return ''
|
|
1106
|
+
}
|
|
1107
|
+
const asText = (v) => (v === null || v === undefined ? '' : String(v));
|
|
1108
|
+
if (spec.includes('{')) {
|
|
1109
|
+
const filled = spec.replace(/\{([^}]+)\}/g, (_, key) => asText(this.getCellValue(row, key.trim())));
|
|
1110
|
+
// A template whose every field is empty leaves only separators:
|
|
1111
|
+
// nothing worth a line.
|
|
1112
|
+
return /[\p{L}\p{N}]/u.test(filled) ? filled.trim() : ''
|
|
1113
|
+
}
|
|
1114
|
+
return asText(this.getCellValue(row, spec))
|
|
1115
|
+
},
|
|
1116
|
+
|
|
1081
1117
|
cellValue(row, col) {
|
|
1082
1118
|
if (col && col.aggregate) {
|
|
1083
1119
|
const cached = this.aggregateValues[String(row[this.rowKey])];
|