@conduction/nextcloud-vue 2.141.0 → 2.143.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/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +27 -0
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue2.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue3.js +2 -1
- package/dist/esm/components/CnAiCompanion/CnAiChatPanel.vue3.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue2.js +9 -0
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue2.js.map +1 -1
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue3.js +21 -22
- package/dist/esm/components/CnAiCompanion/CnAiInput.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +29 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js +28 -13
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +13 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +3 -3
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +21 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +34 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +70 -5
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +5 -3
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +17 -4
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +21 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +36 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +14 -0
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +3 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js +6 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue2.js.map +1 -1
- package/dist/esm/components/CnPageHeader/CnHeaderTrail.vue3.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +31 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +12 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +2 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +4 -0
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +18 -8
- package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue2.js +52 -1
- package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue3.js +119 -65
- package/dist/esm/integrations/builtin/contacts/CnContactsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js +86 -4
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js +67 -5
- package/dist/esm/integrations/builtin/deck/CnDeckCard.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +10 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +12 -3
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +976 -592
- package/dist/esm/utils/buildViewTree.js +23 -8
- package/dist/esm/utils/buildViewTree.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1363 -734
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +976 -592
- package/l10n/en.json +10 -1
- package/l10n/nl.json +12 -3
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +28 -1
- package/src/components/CnAiCompanion/CnAiChatPanel.vue +12 -0
- package/src/components/CnAiCompanion/CnAiInput.vue +32 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +34 -4
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +1 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +15 -1
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +8 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +1 -0
- package/src/components/CnDataTable/CnDataTable.md +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +22 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +1 -0
- package/src/components/CnFactsWidget/CnFactsWidget.vue +34 -3
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +72 -7
- package/src/components/CnFilesBrowser/filesBrowser.js +17 -4
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +20 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +37 -2
- package/src/components/CnIndexPage/useSelfFetchList.js +14 -0
- package/src/components/CnObjectSidebar/CnFilesTab.vue +4 -1
- package/src/components/CnPageHeader/CnHeaderTrail.vue +6 -1
- package/src/components/CnPartyPicker/CnPartyPicker.vue +31 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +21 -1
- package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +6 -0
- package/src/components/CnTimelineWidget/CnTimelineManage.vue +10 -1
- package/src/css/dialog.css +18 -0
- package/src/css/look-board-detail.css +126 -0
- package/src/css/look-board-index.css +95 -1
- package/src/css/look-board.css +90 -1
- package/src/integrations/builtin/contacts/CnContactsTab.vue +101 -26
- package/src/integrations/builtin/contacts/__tests__/CnContactsTabBoardRows.spec.js +67 -0
- package/src/integrations/builtin/deck/CnDeckCard.vue +121 -2
- package/src/integrations/builtin/deck/__tests__/CnDeckCardHeaderActions.spec.js +68 -0
- package/src/utils/buildViewTree.js +23 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnRecordListWidget.vue3.js","sources":["../../../../src/components/CnRecordListWidget/CnRecordListWidget.vue?vue&type=template&id=2c65cbc2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-record-list\"\n\t\t:class=\"[`cn-record-list--${presentation}`, { 'cn-record-list--compact': content.density === 'compact', 'cn-record-list--stacked': content.density === 'stacked', 'cn-record-list--tiles': presentation === 'rows' && content.tiles === true, 'cn-record-list--rule-above': content.ruleAbove === true, 'cn-record-list--data-table': presentation === 'table' && content.tableLook === 'data' }]\"\n\t\tdata-testid=\"cn-record-list\">\n\t\t<p v-if=\"intro && !absent\" class=\"cn-record-list__intro\" data-testid=\"cn-record-list-intro\">\n\t\t\t{{ intro }}\n\t\t</p>\n\t\t<p v-if=\"absent\" class=\"cn-record-list__empty\" data-testid=\"cn-record-list-absent\">\n\t\t\t{{ absentLabel }}\n\t\t</p>\n\t\t<p v-else-if=\"error\" class=\"cn-record-list__error\" data-testid=\"cn-record-list-error\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"loading && rows.length === 0\" class=\"cn-record-list__loading\">\n\t\t\t<NcLoadingIcon :size=\"20\" :name=\"loadingLabel\" />\n\t\t</div>\n\t\t<template v-else-if=\"rows.length === 0\">\n\t\t\t<p v-if=\"emptyLabel !== ''\" class=\"cn-record-list__empty\" data-testid=\"cn-record-list-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\t\t</template>\n\t\t<!-- notice: the rows as sentences in one toned box (\"2 waarschuwingen: ...\"). -->\n\t\t<div\n\t\t\tv-else-if=\"presentation === 'notice'\"\n\t\t\tclass=\"cn-record-list__notice\"\n\t\t\t:class=\"`cn-record-list__notice--${noticeVariant}`\"\n\t\t\trole=\"note\"\n\t\t\tdata-testid=\"cn-record-list-notice\">\n\t\t\t<CnIcon\n\t\t\t\t:name=\"noticeIcon\"\n\t\t\t\t:size=\"18\"\n\t\t\t\tclass=\"cn-record-list__notice-icon\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t\t<p class=\"cn-record-list__notice-text\">\n\t\t\t\t{{ noticeText }}\n\t\t\t</p>\n\t\t</div>\n\t\t<!-- table: one row per record under a header, one cell per `columns`\n\t\t entry; a cell past its `alertAbove` reads bold in the danger colour,\n\t\t a `tone` cell is a toned label, a `sortable` header sorts the rows. -->\n\t\t<table v-else-if=\"presentation === 'table'\" class=\"cn-record-list__table\" data-testid=\"cn-record-list-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"col in tableColumns\"\n\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t:aria-sort=\"col.sortable ? sortStateOf(col.key) : undefined\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__cell--end': col.align === 'end' }\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tv-if=\"col.sortable\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__sort\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-sort-${col.key}`\"\n\t\t\t\t\t\t\t@click=\"toggleTableSort(col.key)\">\n\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t\t<span class=\"cn-record-list__sort-mark\" aria-hidden=\"true\">{{ sortMarkOf(col.key) }}</span>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</th>\n\t\t\t\t\t<th v-if=\"rowActions.length > 0\" scope=\"col\" class=\"cn-record-list__cell--actions\">\n\t\t\t\t\t\t{{ rowActionsHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr v-for=\"item in tableRows\" :key=\"item.key\" data-testid=\"cn-record-list-item\">\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"(cell, cellIndex) in item.cells\"\n\t\t\t\t\t\t:key=\"cell.key\"\n\t\t\t\t\t\t:style=\"cellIndex === 0 && item.depth > 0 ? `padding-inline-start: calc(${item.depth} * 16px)` : undefined\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__cell--end': cell.align === 'end', 'cn-record-list__cell--alert': cell.alert }\">\n\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\tv-if=\"cell.tone\"\n\t\t\t\t\t\t\t:label=\"cell.text\"\n\t\t\t\t\t\t\t:variant=\"cell.tone\"\n\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t<router-link v-else-if=\"cellIndex === 0 && item.to\" :to=\"item.to\" class=\"cn-record-list__cell-text\">\n\t\t\t\t\t\t\t{{ cell.text }}\n\t\t\t\t\t\t</router-link>\n\t\t\t\t\t\t<span v-else class=\"cn-record-list__cell-text\">{{ cell.text }}</span>\n\t\t\t\t\t\t<span v-if=\"cell.sub\" class=\"cn-record-list__cell-sub\">{{ cell.sub }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td v-if=\"rowActions.length > 0\" class=\"cn-record-list__cell--actions\">\n\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\tv-if=\"item.rowActions.length > 0\"\n\t\t\t\t\t\t\t:aria-label=\"rowActionsLabel\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-row-actions\">\n\t\t\t\t\t\t\t<template v-for=\"entry in item.rowActions\" :key=\"`row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t\tv-if=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:href=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:target=\"entry.external ? '_blank' : undefined\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\"\n\t\t\t\t\t\t\t\t\t@click=\"runRowActionEntry(entry.action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<!-- checklist: an optional bar of the done share, then the rows in\n\t\t columns, a done row ticked and an open one an empty circle\n\t\t (DqTenant Inrichten). -->\n\t\t<div\n\t\t\tv-else-if=\"presentation === 'checklist'\"\n\t\t\tclass=\"cn-record-list__checklist-wrap\">\n\t\t\t<div\n\t\t\t\tv-if=\"content.progress\"\n\t\t\t\tclass=\"cn-record-list__checklist-bar\"\n\t\t\t\trole=\"progressbar\"\n\t\t\t\t:aria-valuenow=\"checklistDone\"\n\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t:aria-valuemax=\"items.length\"\n\t\t\t\t:aria-label=\"headerNote || undefined\"\n\t\t\t\tdata-testid=\"cn-record-list-checklist-bar\">\n\t\t\t\t<span class=\"cn-record-list__checklist-fill\" :style=\"{ width: `${checklistPercent}%` }\" />\n\t\t\t</div>\n\t\t\t<ul\n\t\t\t\tclass=\"cn-record-list__checklist\"\n\t\t\t\t:style=\"{ '--cn-record-list-columns': checklistColumns }\"\n\t\t\t\tdata-testid=\"cn-record-list-checklist\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"item in items\"\n\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\tclass=\"cn-record-list__check\"\n\t\t\t\t\t:class=\"{ 'cn-record-list__check--done': isChecked(item.row) }\"\n\t\t\t\t\tdata-testid=\"cn-record-list-check\">\n\t\t\t\t\t<span class=\"cn-record-list__check-mark\" aria-hidden=\"true\">\n\t\t\t\t\t\t<Check v-if=\"isChecked(item.row)\" :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-record-list__check-title\">{{ item.title }}</span>\n\t\t\t\t\t<span class=\"hidden-visually\">{{ isChecked(item.row) ? doneLabel : openLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t\t<!-- notes: a field per row for what happened, recorded on the row's\n\t\t own notes endpoint (DqDagAfsluiten \"Nog open van vandaag\"). -->\n\t\t<CnRecordNoteRows\n\t\t\tv-else-if=\"presentation === 'notes' && noteAction\"\n\t\t\t:items=\"items\"\n\t\t\t:action=\"noteAction\"\n\t\t\t:recordAll=\"noteRecordAll\"\n\t\t\t:leaf=\"content.rowLeaf || null\" />\n\t\t<!-- `groupBy`: a heading per group, each group its own list, named by\n\t\t its heading. Without it this is one list, as before. -->\n\t\t<template v-for=\"group in itemGroups\" v-else :key=\"group.key\">\n\t\t\t<div\n\t\t\t\tv-if=\"group.label && footerGroup !== '' && group.value === footerGroup\"\n\t\t\t\tclass=\"cn-record-list__group-head\"\n\t\t\t\tdata-testid=\"cn-record-list-group-head\">\n\t\t\t\t<h3\n\t\t\t\t\t:id=\"group.headingId\"\n\t\t\t\t\tclass=\"cn-record-list__group-heading\"\n\t\t\t\t\tdata-testid=\"cn-record-list-group-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h3>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ footerAction.label }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t\t<h3\n\t\t\t\tv-else-if=\"group.label\"\n\t\t\t\t:id=\"group.headingId\"\n\t\t\t\tclass=\"cn-record-list__group-heading\"\n\t\t\t\tdata-testid=\"cn-record-list-group-heading\">\n\t\t\t\t{{ group.label }}\n\t\t\t</h3>\n\t\t\t<ul\n\t\t\t\tv-if=\"group.items.length > 0\"\n\t\t\t\tclass=\"cn-record-list__list\"\n\t\t\t\t:aria-labelledby=\"group.label ? group.headingId : null\"\n\t\t\t\t:data-testid=\"isGrouped ? 'cn-record-list-group' : null\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"item in group.items\"\n\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\tclass=\"cn-record-list__item\"\n\t\t\t\t\tdata-testid=\"cn-record-list-item\">\n\t\t\t\t\t<!-- rows with `rowAction`: the title is the link, and one action\n\t\t\t\t\t ends the row instead of the chevron (\"Beoordelen\"). -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-if=\"presentation === 'rows' && item.action\"\n\t\t\t\t\t\tclass=\"cn-record-list__row cn-record-list__row--action\">\n\t\t\t\t\t\t<span v-if=\"item.leading\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__leading\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-leading\">{{ item.leading }}</span>\n\t\t\t\t\t\t<span v-if=\"item.initials\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__avatar\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-avatar\">{{ item.initials }}</span>\n\t\t\t\t\t\t<span v-if=\"item.dot\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__dot\"\n\t\t\t\t\t\t\t:style=\"{ background: item.dot }\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-dot\" />\n\t\t\t\t\t\t<span class=\"cn-record-list__main\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\t\t\tv-if=\"item.title\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__title\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-record-list__title--link': item.tag !== 'div' }\"\n\t\t\t\t\t\t\t\tv-bind=\"item.attrs\">\n\t\t\t\t\t\t\t\t{{ item.title }}\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.flag\" class=\"cn-record-list__flag\" data-testid=\"cn-record-list-flag\">{{ item.flag }}</span>\n\t\t\t\t\t\t<span v-if=\"item.pill || item.badges.length > 0\" class=\"cn-record-list__pills\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"item.pill\"\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"item.due\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__due cn-record-list__due--column\"\n\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__trailing\">{{ item.trailing }}</span>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"item.action.tag\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__action\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-record-list__action--outlined': rowActionOutlined }\"\n\t\t\t\t\t\t\tv-bind=\"item.action.attrs\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-action\"\n\t\t\t\t\t\t\tv-on=\"item.action.tag === 'button' ? { click: () => runRowAction(item.row) } : {}\">\n\t\t\t\t\t\t\t{{ item.action.label }}\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- rows: title, meta and text, then the pill, the date and a chevron. -->\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\tv-else-if=\"presentation === 'rows'\"\n\t\t\t\t\t\tclass=\"cn-record-list__row\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__row--link': item.tag !== 'div' }\"\n\t\t\t\t\t\tv-bind=\"item.attrs\">\n\t\t\t\t\t\t<span v-if=\"item.leading\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__leading\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-leading\">{{ item.leading }}</span>\n\t\t\t\t\t\t<span v-if=\"pillFirst && item.pill\" class=\"cn-record-list__pill-start\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.initials\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__avatar\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-avatar\">{{ item.initials }}</span>\n\t\t\t\t\t\t<span v-if=\"item.dot\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__dot\"\n\t\t\t\t\t\t\t:style=\"{ background: item.dot }\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-dot\" />\n\t\t\t\t\t\t<span class=\"cn-record-list__main\">\n\t\t\t\t\t\t\t<span v-if=\"item.title\" class=\"cn-record-list__title\">{{ item.title }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.text\" class=\"cn-record-list__meta\" data-testid=\"cn-record-list-text\">{{ item.text }}</span>\n\t\t\t\t\t\t\t<!-- `duePlacement: \"below\"`: the due text as a line under the title (DqDagAfsluiten \"Morgen eerst\"). -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"item.due && dueBelow\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__due cn-record-list__due--below\"\n\t\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.links.length > 0\" class=\"cn-record-list__meta\" data-testid=\"cn-record-list-links\">\n\t\t\t\t\t\t\t\t{{ linksLabel }}\n\t\t\t\t\t\t\t\t<template v-for=\"(link, linkIndex) in item.links\" :key=\"link.id\">\n\t\t\t\t\t\t\t\t\t<router-link v-if=\"link.to\" :to=\"link.to\">{{ link.label }}</router-link>\n\t\t\t\t\t\t\t\t\t<span v-else>{{ link.label }}</span><span v-if=\"linkIndex < item.links.length - 1\">, </span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"(item.pill && !pillFirst) || item.badges.length > 0 || (item.due && !dueBelow) || item.trailing || item.flag\" class=\"cn-record-list__aside\">\n\t\t\t\t\t\t\t<span v-if=\"item.flag\" class=\"cn-record-list__flag\" data-testid=\"cn-record-list-flag\">{{ item.flag }}</span>\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"item.pill && !pillFirst\"\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"item.due && !dueBelow\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__due\"\n\t\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__trailing\">{{ item.trailing }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\t\tv-if=\"item.tag !== 'div' && content.chevron !== false\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__chevron\"\n\t\t\t\t\t\t\t:size=\"18\"\n\t\t\t\t\t\t\taria-hidden=\"true\" />\n\t\t\t\t\t\t<template v-if=\"item.tag === 'div'\">\n\t\t\t\t\t\t\t<template v-for=\"(action, actionIndex) in setFieldActions\">\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-if=\"setFieldDone(action, item.row)\"\n\t\t\t\t\t\t\t\t\t:key=\"`set-field-done-${actionIndex}`\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-record-list__set-field-done\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-set-field-done\">\n\t\t\t\t\t\t\t\t\t<Check :size=\"14\" aria-hidden=\"true\" />{{ action.doneLabel }}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:key=\"`set-field-${actionIndex}`\"\n\t\t\t\t\t\t\t\t\t:disabled=\"settingField\"\n\t\t\t\t\t\t\t\t\t:ariaLabel=\"fillRow(action.ariaLabel, item.row) || undefined\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-set-field\"\n\t\t\t\t\t\t\t\t\t@click=\"runSetField(action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\tv-if=\"item.tag === 'div' && item.rowActions.length > 0\"\n\t\t\t\t\t\t\t:aria-label=\"rowActionsLabel\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-row-actions\">\n\t\t\t\t\t\t\t<template v-for=\"entry in item.rowActions\" :key=\"`row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t\tv-if=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:href=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:target=\"entry.external ? '_blank' : undefined\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\"\n\t\t\t\t\t\t\t\t\t@click=\"runRowActionEntry(entry.action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t</component>\n\n\t\t\t\t\t<!-- cards: a framed card per row, the icon and title with the pill\n\t\t\t\t\t beside them, the meta line, and `trailing` as the large figure. -->\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\tv-else-if=\"presentation === 'cards'\"\n\t\t\t\t\t\tclass=\"cn-record-list__card\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__card--link': item.tag !== 'div' }\"\n\t\t\t\t\t\tv-bind=\"item.attrs\"\n\t\t\t\t\t\tdata-testid=\"cn-record-list-card\">\n\t\t\t\t\t\t<span class=\"cn-record-list__card-head\">\n\t\t\t\t\t\t\t<span class=\"cn-record-list__card-title\">\n\t\t\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\t\t\tv-if=\"cardIcons\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-record-list__card-icon\"\n\t\t\t\t\t\t\t\t\t:name=\"item.icon\"\n\t\t\t\t\t\t\t\t\t:size=\"18\" />\n\t\t\t\t\t\t\t\t<span v-if=\"item.title\" class=\"cn-record-list__title\">{{ item.title }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span v-if=\"item.pill || item.badges.length > 0\" class=\"cn-record-list__card-pills\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"item.pill\"\n\t\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__card-value\" data-testid=\"cn-record-list-card-value\">{{ item.trailing }}</span>\n\t\t\t\t\t</component>\n\n\t\t\t\t\t<!-- feed: a round icon, a meta line and the text. -->\n\t\t\t\t\t<div v-else-if=\"presentation === 'feed'\" class=\"cn-record-list__feed-row\">\n\t\t\t\t\t\t<span class=\"cn-record-list__feed-icon\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t<CnIcon :name=\"item.icon\" :size=\"18\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__main\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.text\" class=\"cn-record-list__text\">{{ item.text }}</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- inline: a label and the title, the title a link. -->\n\t\t\t\t\t<div v-else class=\"cn-record-list__inline-row\">\n\t\t\t\t\t\t<span v-if=\"item.label\" class=\"cn-record-list__label\">{{ item.label }}</span>\n\t\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__inline-title\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t\t{{ item.title }}\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- `bar`: a thin track under the row, filled to the row's value\n\t\t\t\t\t against its own maximum or against the largest row. -->\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"presentation === 'rows' && item.bar\"\n\t\t\t\t\t\tclass=\"cn-record-list__bar\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__bar--over': item.bar.over }\"\n\t\t\t\t\t\trole=\"meter\"\n\t\t\t\t\t\t:aria-label=\"item.title || null\"\n\t\t\t\t\t\t:aria-valuenow=\"item.bar.value\"\n\t\t\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t\t\t:aria-valuemax=\"item.bar.max\"\n\t\t\t\t\t\tdata-testid=\"cn-record-list-bar\">\n\t\t\t\t\t\t<span class=\"cn-record-list__bar-fill\" :style=\"{ width: `${item.bar.share}%` }\" />\n\t\t\t\t\t</span>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</template>\n\t\t<p\n\t\t\tv-if=\"actionError\"\n\t\t\tclass=\"cn-record-list__error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-record-list-action-error\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\t\t<div\n\t\t\tv-if=\"footnoteTone && footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)\"\n\t\t\tclass=\"cn-record-list__notice cn-record-list__notice--footnote\"\n\t\t\t:class=\"`cn-record-list__notice--${footnoteTone}`\"\n\t\t\tdata-testid=\"cn-record-list-footnote\">\n\t\t\t<CnIcon\n\t\t\t\t:name=\"footnoteTone === 'info' ? 'InformationOutline' : 'AlertOutline'\"\n\t\t\t\t:size=\"16\"\n\t\t\t\tclass=\"cn-record-list__notice-icon\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t\t<p class=\"cn-record-list__notice-text\">\n\t\t\t\t{{ footnote }}\n\t\t\t</p>\n\t\t</div>\n\t\t<p v-else-if=\"footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)\" class=\"cn-record-list__footnote\" data-testid=\"cn-record-list-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<!-- `footerLink`: a text link under the rows (\"Naar Mijn werk\"). -->\n\t\t<router-link\n\t\t\tv-if=\"footerLink && footerLink.to\"\n\t\t\tclass=\"cn-record-list__footer-link\"\n\t\t\t:to=\"footerLink.to\"\n\t\t\tdata-testid=\"cn-record-list-footer-link\">\n\t\t\t{{ footerLink.label }}\n\t\t</router-link>\n\t\t<a\n\t\t\tv-else-if=\"footerLink\"\n\t\t\tclass=\"cn-record-list__footer-link\"\n\t\t\t:href=\"footerLink.href\"\n\t\t\tdata-testid=\"cn-record-list-footer-link\">{{ footerLink.label }}</a>\n\t\t<!-- `footerAction`: one action under the list, also under the empty\n\t\t text (\"Beroep registreren\"). With `disabledWhen` it greys out and\n\t\t says why (`disabledReason`: \"Kan zodra de beslissing is\n\t\t verzonden\"). -->\n\t\t<div\n\t\t\tv-if=\"footerGroupHead && rows.length === 0 && !error && !loading\"\n\t\t\tclass=\"cn-record-list__group-head\"\n\t\t\tdata-testid=\"cn-record-list-group-head\">\n\t\t\t<h3 class=\"cn-record-list__group-heading\" data-testid=\"cn-record-list-group-heading\">\n\t\t\t\t{{ footerGroupHead }}\n\t\t\t</h3>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t</template>\n\t\t\t\t{{ footerAction.label }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<p\n\t\t\tv-if=\"footerGroup !== '' && footerDisabled && footerAction && footerAction.reason && !error\"\n\t\t\t:id=\"footerReasonId\"\n\t\t\tclass=\"cn-record-list__footer-reason\"\n\t\t\tdata-testid=\"cn-record-list-footer-reason\">\n\t\t\t{{ footerAction.reason }}\n\t\t</p>\n\t\t<div\n\t\t\tv-if=\"footerAction && footerGroup === '' && !error\"\n\t\t\tclass=\"cn-record-list__footer\"\n\t\t\t:class=\"{ 'cn-record-list__footer--wide': footerAction.wide }\"\n\t\t\tdata-testid=\"cn-record-list-footer\">\n\t\t\t<p\n\t\t\t\tv-if=\"footerAction.note\"\n\t\t\t\tclass=\"cn-record-list__footer-note\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-note\">\n\t\t\t\t{{ footerAction.note }}\n\t\t\t</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t:wide=\"footerAction.wide\"\n\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t</template>\n\t\t\t\t{{ footerAction.label }}\n\t\t\t</NcButton>\n\t\t\t<span\n\t\t\t\tv-if=\"footerDisabled && footerAction.reason\"\n\t\t\t\t:id=\"footerReasonId\"\n\t\t\t\tclass=\"cn-record-list__footer-reason\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-reason\">{{ footerAction.reason }}</span>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { inject, ref } from 'vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport CnRecordNoteRows from './CnRecordNoteRows.vue'\nimport { interpolateUrlTokens, useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { actionLink, dispatchAction, interpolateActionTarget } from '../../utils/actionsDispatcher.js'\nimport { isAppInstalled } from '../../utils/appInstalled.js'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { ageInDays } from '../../utils/boardDate.js'\nimport { resolveDue } from '../../utils/dueText.js'\nimport { fillCountLabel } from '../../utils/fillCountLabel.js'\nimport { fillTemplate, firstFilled } from '../../utils/fillTemplate.js'\nimport { unwrapAppConfig } from '../../utils/formatMetric.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport { lensUnavailableText, readLensReports } from '../../utils/lensAvailability.js'\nimport { isObjectRowsSpec, objectRowsOf } from '../../utils/objectRows.js'\nimport { pageFilter, pageSort } from '../../utils/pageControls.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { dropOptionalUnresolved, hasUnresolvedTokens, resolveDeepTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { fetchRowAggregate, isRowAggregate } from '../../utils/rowAggregate.js'\nimport { evaluateVisibleWhen, evaluateVisibleWhenLocal } from '../../utils/visibleWhen.js'\n\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/** Gives each list's footer reason its own element id. */\nlet footerSeq = 0\nconst PRESENTATIONS = ['rows', 'feed', 'inline', 'cards', 'notice', 'table', 'notes', 'checklist']\n\n/**\n * Compare two table cell texts: as numbers when both read as one, else as text.\n *\n * @param {string} a One cell text.\n * @param {string} b The other.\n * @return {number} Negative, zero or positive.\n */\nfunction compareCells(a, b) {\n\tconst x = Number(a)\n\tconst y = Number(b)\n\tif (a !== '' && b !== '' && Number.isFinite(x) && Number.isFinite(y)) {\n\t\treturn x - y\n\t}\n\treturn String(a).localeCompare(String(b))\n}\n\n/** The tones a `notice` list takes. */\nconst NOTICE_VARIANTS = ['info', 'warning', 'error']\n\n/**\n * A row that is a plain string or number (an endpoint answering `[\"...\", \"...\"]`)\n * read as `{ value }`, so the templates reach it as `{value}` and a list\n * without a `title` shows the value itself. An object row is returned as is.\n *\n * @param {(object|string|number)} row The row.\n * @return {(object|string|number)} The row, or `{ value }` for a string or number.\n */\nfunction scalarRow(row) {\n\treturn typeof row === 'string' || typeof row === 'number' ? { value: String(row) } : row\n}\n\n/**\n * Unwrap a value that may be a ref.\n *\n * @param {unknown} value The value.\n * @return {unknown} The plain value.\n */\nfunction unwrap(value) {\n\treturn value && typeof value === 'object' && 'value' in value ? value.value : value\n}\n\n/**\n * CnRecordListWidget — the objects of another schema that point at this\n * record, drawn as the boards draw them (screens-relation-pages).\n *\n * A person page lists its open cases (\"Verlichting fietspad Lindelaan,\n * 2026-0082 · Woo-verzoek, In behandeling, Termijn 1 nov\"), its latest contact\n * moments (an icon by channel, a meta line, the summary) and its relations\n * (\"Secretaris van Buurtvereniging Oost\"). Each is a list of another schema's\n * objects filtered on a reference to this record. The source keys are those of\n * `object-list` (`register`, `schema`, `filter` with the `@objectId` /\n * `@object.<field>` / `@workspace.<key>` tokens, `sort`, `limit`, `extend`,\n * `rowRoute`, `pageControls`), or `endpointSource` (an app endpoint whose\n * payload, after `responsePath`, is the array of rows, as on the object table), or `objectRows`\n * (`{ path, where?, valuePath? }`: rows the page record holds, such as one answer of a case); `avatar` puts a circle with the initials of a name\n * template before the title; what differs is the drawing: `presentation` is `rows`, `feed`\n * or `inline`, and each line is a template (`\"{identifier} · {caseTypeName}\"`,\n * `\"Termijn {deadline|date}\"`). `cards` draws a framed card per row in a\n * grid, with `trailing` as the large figure (board ShBank's accounts).\n *\n * A content-only catalog type: on a card surface the detail host or the\n * dashboard page draws the titled card. The widget emits `header` with `{ link, note }` (the\n * `headerLink` and `headerNote` with `{total}` filled in) for that card's\n * header.\n */\nexport default {\n\tname: 'CnRecordListWidget',\n\n\tcomponents: { Check, ChevronRight, CnIcon, CnRecordNoteRows, CnStatusBadge, NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon },\n\n\tinject: {\n\t\t/** Detail-page object context (`{ objectId, object, register, schema }`). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Page workspace bag, for `@workspace.<key>` tokens. */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** The host app's translate function. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's app config map; its `currency` is the reporting currency of a money token. */\n\t\tcnAppConfig: { default: () => ({}) },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `rowAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The list config: `{ register, schema, filter?, sort?, limit?, offset?, extend?,\n\t\t * presentation?, variant?, lead?, leading?, title?, meta?, text?, label?, pill?, trailing?, icon?, aggregates?,\n\t\t * rowRoute?, rowIdField?, headerLink?, headerNote?, emptyText?, errorText?,\n\t\t * valueLabels?, endpointSource?, bar? }`. `bar` (`{ valueField, maxField?,\n\t\t * overVariant? }`) draws a thin track under each row: filled to\n\t\t * `valueField` against `maxField` (drawn in the error colour past it\n\t\t * with `overVariant: \"error\"`), or without `maxField` against the\n\t\t * largest row. `endpointSource` (`{ url, method?,\n\t\t * params?, responsePath? }`) reads the rows from an app endpoint instead\n\t\t * of `register` / `schema`. `objectRows` (`{ path, where?, valuePath? }`)\n\t\t * lists rows the page record holds, with no request. `valueLabels` maps a field's stored values to the labels\n\t\t * the templates show. `headerNote` and `headerLink.label` fill `{total}`\n\t\t * and `{count:<field>=<value>}`, the loaded rows with that value.\n\t\t * A row that is a plain string or number (an endpoint\n\t\t * answering `[\"…\", \"…\"]`) is read as `{ value }`: templates reach it as\n\t\t * `{value}`, and without `title` a row shows the value itself.\n\t\t * `presentation: \"notice\"` draws the rows as sentences in one box toned by\n\t\t * `variant` (`info`, `warning` or `error`), after an optional `lead`\n\t\t * (`{total}` filled in).\n\t\t * `dot` (a field, or `{ field, colorMap? }`) draws a colour dot before\n\t\t * the title; `flags` (`[{ field, label, value? }]`) draws the labels\n\t\t * of the flags a row has (\"Start\", \"End\") at its end.\n\t\t * `tiles: true` (rows only) draws each row as a framed tile in a grid\n\t\t * of 260px at the least.\n\t\t * `footerLink` (the shape of `headerLink`) ends the card with a text\n\t\t * link under the rows.\n\t\t * `footerAction` (`{ label, icon?, type, ..., disabledWhen?,\n\t\t * disabledReason? }`) ends the card with one action, also under the\n\t\t * empty text; while the visibleWhen condition `disabledWhen` holds the\n\t\t * button is disabled and `disabledReason` shows under it. `note` is a\n\t\t * line above it and `wide: true` stretches it across the card. A list\n\t\t * of such actions draws the first whose `visibleWhen` (a local\n\t\t * condition over the page's record) holds (DqZaaktype Versies:\n\t\t * \"Publiceren\" on a draft, \"Nieuwe versie maken\" otherwise).\n\t\t * `pill.cases` (`[{ when, label, variant? }]`) labels a row by the\n\t\t * first case whose `when` holds on it, else by the pill's own `label`\n\t\t * and `variant` (Concept, Vastgezet, Actief).\n\t\t * `footnoteVariant` (`info`, `warning` or `error`) draws the footnote\n\t\t * as a toned notice box with its icon (DqZaaktype opt-out note).\n\t\t * `tableLook: \"data\"` marks a `table` as a data table, which the board\n\t\t * look draws as its card table (header band, 40px rows, hairlines)\n\t\t * instead of the compact grid (DqZaaktype \"Berichten aan de aanvrager\").\n\t\t * `groupBy` (a field path) draws the rows in groups under a heading\n\t\t * per value, headed by the field's `valueLabels` entry; `groupOrder`\n\t\t * (values) orders the groups and `groupEmptyLabel` heads the rows\n\t\t * without a value.\n\t\t * `density: \"compact\"` draws the rows 10px above and below, at least\n\t\t * 56px tall, with the title at 500 (DqProcesanalyse).\n\t\t * `density: \"stacked\"` stands the rows 10px apart with no rule and no\n\t\t * row padding (DqDagAfsluiten \"Morgen eerst\").\n\t\t * In `rows`, `text` is a line under the meta line (\"12 dagen stil\"),\n\t\t * and `chevron: false` leaves the chevron off a linked row\n\t\t * (DqDashboard).\n\t\t * `presentation: \"checklist\"` draws the rows in `columns` (default 3),\n\t\t * a row for which `done` (a condition over the row) holds ticked, and\n\t\t * `progress: true` adds a bar of the done share (DqTenant Inrichten);\n\t\t * `headerNote` can say \"{count:status=completed} of {total} steps done\".\n\t\t * `aggregates` (`{ key: { register, schema, op: \"count\" | \"max\",\n\t\t * field?, where, text? } }`, `@self.<path>` in `where` read off the\n\t\t * row) asks a figure over each row's related objects, as a table's\n\t\t * `aggregate` column does, and offers it to the row's templates as\n\t\t * `{key}`; `text` (`{ zero?, one?, other }` with `{count}`) offers a\n\t\t * count as words (DqZaaktype Versies \"31 lopende zaken\", \"geen\n\t\t * lopende zaken\").\n\t\t * In `rows`, `ruleAbove: true` rules above the first row too, and\n\t\t * `pillAt: \"start\"` draws the pill before the title (DqZaakDocumenten\n\t\t * \"Weigeringsgronden tot nu toe\").\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current record, for `@object.<field>` tokens. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tsetup(props) {\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst workspaceRaw = inject('cnWorkspaceContext', null)\n\t\tconst appConfigRaw = inject('cnAppConfig', ref({}))\n\t\tconst { data, loading, error, refusal, refetch } = useEndpointSource(\n\t\t\t() => {\n\t\t\t\tconst app = props.content?.requiresApp\n\t\t\t\treturn typeof app === 'string' && app !== '' && !isAppInstalled(app) ? null : (props.content?.endpointSource || null)\n\t\t\t},\n\t\t\t{\n\t\t\t\tctx: () => {\n\t\t\t\t\tconst injected = unwrap(objectCtxRaw) || {}\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...injected,\n\t\t\t\t\t\tobjectId: props.objectId ?? injected.objectId ?? props.objectData?.id ?? null,\n\t\t\t\t\t\tobject: props.objectData || injected.object || null,\n\t\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\t\tconfig: unwrapAppConfig(appConfigRaw) || {},\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\t// A footnote that reads another part of the same answer shares its\n\t\t// request through the endpoint cache.\n\t\tconst footnoteSource = useEndpointSource(\n\t\t\t() => {\n\t\t\t\tconst note = props.content?.footnote\n\t\t\t\tconst source = props.content?.endpointSource\n\t\t\t\tif (!note || typeof note !== 'object' || typeof note.path !== 'string' || !source || typeof source !== 'object') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\treturn { ...source, responsePath: note.path }\n\t\t\t},\n\t\t\t{\n\t\t\t\tctx: () => {\n\t\t\t\t\tconst injected = unwrap(objectCtxRaw) || {}\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...injected,\n\t\t\t\t\t\tobjectId: props.objectId ?? injected.objectId ?? props.objectData?.id ?? null,\n\t\t\t\t\t\tobject: props.objectData || injected.object || null,\n\t\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\t\tconfig: unwrapAppConfig(appConfigRaw) || {},\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\treturn { epData: data, epLoading: loading, epError: error, epRefusal: refusal, epRefetch: refetch, footnoteValue: footnoteSource.data, footnoteRefetch: footnoteSource.refetch }\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The reader's sort of a `table`: the column key and `ascending` or `descending`. */\n\t\t\ttableSort: { key: '', dir: '' },\n\t\t\trows: [],\n\t\t\t/** The `aggregates` figures per row id: `{ [rowId]: { [key]: value } }`. */\n\t\t\taggregateValues: {},\n\t\t\ttotal: 0,\n\t\t\tloading: false,\n\t\t\terror: false,\n\t\t\t/** Personal-lens reports (`@self.lenses`) of the latest response. */\n\t\t\tlenses: {},\n\t\t\t/** Whether `footerAction.disabledWhen` holds. */\n\t\t\tfooterDisabled: false,\n\t\t\tfooterReasonId: `cn-record-list-footer-reason-${++footerSeq}`,\n\t\t\tgroupIdBase: `cn-record-list-group-${footerSeq}`,\n\t\t\t/** The first `emptyTexts` entry whose condition holds, translated; '' for none. */\n\t\t\tconditionalEmptyText: '',\n\t\t\t/** The refusal of the last row action, as the server said it. */\n\t\t\tactionError: '',\n\t\t\tsettingField: false,\n\t\t\t/** Labels of the records a `links` line names, by id. */\n\t\t\tlinkLabels: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} Whether a row's pill comes before its title (`pillAt: \"start\"`). */\n\t\tpillFirst() {\n\t\t\treturn this.content?.pillAt === 'start'\n\t\t},\n\n\t\t/**\n\t\t * The action under the list (`footerAction`: `{ label, icon?, type,\n\t\t * ..., disabledWhen?, disabledReason? }`), labels through the host\n\t\t * translate, or null without a label.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {{label: string, icon: string, reason: string, action: object}|null}\n\t\t */\n\t\tfooterAction() {\n\t\t\tconst action = this.footerActionConfig\n\t\t\tif (!action || typeof action.label !== 'string' || action.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(action.label),\n\t\t\t\ticon: typeof action.icon === 'string' ? action.icon : '',\n\t\t\t\treason: typeof action.disabledReason === 'string' && action.disabledReason !== '' ? this.translate(action.disabledReason) : '',\n\t\t\t\tnote: typeof action.note === 'string' && action.note !== '' ? this.translate(action.note) : '',\n\t\t\t\twide: action.wide === true,\n\t\t\t\taction,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The `footerAction` entry in force. A list of entries draws the first\n\t\t * whose `visibleWhen` (a local condition over the page's record) holds;\n\t\t * an entry without one always holds.\n\t\t *\n\t\t * @spec openspec/changes/record-list-pill-cases-footer-choice/specs/record-list/spec.md#requirement-a-record-lists-footer-action-can-depend-on-the-record\n\t\t * @return {object|null} The entry, or null when none holds.\n\t\t */\n\t\tfooterActionConfig() {\n\t\t\tconst declared = this.content?.footerAction\n\t\t\tconst entries = Array.isArray(declared) ? declared : [declared]\n\t\t\tconst record = this.tokenCtx.object || {}\n\t\t\treturn entries.find((entry) => entry && typeof entry === 'object' && (!entry.visibleWhen || evaluateVisibleWhenLocal(entry.visibleWhen, record))) || null\n\t\t},\n\n\t\t/**\n\t\t * The group value `footerAction.group` puts the action in, with\n\t\t * `groupBy`; '' when the action stands under the list.\n\t\t *\n\t\t * @spec openspec/changes/record-list-group-action/specs/record-list/spec.md#requirement-a-record-lists-action-can-end-a-group-heading-as-a-tonal-pill\n\t\t * @return {string}\n\t\t */\n\t\tfooterGroup() {\n\t\t\tconst group = this.footerActionConfig?.group\n\t\t\tif (!this.footerAction || !this.isGrouped || group === null || group === undefined || group === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn String(group)\n\t\t},\n\n\t\t/**\n\t\t * The heading of the action's group, for the list without rows.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tfooterGroupHead() {\n\t\t\tif (this.footerGroup === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst c = this.content\n\t\t\tconst labels = c.valueLabels && typeof c.valueLabels[c.groupBy] === 'object' ? c.valueLabels[c.groupBy] : {}\n\t\t\tconst named = labels[this.footerGroup] || this.footerGroup\n\t\t\treturn this.translate(named)\n\t\t},\n\n\t\t/** @return {boolean} Whether the action is drawn as a tonal pill (`footerAction.variant: \"tonal\"`). */\n\t\tfooterTonal() {\n\t\t\treturn this.footerActionConfig?.variant === 'tonal'\n\t\t},\n\n\t\t/**\n\t\t * What `footerAction.disabledWhen` depends on, so it is evaluated again\n\t\t * when the condition, the record or the workspace changes.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tfooterDisabledKey() {\n\t\t\tconst cond = this.footerActionConfig?.disabledWhen\n\t\t\tif (!cond) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn JSON.stringify({ cond, object: this.tokenCtx.object, workspace: this.tokenCtx.workspace, total: this.total })\n\t\t},\n\n\t\t/** @return {string} `rows`, `feed`, `inline` or `cards`. */\n\t\t/**\n\t\t * The tone of a `notice` list (`content.variant`): info, warning or error.\n\t\t *\n\t\t * @return {string} The variant, `info` when unset or unknown.\n\t\t * @spec openspec/changes/record-list-string-rows/specs/record-list-string-rows/spec.md#requirement-a-record-list-draws-rows-that-are-plain-strings\n\t\t */\n\t\tnoticeVariant() {\n\t\t\tconst value = this.content?.variant\n\t\t\treturn NOTICE_VARIANTS.includes(value) ? value : 'info'\n\t\t},\n\n\t\t/** @return {string} The icon of the notice tone. */\n\t\tnoticeIcon() {\n\t\t\treturn this.noticeVariant === 'info' ? 'InformationOutline' : 'AlertOutline'\n\t\t},\n\n\t\t/**\n\t\t * The rows of a `notice` list as one paragraph: each row's title, as\n\t\t * sentences, after the optional `lead` with `{total}` filled in.\n\t\t *\n\t\t * @return {string} The text.\n\t\t * @spec openspec/changes/record-list-string-rows/specs/record-list-string-rows/spec.md#requirement-a-record-list-draws-rows-that-are-plain-strings\n\t\t */\n\t\tnoticeText() {\n\t\t\tconst parts = this.items.map((item) => item.title).filter((text) => text !== '')\n\t\t\tconst lead = typeof this.content?.lead === 'string' && this.content.lead !== '' ? this.withTotal(this.content.lead) : ''\n\t\t\treturn [lead, ...parts].filter(Boolean).join(' ')\n\t\t},\n\n\t\tpresentation() {\n\t\t\tconst value = this.content?.presentation\n\t\t\treturn PRESENTATIONS.includes(value) ? value : 'rows'\n\t\t},\n\n\t\t/**\n\t\t * Whether a `cards` card leads its title with an icon: only when the\n\t\t * list declares `icon`, so a card without one has no placeholder.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-cards/specs/record-list-cards/spec.md#requirement-a-record-list-can-draw-its-rows-as-cards\n\t\t */\n\t\tcardIcons() {\n\t\t\tconst icon = this.content?.icon\n\t\t\treturn (typeof icon === 'string' && icon !== '') || (Boolean(icon) && typeof icon === 'object')\n\t\t},\n\n\t\t/** @return {object} The token context: record, id and workspace. */\n\t\ttokenCtx() {\n\t\t\tconst injected = unwrap(this.cnObjectContext) || {}\n\t\t\treturn {\n\t\t\t\t...injected,\n\t\t\t\tobjectId: this.objectId ?? injected.objectId ?? this.objectData?.id ?? null,\n\t\t\t\tobject: this.objectData || injected.object || null,\n\t\t\t\tworkspace: unwrap(this.cnWorkspaceContext) || {},\n\t\t\t}\n\t\t},\n\n\t\t/** @return {object} The filter with its tokens resolved. */\n\t\tresolvedFilter() {\n\t\t\tconst filter = pageFilter(this.content?.pageControls, this.tokenCtx.workspace, this.content?.filter)\n\t\t\treturn dropOptionalUnresolved(resolveFilterTokens(filter, this.tokenCtx))\n\t\t},\n\n\t\t/** @return {boolean} A required token (the record id, say) has no value yet. */\n\t\twaiting() {\n\t\t\treturn hasUnresolvedTokens(this.resolvedFilter)\n\t\t},\n\n\t\t/** @return {object|null} The sort: the page's sort control when the widget listens to one, else its own. */\n\t\teffectiveSort() {\n\t\t\treturn pageSort(this.content?.pageControls, this.tokenCtx.workspace, this.content?.sort)\n\t\t},\n\n\t\t/**\n\t\t * What a template may read beside the row: the app config, whose\n\t\t * `currency` is the reporting currency of a `{path|currency}` token.\n\t\t *\n\t\t * @return {{config: object}} The template context.\n\t\t * @spec openspec/changes/screens-currency-format/specs/currency-format/spec.md#requirement-a-money-value-reads-in-its-currency\n\t\t */\n\t\ttemplateContext() {\n\t\t\treturn { config: unwrapAppConfig(this.cnAppConfig) }\n\t\t},\n\n\t\t/**\n\t\t * Whether the rows come from `endpointSource` rather than OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint\n\t\t */\n\t\tendpointActive() {\n\t\t\tconst source = this.content?.endpointSource\n\t\t\treturn Boolean(source && typeof source === 'object' && source.url)\n\t\t},\n\n\t\t/**\n\t\t * Whether the rows come from the page's own record (`objectRows`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-object-rows/specs/record-list/spec.md#requirement-a-record-list-can-list-rows-the-page-record-holds\n\t\t */\n\t\tobjectRowsActive() {\n\t\t\treturn isObjectRowsSpec(this.content?.objectRows)\n\t\t},\n\n\t\t/**\n\t\t * The rows `objectRows` names on the page record (see utils/objectRows.js).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tobjectRowsList() {\n\t\t\treturn this.objectRowsActive ? objectRowsOf(this.objectData, this.content.objectRows) : []\n\t\t},\n\n\t\t/** @return {string} The page record's rows, to copy into the list when they change. */\n\t\tobjectRowsKey() {\n\t\t\treturn this.objectRowsActive ? JSON.stringify(this.objectRowsList) : ''\n\t\t},\n\n\t\t/** @return {string} The endpoint read's state, to copy into the list when it changes. */\n\t\tendpointKey() {\n\t\t\treturn this.endpointActive ? JSON.stringify([this.epData, this.epLoading, this.epError]) : ''\n\t\t},\n\n\t\t/** @return {number} The fetch cap. */\n\t\tlimit() {\n\t\t\tconst value = Number(this.content?.limit)\n\t\t\treturn Number.isFinite(value) && value > 0 ? Math.floor(value) : 5\n\t\t},\n\n\t\t/** @return {number} How many rows of the list to skip first (`content.offset`), 0 by default. */\n\t\toffset() {\n\t\t\tconst value = Number(this.content?.offset)\n\t\t\treturn Number.isFinite(value) && value > 0 ? Math.floor(value) : 0\n\t\t},\n\n\t\t/** @return {string} What a fetch depends on; a change fetches again. */\n\t\trequestKey() {\n\t\t\tconst c = this.content || {}\n\t\t\treturn JSON.stringify([c.register, c.schema, this.resolvedFilter, this.effectiveSort, this.limit, this.offset, c.extend, this.waiting])\n\t\t},\n\n\t\t/** @return {Array<object>} The rows ready to draw. */\n\t\titems() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst barScale = this.barScale\n\t\t\treturn this.rows.slice(0, this.limit).map((raw, index) => {\n\t\t\t\tconst row = this.withAggregates(scalarRow(raw))\n\t\t\t\tconst link = this.rowLink(row)\n\t\t\t\treturn {\n\t\t\t\t\tkey: (row && (row.id || row['@self']?.id)) || `row-${index}`,\n\t\t\t\t\trow,\n\t\t\t\t\taction: this.rowActionOf(row),\n\t\t\t\t\ttag: link ? 'router-link' : 'div',\n\t\t\t\t\tattrs: link ? { to: link } : {},\n\t\t\t\t\tinitials: this.initialsFor(row),\n\t\t\t\t\ttitle: this.fill(c.title || (row !== raw ? '{value}' : ''), row),\n\t\t\t\t\tmeta: this.metaOf(row),\n\t\t\t\t\ttext: this.fill(c.text, row),\n\t\t\t\t\tlabel: this.fill(c.label, row),\n\t\t\t\t\ttrailing: c.trailing ? firstFilled(c.trailing, row, this.translate, new Date(), this.templateContext) : '',\n\t\t\t\t\tleading: c.leading ? firstFilled(c.leading, row, this.translate, new Date(), this.templateContext) : '',\n\t\t\t\t\tpill: this.pillOf(row),\n\t\t\t\t\tbadges: this.badgesOf(row),\n\t\t\t\t\tdue: this.dueOf(row),\n\t\t\t\t\ticon: this.iconOf(row),\n\t\t\t\t\tbar: this.barOf(row, barScale),\n\t\t\t\t\tdot: this.dotOf(row),\n\t\t\t\t\tflag: this.flagOf(row),\n\t\t\t\t\tlinks: this.linksOf(row),\n\t\t\t\t\trowActions: this.rowActionsOf(row),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether `content.groupBy` names a field to group the rows by. */\n\t\tisGrouped() {\n\t\t\tconst field = this.content?.groupBy\n\t\t\treturn typeof field === 'string' && field !== ''\n\t\t},\n\n\t\t/**\n\t\t * The rows to draw, in groups. With `groupBy` (a field path) one group\n\t\t * per value: in `groupOrder` first, then in the order the rows bring\n\t\t * them, and the rows without a value last. A heading is the value's\n\t\t * `valueLabels` entry for that field, else the value, through the host\n\t\t * translate; the group without a value is headed by `groupEmptyLabel`,\n\t\t * or not at all. Without `groupBy` all rows are one unheaded group.\n\t\t *\n\t\t * @spec openspec/changes/record-list-group-headings/specs/record-list/spec.md#requirement-a-record-list-can-group-its-rows-under-headings\n\t\t * @return {Array<{key: string, value: string, label: string, headingId: string, items: Array<object>}>} The groups.\n\t\t */\n\t\titemGroups() {\n\t\t\tif (!this.isGrouped) {\n\t\t\t\treturn [{ key: 'all', label: '', headingId: '', items: this.items }]\n\t\t\t}\n\t\t\tconst c = this.content\n\t\t\tconst labels = c.valueLabels && typeof c.valueLabels[c.groupBy] === 'object' ? c.valueLabels[c.groupBy] : {}\n\t\t\tconst buckets = new Map()\n\t\t\tfor (const item of this.items) {\n\t\t\t\tconst raw = readPath(item.row, c.groupBy)\n\t\t\t\tconst value = raw === null || raw === undefined || typeof raw === 'object' ? '' : String(raw)\n\t\t\t\tif (!buckets.has(value)) {\n\t\t\t\t\tbuckets.set(value, [])\n\t\t\t\t}\n\t\t\t\tbuckets.get(value).push(item)\n\t\t\t}\n\t\t\tconst order = Array.isArray(c.groupOrder) ? c.groupOrder.map(String) : []\n\t\t\tconst values = [...buckets.keys()].filter((v) => v !== '')\n\t\t\tvalues.sort((a, b) => {\n\t\t\t\tconst ia = order.indexOf(a)\n\t\t\t\tconst ib = order.indexOf(b)\n\t\t\t\treturn (ia === -1 ? order.length : ia) - (ib === -1 ? order.length : ib)\n\t\t\t})\n\t\t\tif (buckets.has('')) {\n\t\t\t\tvalues.push('')\n\t\t\t}\n\t\t\tif (this.footerGroup !== '' && !buckets.has(this.footerGroup)) {\n\t\t\t\tbuckets.set(this.footerGroup, [])\n\t\t\t\tvalues.splice(buckets.has('') ? values.length - 1 : values.length, 0, this.footerGroup)\n\t\t\t}\n\t\t\treturn values.map((value, index) => {\n\t\t\t\tconst named = value === '' ? c.groupEmptyLabel : (labels[value] || value)\n\t\t\t\treturn {\n\t\t\t\t\tkey: `group-${value}`,\n\t\t\t\t\tvalue,\n\t\t\t\t\tlabel: typeof named === 'string' && named !== '' ? this.translate(named) : '',\n\t\t\t\t\theadingId: `${this.groupIdBase}-${index}`,\n\t\t\t\t\titems: buckets.get(value),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The `table` presentation's columns: `{ label, value, align?, alertAbove? }`,\n\t\t * `value` a template over the row, or a list of templates of which the\n\t\t * first that fills is shown (a row that holds only some fields).\n\t\t *\n\t\t * @return {Array<object>} The columns with a key and a translated label.\n\t\t * @spec openspec/changes/record-list-table/specs/record-list-table/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-small-table\n\t\t * @spec openspec/changes/record-list-table-column-candidates/specs/record-list-table/spec.md#requirement-a-table-column-can-name-candidate-templates\n\t\t */\n\t\ttableColumns() {\n\t\t\tconst columns = Array.isArray(this.content?.columns) ? this.content.columns : []\n\t\t\tconst isTemplate = (value) => typeof value === 'string' || (Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === 'string'))\n\t\t\treturn columns\n\t\t\t\t.filter((col) => col && typeof col === 'object' && isTemplate(col.value))\n\t\t\t\t.map((col, index) => ({ ...col, key: `col-${index}`, label: typeof col.label === 'string' ? this.translate(col.label) : '' }))\n\t\t},\n\n\t\t/**\n\t\t * The `table` presentation's rows: one cell per column.\n\t\t *\n\t\t * @return {Array<object>} `{ key, cells: [{ key, text, align, alert }] }`.\n\t\t * @spec openspec/changes/record-list-table/specs/record-list-table/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-small-table\n\t\t */\n\t\ttableRows() {\n\t\t\tconst indentPath = this.content?.indentPath\n\t\t\tconst rows = this.items.map((item) => ({\n\t\t\t\tkey: item.key,\n\t\t\t\trow: item.row,\n\t\t\t\trowActions: this.rowActions.length > 0 ? this.rowActionsOf(item.row) : [],\n\t\t\t\tto: item.attrs.to || null,\n\t\t\t\tdepth: indentPath ? Math.max(0, Math.floor(Number(readPath(item.row, indentPath)) || 0)) : 0,\n\t\t\t\tcells: this.tableColumns.map((col) => {\n\t\t\t\t\tconst text = this.fill(col.value, item.row)\n\t\t\t\t\tconst limit = Number(col.alertAbove)\n\t\t\t\t\tconst value = Number(text)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: col.key,\n\t\t\t\t\t\ttext,\n\t\t\t\t\t\tsub: typeof col.sub === 'string' ? this.fill(col.sub, item.row) : '',\n\t\t\t\t\t\talign: col.align,\n\t\t\t\t\t\talert: col.alertAbove !== undefined && Number.isFinite(limit) && text !== '' && Number.isFinite(value) && value > limit,\n\t\t\t\t\t\t// An empty cell draws no coloured label.\n\t\t\t\t\t\ttone: text === '' ? '' : this.cellToneOf(col, item.row, text),\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t}))\n\t\t\tconst { key, dir } = this.tableSort\n\t\t\tconst index = this.tableColumns.findIndex((col) => col.key === key)\n\t\t\tif (index < 0 || !dir) {\n\t\t\t\treturn rows\n\t\t\t}\n\t\t\tconst sign = dir === 'descending' ? -1 : 1\n\t\t\treturn [...rows].sort((a, b) => sign * compareCells(a.cells[index].text, b.cells[index].text))\n\t\t},\n\n\t\t/**\n\t\t * Whether a row draws its due text under its title (`duePlacement:\n\t\t * \"below\"`) instead of at its end.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-due-below/specs/record-list-due-below/spec.md#requirement-a-rows-due-text-can-sit-under-its-title\n\t\t */\n\t\tdueBelow() {\n\t\t\treturn this.content?.duePlacement === 'below'\n\t\t},\n\n\t\t/** @return {string} The note under the list (`footnote`), translated. */\n\t\tfootnote() {\n\t\t\tconst note = this.content?.footnote\n\t\t\tif (note && typeof note === 'object') {\n\t\t\t\tconst value = this.footnoteValue\n\t\t\t\tif (value === null || value === undefined || value === '' || value === 0 || value === false || typeof note.text !== 'string') {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn this.translate(note.text).replace(/\\{value\\}/g, String(value))\n\t\t\t}\n\t\t\treturn typeof note === 'string' && note !== '' ? this.translate(note) : ''\n\t\t},\n\n\t\t/**\n\t\t * The tone the footnote is drawn in as a notice box\n\t\t * (`content.footnoteVariant`: info, warning or error); '' for a plain\n\t\t * muted line.\n\t\t *\n\t\t * @return {string} The tone, or ''.\n\t\t * @spec openspec/changes/record-list-data-table-and-notice-footnote/specs/record-list/spec.md#requirement-a-record-list-footnote-can-be-a-toned-notice\n\t\t */\n\t\tfootnoteTone() {\n\t\t\tconst tone = this.content?.footnoteVariant\n\t\t\treturn NOTICE_VARIANTS.includes(tone) ? tone : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the footnote reads the answer: it then shows with no rows too.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tfootnoteFromAnswer() {\n\t\t\tconst note = this.content?.footnote\n\t\t\treturn Boolean(note && typeof note === 'object')\n\t\t},\n\n\t\t/**\n\t\t * The largest `bar.valueField` over the rows shown, the scale of a\n\t\t * `bar` without `maxField`. 0 without a `bar`.\n\t\t *\n\t\t * @return {number} The largest value.\n\t\t * @spec openspec/changes/record-list-row-bar/specs/record-list-row-bar/spec.md#requirement-a-record-list-row-can-carry-a-bar\n\t\t */\n\t\tbarScale() {\n\t\t\tconst field = this.content?.bar?.valueField\n\t\t\tif (!field) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, ...this.rows.slice(0, this.limit).map((row) => Number(readPath(row, field)) || 0))\n\t\t},\n\n\t\t/** @return {object|null} The header link with `{total}` filled and tokens resolved; null while an href param is unresolved. */\n\t\theaderLink() {\n\t\t\treturn this.resolveLink(this.content?.headerLink)\n\t\t},\n\n\t\t/**\n\t\t * The text link under the rows (`footerLink`), resolved as the header\n\t\t * link is, as a router location or an href; null without rows.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t * @spec openspec/changes/record-list-footer-link/specs/record-list-footer-link/spec.md#requirement-a-record-list-can-end-with-a-text-link\n\t\t */\n\t\tfooterLink() {\n\t\t\tconst link = this.resolveLink(this.content?.footerLink)\n\t\t\tif (!link || this.error || this.rows.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route) {\n\t\t\t\tconst to = { name: link.route }\n\t\t\t\tif (link.params) {\n\t\t\t\t\tto.params = link.params\n\t\t\t\t}\n\t\t\t\tif (link.query) {\n\t\t\t\t\tto.query = link.query\n\t\t\t\t}\n\t\t\t\treturn { label: link.label, to }\n\t\t\t}\n\t\t\treturn link.href ? { label: link.label, href: link.href } : null\n\t\t},\n\n\t\t/**\n\t\t * The checklist's columns (`content.columns`, 1 to 4, default 3).\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistColumns() {\n\t\t\tconst value = Number(this.content?.columns)\n\t\t\treturn Number.isFinite(value) && value >= 1 ? Math.min(4, Math.floor(value)) : 3\n\t\t},\n\n\t\t/**\n\t\t * How many checklist rows are done.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistDone() {\n\t\t\treturn this.items.filter((item) => this.isChecked(item.row)).length\n\t\t},\n\n\t\t/**\n\t\t * The done share of the checklist, in whole percent.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistPercent() {\n\t\t\treturn this.items.length > 0 ? Math.round((this.checklistDone / this.items.length) * 100) : 0\n\t\t},\n\n\t\t/** @return {string} What a done checklist row says to a screen reader. */\n\t\tdoneLabel() {\n\t\t\treturn t('nextcloud-vue', 'Done')\n\t\t},\n\n\t\t/** @return {string} What an open checklist row says to a screen reader. */\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Not done yet')\n\t\t},\n\n\t\t/** @return {string} The header note with `{total}` filled. */\n\t\theaderNote() {\n\t\t\tconst note = this.content?.headerNote\n\t\t\treturn typeof note === 'string' && note !== '' ? this.withTotal(note) : ''\n\t\t},\n\n\t\t/**\n\t\t * Why the list is empty when a personal lens could not answer\n\t\t * (`@self.lenses.<lens>.available: false`, as for `filter: { _recent: true }`),\n\t\t * or '' to keep `emptyText`. `lensReasonTexts` holds the app's wording,\n\t\t * keyed `<lens>.<reason>` or `<reason>`.\n\t\t *\n\t\t * @return {string} The explanation, or ''.\n\t\t * @spec openspec/changes/screens-record-list-lens-reason/specs/record-list-lens-reason/spec.md#requirement-a-record-list-says-why-a-lens-is-empty\n\t\t */\n\t\tlensReasonText() {\n\t\t\tif (this.rows.length > 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = lensUnavailableText(this.lenses, this.content?.lensReasonTexts)\n\t\t\treturn text ? this.translate(text) : ''\n\t\t},\n\n\t\t/** @return {string} The empty line. */\n\t\t/**\n\t\t * `noteAction` with its labels through the host translate, or null\n\t\t * (`presentation: \"notes\"`).\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-record-list-can-collect-and-record-a-note-per-row\n\t\t * @return {object|null}\n\t\t */\n\t\tnoteAction() {\n\t\t\tconst action = this.content?.noteAction\n\t\t\tif (!action || typeof action !== 'object' || (!action.urlField && !action.url)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tr = (text) => (typeof text === 'string' && text !== '' ? this.translate(text) : '')\n\t\t\treturn {\n\t\t\t\t...action,\n\t\t\t\tlabel: tr(action.label),\n\t\t\t\tfieldLabel: tr(action.fieldLabel),\n\t\t\t\tplaceholder: tr(action.placeholder),\n\t\t\t\treadyLabel: tr(action.readyLabel),\n\t\t\t\terrorText: tr(action.errorText),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * `noteAction.recordAll` translated, its cancel link as a route, or null.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tnoteRecordAll() {\n\t\t\tconst all = this.content?.noteAction?.recordAll\n\t\t\tif (!all || typeof all !== 'object' || !all.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst cancel = all.cancel && all.cancel.label && all.cancel.route\n\t\t\t\t? { label: this.translate(all.cancel.label), to: typeof all.cancel.route === 'string' ? { name: all.cancel.route } : all.cancel.route }\n\t\t\t\t: null\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(all.label),\n\t\t\t\ttitle: all.title ? this.translate(all.title) : '',\n\t\t\t\ttext: all.text ? this.translate(all.text) : '',\n\t\t\t\ticon: all.icon || '',\n\t\t\t\tcancel,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the app the rows come from is absent (`requiresApp`): the\n\t\t * list then says so (`absentText`) instead of reading anything.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tabsent() {\n\t\t\tconst app = this.content?.requiresApp\n\t\t\treturn typeof app === 'string' && app !== '' && !isAppInstalled(app)\n\t\t},\n\n\t\t/** @return {string} The line shown when the source app is absent. */\n\t\tabsentLabel() {\n\t\t\treturn this.content?.absentText ? this.translate(this.content.absentText) : t('nextcloud-vue', 'The app these come from is not installed')\n\t\t},\n\n\t\t/** @return {string} The line above the list (`intro`), translated. */\n\t\tintro() {\n\t\t\tconst text = this.content?.intro\n\t\t\treturn typeof text === 'string' && text !== '' ? this.translate(text) : ''\n\t\t},\n\n\t\t/**\n\t\t * The row actions (`rowActions`), labels translated. Each is a page\n\t\t * action (`type`, dispatched with the row) or `{ endpoint, method? }`,\n\t\t * an app URL called for the row.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\trowActions() {\n\t\t\tconst list = Array.isArray(this.content?.rowActions) ? this.content.rowActions : []\n\t\t\treturn list\n\t\t\t\t.filter((action) => action && typeof action === 'object' && typeof action.label === 'string' && action.label !== '')\n\t\t\t\t.map((action) => ({ ...action, label: this.translate(action.label) }))\n\t\t},\n\n\t\t/**\n\t\t * The `set-field` row actions, drawn as a button on each row.\n\t\t *\n\t\t * @spec openspec/changes/record-list-set-field/specs/record-list/spec.md#requirement-a-row-can-set-a-field-of-the-page-record\n\t\t * @return {Array<object>}\n\t\t */\n\t\tsetFieldActions() {\n\t\t\treturn this.rowActions\n\t\t\t\t.filter((action) => action.type === 'set-field' && typeof action.field === 'string' && action.field !== '')\n\t\t\t\t.map((action) => ({\n\t\t\t\t\t...action,\n\t\t\t\t\tdoneLabel: action.doneLabel ? this.translate(action.doneLabel) : '',\n\t\t\t\t\tariaLabel: action.ariaLabel ? this.translate(action.ariaLabel) : '',\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The heading of the `table` presentation's actions column.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/record-list-table-row-actions/specs/record-list-table/spec.md#requirement-a-table-row-can-carry-a-second-line-and-an-actions-menu\n\t\t */\n\t\t/**\n\t\t * Whether the row action is drawn as an outlined button sized to its\n\t\t * label (`rowAction.variant: \"outlined\"`, DqMijnTeam \"Oppakken\") instead\n\t\t * of the 150px pill (DcMijnActies \"Stem uitbrengen\").\n\t\t *\n\t\t * @return {boolean} True for the outlined variant.\n\t\t * @spec openspec/changes/board-row-action-outlined/specs/board-row-action-outlined/spec.md#requirement-a-dashboard-rows-action-is-an-outlined-button\n\t\t */\n\t\trowActionOutlined() {\n\t\t\treturn this.content?.rowAction?.variant === 'outlined'\n\t\t},\n\n\t\trowActionsHeader() {\n\t\t\tconst own = this.content?.rowActionsHeader\n\t\t\treturn typeof own === 'string' && own !== '' ? this.translate(own) : t('nextcloud-vue', 'Actions')\n\t\t},\n\n\t\t/** @return {string} The accessible name of a row's actions menu. */\n\t\trowActionsLabel() {\n\t\t\tconst own = this.content?.rowActionsLabel\n\t\t\treturn typeof own === 'string' && own !== '' ? this.translate(own) : t('nextcloud-vue', 'Actions for this row')\n\t\t},\n\n\t\t/** @return {string} The words in front of a `links` line. */\n\t\tlinksLabel() {\n\t\t\tconst label = this.content?.links?.label\n\t\t\treturn typeof label === 'string' && label !== '' ? this.translate(label) : ''\n\t\t},\n\n\t\t/** @return {string} The ids a `links` line names, to label them when they change. */\n\t\tlinkIdsKey() {\n\t\t\tconst field = this.content?.links?.field\n\t\t\tif (!field) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst ids = new Set()\n\t\t\tfor (const row of this.rows.slice(0, this.limit)) {\n\t\t\t\tconst list = readPath(row, field)\n\t\t\t\tfor (const id of Array.isArray(list) ? list : []) {\n\t\t\t\t\tif (typeof id === 'string' && id !== '') {\n\t\t\t\t\t\tids.add(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [...ids].join('|')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\tif (this.lensReasonText !== '') {\n\t\t\t\treturn this.lensReasonText\n\t\t\t}\n\t\t\tif (this.conditionalEmptyText !== '') {\n\t\t\t\treturn this.conditionalEmptyText\n\t\t\t}\n\t\t\t// `emptyText: \"\"` says nothing on an empty list.\n\t\t\tif (this.content?.emptyText === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.content?.emptyText ? this.translate(this.content.emptyText) : t('nextcloud-vue', 'Nothing here yet')\n\t\t},\n\n\t\t/**\n\t\t * The error line: an endpoint's refusal (401/403) in its own words,\n\t\t * through the app's catalogue, else `errorText`, else the default.\n\t\t *\n\t\t * @return {string} The error line.\n\t\t * @spec openspec/changes/record-list-endpoint-refusal/specs/record-list/spec.md#requirement-a-refused-endpoint-read-says-why\n\t\t */\n\t\terrorLabel() {\n\t\t\tif (this.endpointActive && this.epRefusal) {\n\t\t\t\treturn this.translate(this.epRefusal)\n\t\t\t}\n\t\t\treturn this.content?.errorText ? this.translate(this.content.errorText) : t('nextcloud-vue', 'This list could not be loaded.')\n\t\t},\n\n\t\t/** @return {string} The spinner's accessible name. */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\t},\n\n\twatch: {\n\t\trequestKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\trows() {\n\t\t\tthis.evaluateEmptyTexts()\n\t\t\tthis.loadAggregates()\n\t\t},\n\n\t\tfooterDisabledKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateFooterDisabled()\n\t\t\t},\n\t\t},\n\n\t\tendpointKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\tobjectRowsKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\tlinkIdsKey() {\n\t\t\tthis.loadLinkLabels()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.onRefresh = () => this.fetchRows()\n\t\tsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t\tthis.fetchRows()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * An href with its `{name}` placeholders filled from `params` (tokens\n\t\t * such as `@object.masterEntityRef` resolved, each value URL-encoded)\n\t\t * and made a Nextcloud URL; null while a value is missing, so the link\n\t\t * is left out rather than pointing nowhere.\n\t\t *\n\t\t * @param {string} href The href, `/apps/<app>/...` with placeholders.\n\t\t * @param {object} params The placeholder values or tokens.\n\t\t * @return {string|null} The URL, or null.\n\t\t * @spec openspec/changes/record-list-header-href-params/specs/record-widgets/spec.md#requirement-a-record-list-header-link-can-fill-its-url-from-the-record\n\t\t */\n\t\tfilledHref(href, params) {\n\t\t\tconst values = resolveFilterTokens(params, this.tokenCtx)\n\t\t\tlet missing = false\n\t\t\tconst path = href.replace(/\\{(\\w+)\\}/g, (match, name) => {\n\t\t\t\tconst value = values[name]\n\t\t\t\tif (value === null || value === undefined || value === '' || typeof value === 'object' || (typeof value === 'string' && value.startsWith('@'))) {\n\t\t\t\t\tmissing = true\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn encodeURIComponent(String(value))\n\t\t\t})\n\t\t\tif (missing) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn path.startsWith('/') && !path.startsWith('//') ? generateUrl(path) : path\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string} The translation.\n\t\t */\n\t\ttranslate(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * A row's colour dot (`dot`: a field name, or `{ field, colorMap? }`):\n\t\t * the field's colour, or its value through `colorMap`. Only a hex\n\t\t * colour, an `rgb()`/`hsl()` colour or a `var(--…)` token is drawn.\n\t\t *\n\t\t * @spec openspec/changes/record-list-dot-flags/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-colour-dot-and-flag-text\n\t\t * @param {object} row The row.\n\t\t * @return {string} The colour, or ''.\n\t\t */\n\t\tdotOf(row) {\n\t\t\tconst dot = this.content?.dot\n\t\t\tconst def = typeof dot === 'string' ? { field: dot } : dot\n\t\t\tif (!def || typeof def !== 'object' || typeof def.field !== 'string' || def.field === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst raw = readPath(row, def.field)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst mapped = def.colorMap && typeof def.colorMap === 'object' && typeof def.colorMap[String(raw)] === 'string' ? def.colorMap[String(raw)] : String(raw)\n\t\t\treturn /^(#[0-9a-f]{3,8}|(rgb|rgba|hsl|hsla)\\([^;{}]*\\)|var\\(--[a-z0-9-]+(,[^;{}]*)?\\))$/i.test(mapped.trim()) ? mapped.trim() : ''\n\t\t},\n\n\t\t/**\n\t\t * A row's flag text (`flags`: `[{ field, label, value? }]`): the\n\t\t * labels of the flags whose field is set (or equals `value`), through\n\t\t * the host translate and joined with \" · \" (\"Start\", \"End\").\n\t\t *\n\t\t * @spec openspec/changes/record-list-dot-flags/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-colour-dot-and-flag-text\n\t\t * @param {object} row The row.\n\t\t * @return {string} The text, or ''.\n\t\t */\n\t\tflagOf(row) {\n\t\t\tconst flags = Array.isArray(this.content?.flags) ? this.content.flags : []\n\t\t\treturn flags\n\t\t\t\t.filter((flag) => flag && typeof flag.field === 'string' && typeof flag.label === 'string' && flag.label !== '')\n\t\t\t\t.filter((flag) => {\n\t\t\t\t\tconst raw = readPath(row, flag.field)\n\t\t\t\t\treturn flag.value !== undefined ? String(raw) === String(flag.value) : raw === true || raw === 'true' || raw === 1\n\t\t\t\t})\n\t\t\t\t.map((flag) => this.translate(flag.label))\n\t\t\t\t.join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Settle whether the footer action is disabled: `disabledWhen` is a\n\t\t * visibleWhen condition read against the page's record (`field`), the\n\t\t * workspace, an endpoint or a source; `total` is the list's total.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * Pick the empty text (`emptyTexts`: `[{ when, text }]`, the first whose\n\t\t * visibleWhen condition holds), for a list that is empty for more than\n\t\t * one reason (\"Everything you opened today has a note\" or \"You have not\n\t\t * opened anything today\"). `emptyText` stays the fallback.\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-record-list-can-say-why-it-is-empty\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync evaluateEmptyTexts() {\n\t\t\tconst options = Array.isArray(this.content?.emptyTexts) ? this.content.emptyTexts : []\n\t\t\tif (options.length === 0 || this.rows.length > 0) {\n\t\t\t\tthis.conditionalEmptyText = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst run = this.emptyRun = (this.emptyRun || 0) + 1\n\t\t\tfor (const option of options) {\n\t\t\t\tif (!option || typeof option.text !== 'string' || !option.when) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst holds = await evaluateVisibleWhen(option.when, this.tokenCtx)\n\t\t\t\tif (run !== this.emptyRun) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (holds) {\n\t\t\t\t\tthis.conditionalEmptyText = this.translate(option.text)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.conditionalEmptyText = ''\n\t\t},\n\n\t\tasync evaluateFooterDisabled() {\n\t\t\tconst cond = this.footerActionConfig?.disabledWhen\n\t\t\tif (!cond) {\n\t\t\t\tthis.footerDisabled = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst ctx = { ...this.tokenCtx, object: { ...(this.tokenCtx.object || {}), total: this.total } }\n\t\t\tconst key = this.footerDisabledKey\n\t\t\tconst disabled = await evaluateVisibleWhen(cond, ctx)\n\t\t\tif (key === this.footerDisabledKey) {\n\t\t\t\tthis.footerDisabled = disabled\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the footer action through the page's dispatcher, with the page's\n\t\t * record as the token context.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {unknown} What the dispatcher returns.\n\t\t */\n\t\trunFooterAction() {\n\t\t\tconst declared = this.footerAction?.action\n\t\t\tif (!declared || this.footerDisabled) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst { disabledWhen, disabledReason, group, variant, visibleWhen, note, wide, ...action } = declared\n\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\treturn this.cnDispatchAction(action)\n\t\t\t}\n\t\t\treturn dispatchAction(action, { router: this.$router || null, tokenCtx: this.tokenCtx, source: { register: this.content?.register, schema: this.content?.schema } })\n\t\t},\n\n\t\t/**\n\t\t * A row's `bar`: its value, the maximum it is measured against (the\n\t\t * row's `maxField`, else the largest row), the filled share and\n\t\t * whether it is over that maximum. Null without `bar` or a value.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {number} scale The largest value over the rows shown.\n\t\t * @return {{value: number, max: number, share: number, over: boolean}|null} The bar.\n\t\t * @spec openspec/changes/record-list-row-bar/specs/record-list-row-bar/spec.md#requirement-a-record-list-row-can-carry-a-bar\n\t\t */\n\t\tbarOf(row, scale) {\n\t\t\tconst bar = this.content?.bar\n\t\t\tif (!bar || typeof bar !== 'object' || !bar.valueField) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst value = Number(readPath(row, bar.valueField))\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst ownMax = bar.maxField ? Number(readPath(row, bar.maxField)) : NaN\n\t\t\tconst max = bar.maxField ? (Number.isFinite(ownMax) && ownMax > 0 ? ownMax : 0) : scale\n\t\t\tconst share = max > 0 ? Math.min(100, Math.max(0, (value / max) * 100)) : 0\n\t\t\tconst over = Boolean(bar.maxField) && bar.overVariant === 'error' && max > 0 && value > max\n\t\t\treturn { value, max, share, over }\n\t\t},\n\n\t\t/**\n\t\t * The initials of the row's avatar (`avatar`: a name template such as\n\t\t * `\"{client.name}\"`, or `{ text }`), or '' without one.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} One or two letters.\n\t\t * @spec openspec/changes/screens-record-list-avatar/specs/record-list-avatar/spec.md#requirement-a-record-list-row-can-carry-an-avatar\n\t\t */\n\t\tinitialsFor(row) {\n\t\t\tconst avatar = this.content?.avatar\n\t\t\tconst template = typeof avatar === 'string' ? avatar : (avatar && typeof avatar === 'object' ? avatar.text : '')\n\t\t\treturn initialsOf(this.fill(template, row))\n\t\t},\n\n\t\t/**\n\t\t * Fill a template from a row, after translating it.\n\t\t *\n\t\t * @param {string} template The template.\n\t\t * @param {object} row The row.\n\t\t * @return {string} The text, '' when a token is empty.\n\t\t */\n\t\tfill(template, row) {\n\t\t\t// A list is candidates: the first that fills (\"{summary}\", else \"{subject}\").\n\t\t\tif (Array.isArray(template)) {\n\t\t\t\treturn firstFilled(template, this.labelledRow(row), (text) => this.translate(text), new Date(), this.templateContext)\n\t\t\t}\n\t\t\treturn typeof template === 'string' && template !== '' ? fillTemplate(this.translate(template), this.labelledRow(row), new Date(), this.templateContext) : ''\n\t\t},\n\n\t\t/**\n\t\t * The row as the templates read it: a field named in `valueLabels`\n\t\t * (`{ channel: { phone: \"Phone\", telefoon: \"Phone\" } }`) shows the\n\t\t * translated label of its stored value, so \"{channel}\" reads \"Telefoon\"\n\t\t * for both spellings the data holds. A value without a label stays as\n\t\t * stored. The pill, the badges and the sort read the stored value.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The row, or a shallow copy with labelled fields.\n\t\t * @spec openspec/changes/screens-record-list-value-labels/specs/record-list-value-labels/spec.md#requirement-a-record-list-template-can-show-a-label-for-a-stored-value\n\t\t */\n\t\tlabelledRow(row) {\n\t\t\tconst map = this.content?.valueLabels\n\t\t\tif (!row || typeof row !== 'object' || !map || typeof map !== 'object') {\n\t\t\t\treturn row\n\t\t\t}\n\t\t\tlet out = row\n\t\t\tfor (const [field, labels] of Object.entries(map)) {\n\t\t\t\tconst raw = row[field]\n\t\t\t\tif (!labels || typeof labels !== 'object' || (typeof raw !== 'string' && typeof raw !== 'number')) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst label = labels[String(raw)]\n\t\t\t\tif (typeof label === 'string' && label !== '') {\n\t\t\t\t\tif (out === row) {\n\t\t\t\t\t\tout = { ...row }\n\t\t\t\t\t}\n\t\t\t\t\tout[field] = this.translate(label)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Fill a translated label's counts: `{total}` is the list's total, and\n\t\t * `{count:<field>=<value>}` the loaded rows whose field reads that\n\t\t * value (\"{count:status=done} van {total} stappen klaar\"). The count\n\t\t * reads the rows the list loaded, so it is exact when `limit` covers\n\t\t * the list.\n\t\t *\n\t\t * @param {string} label The label.\n\t\t * @return {string} The text.\n\t\t */\n\t\t/**\n\t\t * A `{ label, route, params?, query? }` or `{ label, href }` link with\n\t\t * `{total}` filled and tokens resolved, or null.\n\t\t *\n\t\t * @param {object|undefined} link The declared link.\n\t\t * @return {object|null} The resolved link.\n\t\t */\n\t\tresolveLink(link) {\n\t\t\tif (!link || typeof link !== 'object' || typeof link.label !== 'string' || link.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst resolved = { label: this.withTotal(link.label) }\n\t\t\tif (link.route) {\n\t\t\t\tresolved.route = link.route\n\t\t\t\tif (link.params && typeof link.params === 'object') {\n\t\t\t\t\tresolved.params = resolveFilterTokens(link.params, this.tokenCtx)\n\t\t\t\t}\n\t\t\t\tif (link.query && typeof link.query === 'object') {\n\t\t\t\t\tresolved.query = resolveFilterTokens(link.query, this.tokenCtx)\n\t\t\t\t}\n\t\t\t} else if (typeof link.href === 'string') {\n\t\t\t\tif (link.params && typeof link.params === 'object') {\n\t\t\t\t\tconst href = this.filledHref(link.href, link.params)\n\t\t\t\t\tif (href === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tresolved.href = href\n\t\t\t\t} else {\n\t\t\t\t\tresolved.href = link.href\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\twithTotal(label) {\n\t\t\treturn fillCountLabel(this.translate(label), this.total, this.rows)\n\t\t},\n\n\t\t/**\n\t\t * The route a row opens: `rowRoute` with the id at `rowIdField`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object|null} The router location, or null.\n\t\t */\n\t\t/**\n\t\t * The one action that ends a row (`rowAction`): its label (from\n\t\t * `labels.map` by the row's `labels.field`, else `label`), and how it\n\t\t * renders: a link when it only navigates, else a button that\n\t\t * dispatches. Null without the key or a label.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {{label: string, tag: string, attrs: object}|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\trowActionOf(row) {\n\t\t\tconst action = this.content?.rowAction\n\t\t\tif (!action || typeof action !== 'object' || !row) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tlet label = typeof action.label === 'string' ? action.label : ''\n\t\t\tconst by = action.labels\n\t\t\tif (by && typeof by === 'object' && typeof by.field === 'string' && by.map && typeof by.map === 'object') {\n\t\t\t\tconst raw = readPath(row, by.field)\n\t\t\t\tif (raw !== null && raw !== undefined && typeof by.map[String(raw)] === 'string') {\n\t\t\t\t\tlabel = by.map[String(raw)]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tlabel = this.translate(label)\n\t\t\tconst link = this.rowActionLink(action, row)\n\t\t\tif (link) {\n\t\t\t\treturn link.external\n\t\t\t\t\t? { label, tag: 'a', attrs: { href: link.href, target: '_blank', rel: 'noopener' } }\n\t\t\t\t\t: { label, tag: 'router-link', attrs: { to: link.to } }\n\t\t\t}\n\t\t\treturn { label, tag: 'button', attrs: { type: 'button' } }\n\t\t},\n\n\t\t/**\n\t\t * The link a `rowAction` that only navigates renders as: `open-page`\n\t\t * opens that page for the row's id, `navigate` reads its\n\t\t * `@object.<field>` / `@objectId` tokens off the row. Null for any\n\t\t * other action, which is dispatched on click.\n\t\t *\n\t\t * @param {object} action The declared row action.\n\t\t * @param {object} row The row.\n\t\t * @return {{href: string, to: (string|object|null), external: boolean}|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\trowActionLink(action, row) {\n\t\t\tif (action.confirm) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (action.type === 'open-page') {\n\t\t\t\tconst id = this.rowIdOf(row)\n\t\t\t\tif (!this.$router || id === null || typeof action.target !== 'string' || action.target === '') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst to = { name: action.target, params: { id } }\n\t\t\t\ttry {\n\t\t\t\t\tconst href = this.$router.resolve(to).href\n\t\t\t\t\treturn href ? { href, to, external: false } : null\n\t\t\t\t} catch {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (action.type !== 'navigate') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst target = interpolateActionTarget(action.target, this.rowTokenCtx(row))\n\t\t\t// An external target needs no router; an in-app one does.\n\t\t\treturn actionLink({ ...action, target }, { router: this.$router || null })\n\t\t},\n\n\t\t/**\n\t\t * The token context of a row: the row is `@object`, its id `@objectId`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The token context.\n\t\t */\n\t\trowTokenCtx(row) {\n\t\t\treturn { ...this.tokenCtx, objectId: this.rowIdOf(row), object: row }\n\t\t},\n\n\t\t/**\n\t\t * The id of a row (`rowIdField`, else `id`, else `@self.id`), or null.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string|null} The id.\n\t\t */\n\t\trowIdOf(row) {\n\t\t\tconst field = this.content?.rowIdField\n\t\t\tconst id = field ? readPath(row, field) : (row && (row.id || row['@self']?.id))\n\t\t\treturn (id === null || id === undefined || id === '' || typeof id === 'object') ? null : String(id)\n\t\t},\n\n\t\t/**\n\t\t * Run a `rowAction` that is not a plain link through the page's\n\t\t * dispatcher: a `handler` gets the row as its last argument, an\n\t\t * `open-modal` gets it as the `row` prop, an `object-op` acts on it.\n\t\t * With `endpoint` it calls that app URL for the row, as a `rowActions`\n\t\t * endpoint entry does.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {unknown} What the dispatcher returns.\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t * @spec openspec/changes/record-list-row-action-endpoint/specs/record-list/spec.md#requirement-a-rows-one-action-can-call-an-app-endpoint-for-that-row\n\t\t */\n\t\trunRowAction(row) {\n\t\t\tconst action = this.content?.rowAction\n\t\t\tif (!action || typeof action !== 'object') {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tif (typeof action.endpoint === 'string' && action.endpoint !== '') {\n\t\t\t\treturn this.runRowActionEntry(action, row)\n\t\t\t}\n\t\t\tconst type = action.type || 'handler'\n\t\t\tlet wrapped = action\n\t\t\tif (type === 'handler') {\n\t\t\t\twrapped = { ...action, args: [...(action.args || []), row] }\n\t\t\t} else if (type === 'open-modal') {\n\t\t\t\twrapped = { ...action, props: { ...(action.props || {}), row } }\n\t\t\t}\n\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\treturn this.cnDispatchAction(wrapped)\n\t\t\t}\n\t\t\treturn dispatchAction(wrapped, { router: this.$router || null, row, tokenCtx: this.rowTokenCtx(row), source: { register: this.content?.register, schema: this.content?.schema } })\n\t\t},\n\n\t\trowLink(row) {\n\t\t\t// `rowRouteField`: the route name read from the row, for a list\n\t\t\t// whose rows open different pages (a case and a task).\n\t\t\tconst byField = this.content?.rowRouteField ? readPath(row, this.content.rowRouteField) : null\n\t\t\tconst route = (typeof byField === 'string' && byField !== '') ? byField : this.content?.rowRoute\n\t\t\tif (!route || !this.$router || !row) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst field = this.content?.rowIdField\n\t\t\tconst id = field ? readPath(row, field) : (row.id || row['@self']?.id)\n\t\t\tif (id === null || id === undefined || id === '' || typeof id === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { name: route, params: { id: String(id) } }\n\t\t},\n\n\t\t/**\n\t\t * The row's due text (`due`: `{ field, todayLabel?, overdueLabel?, upcomingLabel?, upcomingWeeksLabel?, upcomingWeeksFrom?, emptyText? }`):\n\t\t * \"3 dagen te laat\" in the danger tone, \"Vandaag\", the date or the time\n\t\t * left (\"nog 4 dagen\") otherwise, `emptyText` when the field is empty.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {{text: string, tone: string}|null} The text and tone, or null.\n\t\t * @spec openspec/changes/screens-due-text/specs/due-text/spec.md#requirement-a-due-date-reads-as-text-with-a-tone\n\t\t */\n\t\tdueOf(row) {\n\t\t\tconst due = this.content?.due\n\t\t\tif (!due || typeof due !== 'object' || !due.field) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolveDue(readPath(row, due.field), due, (text) => this.translate(text))\n\t\t},\n\n\t\t/**\n\t\t * Ask every `content.aggregates` figure (`{ key: { register, schema,\n\t\t * op: \"count\" | \"max\", field?, where } }`, `@self.<path>` in `where`\n\t\t * read off the row) for each row shown, as a table's `aggregate`\n\t\t * column does. A failed figure is left out; a stale batch is dropped.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\tasync loadAggregates() {\n\t\t\tconst declared = this.content?.aggregates\n\t\t\tconst entries = declared && typeof declared === 'object' ? Object.entries(declared).filter(([, agg]) => isRowAggregate(agg)) : []\n\t\t\tconst id = (this.aggregateRequestId = (this.aggregateRequestId || 0) + 1)\n\t\t\tif (entries.length === 0) {\n\t\t\t\tthis.aggregateValues = {}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = {}\n\t\t\tconst jobs = []\n\t\t\tfor (const raw of this.rows.slice(0, this.limit)) {\n\t\t\t\tconst row = scalarRow(raw)\n\t\t\t\tconst rowId = row && typeof row === 'object' ? (row.id || row['@self']?.id) : null\n\t\t\t\tif (!rowId) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnext[rowId] = {}\n\t\t\t\tfor (const [key, agg] of entries) {\n\t\t\t\t\tjobs.push(fetchRowAggregate(agg, row)\n\t\t\t\t\t\t.then((value) => {\n\t\t\t\t\t\t\tnext[rowId][key] = this.aggregateText(agg, value)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => {}))\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (id === this.aggregateRequestId) {\n\t\t\t\tthis.aggregateValues = next\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A count read through the aggregate's `text` forms (`{ zero?, one?,\n\t\t * other }`, `{count}` filled in, translated), else the figure itself.\n\t\t *\n\t\t * @param {object} agg The aggregate declaration.\n\t\t * @param {unknown} value The figure.\n\t\t * @return {unknown} The text, or the figure.\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\taggregateText(agg, value) {\n\t\t\tconst forms = agg && agg.text\n\t\t\tconst count = Number(value)\n\t\t\tif (!forms || typeof forms !== 'object' || !Number.isFinite(count)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst form = (count === 0 && forms.zero) || (count === 1 && forms.one) || forms.other || forms.one\n\t\t\treturn typeof form === 'string' ? this.translate(form).replace(/\\{count\\}/g, String(count)) : value\n\t\t},\n\n\t\t/**\n\t\t * The row with its `aggregates` figures under their keys.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The row, its figures added when it has any.\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\twithAggregates(row) {\n\t\t\tif (!row || typeof row !== 'object') {\n\t\t\t\treturn row\n\t\t\t}\n\t\t\tconst figures = this.aggregateValues[row.id || row['@self']?.id]\n\t\t\treturn figures ? { ...row, ...figures } : row\n\t\t},\n\n\t\t/**\n\t\t * Whether a checklist row is done: `content.done` (a condition over\n\t\t * the row) holds for it.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tisChecked(row) {\n\t\t\tconst done = this.content?.done\n\t\t\treturn Boolean(done && typeof done === 'object' && row && evaluateVisibleWhenLocal(done, row))\n\t\t},\n\n\t\t/**\n\t\t * A `count` badge: how many entries a row's field holds (a list counts\n\t\t * its items, a number is itself), as `one` or `other` with `{count}`.\n\t\t * Nothing at 0.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {{field: string, one?: string, other?: string, variant?: string}} badge The declaration.\n\t\t * @param {number} index The badge's place, for its key.\n\t\t * @return {object|null} The badge.\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tcountBadgeOf(row, badge, index) {\n\t\t\tconst raw = readPath(row, badge.field)\n\t\t\tconst count = Array.isArray(raw) ? raw.length : Number(raw)\n\t\t\tif (!Number.isFinite(count) || count < 1) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst template = count === 1 ? (badge.one || badge.other) : (badge.other || badge.one)\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `count-${index}`,\n\t\t\t\tkind: 'count',\n\t\t\t\tlabel: this.translate(template).replace(/\\{count\\}/g, String(count)),\n\t\t\t\tvariant: isBadgeVariant(badge.variant) ? badge.variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The badge variant of a `table` cell with a `tone`\n\t\t * (`{ field?, map, default?, override?: { when, tone } }`): the value at\n\t\t * `field` (else the cell text) looked up in `map`, else `default`. While\n\t\t * `override.when` (a condition over the row) holds, the cell takes\n\t\t * `override.tone` instead, so a verdict is never green unless a second\n\t\t * field allows it.\n\t\t *\n\t\t * @param {object} col The column.\n\t\t * @param {object} row The row.\n\t\t * @param {string} text The cell text.\n\t\t * @return {string} A badge variant, or '' for a plain cell.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\tcellToneOf(col, row, text) {\n\t\t\tconst tone = col.tone\n\t\t\tif (!tone || typeof tone !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet variant\n\t\t\tif (tone.override && typeof tone.override === 'object' && evaluateVisibleWhenLocal(tone.override.when, row || {})) {\n\t\t\t\tvariant = tone.override.tone\n\t\t\t} else {\n\t\t\t\tconst value = tone.field ? readPath(row, tone.field) : text\n\t\t\t\tconst map = tone.map && typeof tone.map === 'object' ? tone.map : {}\n\t\t\t\tvariant = Object.hasOwn(map, String(value)) ? map[String(value)] : tone.default\n\t\t\t}\n\t\t\treturn isBadgeVariant(variant) ? variant : 'default'\n\t\t},\n\n\t\t/**\n\t\t * The `aria-sort` of a sortable `table` column.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @return {string} `ascending`, `descending` or `none`.\n\t\t */\n\t\tsortStateOf(key) {\n\t\t\treturn this.tableSort.key === key && this.tableSort.dir ? this.tableSort.dir : 'none'\n\t\t},\n\n\t\t/**\n\t\t * The arrow after a sortable column's label.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @return {string} An up or down arrow, or '' while the column is not the sort.\n\t\t */\n\t\tsortMarkOf(key) {\n\t\t\tconst state = this.sortStateOf(key)\n\t\t\tif (state === 'ascending') {\n\t\t\t\treturn '▲'\n\t\t\t}\n\t\t\treturn state === 'descending' ? '▼' : ''\n\t\t},\n\n\t\t/**\n\t\t * Sort the `table` by a column: ascending first, then descending.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\ttoggleTableSort(key) {\n\t\t\tconst dir = this.tableSort.key === key && this.tableSort.dir === 'ascending' ? 'descending' : 'ascending'\n\t\t\tthis.tableSort = { key, dir }\n\t\t},\n\n\t\t/**\n\t\t * The rows of a read with `flattenPath` set: each entry of the list at\n\t\t * that path on a record becomes a row, with the record at `@parent`.\n\t\t * A record without the list adds no row. Without `flattenPath` the\n\t\t * records are the rows.\n\t\t *\n\t\t * @param {Array<object>} records The records read.\n\t\t * @return {Array<object>} The rows.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\tflattenRows(records) {\n\t\t\tconst path = this.content?.flattenPath\n\t\t\tif (typeof path !== 'string' || path === '') {\n\t\t\t\treturn records\n\t\t\t}\n\t\t\treturn records.flatMap((record) => {\n\t\t\t\tconst list = readPath(record, path)\n\t\t\t\treturn Array.isArray(list)\n\t\t\t\t\t? list.filter((entry) => entry && typeof entry === 'object').map((entry) => ({ ...entry, '@parent': record }))\n\t\t\t\t\t: []\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The row actions shown on one row: those whose `visibleWhen` (a\n\t\t * condition over the row) holds. An `href` action is a template over\n\t\t * the row and shows only when it fills to a web address or an\n\t\t * instance path; a web address opens in a new tab.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{action: object, index: number, href: string, external: boolean}>} The visible actions, with their place in `rowActions`.\n\t\t * @spec openspec/changes/record-list-row-rules/specs/record-list-row-rules/spec.md#requirement-a-row-action-can-depend-on-the-row\n\t\t */\n\t\trowActionsOf(row) {\n\t\t\tconst shown = []\n\t\t\tthis.rowActions.forEach((action, index) => {\n\t\t\t\tif (action.type === 'set-field') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (action.visibleWhen && !evaluateVisibleWhenLocal(action.visibleWhen, row || {})) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (typeof action.href !== 'string') {\n\t\t\t\t\tshown.push({ action, index, href: '', external: false })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst href = this.fill(action.href, row).trim()\n\t\t\t\tconst external = /^https?:\\/\\//i.test(href)\n\t\t\t\tif (external || (href.startsWith('/') && !href.startsWith('//'))) {\n\t\t\t\t\tshown.push({ action, index, href, external })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn shown\n\t\t},\n\n\t\t/**\n\t\t * A row's `links` line: the ids at `links.field`, each labelled from\n\t\t * `links.labelSource` (`{ register, schema, template }`) once read, else\n\t\t * `links.fallback`, and routed by `links.route` with `{value}` the id.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{id: string, label: string, to: (object|null)}>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tlinksOf(row) {\n\t\t\tconst spec = this.content?.links\n\t\t\tif (!spec || typeof spec !== 'object' || !spec.field) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst list = readPath(row, spec.field)\n\t\t\tif (!Array.isArray(list)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst fallback = typeof spec.fallback === 'string' ? this.translate(spec.fallback) : ''\n\t\t\treturn list.filter((id) => typeof id === 'string' && id !== '').map((id) => {\n\t\t\t\tlet to = null\n\t\t\t\tif (spec.route && typeof spec.route === 'object' && spec.route.name && this.$router) {\n\t\t\t\t\tconst params = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(spec.route.params || {})) {\n\t\t\t\t\t\tparams[key] = value === '{value}' ? id : value\n\t\t\t\t\t}\n\t\t\t\t\tto = { name: spec.route.name, params }\n\t\t\t\t}\n\t\t\t\treturn { id, label: this.linkLabels[id] || fallback || id, to }\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Read the labels of the records the `links` lines name, ten at most.\n\t\t * A record that cannot be read keeps the fallback; its link still opens.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLinkLabels() {\n\t\t\tconst spec = this.content?.links?.labelSource\n\t\t\tif (!spec || !spec.register || !spec.schema || this.linkIdsKey === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst wanted = this.linkIdsKey.split('|').filter((id) => !this.linkLabels[id]).slice(0, 10)\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\tawait Promise.all(wanted.map(async (id) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { data } = await axios.get(generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}', { register: spec.register, schema: spec.schema, id }))\n\t\t\t\t\tconst label = fillTemplate(this.translate(spec.template || '{title}'), data || {})\n\t\t\t\t\tif (label !== '') {\n\t\t\t\t\t\tthis.linkLabels = { ...this.linkLabels, [id]: label }\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// The link still opens; only its text stays the fallback.\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Fill `{field}` placeholders from a row. A text that is one placeholder\n\t\t * keeps the value's type.\n\t\t *\n\t\t * @param {string} text The template.\n\t\t * @param {object} row The row.\n\t\t * @return {unknown} The filled value.\n\t\t */\n\t\tfillRow(text, row) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst whole = text.match(/^\\{([\\w.@]+)\\}$/)\n\t\t\tif (whole) {\n\t\t\t\treturn readPath(row, whole[1]) ?? ''\n\t\t\t}\n\t\t\treturn text.replace(/\\{([\\w.@]+)\\}/g, (_m, field) => String(readPath(row, field) ?? ''))\n\t\t},\n\n\t\t/**\n\t\t * Whether the page's record already holds the value a `set-field`\n\t\t * action would write for this row.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tsetFieldDone(action, row) {\n\t\t\tconst object = this.tokenCtx.object || {}\n\t\t\tconst current = readPath(object, action.field)\n\t\t\tconst value = this.fillRow(action.value, row)\n\t\t\treturn Boolean(action.doneLabel) && value !== '' && current !== undefined && current !== null && String(current) === String(value)\n\t\t},\n\n\t\t/**\n\t\t * Write one field of the page's record from a row with one PATCH, hand\n\t\t * the saved record to the page, and read the list again.\n\t\t *\n\t\t * @spec openspec/changes/record-list-set-field/specs/record-list/spec.md#requirement-a-row-can-set-a-field-of-the-page-record\n\t\t * @param {object} action The `set-field` action.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync runSetField(action, row) {\n\t\t\tconst context = this.tokenCtx\n\t\t\tif (this.settingField || !context.register || !context.schema || !context.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.actionError = ''\n\t\t\tthis.settingField = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\t\tconst url = generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(context.register)}/${encodeURIComponent(context.schema)}/${encodeURIComponent(context.objectId)}`)\n\t\t\t\tconst { data } = await axios.patch(url, { [action.field]: this.fillRow(action.value, row) })\n\t\t\t\tconst setObject = unwrap(this.cnObjectContext)?.setObject\n\t\t\t\tif (typeof setObject === 'function' && data && typeof data === 'object') {\n\t\t\t\t\tsetObject(data)\n\t\t\t\t}\n\t\t\t\tif (typeof this.epRefetch === 'function' && this.endpointActive) {\n\t\t\t\t\tawait this.epRefetch(true)\n\t\t\t\t\tif (typeof this.footnoteRefetch === 'function' && this.footnoteFromAnswer) {\n\t\t\t\t\t\tawait this.footnoteRefetch(false)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tawait this.fetchRows()\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst said = error?.response?.data?.error ?? error?.response?.data?.message\n\t\t\t\tthis.actionError = typeof said === 'string' && said !== ''\n\t\t\t\t\t? said\n\t\t\t\t\t: (action.errorText ? this.translate(action.errorText) : t('nextcloud-vue', 'This did not work. Try again.'))\n\t\t\t} finally {\n\t\t\t\tthis.settingField = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one of `rowActions` for a row: an `endpoint` is called with the\n\t\t * row's `{field}` tokens and the page's `@objectId` filled in, then the\n\t\t * list reads again; a refusal shows the server's sentence. Any other\n\t\t * entry is a page action, dispatched as `rowAction` is.\n\t\t *\n\t\t * @param {object} action The entry.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tasync runRowActionEntry(action, row) {\n\t\t\tthis.actionError = ''\n\t\t\tif (typeof action.endpoint !== 'string' || action.endpoint === '') {\n\t\t\t\tconst { label, ...declared } = action\n\t\t\t\tconst type = declared.type || 'handler'\n\t\t\t\tlet wrapped = declared\n\t\t\t\tif (type === 'handler') {\n\t\t\t\t\twrapped = { ...declared, args: [...(declared.args || []), row] }\n\t\t\t\t} else if (type === 'open-modal') {\n\t\t\t\t\twrapped = { ...declared, props: { ...resolveDeepTokens(declared.props || {}, this.tokenCtx), row } }\n\t\t\t\t}\n\t\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tthis.cnDispatchAction(wrapped)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdispatchAction(wrapped, { router: this.$router || null, row, tokenCtx: this.rowTokenCtx(row) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\tconst path = interpolateUrlTokens(action.endpoint, this.tokenCtx).replace(/\\{([\\w.@]+)\\}/g, (_match, field) => encodeURIComponent(String(readPath(row, field) ?? '')))\n\t\t\tconst method = typeof action.method === 'string' ? action.method.toLowerCase() : 'post'\n\t\t\ttry {\n\t\t\t\tawait axios.request({ method, url: generateUrl(path) })\n\t\t\t\tif (typeof this.epRefetch === 'function' && this.endpointActive) {\n\t\t\t\t\tawait this.epRefetch(true)\n\t\t\t\t} else {\n\t\t\t\t\tawait this.fetchRows()\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst said = error?.response?.data?.error ?? error?.response?.data?.message\n\t\t\t\tthis.actionError = typeof said === 'string' && said !== ''\n\t\t\t\t\t? said\n\t\t\t\t\t: (action.errorText ? this.translate(action.errorText) : t('nextcloud-vue', 'This did not work. Try again.'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The row's extra badges (`badges`): a coloured badge from a field\n\t\t * (`{ field, labels?, colorMap?, variant?, hideValues? }`, the value\n\t\t * shown unless `hideValues` lists it) and an age badge\n\t\t * (`{ kind: \"stale\", field, afterDays, label?, variant? }`, shown when the\n\t\t * date field is older than `afterDays` whole days; `{days}` in the\n\t\t * label is the age).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{key: string, kind: string, label: string, variant: string}>} The badges that apply.\n\t\t * @spec openspec/changes/screens-record-list-badges/specs/record-list-badges/spec.md#requirement-a-record-list-row-can-carry-badges\n\t\t */\n\t\tbadgesOf(row) {\n\t\t\tconst declared = Array.isArray(this.content?.badges) ? this.content.badges : []\n\t\t\tconst out = []\n\t\t\tdeclared.forEach((badge, index) => {\n\t\t\t\tif (!badge || typeof badge !== 'object' || !badge.field) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (badge.kind === 'count') {\n\t\t\t\t\tconst made = this.countBadgeOf(row, badge, index)\n\t\t\t\t\tif (made) {\n\t\t\t\t\t\tout.push(made)\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (badge.kind === 'stale') {\n\t\t\t\t\tconst days = ageInDays(readPath(row, badge.field))\n\t\t\t\t\tconst after = Number(badge.afterDays)\n\t\t\t\t\tif (days === null || !Number.isFinite(after) || days <= after) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tconst template = this.translate(badge.label || 'Stale')\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tkey: `stale-${index}`,\n\t\t\t\t\t\tkind: 'stale',\n\t\t\t\t\t\tlabel: template.replace(/\\{days\\}/g, String(days)),\n\t\t\t\t\t\tvariant: isBadgeVariant(badge.variant) ? badge.variant : 'warning',\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst made = this.pillOf(row, badge)\n\t\t\t\tif (made) {\n\t\t\t\t\tout.push({ key: `field-${index}`, kind: 'field', ...made })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * The row's meta line. A string is one template, and one empty token\n\t\t * empties it. `{ parts: [\"{identifier}\", \"{caseTypeName}\", \"{handler}\"],\n\t\t * separator? }` fills each part on its own, drops the empty ones and\n\t\t * joins the rest (default \" · \"), so a row without a handler still\n\t\t * reads \"2026-0082 · Woo-verzoek\".\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} The meta line, '' when nothing fills.\n\t\t * @spec openspec/changes/screens-record-list-meta-parts/specs/record-list-meta-parts/spec.md#requirement-a-meta-line-of-parts-skips-the-empty-ones\n\t\t */\n\t\tmetaOf(row) {\n\t\t\tconst meta = this.content?.meta\n\t\t\tif (!meta || typeof meta !== 'object' || !Array.isArray(meta.parts)) {\n\t\t\t\treturn this.fill(meta, row)\n\t\t\t}\n\t\t\tconst separator = typeof meta.separator === 'string' ? meta.separator : ' · '\n\t\t\treturn meta.parts\n\t\t\t\t.map((part) => this.fill(part, row))\n\t\t\t\t.filter((text) => text !== '')\n\t\t\t\t.join(separator)\n\t\t},\n\n\t\t/**\n\t\t * The row's pill: `{ field, labels?, colorMap?, variant?, hideValues? }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} [config] A pill config; the widget's `pill` by default.\n\t\t * @return {{label: string, variant: string}|null} The pill, or null.\n\t\t */\n\t\tpillOf(row, config) {\n\t\t\tconst pill = config || this.content?.pill\n\t\t\tif (pill && typeof pill === 'object' && Array.isArray(pill.cases)) {\n\t\t\t\treturn this.pillCaseOf(row, pill)\n\t\t\t}\n\t\t\tif (!pill || typeof pill !== 'object' || !pill.field) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(row, pill.field)\n\t\t\tif (raw === null || raw === undefined || raw === '' || typeof raw === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst key = String(raw)\n\t\t\tif (Array.isArray(pill.hideValues) && pill.hideValues.map(String).includes(key)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = pill.labels && typeof pill.labels === 'object' ? pill.labels : {}\n\t\t\tconst map = pill.colorMap && typeof pill.colorMap === 'object' ? pill.colorMap : {}\n\t\t\tconst found = Object.keys(map).find((k) => k.toLowerCase() === key.toLowerCase())\n\t\t\tconst variant = found ? map[found] : pill.variant\n\t\t\treturn {\n\t\t\t\tlabel: labels[key] ? this.translate(labels[key]) : key,\n\t\t\t\tvariant: isBadgeVariant(variant) ? variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The pill of `{ cases: [{ when, label, variant? }], label?, variant? }`:\n\t\t * the first case whose `when` (a local condition over the row) holds,\n\t\t * else the pill's own `label` and `variant`, else none. For a state that\n\t\t * reads more than one field (Concept, Actief, Vastgezet).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} pill The pill config.\n\t\t * @return {{label: string, variant: string}|null} The pill, or null.\n\t\t * @spec openspec/changes/record-list-pill-cases-footer-choice/specs/record-list/spec.md#requirement-a-record-list-row-pill-can-read-a-state-from-several-fields\n\t\t */\n\t\tpillCaseOf(row, pill) {\n\t\t\tconst found = pill.cases.find((entry) => entry && typeof entry === 'object' && entry.when && evaluateVisibleWhenLocal(entry.when, row || {}))\n\t\t\tconst chosen = found || pill\n\t\t\tif (typeof chosen.label !== 'string' || chosen.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(chosen.label),\n\t\t\t\tvariant: isBadgeVariant(chosen.variant) ? chosen.variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The feed icon: an icon name, or `{ field, map, default }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} The MDI icon name.\n\t\t */\n\t\ticonOf(row) {\n\t\t\tconst icon = this.content?.icon\n\t\t\tif (typeof icon === 'string' && icon !== '') {\n\t\t\t\treturn icon\n\t\t\t}\n\t\t\tif (icon && typeof icon === 'object') {\n\t\t\t\tconst raw = icon.field ? readPath(row, icon.field) : undefined\n\t\t\t\tconst map = icon.map && typeof icon.map === 'object' ? icon.map : {}\n\t\t\t\tif (raw !== null && raw !== undefined && map[String(raw)]) {\n\t\t\t\t\treturn map[String(raw)]\n\t\t\t\t}\n\t\t\t\tif (typeof icon.default === 'string' && icon.default !== '') {\n\t\t\t\t\treturn icon.default\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 'CircleSmall'\n\t\t},\n\n\t\t/** Tell the card around this list what its header shows. */\n\t\temitHeader() {\n\t\t\tconst header = { link: this.headerLink, note: this.headerNote }\n\t\t\t// `headerSubtitle`: the counts as the muted line under the card title.\n\t\t\tconst subtitle = this.content?.headerSubtitle\n\t\t\tif (typeof subtitle === 'string' && subtitle !== '' && !this.error) {\n\t\t\t\theader.subtitle = this.withTotal(subtitle)\n\t\t\t}\n\t\t\t// `headerCount: true`: the card draws the total as a chip after its title.\n\t\t\tif (this.content?.headerCount === true && !this.error) {\n\t\t\t\theader.count = this.total\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event header Emitted after every read with the card header's parts.\n\t\t\t * @type {{link: (object|null), note: string, count: (number|undefined), subtitle: (string|undefined)}} The header link (resolved, with `{total}` filled), the note, with `headerCount` the total, and with `headerSubtitle` the line under the title.\n\t\t\t */\n\t\t\tthis.$emit('header', header)\n\t\t},\n\n\t\t/**\n\t\t * The rank list of a sort (`{ field, rank: [\"urgent\", \"high\", \"normal\", \"low\"], then? }`),\n\t\t * or null when the sort has none or the list's own filter already fixes the field.\n\t\t *\n\t\t * @param {object|null} sort The effective sort.\n\t\t * @return {Array<string>|null} The values in rank order.\n\t\t * @spec openspec/changes/screens-enum-rank-sort/specs/enum-rank-sort/spec.md#requirement-a-record-list-can-sort-by-the-rank-of-an-enum-value\n\t\t */\n\t\trankOf(sort) {\n\t\t\tif (!sort || typeof sort !== 'object' || !sort.field || !Array.isArray(sort.rank)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst rank = sort.rank.filter((value) => typeof value === 'string' && value !== '')\n\t\t\tif (rank.length === 0 || Object.hasOwn(this.resolvedFilter || {}, sort.field)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn rank\n\t\t},\n\n\t\t/**\n\t\t * Read a list in the rank of an enum field. The list endpoint orders a\n\t\t * text field alphabetically (\"high\", \"low\", \"normal\", \"urgent\"), so the\n\t\t * rows are read one rank at a time, best first, each with the rest of the\n\t\t * sort (`then`) inside it, until the page is full; the rows with a value\n\t\t * outside the rank (or none) follow. The result is exact, not a client-side\n\t\t * sort of a partial page. It costs one request for the total, one per rank\n\t\t * value read and one for the remainder.\n\t\t *\n\t\t * @param {(params: object) => Promise<object>} get Reads the list with the given params.\n\t\t * @param {object} base The params without any order.\n\t\t * @param {{field: string, then?: {field: string, dir?: string}}} sort The sort.\n\t\t * @param {Array<string>} rank The values in rank order.\n\t\t * @return {Promise<{rows: Array<object>, total: number}>} The page and the total.\n\t\t * @spec openspec/changes/screens-enum-rank-sort/specs/enum-rank-sort/spec.md#requirement-a-record-list-can-sort-by-the-rank-of-an-enum-value\n\t\t */\n\t\tasync fetchRanked(get, base, sort, rank) {\n\t\t\tconst order = {}\n\t\t\tif (sort.then && typeof sort.then === 'object' && sort.then.field) {\n\t\t\t\torder[`_order[${sort.then.field}]`] = sort.then.dir === 'desc' ? 'desc' : 'asc'\n\t\t\t}\n\t\t\tconst read = async (extra) => {\n\t\t\t\tconst response = await get({ ...base, ...order, ...extra })\n\t\t\t\tconst data = response && response.data ? response.data : {}\n\t\t\t\treturn { results: Array.isArray(data.results) ? data.results : [], total: data.total }\n\t\t\t}\n\t\t\tconst head = await read({ _limit: 1 })\n\t\t\tconst rows = []\n\t\t\tconst seen = new Set()\n\t\t\tconst idOf = (row) => (row && (row.id || row['@self']?.id)) || null\n\t\t\tconst take = (list) => {\n\t\t\t\tfor (const row of list) {\n\t\t\t\t\tconst id = idOf(row)\n\t\t\t\t\tif (id !== null && seen.has(id)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (id !== null) {\n\t\t\t\t\t\tseen.add(id)\n\t\t\t\t\t}\n\t\t\t\t\tif (rows.length < this.limit) {\n\t\t\t\t\t\trows.push(row)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const value of rank) {\n\t\t\t\tif (rows.length >= this.limit) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttake((await read({ [sort.field]: value, _limit: this.limit - rows.length })).results)\n\t\t\t}\n\t\t\tif (rows.length < this.limit) {\n\t\t\t\ttake((await read({ _limit: this.limit + rows.length })).results)\n\t\t\t}\n\t\t\treturn { rows, total: typeof head.total === 'number' ? head.total : rows.length }\n\t\t},\n\n\t\t/**\n\t\t * Copy the endpoint read into the list: its payload must be an array of\n\t\t * rows (anything else is an empty list), and a failed read is an error.\n\t\t *\n\t\t * @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint\n\t\t */\n\t\ttakeEndpointRows() {\n\t\t\tthis.rows = this.flattenRows(Array.isArray(this.epData) ? this.epData : [])\n\t\t\tthis.total = this.rows.length\n\t\t\tthis.loading = this.epLoading === true\n\t\t\tthis.error = Boolean(this.epError)\n\t\t\tthis.lenses = {}\n\t\t\tif (!this.loading) {\n\t\t\t\tthis.emitHeader()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch the list. Sends nothing while a required token is unresolved\n\t\t * or the source is incomplete.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchRows() {\n\t\t\tconst c = this.content || {}\n\t\t\tif (this.absent) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.endpointActive) {\n\t\t\t\tthis.takeEndpointRows()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.objectRowsActive) {\n\t\t\t\tthis.rows = this.flattenRows(this.objectRowsList.map((row, index) => (row.id === undefined ? { id: `row-${index}`, ...row } : row)))\n\t\t\t\tthis.total = this.rows.length\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.error = false\n\t\t\t\tthis.lenses = {}\n\t\t\t\tthis.emitHeader()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!c.register || !c.schema || this.waiting) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = false\n\t\t\t\tthis.emitHeader()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = false\n\t\t\tconst run = this.fetchRun = (this.fetchRun || 0) + 1\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: c.register, schema: c.schema })\n\t\t\t\tconst sort = this.effectiveSort\n\t\t\t\tconst params = { _limit: this.limit }\n\t\t\t\tif (this.offset > 0) {\n\t\t\t\t\tparams._offset = this.offset\n\t\t\t\t}\n\t\t\t\t// A rank sort (`sort.rank`) cannot be one `_order`: the list endpoint\n\t\t\t\t// orders a text field alphabetically. It is read group by group below.\n\t\t\t\tconst rank = this.rankOf(sort)\n\t\t\t\tif (!rank && sort && typeof sort === 'object' && sort.field) {\n\t\t\t\t\tparams[`_order[${sort.field}]`] = sort.dir === 'desc' ? 'desc' : 'asc'\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(c.extend)) {\n\t\t\t\t\tconst extend = c.extend.filter((e) => typeof e === 'string' && e !== '')\n\t\t\t\t\tif (extend.length > 0) {\n\t\t\t\t\t\tparams._extend = extend\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, value] of Object.entries(this.resolvedFilter)) {\n\t\t\t\t\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\t\tfor (const [op, operand] of Object.entries(value)) {\n\t\t\t\t\t\t\tparams[`${key}[${op}]`] = operand\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value !== '' && value !== null && value !== undefined) {\n\t\t\t\t\t\tparams[key] = value\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (rank) {\n\t\t\t\t\t// Several requests: a fetch started later (the sort changed\n\t\t\t\t\t// meanwhile) must not be overwritten by this one.\n\t\t\t\t\tconst ranked = await this.fetchRanked((query) => axios.get(url, { params: query }), params, sort, rank)\n\t\t\t\t\tif (run !== this.fetchRun) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthis.rows = this.flattenRows(ranked.rows)\n\t\t\t\t\tthis.total = this.content?.flattenPath ? this.rows.length : ranked.total\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst data = response && response.data ? response.data : {}\n\t\t\t\tthis.rows = this.flattenRows(Array.isArray(data.results) ? data.results : [])\n\t\t\t\tthis.total = typeof data.total === 'number' && !this.content?.flattenPath ? data.total : this.rows.length\n\t\t\t\tthis.lenses = readLensReports(data)\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnRecordListWidget] failed to load objects:', e)\n\t\t\t\tthis.lenses = {}\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = true\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.emitHeader()\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-record-list__checklist-bar {\n\theight: 8px;\n\tmargin-block-end: 16px;\n\tborder-radius: 4px;\n\tbackground: var(--color-background-dark);\n\toverflow: hidden;\n}\n\n.cn-record-list__checklist-fill {\n\tdisplay: block;\n\theight: 100%;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element);\n}\n\n.cn-record-list__checklist {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-record-list-columns, 3), minmax(0, 1fr));\n\tgap: 8px 16px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-record-list__check {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 28px;\n}\n\n.cn-record-list__check--done {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__check-mark {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 20px;\n\theight: 20px;\n\tborder: 2px solid var(--color-border-maxcontrast);\n\tborder-radius: 50%;\n}\n\n.cn-record-list__check--done .cn-record-list__check-mark {\n\tborder-color: transparent;\n\tbackground: var(--color-success-hover, var(--color-background-dark));\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n@media (max-width: 640px) {\n\t.cn-record-list__checklist {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n\n.cn-record-list__set-field-done {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tcolor: var(--color-success-text, var(--color-success));\n\tfont-weight: bold;\n}\n\n.cn-record-list__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-record-list__group-heading {\n\tmargin: 6px 0 0;\n\tfont-size: 15px;\n\tfont-weight: 700;\n\tline-height: 1.4;\n}\n\n.cn-record-list__group-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin-top: 6px;\n}\n\n.cn-record-list__group-head .cn-record-list__group-heading {\n\tmargin: 0;\n}\n\n.cn-record-list__action--tonal.button-vue {\n\tmin-height: 34px;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder: 0;\n\tborder-radius: 17px;\n\tbackground-color: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.cn-record-list__action--tonal.button-vue:hover:not(:disabled) {\n\tbackground-color: var(--color-primary-element-light-hover);\n}\n\n.cn-record-list__footer {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 6px;\n\tmargin-top: 10px;\n}\n\n.cn-record-list__footer--wide {\n\talign-items: stretch;\n}\n\n.cn-record-list__footer-note {\n\tmargin: 0 0 6px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__footer-reason {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__empty,\n.cn-record-list__error {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-record-list__notice {\n\tdisplay: flex;\n\tgap: 10px;\n\talign-items: flex-start;\n\tpadding: 12px 14px;\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground: var(--color-primary-element-light, var(--color-background-dark));\n\tcolor: var(--color-main-text);\n}\n\n.cn-record-list__notice--warning {\n\tbackground: var(--color-warning-light, rgba(255, 196, 0, 0.12));\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-record-list__notice--error {\n\tbackground: var(--color-error-light, rgba(219, 0, 0, 0.08));\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-record-list__notice--footnote {\n\tmargin-top: 12px;\n}\n\n.cn-record-list__notice-icon {\n\tflex: 0 0 auto;\n\tmargin-top: 1px;\n}\n\n.cn-record-list__notice-text {\n\tmargin: 0;\n\tline-height: 1.5;\n}\n\n.cn-record-list__loading {\n\tdisplay: flex;\n\tjustify-content: center;\n\tpadding: 8px 0;\n}\n\n/* rows */\n.cn-record-list--rows .cn-record-list__item + .cn-record-list__item,\n.cn-record-list--rule-above .cn-record-list__item:first-child {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__pill-start {\n\tdisplay: flex;\n\tflex: none;\n}\n\n.cn-record-list__bar {\n\tbackground: var(--color-border);\n\tborder-radius: 3px;\n\tdisplay: block;\n\theight: 6px;\n\tmargin: -6px 0 12px;\n\toverflow: hidden;\n}\n\n.cn-record-list__bar-fill {\n\tbackground: var(--color-primary-element);\n\tdisplay: block;\n\theight: 100%;\n}\n\n.cn-record-list__bar--over .cn-record-list__bar-fill {\n\tbackground: var(--color-error);\n}\n\n.cn-record-list__row {\n\talign-items: center;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tgap: 16px;\n\tpadding: 12px 0;\n\ttext-decoration: none;\n}\n\n.cn-record-list__row--link:hover .cn-record-list__title,\n.cn-record-list__row--link:focus-visible .cn-record-list__title {\n\ttext-decoration: underline;\n}\n\n.cn-record-list__dot {\n\tflex: 0 0 14px;\n\twidth: 14px;\n\theight: 14px;\n\tborder-radius: 50%;\n}\n\n.cn-record-list__flag {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-hover);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 12px;\n\tfont-weight: 700;\n\theight: 36px;\n\tjustify-content: center;\n\twidth: 36px;\n}\n\n.cn-record-list__main {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-record-list__title {\n\tfont-size: 15px;\n\tfont-weight: 700;\n}\n\n.cn-record-list--compact .cn-record-list__row {\n\tbox-sizing: border-box;\n\tmin-height: 56px;\n\tpadding: 10px 0;\n}\n\n.cn-record-list--compact .cn-record-list__title {\n\tfont-weight: 500;\n}\n\n/* `density: \"stacked\"`: the rows stand 10px apart with no rule and no row\n padding, a short side list (DqDagAfsluiten \"Morgen eerst\"). */\n.cn-record-list--stacked .cn-record-list__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n}\n\n.cn-record-list--stacked .cn-record-list__row {\n\tmin-height: 0;\n\tpadding: 0;\n}\n\n.cn-record-list--stacked .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 0;\n}\n\n.cn-record-list__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__aside {\n\talign-items: center;\n\tdisplay: flex;\n\tflex: none;\n\tgap: 16px;\n}\n\n.cn-record-list__leading {\n\tflex: 0 0 52px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tfont-variant-numeric: tabular-nums;\n}\n\n.cn-record-list__trailing {\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__due {\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__due--danger {\n\tcolor: var(--color-text-error, var(--color-error-text));\n\tfont-weight: 600;\n}\n\n.cn-record-list__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n\tfont-size: 14px;\n}\n\n.cn-record-list__table th {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n\ttext-align: start;\n}\n\n.cn-record-list__table td {\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-record-list__cell-sub {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__table .cn-record-list__cell--actions {\n\twidth: 1%;\n\tpadding-inline-start: 12px;\n\ttext-align: end;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__sort {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\talign-items: center;\n\tmin-height: 0;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n\tcursor: pointer;\n}\n\n.cn-record-list__sort:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-record-list__sort-mark {\n\tfont-size: 10px;\n}\n\n.cn-record-list__table .cn-record-list__cell--end {\n\tpadding-inline-start: 12px;\n\ttext-align: end;\n\tfont-variant-numeric: tabular-nums;\n}\n\n.cn-record-list__table .cn-record-list__cell--alert {\n\tcolor: var(--color-text-error, var(--color-error-text));\n\tfont-weight: 700;\n}\n\n.cn-record-list__intro {\n\tmargin: 0 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__footnote {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__due--soon {\n\tcolor: var(--color-text-warning, var(--color-warning-text));\n\tfont-weight: 600;\n}\n\n.cn-record-list__due--empty {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__row--action {\n\tflex-wrap: wrap;\n\tgap: 8px 16px;\n\tpadding: 14px 0;\n}\n\n.cn-record-list__row--action .cn-record-list__main {\n\tflex: 1 1 280px;\n\tgap: 3px;\n}\n\n.cn-record-list__title--link {\n\tcolor: var(--color-main-text);\n\ttext-decoration: underline;\n}\n\n.cn-record-list__pills {\n\tdisplay: flex;\n\tflex: 0 0 120px;\n\tgap: 6px;\n\tjustify-content: flex-end;\n}\n\n.cn-record-list__due--below {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: normal;\n}\n\n.cn-record-list__footer-link {\n\talign-self: flex-start;\n\tpadding-top: 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttext-decoration: underline;\n}\n\n.cn-record-list__due--column {\n\tflex: 0 0 96px;\n\tfont-size: 13px;\n\ttext-align: end;\n}\n\n.cn-record-list__action {\n\talign-items: center;\n\tbackground: var(--color-primary-element-light);\n\tborder: 0;\n\tborder-radius: 17px;\n\tbox-sizing: border-box;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tcursor: pointer;\n\tdisplay: inline-flex;\n\tflex: 0 0 150px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\theight: 34px;\n\tjustify-content: center;\n\tpadding: 0 14px;\n\ttext-decoration: none;\n}\n\n.cn-record-list__action:hover,\n.cn-record-list__action:focus-visible {\n\tbackground: var(--color-primary-element-light-hover, var(--color-primary-element-light));\n}\n\n.cn-record-list__chevron {\n\tcolor: var(--color-text-maxcontrast);\n\tflex: none;\n}\n\n/* tiles (`tiles: true`, DqZaaktypeOverzicht \"Statussen\"): rows as framed\n tiles in a grid, the title at 14px regular. The selectors outrank the board\n look's list row rules. */\n.cn-record-list.cn-record-list--tiles .cn-record-list__list {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n\tgap: 8px;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item {\n\tborder-top: 0;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item .cn-record-list__row {\n\tbox-sizing: border-box;\n\theight: 100%;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 8px 10px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-radius: 8px;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item .cn-record-list__title {\n\tfont-size: 14px;\n\tfont-weight: 400;\n}\n\n/* cards (board ShBank): a grid of framed cards, 240px at the least. */\n.cn-record-list--cards .cn-record-list__list {\n\talign-items: start;\n\tdisplay: grid;\n\tgap: 16px;\n\tgrid-template-columns: repeat(auto-fit, minmax(240px, 1fr));\n}\n\n.cn-record-list__card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 12px;\n\tbox-sizing: border-box;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tpadding: 16px 18px;\n\ttext-decoration: none;\n}\n\n.cn-record-list__card--link:hover,\n.cn-record-list__card--link:focus-visible {\n\tborder-color: var(--color-border-dark, var(--color-border));\n}\n\n.cn-record-list__card--link:hover .cn-record-list__title,\n.cn-record-list__card--link:focus-visible .cn-record-list__title {\n\ttext-decoration: underline;\n}\n\n.cn-record-list__card-head {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: 8px;\n\tjustify-content: space-between;\n}\n\n.cn-record-list__card-title {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-record-list__card-icon {\n\tcolor: var(--color-primary-element);\n\tflex: none;\n}\n\n.cn-record-list__card-pills {\n\tdisplay: flex;\n\tflex: none;\n\tgap: 6px;\n}\n\n.cn-record-list__card-value {\n\tfont-size: 24px;\n\tfont-weight: 700;\n}\n\n/* feed */\n.cn-record-list--feed .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__feed-row {\n\talign-items: flex-start;\n\tdisplay: flex;\n\tgap: 14px;\n\tpadding: 12px 0;\n}\n\n.cn-record-list__feed-icon {\n\talign-items: center;\n\tbackground: var(--color-primary-element-light);\n\tborder-radius: 50%;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tdisplay: flex;\n\tflex: none;\n\theight: 36px;\n\tjustify-content: center;\n\twidth: 36px;\n}\n\n.cn-record-list__text {\n\tfont-size: 15px;\n}\n\n.cn-record-list--feed .cn-record-list__main {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n/* inline */\n.cn-record-list__inline-row {\n\tpadding: 4px 0;\n}\n\n.cn-record-list__label {\n\tmargin-inline-end: 4px;\n}\n\n.cn-record-list__inline-title {\n\tcolor: var(--color-main-text);\n}\n\na.cn-record-list__inline-title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n</style>\n\n<style>\n/* In a narrow side column a row stacks: title, meta, then pill and date. */\n.cn-detail-page__side .cn-record-list__row {\n\talign-items: flex-start;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-detail-page__side .cn-record-list__row .cn-record-list__title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n\n.cn-detail-page__side .cn-record-list__chevron {\n\tdisplay: none;\n}\n\n/* A row is a touch target of at least 44px on a phone. */\n@media (max-width: 640px) {\n\t.cn-record-list__row {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_toDisplayString","_createVNode","_Fragment","_renderList","_createElementVNode","_createTextVNode","_normalizeStyle","_createBlock","_openBlock","_resolveDynamicComponent","_mergeProps","_toHandlers"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnRecordListWidget.vue3.js","sources":["../../../../src/components/CnRecordListWidget/CnRecordListWidget.vue?vue&type=template&id=544b79cd&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div\n\t\tclass=\"cn-record-list\"\n\t\t:class=\"[`cn-record-list--${presentation}`, { 'cn-record-list--compact': content.density === 'compact', 'cn-record-list--stacked': content.density === 'stacked', 'cn-record-list--tiles': presentation === 'rows' && content.tiles === true, 'cn-record-list--rule-above': content.ruleAbove === true, 'cn-record-list--data-table': presentation === 'table' && content.tableLook === 'data' }]\"\n\t\tdata-testid=\"cn-record-list\">\n\t\t<p v-if=\"intro && !absent\" class=\"cn-record-list__intro\" data-testid=\"cn-record-list-intro\">\n\t\t\t{{ intro }}\n\t\t</p>\n\t\t<p v-if=\"absent\" class=\"cn-record-list__empty\" data-testid=\"cn-record-list-absent\">\n\t\t\t{{ absentLabel }}\n\t\t</p>\n\t\t<p v-else-if=\"error\" class=\"cn-record-list__error\" data-testid=\"cn-record-list-error\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"loading && rows.length === 0\" class=\"cn-record-list__loading\">\n\t\t\t<NcLoadingIcon :size=\"20\" :name=\"loadingLabel\" />\n\t\t</div>\n\t\t<template v-else-if=\"rows.length === 0\">\n\t\t\t<p v-if=\"emptyLabel !== ''\" class=\"cn-record-list__empty\" data-testid=\"cn-record-list-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\t\t</template>\n\t\t<!-- notice: the rows as sentences in one toned box (\"2 waarschuwingen: ...\"). -->\n\t\t<div\n\t\t\tv-else-if=\"presentation === 'notice'\"\n\t\t\tclass=\"cn-record-list__notice\"\n\t\t\t:class=\"`cn-record-list__notice--${noticeVariant}`\"\n\t\t\trole=\"note\"\n\t\t\tdata-testid=\"cn-record-list-notice\">\n\t\t\t<CnIcon\n\t\t\t\t:name=\"noticeIcon\"\n\t\t\t\t:size=\"18\"\n\t\t\t\tclass=\"cn-record-list__notice-icon\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t\t<p class=\"cn-record-list__notice-text\">\n\t\t\t\t{{ noticeText }}\n\t\t\t</p>\n\t\t</div>\n\t\t<!-- table: one row per record under a header, one cell per `columns`\n\t\t entry; a cell past its `alertAbove` reads bold in the danger colour,\n\t\t a `tone` cell is a toned label, a `sortable` header sorts the rows. -->\n\t\t<table v-else-if=\"presentation === 'table'\" class=\"cn-record-list__table\" data-testid=\"cn-record-list-table\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th\n\t\t\t\t\t\tv-for=\"col in tableColumns\"\n\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t:aria-sort=\"col.sortable ? sortStateOf(col.key) : undefined\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__cell--end': col.align === 'end' }\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tv-if=\"col.sortable\"\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__sort\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-sort-${col.key}`\"\n\t\t\t\t\t\t\t@click=\"toggleTableSort(col.key)\">\n\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t\t<span class=\"cn-record-list__sort-mark\" aria-hidden=\"true\">{{ sortMarkOf(col.key) }}</span>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</th>\n\t\t\t\t\t<th v-if=\"rowActions.length > 0\" scope=\"col\" class=\"cn-record-list__cell--actions\">\n\t\t\t\t\t\t{{ rowActionsHeader }}\n\t\t\t\t\t</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t<tr v-for=\"item in tableRows\" :key=\"item.key\" data-testid=\"cn-record-list-item\">\n\t\t\t\t\t<td\n\t\t\t\t\t\tv-for=\"(cell, cellIndex) in item.cells\"\n\t\t\t\t\t\t:key=\"cell.key\"\n\t\t\t\t\t\t:style=\"cellIndex === 0 && item.depth > 0 ? `padding-inline-start: calc(${item.depth} * 16px)` : undefined\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__cell--end': cell.align === 'end', 'cn-record-list__cell--alert': cell.alert }\">\n\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\tv-if=\"cell.tone\"\n\t\t\t\t\t\t\t:label=\"cell.text\"\n\t\t\t\t\t\t\t:variant=\"cell.tone\"\n\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t<router-link v-else-if=\"cellIndex === 0 && item.to\" :to=\"item.to\" class=\"cn-record-list__cell-text\">\n\t\t\t\t\t\t\t{{ cell.text }}\n\t\t\t\t\t\t</router-link>\n\t\t\t\t\t\t<span v-else class=\"cn-record-list__cell-text\">{{ cell.text }}</span>\n\t\t\t\t\t\t<span v-if=\"cell.sub\" class=\"cn-record-list__cell-sub\">{{ cell.sub }}</span>\n\t\t\t\t\t</td>\n\t\t\t\t\t<td v-if=\"rowActions.length > 0\" class=\"cn-record-list__cell--actions\">\n\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\tv-if=\"item.rowActions.length > 0\"\n\t\t\t\t\t\t\t:aria-label=\"rowActionsLabel\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-row-actions\">\n\t\t\t\t\t\t\t<template v-for=\"entry in item.rowActions\" :key=\"`row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t\tv-if=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:href=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:target=\"entry.external ? '_blank' : undefined\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\"\n\t\t\t\t\t\t\t\t\t@click=\"runRowActionEntry(entry.action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n\t\t\t</tbody>\n\t\t</table>\n\t\t<!-- checklist: an optional bar of the done share, then the rows in\n\t\t columns, a done row ticked and an open one an empty circle\n\t\t (DqTenant Inrichten). -->\n\t\t<div\n\t\t\tv-else-if=\"presentation === 'checklist'\"\n\t\t\tclass=\"cn-record-list__checklist-wrap\">\n\t\t\t<div\n\t\t\t\tv-if=\"content.progress\"\n\t\t\t\tclass=\"cn-record-list__checklist-bar\"\n\t\t\t\trole=\"progressbar\"\n\t\t\t\t:aria-valuenow=\"checklistDone\"\n\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t:aria-valuemax=\"items.length\"\n\t\t\t\t:aria-label=\"headerNote || undefined\"\n\t\t\t\tdata-testid=\"cn-record-list-checklist-bar\">\n\t\t\t\t<span class=\"cn-record-list__checklist-fill\" :style=\"{ width: `${checklistPercent}%` }\" />\n\t\t\t</div>\n\t\t\t<ul\n\t\t\t\tclass=\"cn-record-list__checklist\"\n\t\t\t\t:style=\"{ '--cn-record-list-columns': checklistColumns }\"\n\t\t\t\tdata-testid=\"cn-record-list-checklist\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"item in items\"\n\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\tclass=\"cn-record-list__check\"\n\t\t\t\t\t:class=\"{ 'cn-record-list__check--done': isChecked(item.row) }\"\n\t\t\t\t\tdata-testid=\"cn-record-list-check\">\n\t\t\t\t\t<span class=\"cn-record-list__check-mark\" aria-hidden=\"true\">\n\t\t\t\t\t\t<Check v-if=\"isChecked(item.row)\" :size=\"14\" />\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-record-list__check-title\">{{ item.title }}</span>\n\t\t\t\t\t<span class=\"hidden-visually\">{{ isChecked(item.row) ? doneLabel : openLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\t\t<!-- notes: a field per row for what happened, recorded on the row's\n\t\t own notes endpoint (DqDagAfsluiten \"Nog open van vandaag\"). -->\n\t\t<CnRecordNoteRows\n\t\t\tv-else-if=\"presentation === 'notes' && noteAction\"\n\t\t\t:items=\"items\"\n\t\t\t:action=\"noteAction\"\n\t\t\t:recordAll=\"noteRecordAll\"\n\t\t\t:leaf=\"content.rowLeaf || null\" />\n\t\t<!-- `groupBy`: a heading per group, each group its own list, named by\n\t\t its heading. Without it this is one list, as before. -->\n\t\t<template v-for=\"group in itemGroups\" v-else :key=\"group.key\">\n\t\t\t<div\n\t\t\t\tv-if=\"group.label && footerGroup !== '' && group.value === footerGroup\"\n\t\t\t\tclass=\"cn-record-list__group-head\"\n\t\t\t\tdata-testid=\"cn-record-list-group-head\">\n\t\t\t\t<h3\n\t\t\t\t\t:id=\"group.headingId\"\n\t\t\t\t\tclass=\"cn-record-list__group-heading\"\n\t\t\t\t\tdata-testid=\"cn-record-list-group-heading\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h3>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ footerAction.label }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t\t<h3\n\t\t\t\tv-else-if=\"group.label\"\n\t\t\t\t:id=\"group.headingId\"\n\t\t\t\tclass=\"cn-record-list__group-heading\"\n\t\t\t\tdata-testid=\"cn-record-list-group-heading\">\n\t\t\t\t{{ group.label }}\n\t\t\t</h3>\n\t\t\t<ul\n\t\t\t\tv-if=\"group.items.length > 0\"\n\t\t\t\tclass=\"cn-record-list__list\"\n\t\t\t\t:class=\"{ 'cn-record-list__list--avatar-small': avatarSmall }\"\n\t\t\t\t:aria-labelledby=\"group.label ? group.headingId : null\"\n\t\t\t\t:data-testid=\"isGrouped ? 'cn-record-list-group' : null\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"item in group.items\"\n\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\tclass=\"cn-record-list__item\"\n\t\t\t\t\tdata-testid=\"cn-record-list-item\">\n\t\t\t\t\t<!-- rows with `rowAction`: the title is the link, and one action\n\t\t\t\t\t ends the row instead of the chevron (\"Beoordelen\"). -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-if=\"presentation === 'rows' && item.action\"\n\t\t\t\t\t\tclass=\"cn-record-list__row cn-record-list__row--action\">\n\t\t\t\t\t\t<span v-if=\"item.leading\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__leading\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-leading\">{{ item.leading }}</span>\n\t\t\t\t\t\t<span v-if=\"item.initials\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__avatar\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-avatar\">{{ item.initials }}</span>\n\t\t\t\t\t\t<span v-if=\"item.dot\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__dot\"\n\t\t\t\t\t\t\t:style=\"{ background: item.dot }\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-dot\" />\n\t\t\t\t\t\t<span class=\"cn-record-list__main\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\t\t\tv-if=\"item.title\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__title\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-record-list__title--link': item.tag !== 'div' }\"\n\t\t\t\t\t\t\t\tv-bind=\"item.attrs\">\n\t\t\t\t\t\t\t\t{{ item.title }}\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.flag\" class=\"cn-record-list__flag\" data-testid=\"cn-record-list-flag\">{{ item.flag }}</span>\n\t\t\t\t\t\t<span v-if=\"item.pill || item.badges.length > 0\" class=\"cn-record-list__pills\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"item.pill\"\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"item.due\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__due cn-record-list__due--column\"\n\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__trailing\">{{ item.trailing }}</span>\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"item.action.tag\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__action\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-record-list__action--outlined': rowActionOutlined }\"\n\t\t\t\t\t\t\tv-bind=\"item.action.attrs\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-action\"\n\t\t\t\t\t\t\tv-on=\"item.action.tag === 'button' ? { click: () => runRowAction(item.row) } : {}\">\n\t\t\t\t\t\t\t{{ item.action.label }}\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- rows: title, meta and text, then the pill, the date and a chevron. -->\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\tv-else-if=\"presentation === 'rows'\"\n\t\t\t\t\t\tclass=\"cn-record-list__row\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__row--link': item.tag !== 'div' }\"\n\t\t\t\t\t\tv-bind=\"item.attrs\">\n\t\t\t\t\t\t<span v-if=\"item.leading\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__leading\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-leading\">{{ item.leading }}</span>\n\t\t\t\t\t\t<span v-if=\"pillFirst && item.pill\" class=\"cn-record-list__pill-start\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.initials\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__avatar\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-avatar\">{{ item.initials }}</span>\n\t\t\t\t\t\t<span v-if=\"item.dot\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__dot\"\n\t\t\t\t\t\t\t:style=\"{ background: item.dot }\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-dot\" />\n\t\t\t\t\t\t<span class=\"cn-record-list__main\">\n\t\t\t\t\t\t\t<span v-if=\"item.title\" class=\"cn-record-list__title\">{{ item.title }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.text\" class=\"cn-record-list__meta\" data-testid=\"cn-record-list-text\">{{ item.text }}</span>\n\t\t\t\t\t\t\t<!-- `duePlacement: \"below\"`: the due text as a line under the title (DqDagAfsluiten \"Morgen eerst\"). -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"item.due && dueBelow\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__due cn-record-list__due--below\"\n\t\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.links.length > 0\" class=\"cn-record-list__meta\" data-testid=\"cn-record-list-links\">\n\t\t\t\t\t\t\t\t{{ linksLabel }}\n\t\t\t\t\t\t\t\t<template v-for=\"(link, linkIndex) in item.links\" :key=\"link.id\">\n\t\t\t\t\t\t\t\t\t<router-link v-if=\"link.to\" :to=\"link.to\">{{ link.label }}</router-link>\n\t\t\t\t\t\t\t\t\t<span v-else>{{ link.label }}</span><span v-if=\"linkIndex < item.links.length - 1\">, </span>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"(item.pill && !pillFirst) || item.badges.length > 0 || (item.due && !dueBelow) || item.trailing || item.flag\" class=\"cn-record-list__aside\">\n\t\t\t\t\t\t\t<span v-if=\"item.flag\" class=\"cn-record-list__flag\" data-testid=\"cn-record-list-flag\">{{ item.flag }}</span>\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"item.pill && !pillFirst\"\n\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"item.due && !dueBelow\"\n\t\t\t\t\t\t\t\tclass=\"cn-record-list__due\"\n\t\t\t\t\t\t\t\t:class=\"[`cn-record-list__due--${item.due.tone}`, { 'cn-record-list__due--soon': item.due.soon }]\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-due\">{{ item.due.text }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__trailing\">{{ item.trailing }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<ChevronRight\n\t\t\t\t\t\t\tv-if=\"item.tag !== 'div' && content.chevron !== false\"\n\t\t\t\t\t\t\tclass=\"cn-record-list__chevron\"\n\t\t\t\t\t\t\t:size=\"18\"\n\t\t\t\t\t\t\taria-hidden=\"true\" />\n\t\t\t\t\t\t<template v-if=\"item.tag === 'div'\">\n\t\t\t\t\t\t\t<template v-for=\"(action, actionIndex) in setFieldActions\">\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-if=\"setFieldDone(action, item.row)\"\n\t\t\t\t\t\t\t\t\t:key=\"`set-field-done-${actionIndex}`\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-record-list__set-field-done\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-set-field-done\">\n\t\t\t\t\t\t\t\t\t<Check :size=\"14\" aria-hidden=\"true\" />{{ action.doneLabel }}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:key=\"`set-field-${actionIndex}`\"\n\t\t\t\t\t\t\t\t\t:disabled=\"settingField\"\n\t\t\t\t\t\t\t\t\t:ariaLabel=\"fillRow(action.ariaLabel, item.row) || undefined\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-record-list-set-field\"\n\t\t\t\t\t\t\t\t\t@click=\"runSetField(action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\tv-if=\"item.tag === 'div' && item.rowActions.length > 0\"\n\t\t\t\t\t\t\t:aria-label=\"rowActionsLabel\"\n\t\t\t\t\t\t\tdata-testid=\"cn-record-list-row-actions\">\n\t\t\t\t\t\t\t<template v-for=\"entry in item.rowActions\" :key=\"`row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\t\t\tv-if=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:href=\"entry.href\"\n\t\t\t\t\t\t\t\t\t:target=\"entry.external ? '_blank' : undefined\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:closeAfterClick=\"true\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-row-action-${entry.index}`\"\n\t\t\t\t\t\t\t\t\t@click=\"runRowActionEntry(entry.action, item.row)\">\n\t\t\t\t\t\t\t\t\t{{ entry.action.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t</component>\n\n\t\t\t\t\t<!-- cards: a framed card per row, the icon and title with the pill\n\t\t\t\t\t beside them, the meta line, and `trailing` as the large figure. -->\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"item.tag\"\n\t\t\t\t\t\tv-else-if=\"presentation === 'cards'\"\n\t\t\t\t\t\tclass=\"cn-record-list__card\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__card--link': item.tag !== 'div' }\"\n\t\t\t\t\t\tv-bind=\"item.attrs\"\n\t\t\t\t\t\tdata-testid=\"cn-record-list-card\">\n\t\t\t\t\t\t<span class=\"cn-record-list__card-head\">\n\t\t\t\t\t\t\t<span class=\"cn-record-list__card-title\">\n\t\t\t\t\t\t\t\t<CnIcon\n\t\t\t\t\t\t\t\t\tv-if=\"cardIcons\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-record-list__card-icon\"\n\t\t\t\t\t\t\t\t\t:name=\"item.icon\"\n\t\t\t\t\t\t\t\t\t:size=\"18\" />\n\t\t\t\t\t\t\t\t<span v-if=\"item.title\" class=\"cn-record-list__title\">{{ item.title }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span v-if=\"item.pill || item.badges.length > 0\" class=\"cn-record-list__card-pills\">\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-if=\"item.pill\"\n\t\t\t\t\t\t\t\t\t:label=\"item.pill.label\"\n\t\t\t\t\t\t\t\t\t:variant=\"item.pill.variant\"\n\t\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\tv-for=\"badge in item.badges\"\n\t\t\t\t\t\t\t\t\t:key=\"badge.key\"\n\t\t\t\t\t\t\t\t\t:label=\"badge.label\"\n\t\t\t\t\t\t\t\t\t:variant=\"badge.variant\"\n\t\t\t\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-record-list-badge-${badge.kind}`\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t<span v-if=\"item.trailing\" class=\"cn-record-list__card-value\" data-testid=\"cn-record-list-card-value\">{{ item.trailing }}</span>\n\t\t\t\t\t</component>\n\n\t\t\t\t\t<!-- feed: a round icon, a meta line and the text. -->\n\t\t\t\t\t<div v-else-if=\"presentation === 'feed'\" class=\"cn-record-list__feed-row\">\n\t\t\t\t\t\t<span class=\"cn-record-list__feed-icon\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t<CnIcon :name=\"item.icon\" :size=\"18\" />\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__main\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-record-list__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t<span v-if=\"item.text\" class=\"cn-record-list__text\">{{ item.text }}</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- inline: a label and the title, the title a link. -->\n\t\t\t\t\t<div v-else class=\"cn-record-list__inline-row\">\n\t\t\t\t\t\t<span v-if=\"item.label\" class=\"cn-record-list__label\">{{ item.label }}</span>\n\t\t\t\t\t\t<component :is=\"item.tag\" class=\"cn-record-list__inline-title\" v-bind=\"item.attrs\">\n\t\t\t\t\t\t\t{{ item.title }}\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</div>\n\t\t\t\t\t<!-- `bar`: a thin track under the row, filled to the row's value\n\t\t\t\t\t against its own maximum or against the largest row. -->\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"presentation === 'rows' && item.bar\"\n\t\t\t\t\t\tclass=\"cn-record-list__bar\"\n\t\t\t\t\t\t:class=\"{ 'cn-record-list__bar--over': item.bar.over }\"\n\t\t\t\t\t\trole=\"meter\"\n\t\t\t\t\t\t:aria-label=\"item.title || null\"\n\t\t\t\t\t\t:aria-valuenow=\"item.bar.value\"\n\t\t\t\t\t\taria-valuemin=\"0\"\n\t\t\t\t\t\t:aria-valuemax=\"item.bar.max\"\n\t\t\t\t\t\tdata-testid=\"cn-record-list-bar\">\n\t\t\t\t\t\t<span class=\"cn-record-list__bar-fill\" :style=\"{ width: `${item.bar.share}%` }\" />\n\t\t\t\t\t</span>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</template>\n\t\t<p\n\t\t\tv-if=\"actionError\"\n\t\t\tclass=\"cn-record-list__error\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-record-list-action-error\">\n\t\t\t{{ actionError }}\n\t\t</p>\n\t\t<div\n\t\t\tv-if=\"footnoteTone && footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)\"\n\t\t\tclass=\"cn-record-list__notice cn-record-list__notice--footnote\"\n\t\t\t:class=\"`cn-record-list__notice--${footnoteTone}`\"\n\t\t\tdata-testid=\"cn-record-list-footnote\">\n\t\t\t<CnIcon\n\t\t\t\t:name=\"footnoteTone === 'info' ? 'InformationOutline' : 'AlertOutline'\"\n\t\t\t\t:size=\"16\"\n\t\t\t\tclass=\"cn-record-list__notice-icon\"\n\t\t\t\taria-hidden=\"true\" />\n\t\t\t<p class=\"cn-record-list__notice-text\">\n\t\t\t\t{{ footnote }}\n\t\t\t</p>\n\t\t</div>\n\t\t<p v-else-if=\"footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)\" class=\"cn-record-list__footnote\" data-testid=\"cn-record-list-footnote\">\n\t\t\t{{ footnote }}\n\t\t</p>\n\t\t<!-- `footerLink`: a text link under the rows (\"Naar Mijn werk\"). -->\n\t\t<router-link\n\t\t\tv-if=\"footerLink && footerLink.to\"\n\t\t\tclass=\"cn-record-list__footer-link\"\n\t\t\t:to=\"footerLink.to\"\n\t\t\tdata-testid=\"cn-record-list-footer-link\">\n\t\t\t{{ footerLink.label }}\n\t\t</router-link>\n\t\t<a\n\t\t\tv-else-if=\"footerLink\"\n\t\t\tclass=\"cn-record-list__footer-link\"\n\t\t\t:href=\"footerLink.href\"\n\t\t\tdata-testid=\"cn-record-list-footer-link\">{{ footerLink.label }}</a>\n\t\t<!-- `footerAction`: one action under the list, also under the empty\n\t\t text (\"Beroep registreren\"). With `disabledWhen` it greys out and\n\t\t says why (`disabledReason`: \"Kan zodra de beslissing is\n\t\t verzonden\"). -->\n\t\t<div\n\t\t\tv-if=\"footerGroupHead && rows.length === 0 && !error && !loading\"\n\t\t\tclass=\"cn-record-list__group-head\"\n\t\t\tdata-testid=\"cn-record-list-group-head\">\n\t\t\t<h3 class=\"cn-record-list__group-heading\" data-testid=\"cn-record-list-group-heading\">\n\t\t\t\t{{ footerGroupHead }}\n\t\t\t</h3>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t</template>\n\t\t\t\t{{ footerAction.label }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<p\n\t\t\tv-if=\"footerGroup !== '' && footerDisabled && footerAction && footerAction.reason && !error\"\n\t\t\t:id=\"footerReasonId\"\n\t\t\tclass=\"cn-record-list__footer-reason\"\n\t\t\tdata-testid=\"cn-record-list-footer-reason\">\n\t\t\t{{ footerAction.reason }}\n\t\t</p>\n\t\t<div\n\t\t\tv-if=\"footerAction && footerGroup === '' && !error\"\n\t\t\tclass=\"cn-record-list__footer\"\n\t\t\t:class=\"{ 'cn-record-list__footer--wide': footerAction.wide }\"\n\t\t\tdata-testid=\"cn-record-list-footer\">\n\t\t\t<p\n\t\t\t\tv-if=\"footerAction.note\"\n\t\t\t\tclass=\"cn-record-list__footer-note\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-note\">\n\t\t\t\t{{ footerAction.note }}\n\t\t\t</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:class=\"{ 'cn-record-list__action--tonal': footerTonal }\"\n\t\t\t\t:wide=\"footerAction.wide\"\n\t\t\t\t:disabled=\"footerDisabled\"\n\t\t\t\t:aria-describedby=\"footerDisabled && footerAction.reason ? footerReasonId : null\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-action\"\n\t\t\t\t@click=\"runFooterAction\">\n\t\t\t\t<template v-if=\"footerAction.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"footerAction.icon\" :size=\"16\" />\n\t\t\t\t</template>\n\t\t\t\t{{ footerAction.label }}\n\t\t\t</NcButton>\n\t\t\t<span\n\t\t\t\tv-if=\"footerDisabled && footerAction.reason\"\n\t\t\t\t:id=\"footerReasonId\"\n\t\t\t\tclass=\"cn-record-list__footer-reason\"\n\t\t\t\tdata-testid=\"cn-record-list-footer-reason\">{{ footerAction.reason }}</span>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport { inject, ref } from 'vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport CnIcon from '../CnIcon/CnIcon.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport CnRecordNoteRows from './CnRecordNoteRows.vue'\nimport { interpolateUrlTokens, useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { actionLink, dispatchAction, interpolateActionTarget } from '../../utils/actionsDispatcher.js'\nimport { isAppInstalled } from '../../utils/appInstalled.js'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { ageInDays } from '../../utils/boardDate.js'\nimport { resolveDue } from '../../utils/dueText.js'\nimport { fillCountLabel } from '../../utils/fillCountLabel.js'\nimport { fillTemplate, firstFilled } from '../../utils/fillTemplate.js'\nimport { unwrapAppConfig } from '../../utils/formatMetric.js'\nimport { initialsOf } from '../../utils/initials.js'\nimport { lensUnavailableText, readLensReports } from '../../utils/lensAvailability.js'\nimport { isObjectRowsSpec, objectRowsOf } from '../../utils/objectRows.js'\nimport { pageFilter, pageSort } from '../../utils/pageControls.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { dropOptionalUnresolved, hasUnresolvedTokens, resolveDeepTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { fetchRowAggregate, isRowAggregate } from '../../utils/rowAggregate.js'\nimport { evaluateVisibleWhen, evaluateVisibleWhenLocal } from '../../utils/visibleWhen.js'\n\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/** Gives each list's footer reason its own element id. */\nlet footerSeq = 0\nconst PRESENTATIONS = ['rows', 'feed', 'inline', 'cards', 'notice', 'table', 'notes', 'checklist']\n\n/**\n * Compare two table cell texts: as numbers when both read as one, else as text.\n *\n * @param {string} a One cell text.\n * @param {string} b The other.\n * @return {number} Negative, zero or positive.\n */\nfunction compareCells(a, b) {\n\tconst x = Number(a)\n\tconst y = Number(b)\n\tif (a !== '' && b !== '' && Number.isFinite(x) && Number.isFinite(y)) {\n\t\treturn x - y\n\t}\n\treturn String(a).localeCompare(String(b))\n}\n\n/** The tones a `notice` list takes. */\nconst NOTICE_VARIANTS = ['info', 'warning', 'error']\n\n/**\n * A row that is a plain string or number (an endpoint answering `[\"...\", \"...\"]`)\n * read as `{ value }`, so the templates reach it as `{value}` and a list\n * without a `title` shows the value itself. An object row is returned as is.\n *\n * @param {(object|string|number)} row The row.\n * @return {(object|string|number)} The row, or `{ value }` for a string or number.\n */\nfunction scalarRow(row) {\n\treturn typeof row === 'string' || typeof row === 'number' ? { value: String(row) } : row\n}\n\n/**\n * Unwrap a value that may be a ref.\n *\n * @param {unknown} value The value.\n * @return {unknown} The plain value.\n */\nfunction unwrap(value) {\n\treturn value && typeof value === 'object' && 'value' in value ? value.value : value\n}\n\n/**\n * CnRecordListWidget — the objects of another schema that point at this\n * record, drawn as the boards draw them (screens-relation-pages).\n *\n * A person page lists its open cases (\"Verlichting fietspad Lindelaan,\n * 2026-0082 · Woo-verzoek, In behandeling, Termijn 1 nov\"), its latest contact\n * moments (an icon by channel, a meta line, the summary) and its relations\n * (\"Secretaris van Buurtvereniging Oost\"). Each is a list of another schema's\n * objects filtered on a reference to this record. The source keys are those of\n * `object-list` (`register`, `schema`, `filter` with the `@objectId` /\n * `@object.<field>` / `@workspace.<key>` tokens, `sort`, `limit`, `extend`,\n * `rowRoute`, `pageControls`), or `endpointSource` (an app endpoint whose\n * payload, after `responsePath`, is the array of rows, as on the object table), or `objectRows`\n * (`{ path, where?, valuePath? }`: rows the page record holds, such as one answer of a case); `avatar` puts a circle with the initials of a name\n * template before the title (`{ text, size: 32 }` draws the 32px circle 12px from the title, as DqZaakBesluiten); what differs is the drawing: `presentation` is `rows`, `feed`\n * or `inline`, and each line is a template (`\"{identifier} · {caseTypeName}\"`,\n * `\"Termijn {deadline|date}\"`). `cards` draws a framed card per row in a\n * grid, with `trailing` as the large figure (board ShBank's accounts).\n *\n * A content-only catalog type: on a card surface the detail host or the\n * dashboard page draws the titled card. The widget emits `header` with `{ link, note }` (the\n * `headerLink` and `headerNote` with `{total}` filled in) for that card's\n * header.\n */\nexport default {\n\tname: 'CnRecordListWidget',\n\n\tcomponents: { Check, ChevronRight, CnIcon, CnRecordNoteRows, CnStatusBadge, NcActionButton, NcActionLink, NcActions, NcButton, NcLoadingIcon },\n\n\tinject: {\n\t\t/** Detail-page object context (`{ objectId, object, register, schema }`). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Page workspace bag, for `@workspace.<key>` tokens. */\n\t\tcnWorkspaceContext: { default: null },\n\t\t/** The host app's translate function. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's app config map; its `currency` is the reporting currency of a money token. */\n\t\tcnAppConfig: { default: () => ({}) },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `rowAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The list config: `{ register, schema, filter?, sort?, limit?, offset?, extend?,\n\t\t * presentation?, variant?, lead?, leading?, title?, meta?, text?, label?, pill?, trailing?, icon?, aggregates?,\n\t\t * rowRoute?, rowIdField?, headerLink?, headerNote?, emptyText?, errorText?,\n\t\t * valueLabels?, endpointSource?, bar? }`. `bar` (`{ valueField, maxField?,\n\t\t * overVariant? }`) draws a thin track under each row: filled to\n\t\t * `valueField` against `maxField` (drawn in the error colour past it\n\t\t * with `overVariant: \"error\"`), or without `maxField` against the\n\t\t * largest row. `endpointSource` (`{ url, method?,\n\t\t * params?, responsePath? }`) reads the rows from an app endpoint instead\n\t\t * of `register` / `schema`. `objectRows` (`{ path, where?, valuePath? }`)\n\t\t * lists rows the page record holds, with no request. `valueLabels` maps a field's stored values to the labels\n\t\t * the templates show. `headerNote` and `headerLink.label` fill `{total}`\n\t\t * and `{count:<field>=<value>}`, the loaded rows with that value.\n\t\t * A row that is a plain string or number (an endpoint\n\t\t * answering `[\"…\", \"…\"]`) is read as `{ value }`: templates reach it as\n\t\t * `{value}`, and without `title` a row shows the value itself.\n\t\t * `presentation: \"notice\"` draws the rows as sentences in one box toned by\n\t\t * `variant` (`info`, `warning` or `error`), after an optional `lead`\n\t\t * (`{total}` filled in).\n\t\t * `dot` (a field, or `{ field, colorMap? }`) draws a colour dot before\n\t\t * the title; `flags` (`[{ field, label, value? }]`) draws the labels\n\t\t * of the flags a row has (\"Start\", \"End\") at its end.\n\t\t * `tiles: true` (rows only) draws each row as a framed tile in a grid\n\t\t * of 260px at the least.\n\t\t * `footerLink` (the shape of `headerLink`) ends the card with a text\n\t\t * link under the rows.\n\t\t * `footerAction` (`{ label, icon?, type, ..., disabledWhen?,\n\t\t * disabledReason? }`) ends the card with one action, also under the\n\t\t * empty text; while the visibleWhen condition `disabledWhen` holds the\n\t\t * button is disabled and `disabledReason` shows under it. `note` is a\n\t\t * line above it and `wide: true` stretches it across the card. A list\n\t\t * of such actions draws the first whose `visibleWhen` (a local\n\t\t * condition over the page's record) holds (DqZaaktype Versies:\n\t\t * \"Publiceren\" on a draft, \"Nieuwe versie maken\" otherwise).\n\t\t * `pill.cases` (`[{ when, label, variant? }]`) labels a row by the\n\t\t * first case whose `when` holds on it, else by the pill's own `label`\n\t\t * and `variant` (Concept, Vastgezet, Actief).\n\t\t * `footnoteVariant` (`info`, `warning` or `error`) draws the footnote\n\t\t * as a toned notice box with its icon (DqZaaktype opt-out note).\n\t\t * `tableLook: \"data\"` marks a `table` as a data table, which the board\n\t\t * look draws as its card table (header band, 40px rows, hairlines)\n\t\t * instead of the compact grid (DqZaaktype \"Berichten aan de aanvrager\").\n\t\t * `groupBy` (a field path) draws the rows in groups under a heading\n\t\t * per value, headed by the field's `valueLabels` entry; `groupOrder`\n\t\t * (values) orders the groups and `groupEmptyLabel` heads the rows\n\t\t * without a value.\n\t\t * `density: \"compact\"` draws the rows 10px above and below, at least\n\t\t * 56px tall, with the title at 500 (DqProcesanalyse).\n\t\t * `density: \"stacked\"` stands the rows 10px apart with no rule and no\n\t\t * row padding (DqDagAfsluiten \"Morgen eerst\").\n\t\t * In `rows`, `text` is a line under the meta line (\"12 dagen stil\"),\n\t\t * and `chevron: false` leaves the chevron off a linked row\n\t\t * (DqDashboard).\n\t\t * `presentation: \"checklist\"` draws the rows in `columns` (default 3),\n\t\t * a row for which `done` (a condition over the row) holds ticked, and\n\t\t * `progress: true` adds a bar of the done share (DqTenant Inrichten);\n\t\t * `headerNote` can say \"{count:status=completed} of {total} steps done\".\n\t\t * `aggregates` (`{ key: { register, schema, op: \"count\" | \"max\",\n\t\t * field?, where, text? } }`, `@self.<path>` in `where` read off the\n\t\t * row) asks a figure over each row's related objects, as a table's\n\t\t * `aggregate` column does, and offers it to the row's templates as\n\t\t * `{key}`; `text` (`{ zero?, one?, other }` with `{count}`) offers a\n\t\t * count as words (DqZaaktype Versies \"31 lopende zaken\", \"geen\n\t\t * lopende zaken\").\n\t\t * In `rows`, `ruleAbove: true` rules above the first row too, and\n\t\t * `pillAt: \"start\"` draws the pill before the title (DqZaakDocumenten\n\t\t * \"Weigeringsgronden tot nu toe\").\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current record, for `@object.<field>` tokens. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tsetup(props) {\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst workspaceRaw = inject('cnWorkspaceContext', null)\n\t\tconst appConfigRaw = inject('cnAppConfig', ref({}))\n\t\tconst { data, loading, error, refusal, refetch } = useEndpointSource(\n\t\t\t() => {\n\t\t\t\tconst app = props.content?.requiresApp\n\t\t\t\treturn typeof app === 'string' && app !== '' && !isAppInstalled(app) ? null : (props.content?.endpointSource || null)\n\t\t\t},\n\t\t\t{\n\t\t\t\tctx: () => {\n\t\t\t\t\tconst injected = unwrap(objectCtxRaw) || {}\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...injected,\n\t\t\t\t\t\tobjectId: props.objectId ?? injected.objectId ?? props.objectData?.id ?? null,\n\t\t\t\t\t\tobject: props.objectData || injected.object || null,\n\t\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\t\tconfig: unwrapAppConfig(appConfigRaw) || {},\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\t// A footnote that reads another part of the same answer shares its\n\t\t// request through the endpoint cache.\n\t\tconst footnoteSource = useEndpointSource(\n\t\t\t() => {\n\t\t\t\tconst note = props.content?.footnote\n\t\t\t\tconst source = props.content?.endpointSource\n\t\t\t\tif (!note || typeof note !== 'object' || typeof note.path !== 'string' || !source || typeof source !== 'object') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\treturn { ...source, responsePath: note.path }\n\t\t\t},\n\t\t\t{\n\t\t\t\tctx: () => {\n\t\t\t\t\tconst injected = unwrap(objectCtxRaw) || {}\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...injected,\n\t\t\t\t\t\tobjectId: props.objectId ?? injected.objectId ?? props.objectData?.id ?? null,\n\t\t\t\t\t\tobject: props.objectData || injected.object || null,\n\t\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\t\tconfig: unwrapAppConfig(appConfigRaw) || {},\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t},\n\t\t)\n\t\treturn { epData: data, epLoading: loading, epError: error, epRefusal: refusal, epRefetch: refetch, footnoteValue: footnoteSource.data, footnoteRefetch: footnoteSource.refetch }\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The reader's sort of a `table`: the column key and `ascending` or `descending`. */\n\t\t\ttableSort: { key: '', dir: '' },\n\t\t\trows: [],\n\t\t\t/** The `aggregates` figures per row id: `{ [rowId]: { [key]: value } }`. */\n\t\t\taggregateValues: {},\n\t\t\ttotal: 0,\n\t\t\tloading: false,\n\t\t\terror: false,\n\t\t\t/** Personal-lens reports (`@self.lenses`) of the latest response. */\n\t\t\tlenses: {},\n\t\t\t/** Whether `footerAction.disabledWhen` holds. */\n\t\t\tfooterDisabled: false,\n\t\t\tfooterReasonId: `cn-record-list-footer-reason-${++footerSeq}`,\n\t\t\tgroupIdBase: `cn-record-list-group-${footerSeq}`,\n\t\t\t/** The first `emptyTexts` entry whose condition holds, translated; '' for none. */\n\t\t\tconditionalEmptyText: '',\n\t\t\t/** The refusal of the last row action, as the server said it. */\n\t\t\tactionError: '',\n\t\t\tsettingField: false,\n\t\t\t/** Labels of the records a `links` line names, by id. */\n\t\t\tlinkLabels: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the avatar is the 32px circle (`avatar.size: 32`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-avatar-size/specs/record-list-avatar/spec.md#requirement-a-record-list-avatar-can-be-the-small-circle\n\t\t */\n\t\tavatarSmall() {\n\t\t\tconst avatar = this.content?.avatar\n\t\t\treturn Boolean(avatar && typeof avatar === 'object' && Number(avatar.size) === 32)\n\t\t},\n\n\t\t/** @return {boolean} Whether a row's pill comes before its title (`pillAt: \"start\"`). */\n\t\tpillFirst() {\n\t\t\treturn this.content?.pillAt === 'start'\n\t\t},\n\n\t\t/**\n\t\t * The action under the list (`footerAction`: `{ label, icon?, type,\n\t\t * ..., disabledWhen?, disabledReason? }`), labels through the host\n\t\t * translate, or null without a label.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {{label: string, icon: string, reason: string, action: object}|null}\n\t\t */\n\t\tfooterAction() {\n\t\t\tconst action = this.footerActionConfig\n\t\t\tif (!action || typeof action.label !== 'string' || action.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(action.label),\n\t\t\t\ticon: typeof action.icon === 'string' ? action.icon : '',\n\t\t\t\treason: typeof action.disabledReason === 'string' && action.disabledReason !== '' ? this.translate(action.disabledReason) : '',\n\t\t\t\tnote: typeof action.note === 'string' && action.note !== '' ? this.translate(action.note) : '',\n\t\t\t\twide: action.wide === true,\n\t\t\t\taction,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The `footerAction` entry in force. A list of entries draws the first\n\t\t * whose `visibleWhen` (a local condition over the page's record) holds;\n\t\t * an entry without one always holds.\n\t\t *\n\t\t * @spec openspec/changes/record-list-pill-cases-footer-choice/specs/record-list/spec.md#requirement-a-record-lists-footer-action-can-depend-on-the-record\n\t\t * @return {object|null} The entry, or null when none holds.\n\t\t */\n\t\tfooterActionConfig() {\n\t\t\tconst declared = this.content?.footerAction\n\t\t\tconst entries = Array.isArray(declared) ? declared : [declared]\n\t\t\tconst record = this.tokenCtx.object || {}\n\t\t\treturn entries.find((entry) => entry && typeof entry === 'object' && (!entry.visibleWhen || evaluateVisibleWhenLocal(entry.visibleWhen, record))) || null\n\t\t},\n\n\t\t/**\n\t\t * The group value `footerAction.group` puts the action in, with\n\t\t * `groupBy`; '' when the action stands under the list.\n\t\t *\n\t\t * @spec openspec/changes/record-list-group-action/specs/record-list/spec.md#requirement-a-record-lists-action-can-end-a-group-heading-as-a-tonal-pill\n\t\t * @return {string}\n\t\t */\n\t\tfooterGroup() {\n\t\t\tconst group = this.footerActionConfig?.group\n\t\t\tif (!this.footerAction || !this.isGrouped || group === null || group === undefined || group === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn String(group)\n\t\t},\n\n\t\t/**\n\t\t * The heading of the action's group, for the list without rows.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tfooterGroupHead() {\n\t\t\tif (this.footerGroup === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst c = this.content\n\t\t\tconst labels = c.valueLabels && typeof c.valueLabels[c.groupBy] === 'object' ? c.valueLabels[c.groupBy] : {}\n\t\t\tconst named = labels[this.footerGroup] || this.footerGroup\n\t\t\treturn this.translate(named)\n\t\t},\n\n\t\t/** @return {boolean} Whether the action is drawn as a tonal pill (`footerAction.variant: \"tonal\"`). */\n\t\tfooterTonal() {\n\t\t\treturn this.footerActionConfig?.variant === 'tonal'\n\t\t},\n\n\t\t/**\n\t\t * What `footerAction.disabledWhen` depends on, so it is evaluated again\n\t\t * when the condition, the record or the workspace changes.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tfooterDisabledKey() {\n\t\t\tconst cond = this.footerActionConfig?.disabledWhen\n\t\t\tif (!cond) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn JSON.stringify({ cond, object: this.tokenCtx.object, workspace: this.tokenCtx.workspace, total: this.total })\n\t\t},\n\n\t\t/** @return {string} `rows`, `feed`, `inline` or `cards`. */\n\t\t/**\n\t\t * The tone of a `notice` list (`content.variant`): info, warning or error.\n\t\t *\n\t\t * @return {string} The variant, `info` when unset or unknown.\n\t\t * @spec openspec/changes/record-list-string-rows/specs/record-list-string-rows/spec.md#requirement-a-record-list-draws-rows-that-are-plain-strings\n\t\t */\n\t\tnoticeVariant() {\n\t\t\tconst value = this.content?.variant\n\t\t\treturn NOTICE_VARIANTS.includes(value) ? value : 'info'\n\t\t},\n\n\t\t/** @return {string} The icon of the notice tone. */\n\t\tnoticeIcon() {\n\t\t\treturn this.noticeVariant === 'info' ? 'InformationOutline' : 'AlertOutline'\n\t\t},\n\n\t\t/**\n\t\t * The rows of a `notice` list as one paragraph: each row's title, as\n\t\t * sentences, after the optional `lead` with `{total}` filled in.\n\t\t *\n\t\t * @return {string} The text.\n\t\t * @spec openspec/changes/record-list-string-rows/specs/record-list-string-rows/spec.md#requirement-a-record-list-draws-rows-that-are-plain-strings\n\t\t */\n\t\tnoticeText() {\n\t\t\tconst parts = this.items.map((item) => item.title).filter((text) => text !== '')\n\t\t\tconst lead = typeof this.content?.lead === 'string' && this.content.lead !== '' ? this.withTotal(this.content.lead) : ''\n\t\t\treturn [lead, ...parts].filter(Boolean).join(' ')\n\t\t},\n\n\t\tpresentation() {\n\t\t\tconst value = this.content?.presentation\n\t\t\treturn PRESENTATIONS.includes(value) ? value : 'rows'\n\t\t},\n\n\t\t/**\n\t\t * Whether a `cards` card leads its title with an icon: only when the\n\t\t * list declares `icon`, so a card without one has no placeholder.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-cards/specs/record-list-cards/spec.md#requirement-a-record-list-can-draw-its-rows-as-cards\n\t\t */\n\t\tcardIcons() {\n\t\t\tconst icon = this.content?.icon\n\t\t\treturn (typeof icon === 'string' && icon !== '') || (Boolean(icon) && typeof icon === 'object')\n\t\t},\n\n\t\t/** @return {object} The token context: record, id and workspace. */\n\t\ttokenCtx() {\n\t\t\tconst injected = unwrap(this.cnObjectContext) || {}\n\t\t\treturn {\n\t\t\t\t...injected,\n\t\t\t\tobjectId: this.objectId ?? injected.objectId ?? this.objectData?.id ?? null,\n\t\t\t\tobject: this.objectData || injected.object || null,\n\t\t\t\tworkspace: unwrap(this.cnWorkspaceContext) || {},\n\t\t\t}\n\t\t},\n\n\t\t/** @return {object} The filter with its tokens resolved. */\n\t\tresolvedFilter() {\n\t\t\tconst filter = pageFilter(this.content?.pageControls, this.tokenCtx.workspace, this.content?.filter)\n\t\t\treturn dropOptionalUnresolved(resolveFilterTokens(filter, this.tokenCtx))\n\t\t},\n\n\t\t/** @return {boolean} A required token (the record id, say) has no value yet. */\n\t\twaiting() {\n\t\t\treturn hasUnresolvedTokens(this.resolvedFilter)\n\t\t},\n\n\t\t/** @return {object|null} The sort: the page's sort control when the widget listens to one, else its own. */\n\t\teffectiveSort() {\n\t\t\treturn pageSort(this.content?.pageControls, this.tokenCtx.workspace, this.content?.sort)\n\t\t},\n\n\t\t/**\n\t\t * What a template may read beside the row: the app config, whose\n\t\t * `currency` is the reporting currency of a `{path|currency}` token.\n\t\t *\n\t\t * @return {{config: object}} The template context.\n\t\t * @spec openspec/changes/screens-currency-format/specs/currency-format/spec.md#requirement-a-money-value-reads-in-its-currency\n\t\t */\n\t\ttemplateContext() {\n\t\t\treturn { config: unwrapAppConfig(this.cnAppConfig) }\n\t\t},\n\n\t\t/**\n\t\t * Whether the rows come from `endpointSource` rather than OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint\n\t\t */\n\t\tendpointActive() {\n\t\t\tconst source = this.content?.endpointSource\n\t\t\treturn Boolean(source && typeof source === 'object' && source.url)\n\t\t},\n\n\t\t/**\n\t\t * Whether the rows come from the page's own record (`objectRows`).\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-object-rows/specs/record-list/spec.md#requirement-a-record-list-can-list-rows-the-page-record-holds\n\t\t */\n\t\tobjectRowsActive() {\n\t\t\treturn isObjectRowsSpec(this.content?.objectRows)\n\t\t},\n\n\t\t/**\n\t\t * The rows `objectRows` names on the page record (see utils/objectRows.js).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tobjectRowsList() {\n\t\t\treturn this.objectRowsActive ? objectRowsOf(this.objectData, this.content.objectRows) : []\n\t\t},\n\n\t\t/** @return {string} The page record's rows, to copy into the list when they change. */\n\t\tobjectRowsKey() {\n\t\t\treturn this.objectRowsActive ? JSON.stringify(this.objectRowsList) : ''\n\t\t},\n\n\t\t/** @return {string} The endpoint read's state, to copy into the list when it changes. */\n\t\tendpointKey() {\n\t\t\treturn this.endpointActive ? JSON.stringify([this.epData, this.epLoading, this.epError]) : ''\n\t\t},\n\n\t\t/** @return {number} The fetch cap. */\n\t\tlimit() {\n\t\t\tconst value = Number(this.content?.limit)\n\t\t\treturn Number.isFinite(value) && value > 0 ? Math.floor(value) : 5\n\t\t},\n\n\t\t/** @return {number} How many rows of the list to skip first (`content.offset`), 0 by default. */\n\t\toffset() {\n\t\t\tconst value = Number(this.content?.offset)\n\t\t\treturn Number.isFinite(value) && value > 0 ? Math.floor(value) : 0\n\t\t},\n\n\t\t/** @return {string} What a fetch depends on; a change fetches again. */\n\t\trequestKey() {\n\t\t\tconst c = this.content || {}\n\t\t\treturn JSON.stringify([c.register, c.schema, this.resolvedFilter, this.effectiveSort, this.limit, this.offset, c.extend, this.waiting])\n\t\t},\n\n\t\t/** @return {Array<object>} The rows ready to draw. */\n\t\titems() {\n\t\t\tconst c = this.content || {}\n\t\t\tconst barScale = this.barScale\n\t\t\treturn this.rows.slice(0, this.limit).map((raw, index) => {\n\t\t\t\tconst row = this.withAggregates(scalarRow(raw))\n\t\t\t\tconst link = this.rowLink(row)\n\t\t\t\treturn {\n\t\t\t\t\tkey: (row && (row.id || row['@self']?.id)) || `row-${index}`,\n\t\t\t\t\trow,\n\t\t\t\t\taction: this.rowActionOf(row),\n\t\t\t\t\ttag: link ? 'router-link' : 'div',\n\t\t\t\t\tattrs: link ? { to: link } : {},\n\t\t\t\t\tinitials: this.initialsFor(row),\n\t\t\t\t\ttitle: this.fill(c.title || (row !== raw ? '{value}' : ''), row),\n\t\t\t\t\tmeta: this.metaOf(row),\n\t\t\t\t\ttext: this.fill(c.text, row),\n\t\t\t\t\tlabel: this.fill(c.label, row),\n\t\t\t\t\ttrailing: c.trailing ? firstFilled(c.trailing, row, this.translate, new Date(), this.templateContext) : '',\n\t\t\t\t\tleading: c.leading ? firstFilled(c.leading, row, this.translate, new Date(), this.templateContext) : '',\n\t\t\t\t\tpill: this.pillOf(row),\n\t\t\t\t\tbadges: this.badgesOf(row),\n\t\t\t\t\tdue: this.dueOf(row),\n\t\t\t\t\ticon: this.iconOf(row),\n\t\t\t\t\tbar: this.barOf(row, barScale),\n\t\t\t\t\tdot: this.dotOf(row),\n\t\t\t\t\tflag: this.flagOf(row),\n\t\t\t\t\tlinks: this.linksOf(row),\n\t\t\t\t\trowActions: this.rowActionsOf(row),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether `content.groupBy` names a field to group the rows by. */\n\t\tisGrouped() {\n\t\t\tconst field = this.content?.groupBy\n\t\t\treturn typeof field === 'string' && field !== ''\n\t\t},\n\n\t\t/**\n\t\t * The rows to draw, in groups. With `groupBy` (a field path) one group\n\t\t * per value: in `groupOrder` first, then in the order the rows bring\n\t\t * them, and the rows without a value last. A heading is the value's\n\t\t * `valueLabels` entry for that field, else the value, through the host\n\t\t * translate; the group without a value is headed by `groupEmptyLabel`,\n\t\t * or not at all. Without `groupBy` all rows are one unheaded group.\n\t\t *\n\t\t * @spec openspec/changes/record-list-group-headings/specs/record-list/spec.md#requirement-a-record-list-can-group-its-rows-under-headings\n\t\t * @return {Array<{key: string, value: string, label: string, headingId: string, items: Array<object>}>} The groups.\n\t\t */\n\t\titemGroups() {\n\t\t\tif (!this.isGrouped) {\n\t\t\t\treturn [{ key: 'all', label: '', headingId: '', items: this.items }]\n\t\t\t}\n\t\t\tconst c = this.content\n\t\t\tconst labels = c.valueLabels && typeof c.valueLabels[c.groupBy] === 'object' ? c.valueLabels[c.groupBy] : {}\n\t\t\tconst buckets = new Map()\n\t\t\tfor (const item of this.items) {\n\t\t\t\tconst raw = readPath(item.row, c.groupBy)\n\t\t\t\tconst value = raw === null || raw === undefined || typeof raw === 'object' ? '' : String(raw)\n\t\t\t\tif (!buckets.has(value)) {\n\t\t\t\t\tbuckets.set(value, [])\n\t\t\t\t}\n\t\t\t\tbuckets.get(value).push(item)\n\t\t\t}\n\t\t\tconst order = Array.isArray(c.groupOrder) ? c.groupOrder.map(String) : []\n\t\t\tconst values = [...buckets.keys()].filter((v) => v !== '')\n\t\t\tvalues.sort((a, b) => {\n\t\t\t\tconst ia = order.indexOf(a)\n\t\t\t\tconst ib = order.indexOf(b)\n\t\t\t\treturn (ia === -1 ? order.length : ia) - (ib === -1 ? order.length : ib)\n\t\t\t})\n\t\t\tif (buckets.has('')) {\n\t\t\t\tvalues.push('')\n\t\t\t}\n\t\t\tif (this.footerGroup !== '' && !buckets.has(this.footerGroup)) {\n\t\t\t\tbuckets.set(this.footerGroup, [])\n\t\t\t\tvalues.splice(buckets.has('') ? values.length - 1 : values.length, 0, this.footerGroup)\n\t\t\t}\n\t\t\treturn values.map((value, index) => {\n\t\t\t\tconst named = value === '' ? c.groupEmptyLabel : (labels[value] || value)\n\t\t\t\treturn {\n\t\t\t\t\tkey: `group-${value}`,\n\t\t\t\t\tvalue,\n\t\t\t\t\tlabel: typeof named === 'string' && named !== '' ? this.translate(named) : '',\n\t\t\t\t\theadingId: `${this.groupIdBase}-${index}`,\n\t\t\t\t\titems: buckets.get(value),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The `table` presentation's columns: `{ label, value, align?, alertAbove? }`,\n\t\t * `value` a template over the row, or a list of templates of which the\n\t\t * first that fills is shown (a row that holds only some fields).\n\t\t *\n\t\t * @return {Array<object>} The columns with a key and a translated label.\n\t\t * @spec openspec/changes/record-list-table/specs/record-list-table/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-small-table\n\t\t * @spec openspec/changes/record-list-table-column-candidates/specs/record-list-table/spec.md#requirement-a-table-column-can-name-candidate-templates\n\t\t */\n\t\ttableColumns() {\n\t\t\tconst columns = Array.isArray(this.content?.columns) ? this.content.columns : []\n\t\t\tconst isTemplate = (value) => typeof value === 'string' || (Array.isArray(value) && value.length > 0 && value.every((entry) => typeof entry === 'string'))\n\t\t\treturn columns\n\t\t\t\t.filter((col) => col && typeof col === 'object' && isTemplate(col.value))\n\t\t\t\t.map((col, index) => ({ ...col, key: `col-${index}`, label: typeof col.label === 'string' ? this.translate(col.label) : '' }))\n\t\t},\n\n\t\t/**\n\t\t * The `table` presentation's rows: one cell per column.\n\t\t *\n\t\t * @return {Array<object>} `{ key, cells: [{ key, text, align, alert }] }`.\n\t\t * @spec openspec/changes/record-list-table/specs/record-list-table/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-small-table\n\t\t */\n\t\ttableRows() {\n\t\t\tconst indentPath = this.content?.indentPath\n\t\t\tconst rows = this.items.map((item) => ({\n\t\t\t\tkey: item.key,\n\t\t\t\trow: item.row,\n\t\t\t\trowActions: this.rowActions.length > 0 ? this.rowActionsOf(item.row) : [],\n\t\t\t\tto: item.attrs.to || null,\n\t\t\t\tdepth: indentPath ? Math.max(0, Math.floor(Number(readPath(item.row, indentPath)) || 0)) : 0,\n\t\t\t\tcells: this.tableColumns.map((col) => {\n\t\t\t\t\tconst text = this.fill(col.value, item.row)\n\t\t\t\t\tconst limit = Number(col.alertAbove)\n\t\t\t\t\tconst value = Number(text)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: col.key,\n\t\t\t\t\t\ttext,\n\t\t\t\t\t\tsub: typeof col.sub === 'string' ? this.fill(col.sub, item.row) : '',\n\t\t\t\t\t\talign: col.align,\n\t\t\t\t\t\talert: col.alertAbove !== undefined && Number.isFinite(limit) && text !== '' && Number.isFinite(value) && value > limit,\n\t\t\t\t\t\t// An empty cell draws no coloured label.\n\t\t\t\t\t\ttone: text === '' ? '' : this.cellToneOf(col, item.row, text),\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t}))\n\t\t\tconst { key, dir } = this.tableSort\n\t\t\tconst index = this.tableColumns.findIndex((col) => col.key === key)\n\t\t\tif (index < 0 || !dir) {\n\t\t\t\treturn rows\n\t\t\t}\n\t\t\tconst sign = dir === 'descending' ? -1 : 1\n\t\t\treturn [...rows].sort((a, b) => sign * compareCells(a.cells[index].text, b.cells[index].text))\n\t\t},\n\n\t\t/**\n\t\t * Whether a row draws its due text under its title (`duePlacement:\n\t\t * \"below\"`) instead of at its end.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-due-below/specs/record-list-due-below/spec.md#requirement-a-rows-due-text-can-sit-under-its-title\n\t\t */\n\t\tdueBelow() {\n\t\t\treturn this.content?.duePlacement === 'below'\n\t\t},\n\n\t\t/** @return {string} The note under the list (`footnote`), translated. */\n\t\tfootnote() {\n\t\t\tconst note = this.content?.footnote\n\t\t\tif (note && typeof note === 'object') {\n\t\t\t\tconst value = this.footnoteValue\n\t\t\t\tif (value === null || value === undefined || value === '' || value === 0 || value === false || typeof note.text !== 'string') {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn this.translate(note.text).replace(/\\{value\\}/g, String(value))\n\t\t\t}\n\t\t\treturn typeof note === 'string' && note !== '' ? this.translate(note) : ''\n\t\t},\n\n\t\t/**\n\t\t * The tone the footnote is drawn in as a notice box\n\t\t * (`content.footnoteVariant`: info, warning or error); '' for a plain\n\t\t * muted line.\n\t\t *\n\t\t * @return {string} The tone, or ''.\n\t\t * @spec openspec/changes/record-list-data-table-and-notice-footnote/specs/record-list/spec.md#requirement-a-record-list-footnote-can-be-a-toned-notice\n\t\t */\n\t\tfootnoteTone() {\n\t\t\tconst tone = this.content?.footnoteVariant\n\t\t\treturn NOTICE_VARIANTS.includes(tone) ? tone : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the footnote reads the answer: it then shows with no rows too.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tfootnoteFromAnswer() {\n\t\t\tconst note = this.content?.footnote\n\t\t\treturn Boolean(note && typeof note === 'object')\n\t\t},\n\n\t\t/**\n\t\t * The largest `bar.valueField` over the rows shown, the scale of a\n\t\t * `bar` without `maxField`. 0 without a `bar`.\n\t\t *\n\t\t * @return {number} The largest value.\n\t\t * @spec openspec/changes/record-list-row-bar/specs/record-list-row-bar/spec.md#requirement-a-record-list-row-can-carry-a-bar\n\t\t */\n\t\tbarScale() {\n\t\t\tconst field = this.content?.bar?.valueField\n\t\t\tif (!field) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, ...this.rows.slice(0, this.limit).map((row) => Number(readPath(row, field)) || 0))\n\t\t},\n\n\t\t/** @return {object|null} The header link with `{total}` filled and tokens resolved; null while an href param is unresolved. */\n\t\theaderLink() {\n\t\t\treturn this.resolveLink(this.content?.headerLink)\n\t\t},\n\n\t\t/**\n\t\t * The text link under the rows (`footerLink`), resolved as the header\n\t\t * link is, as a router location or an href; null without rows.\n\t\t *\n\t\t * @return {{label: string, to?: object, href?: string}|null}\n\t\t * @spec openspec/changes/record-list-footer-link/specs/record-list-footer-link/spec.md#requirement-a-record-list-can-end-with-a-text-link\n\t\t */\n\t\tfooterLink() {\n\t\t\tconst link = this.resolveLink(this.content?.footerLink)\n\t\t\tif (!link || this.error || this.rows.length === 0) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (link.route) {\n\t\t\t\tconst to = { name: link.route }\n\t\t\t\tif (link.params) {\n\t\t\t\t\tto.params = link.params\n\t\t\t\t}\n\t\t\t\tif (link.query) {\n\t\t\t\t\tto.query = link.query\n\t\t\t\t}\n\t\t\t\treturn { label: link.label, to }\n\t\t\t}\n\t\t\treturn link.href ? { label: link.label, href: link.href } : null\n\t\t},\n\n\t\t/**\n\t\t * The checklist's columns (`content.columns`, 1 to 4, default 3).\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistColumns() {\n\t\t\tconst value = Number(this.content?.columns)\n\t\t\treturn Number.isFinite(value) && value >= 1 ? Math.min(4, Math.floor(value)) : 3\n\t\t},\n\n\t\t/**\n\t\t * How many checklist rows are done.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistDone() {\n\t\t\treturn this.items.filter((item) => this.isChecked(item.row)).length\n\t\t},\n\n\t\t/**\n\t\t * The done share of the checklist, in whole percent.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tchecklistPercent() {\n\t\t\treturn this.items.length > 0 ? Math.round((this.checklistDone / this.items.length) * 100) : 0\n\t\t},\n\n\t\t/** @return {string} What a done checklist row says to a screen reader. */\n\t\tdoneLabel() {\n\t\t\treturn t('nextcloud-vue', 'Done')\n\t\t},\n\n\t\t/** @return {string} What an open checklist row says to a screen reader. */\n\t\topenLabel() {\n\t\t\treturn t('nextcloud-vue', 'Not done yet')\n\t\t},\n\n\t\t/** @return {string} The header note with `{total}` filled. */\n\t\theaderNote() {\n\t\t\tconst note = this.content?.headerNote\n\t\t\treturn typeof note === 'string' && note !== '' ? this.withTotal(note) : ''\n\t\t},\n\n\t\t/**\n\t\t * Why the list is empty when a personal lens could not answer\n\t\t * (`@self.lenses.<lens>.available: false`, as for `filter: { _recent: true }`),\n\t\t * or '' to keep `emptyText`. `lensReasonTexts` holds the app's wording,\n\t\t * keyed `<lens>.<reason>` or `<reason>`.\n\t\t *\n\t\t * @return {string} The explanation, or ''.\n\t\t * @spec openspec/changes/screens-record-list-lens-reason/specs/record-list-lens-reason/spec.md#requirement-a-record-list-says-why-a-lens-is-empty\n\t\t */\n\t\tlensReasonText() {\n\t\t\tif (this.rows.length > 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst text = lensUnavailableText(this.lenses, this.content?.lensReasonTexts)\n\t\t\treturn text ? this.translate(text) : ''\n\t\t},\n\n\t\t/** @return {string} The empty line. */\n\t\t/**\n\t\t * `noteAction` with its labels through the host translate, or null\n\t\t * (`presentation: \"notes\"`).\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-record-list-can-collect-and-record-a-note-per-row\n\t\t * @return {object|null}\n\t\t */\n\t\tnoteAction() {\n\t\t\tconst action = this.content?.noteAction\n\t\t\tif (!action || typeof action !== 'object' || (!action.urlField && !action.url)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tr = (text) => (typeof text === 'string' && text !== '' ? this.translate(text) : '')\n\t\t\treturn {\n\t\t\t\t...action,\n\t\t\t\tlabel: tr(action.label),\n\t\t\t\tfieldLabel: tr(action.fieldLabel),\n\t\t\t\tplaceholder: tr(action.placeholder),\n\t\t\t\treadyLabel: tr(action.readyLabel),\n\t\t\t\terrorText: tr(action.errorText),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * `noteAction.recordAll` translated, its cancel link as a route, or null.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tnoteRecordAll() {\n\t\t\tconst all = this.content?.noteAction?.recordAll\n\t\t\tif (!all || typeof all !== 'object' || !all.label) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst cancel = all.cancel && all.cancel.label && all.cancel.route\n\t\t\t\t? { label: this.translate(all.cancel.label), to: typeof all.cancel.route === 'string' ? { name: all.cancel.route } : all.cancel.route }\n\t\t\t\t: null\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(all.label),\n\t\t\t\ttitle: all.title ? this.translate(all.title) : '',\n\t\t\t\ttext: all.text ? this.translate(all.text) : '',\n\t\t\t\ticon: all.icon || '',\n\t\t\t\tcancel,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether the app the rows come from is absent (`requiresApp`): the\n\t\t * list then says so (`absentText`) instead of reading anything.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tabsent() {\n\t\t\tconst app = this.content?.requiresApp\n\t\t\treturn typeof app === 'string' && app !== '' && !isAppInstalled(app)\n\t\t},\n\n\t\t/** @return {string} The line shown when the source app is absent. */\n\t\tabsentLabel() {\n\t\t\treturn this.content?.absentText ? this.translate(this.content.absentText) : t('nextcloud-vue', 'The app these come from is not installed')\n\t\t},\n\n\t\t/** @return {string} The line above the list (`intro`), translated. */\n\t\tintro() {\n\t\t\tconst text = this.content?.intro\n\t\t\treturn typeof text === 'string' && text !== '' ? this.translate(text) : ''\n\t\t},\n\n\t\t/**\n\t\t * The row actions (`rowActions`), labels translated. Each is a page\n\t\t * action (`type`, dispatched with the row) or `{ endpoint, method? }`,\n\t\t * an app URL called for the row.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\trowActions() {\n\t\t\tconst list = Array.isArray(this.content?.rowActions) ? this.content.rowActions : []\n\t\t\treturn list\n\t\t\t\t.filter((action) => action && typeof action === 'object' && typeof action.label === 'string' && action.label !== '')\n\t\t\t\t.map((action) => ({ ...action, label: this.translate(action.label) }))\n\t\t},\n\n\t\t/**\n\t\t * The `set-field` row actions, drawn as a button on each row.\n\t\t *\n\t\t * @spec openspec/changes/record-list-set-field/specs/record-list/spec.md#requirement-a-row-can-set-a-field-of-the-page-record\n\t\t * @return {Array<object>}\n\t\t */\n\t\tsetFieldActions() {\n\t\t\treturn this.rowActions\n\t\t\t\t.filter((action) => action.type === 'set-field' && typeof action.field === 'string' && action.field !== '')\n\t\t\t\t.map((action) => ({\n\t\t\t\t\t...action,\n\t\t\t\t\tdoneLabel: action.doneLabel ? this.translate(action.doneLabel) : '',\n\t\t\t\t\tariaLabel: action.ariaLabel ? this.translate(action.ariaLabel) : '',\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The heading of the `table` presentation's actions column.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/record-list-table-row-actions/specs/record-list-table/spec.md#requirement-a-table-row-can-carry-a-second-line-and-an-actions-menu\n\t\t */\n\t\t/**\n\t\t * Whether the row action is drawn as an outlined button sized to its\n\t\t * label (`rowAction.variant: \"outlined\"`, DqMijnTeam \"Oppakken\") instead\n\t\t * of the 150px pill (DcMijnActies \"Stem uitbrengen\").\n\t\t *\n\t\t * @return {boolean} True for the outlined variant.\n\t\t * @spec openspec/changes/board-row-action-outlined/specs/board-row-action-outlined/spec.md#requirement-a-dashboard-rows-action-is-an-outlined-button\n\t\t */\n\t\trowActionOutlined() {\n\t\t\treturn this.content?.rowAction?.variant === 'outlined'\n\t\t},\n\n\t\trowActionsHeader() {\n\t\t\tconst own = this.content?.rowActionsHeader\n\t\t\treturn typeof own === 'string' && own !== '' ? this.translate(own) : t('nextcloud-vue', 'Actions')\n\t\t},\n\n\t\t/** @return {string} The accessible name of a row's actions menu. */\n\t\trowActionsLabel() {\n\t\t\tconst own = this.content?.rowActionsLabel\n\t\t\treturn typeof own === 'string' && own !== '' ? this.translate(own) : t('nextcloud-vue', 'Actions for this row')\n\t\t},\n\n\t\t/** @return {string} The words in front of a `links` line. */\n\t\tlinksLabel() {\n\t\t\tconst label = this.content?.links?.label\n\t\t\treturn typeof label === 'string' && label !== '' ? this.translate(label) : ''\n\t\t},\n\n\t\t/** @return {string} The ids a `links` line names, to label them when they change. */\n\t\tlinkIdsKey() {\n\t\t\tconst field = this.content?.links?.field\n\t\t\tif (!field) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst ids = new Set()\n\t\t\tfor (const row of this.rows.slice(0, this.limit)) {\n\t\t\t\tconst list = readPath(row, field)\n\t\t\t\tfor (const id of Array.isArray(list) ? list : []) {\n\t\t\t\t\tif (typeof id === 'string' && id !== '') {\n\t\t\t\t\t\tids.add(id)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn [...ids].join('|')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\tif (this.lensReasonText !== '') {\n\t\t\t\treturn this.lensReasonText\n\t\t\t}\n\t\t\tif (this.conditionalEmptyText !== '') {\n\t\t\t\treturn this.conditionalEmptyText\n\t\t\t}\n\t\t\t// `emptyText: \"\"` says nothing on an empty list.\n\t\t\tif (this.content?.emptyText === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.content?.emptyText ? this.translate(this.content.emptyText) : t('nextcloud-vue', 'Nothing here yet')\n\t\t},\n\n\t\t/**\n\t\t * The error line: an endpoint's refusal (401/403) in its own words,\n\t\t * through the app's catalogue, else `errorText`, else the default.\n\t\t *\n\t\t * @return {string} The error line.\n\t\t * @spec openspec/changes/record-list-endpoint-refusal/specs/record-list/spec.md#requirement-a-refused-endpoint-read-says-why\n\t\t */\n\t\terrorLabel() {\n\t\t\tif (this.endpointActive && this.epRefusal) {\n\t\t\t\treturn this.translate(this.epRefusal)\n\t\t\t}\n\t\t\treturn this.content?.errorText ? this.translate(this.content.errorText) : t('nextcloud-vue', 'This list could not be loaded.')\n\t\t},\n\n\t\t/** @return {string} The spinner's accessible name. */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\t},\n\n\twatch: {\n\t\trequestKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\trows() {\n\t\t\tthis.evaluateEmptyTexts()\n\t\t\tthis.loadAggregates()\n\t\t},\n\n\t\tfooterDisabledKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.evaluateFooterDisabled()\n\t\t\t},\n\t\t},\n\n\t\tendpointKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\tobjectRowsKey() {\n\t\t\tthis.fetchRows()\n\t\t},\n\n\t\tlinkIdsKey() {\n\t\t\tthis.loadLinkLabels()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.onRefresh = () => this.fetchRows()\n\t\tsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t\tthis.fetchRows()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(PAGE_REFRESH_CHANNEL, this.onRefresh)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * An href with its `{name}` placeholders filled from `params` (tokens\n\t\t * such as `@object.masterEntityRef` resolved, each value URL-encoded)\n\t\t * and made a Nextcloud URL; null while a value is missing, so the link\n\t\t * is left out rather than pointing nowhere.\n\t\t *\n\t\t * @param {string} href The href, `/apps/<app>/...` with placeholders.\n\t\t * @param {object} params The placeholder values or tokens.\n\t\t * @return {string|null} The URL, or null.\n\t\t * @spec openspec/changes/record-list-header-href-params/specs/record-widgets/spec.md#requirement-a-record-list-header-link-can-fill-its-url-from-the-record\n\t\t */\n\t\tfilledHref(href, params) {\n\t\t\tconst values = resolveFilterTokens(params, this.tokenCtx)\n\t\t\tlet missing = false\n\t\t\tconst path = href.replace(/\\{(\\w+)\\}/g, (match, name) => {\n\t\t\t\tconst value = values[name]\n\t\t\t\tif (value === null || value === undefined || value === '' || typeof value === 'object' || (typeof value === 'string' && value.startsWith('@'))) {\n\t\t\t\t\tmissing = true\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn encodeURIComponent(String(value))\n\t\t\t})\n\t\t\tif (missing) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn path.startsWith('/') && !path.startsWith('//') ? generateUrl(path) : path\n\t\t},\n\n\t\t/**\n\t\t * Translate a manifest string through the host app.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string} The translation.\n\t\t */\n\t\ttranslate(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * A row's colour dot (`dot`: a field name, or `{ field, colorMap? }`):\n\t\t * the field's colour, or its value through `colorMap`. Only a hex\n\t\t * colour, an `rgb()`/`hsl()` colour or a `var(--…)` token is drawn.\n\t\t *\n\t\t * @spec openspec/changes/record-list-dot-flags/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-colour-dot-and-flag-text\n\t\t * @param {object} row The row.\n\t\t * @return {string} The colour, or ''.\n\t\t */\n\t\tdotOf(row) {\n\t\t\tconst dot = this.content?.dot\n\t\t\tconst def = typeof dot === 'string' ? { field: dot } : dot\n\t\t\tif (!def || typeof def !== 'object' || typeof def.field !== 'string' || def.field === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst raw = readPath(row, def.field)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst mapped = def.colorMap && typeof def.colorMap === 'object' && typeof def.colorMap[String(raw)] === 'string' ? def.colorMap[String(raw)] : String(raw)\n\t\t\treturn /^(#[0-9a-f]{3,8}|(rgb|rgba|hsl|hsla)\\([^;{}]*\\)|var\\(--[a-z0-9-]+(,[^;{}]*)?\\))$/i.test(mapped.trim()) ? mapped.trim() : ''\n\t\t},\n\n\t\t/**\n\t\t * A row's flag text (`flags`: `[{ field, label, value? }]`): the\n\t\t * labels of the flags whose field is set (or equals `value`), through\n\t\t * the host translate and joined with \" · \" (\"Start\", \"End\").\n\t\t *\n\t\t * @spec openspec/changes/record-list-dot-flags/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-colour-dot-and-flag-text\n\t\t * @param {object} row The row.\n\t\t * @return {string} The text, or ''.\n\t\t */\n\t\tflagOf(row) {\n\t\t\tconst flags = Array.isArray(this.content?.flags) ? this.content.flags : []\n\t\t\treturn flags\n\t\t\t\t.filter((flag) => flag && typeof flag.field === 'string' && typeof flag.label === 'string' && flag.label !== '')\n\t\t\t\t.filter((flag) => {\n\t\t\t\t\tconst raw = readPath(row, flag.field)\n\t\t\t\t\treturn flag.value !== undefined ? String(raw) === String(flag.value) : raw === true || raw === 'true' || raw === 1\n\t\t\t\t})\n\t\t\t\t.map((flag) => this.translate(flag.label))\n\t\t\t\t.join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * Settle whether the footer action is disabled: `disabledWhen` is a\n\t\t * visibleWhen condition read against the page's record (`field`), the\n\t\t * workspace, an endpoint or a source; `total` is the list's total.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {Promise<void>}\n\t\t */\n\t\t/**\n\t\t * Pick the empty text (`emptyTexts`: `[{ when, text }]`, the first whose\n\t\t * visibleWhen condition holds), for a list that is empty for more than\n\t\t * one reason (\"Everything you opened today has a note\" or \"You have not\n\t\t * opened anything today\"). `emptyText` stays the fallback.\n\t\t *\n\t\t * @spec openspec/changes/record-list-notes/specs/record-list-notes/spec.md#requirement-a-record-list-can-say-why-it-is-empty\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync evaluateEmptyTexts() {\n\t\t\tconst options = Array.isArray(this.content?.emptyTexts) ? this.content.emptyTexts : []\n\t\t\tif (options.length === 0 || this.rows.length > 0) {\n\t\t\t\tthis.conditionalEmptyText = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst run = this.emptyRun = (this.emptyRun || 0) + 1\n\t\t\tfor (const option of options) {\n\t\t\t\tif (!option || typeof option.text !== 'string' || !option.when) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst holds = await evaluateVisibleWhen(option.when, this.tokenCtx)\n\t\t\t\tif (run !== this.emptyRun) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (holds) {\n\t\t\t\t\tthis.conditionalEmptyText = this.translate(option.text)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.conditionalEmptyText = ''\n\t\t},\n\n\t\tasync evaluateFooterDisabled() {\n\t\t\tconst cond = this.footerActionConfig?.disabledWhen\n\t\t\tif (!cond) {\n\t\t\t\tthis.footerDisabled = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst ctx = { ...this.tokenCtx, object: { ...(this.tokenCtx.object || {}), total: this.total } }\n\t\t\tconst key = this.footerDisabledKey\n\t\t\tconst disabled = await evaluateVisibleWhen(cond, ctx)\n\t\t\tif (key === this.footerDisabledKey) {\n\t\t\t\tthis.footerDisabled = disabled\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the footer action through the page's dispatcher, with the page's\n\t\t * record as the token context.\n\t\t *\n\t\t * @spec openspec/changes/record-list-footer-action/specs/record-list/spec.md#requirement-a-record-list-can-end-with-an-action-that-says-why-it-is-disabled\n\t\t * @return {unknown} What the dispatcher returns.\n\t\t */\n\t\trunFooterAction() {\n\t\t\tconst declared = this.footerAction?.action\n\t\t\tif (!declared || this.footerDisabled) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst { disabledWhen, disabledReason, group, variant, visibleWhen, note, wide, ...action } = declared\n\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\treturn this.cnDispatchAction(action)\n\t\t\t}\n\t\t\treturn dispatchAction(action, { router: this.$router || null, tokenCtx: this.tokenCtx, source: { register: this.content?.register, schema: this.content?.schema } })\n\t\t},\n\n\t\t/**\n\t\t * A row's `bar`: its value, the maximum it is measured against (the\n\t\t * row's `maxField`, else the largest row), the filled share and\n\t\t * whether it is over that maximum. Null without `bar` or a value.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {number} scale The largest value over the rows shown.\n\t\t * @return {{value: number, max: number, share: number, over: boolean}|null} The bar.\n\t\t * @spec openspec/changes/record-list-row-bar/specs/record-list-row-bar/spec.md#requirement-a-record-list-row-can-carry-a-bar\n\t\t */\n\t\tbarOf(row, scale) {\n\t\t\tconst bar = this.content?.bar\n\t\t\tif (!bar || typeof bar !== 'object' || !bar.valueField) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst value = Number(readPath(row, bar.valueField))\n\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst ownMax = bar.maxField ? Number(readPath(row, bar.maxField)) : NaN\n\t\t\tconst max = bar.maxField ? (Number.isFinite(ownMax) && ownMax > 0 ? ownMax : 0) : scale\n\t\t\tconst share = max > 0 ? Math.min(100, Math.max(0, (value / max) * 100)) : 0\n\t\t\tconst over = Boolean(bar.maxField) && bar.overVariant === 'error' && max > 0 && value > max\n\t\t\treturn { value, max, share, over }\n\t\t},\n\n\t\t/**\n\t\t * The initials of the row's avatar (`avatar`: a name template such as\n\t\t * `\"{client.name}\"`, or `{ text }`), or '' without one.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} One or two letters.\n\t\t * @spec openspec/changes/screens-record-list-avatar/specs/record-list-avatar/spec.md#requirement-a-record-list-row-can-carry-an-avatar\n\t\t */\n\t\tinitialsFor(row) {\n\t\t\tconst avatar = this.content?.avatar\n\t\t\tconst template = typeof avatar === 'string' ? avatar : (avatar && typeof avatar === 'object' ? avatar.text : '')\n\t\t\treturn initialsOf(this.fill(template, row))\n\t\t},\n\n\t\t/**\n\t\t * Fill a template from a row, after translating it.\n\t\t *\n\t\t * @param {string} template The template.\n\t\t * @param {object} row The row.\n\t\t * @return {string} The text, '' when a token is empty.\n\t\t */\n\t\tfill(template, row) {\n\t\t\t// A list is candidates: the first that fills (\"{summary}\", else \"{subject}\").\n\t\t\tif (Array.isArray(template)) {\n\t\t\t\treturn firstFilled(template, this.labelledRow(row), (text) => this.translate(text), new Date(), this.templateContext)\n\t\t\t}\n\t\t\treturn typeof template === 'string' && template !== '' ? fillTemplate(this.translate(template), this.labelledRow(row), new Date(), this.templateContext) : ''\n\t\t},\n\n\t\t/**\n\t\t * The row as the templates read it: a field named in `valueLabels`\n\t\t * (`{ channel: { phone: \"Phone\", telefoon: \"Phone\" } }`) shows the\n\t\t * translated label of its stored value, so \"{channel}\" reads \"Telefoon\"\n\t\t * for both spellings the data holds. A value without a label stays as\n\t\t * stored. The pill, the badges and the sort read the stored value.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The row, or a shallow copy with labelled fields.\n\t\t * @spec openspec/changes/screens-record-list-value-labels/specs/record-list-value-labels/spec.md#requirement-a-record-list-template-can-show-a-label-for-a-stored-value\n\t\t */\n\t\tlabelledRow(row) {\n\t\t\tconst map = this.content?.valueLabels\n\t\t\tif (!row || typeof row !== 'object' || !map || typeof map !== 'object') {\n\t\t\t\treturn row\n\t\t\t}\n\t\t\tlet out = row\n\t\t\tfor (const [field, labels] of Object.entries(map)) {\n\t\t\t\tconst raw = row[field]\n\t\t\t\tif (!labels || typeof labels !== 'object' || (typeof raw !== 'string' && typeof raw !== 'number')) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst label = labels[String(raw)]\n\t\t\t\tif (typeof label === 'string' && label !== '') {\n\t\t\t\t\tif (out === row) {\n\t\t\t\t\t\tout = { ...row }\n\t\t\t\t\t}\n\t\t\t\t\tout[field] = this.translate(label)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * Fill a translated label's counts: `{total}` is the list's total, and\n\t\t * `{count:<field>=<value>}` the loaded rows whose field reads that\n\t\t * value (\"{count:status=done} van {total} stappen klaar\"). The count\n\t\t * reads the rows the list loaded, so it is exact when `limit` covers\n\t\t * the list.\n\t\t *\n\t\t * @param {string} label The label.\n\t\t * @return {string} The text.\n\t\t */\n\t\t/**\n\t\t * A `{ label, route, params?, query? }` or `{ label, href }` link with\n\t\t * `{total}` filled and tokens resolved, or null.\n\t\t *\n\t\t * @param {object|undefined} link The declared link.\n\t\t * @return {object|null} The resolved link.\n\t\t */\n\t\tresolveLink(link) {\n\t\t\tif (!link || typeof link !== 'object' || typeof link.label !== 'string' || link.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst resolved = { label: this.withTotal(link.label) }\n\t\t\tif (link.route) {\n\t\t\t\tresolved.route = link.route\n\t\t\t\tif (link.params && typeof link.params === 'object') {\n\t\t\t\t\tresolved.params = resolveFilterTokens(link.params, this.tokenCtx)\n\t\t\t\t}\n\t\t\t\tif (link.query && typeof link.query === 'object') {\n\t\t\t\t\tresolved.query = resolveFilterTokens(link.query, this.tokenCtx)\n\t\t\t\t}\n\t\t\t} else if (typeof link.href === 'string') {\n\t\t\t\tif (link.params && typeof link.params === 'object') {\n\t\t\t\t\tconst href = this.filledHref(link.href, link.params)\n\t\t\t\t\tif (href === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tresolved.href = href\n\t\t\t\t} else {\n\t\t\t\t\tresolved.href = link.href\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\twithTotal(label) {\n\t\t\treturn fillCountLabel(this.translate(label), this.total, this.rows)\n\t\t},\n\n\t\t/**\n\t\t * The route a row opens: `rowRoute` with the id at `rowIdField`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object|null} The router location, or null.\n\t\t */\n\t\t/**\n\t\t * The one action that ends a row (`rowAction`): its label (from\n\t\t * `labels.map` by the row's `labels.field`, else `label`), and how it\n\t\t * renders: a link when it only navigates, else a button that\n\t\t * dispatches. Null without the key or a label.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {{label: string, tag: string, attrs: object}|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\trowActionOf(row) {\n\t\t\tconst action = this.content?.rowAction\n\t\t\tif (!action || typeof action !== 'object' || !row) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tlet label = typeof action.label === 'string' ? action.label : ''\n\t\t\tconst by = action.labels\n\t\t\tif (by && typeof by === 'object' && typeof by.field === 'string' && by.map && typeof by.map === 'object') {\n\t\t\t\tconst raw = readPath(row, by.field)\n\t\t\t\tif (raw !== null && raw !== undefined && typeof by.map[String(raw)] === 'string') {\n\t\t\t\t\tlabel = by.map[String(raw)]\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tlabel = this.translate(label)\n\t\t\tconst link = this.rowActionLink(action, row)\n\t\t\tif (link) {\n\t\t\t\treturn link.external\n\t\t\t\t\t? { label, tag: 'a', attrs: { href: link.href, target: '_blank', rel: 'noopener' } }\n\t\t\t\t\t: { label, tag: 'router-link', attrs: { to: link.to } }\n\t\t\t}\n\t\t\treturn { label, tag: 'button', attrs: { type: 'button' } }\n\t\t},\n\n\t\t/**\n\t\t * The link a `rowAction` that only navigates renders as: `open-page`\n\t\t * opens that page for the row's id, `navigate` reads its\n\t\t * `@object.<field>` / `@objectId` tokens off the row. Null for any\n\t\t * other action, which is dispatched on click.\n\t\t *\n\t\t * @param {object} action The declared row action.\n\t\t * @param {object} row The row.\n\t\t * @return {{href: string, to: (string|object|null), external: boolean}|null}\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t */\n\t\trowActionLink(action, row) {\n\t\t\tif (action.confirm) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (action.type === 'open-page') {\n\t\t\t\tconst id = this.rowIdOf(row)\n\t\t\t\tif (!this.$router || id === null || typeof action.target !== 'string' || action.target === '') {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t\tconst to = { name: action.target, params: { id } }\n\t\t\t\ttry {\n\t\t\t\t\tconst href = this.$router.resolve(to).href\n\t\t\t\t\treturn href ? { href, to, external: false } : null\n\t\t\t\t} catch {\n\t\t\t\t\treturn null\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (action.type !== 'navigate') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst target = interpolateActionTarget(action.target, this.rowTokenCtx(row))\n\t\t\t// An external target needs no router; an in-app one does.\n\t\t\treturn actionLink({ ...action, target }, { router: this.$router || null })\n\t\t},\n\n\t\t/**\n\t\t * The token context of a row: the row is `@object`, its id `@objectId`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The token context.\n\t\t */\n\t\trowTokenCtx(row) {\n\t\t\treturn { ...this.tokenCtx, objectId: this.rowIdOf(row), object: row }\n\t\t},\n\n\t\t/**\n\t\t * The id of a row (`rowIdField`, else `id`, else `@self.id`), or null.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string|null} The id.\n\t\t */\n\t\trowIdOf(row) {\n\t\t\tconst field = this.content?.rowIdField\n\t\t\tconst id = field ? readPath(row, field) : (row && (row.id || row['@self']?.id))\n\t\t\treturn (id === null || id === undefined || id === '' || typeof id === 'object') ? null : String(id)\n\t\t},\n\n\t\t/**\n\t\t * Run a `rowAction` that is not a plain link through the page's\n\t\t * dispatcher: a `handler` gets the row as its last argument, an\n\t\t * `open-modal` gets it as the `row` prop, an `object-op` acts on it.\n\t\t * With `endpoint` it calls that app URL for the row, as a `rowActions`\n\t\t * endpoint entry does.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {unknown} What the dispatcher returns.\n\t\t * @spec openspec/changes/screens-record-list-row-action/specs/record-list/spec.md\n\t\t * @spec openspec/changes/record-list-row-action-endpoint/specs/record-list/spec.md#requirement-a-rows-one-action-can-call-an-app-endpoint-for-that-row\n\t\t */\n\t\trunRowAction(row) {\n\t\t\tconst action = this.content?.rowAction\n\t\t\tif (!action || typeof action !== 'object') {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tif (typeof action.endpoint === 'string' && action.endpoint !== '') {\n\t\t\t\treturn this.runRowActionEntry(action, row)\n\t\t\t}\n\t\t\tconst type = action.type || 'handler'\n\t\t\tlet wrapped = action\n\t\t\tif (type === 'handler') {\n\t\t\t\twrapped = { ...action, args: [...(action.args || []), row] }\n\t\t\t} else if (type === 'open-modal') {\n\t\t\t\twrapped = { ...action, props: { ...(action.props || {}), row } }\n\t\t\t}\n\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\treturn this.cnDispatchAction(wrapped)\n\t\t\t}\n\t\t\treturn dispatchAction(wrapped, { router: this.$router || null, row, tokenCtx: this.rowTokenCtx(row), source: { register: this.content?.register, schema: this.content?.schema } })\n\t\t},\n\n\t\trowLink(row) {\n\t\t\t// `rowRouteField`: the route name read from the row, for a list\n\t\t\t// whose rows open different pages (a case and a task).\n\t\t\tconst byField = this.content?.rowRouteField ? readPath(row, this.content.rowRouteField) : null\n\t\t\tconst route = (typeof byField === 'string' && byField !== '') ? byField : this.content?.rowRoute\n\t\t\tif (!route || !this.$router || !row) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst field = this.content?.rowIdField\n\t\t\tconst id = field ? readPath(row, field) : (row.id || row['@self']?.id)\n\t\t\tif (id === null || id === undefined || id === '' || typeof id === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { name: route, params: { id: String(id) } }\n\t\t},\n\n\t\t/**\n\t\t * The row's due text (`due`: `{ field, todayLabel?, overdueLabel?, upcomingLabel?, upcomingWeeksLabel?, upcomingWeeksFrom?, emptyText? }`):\n\t\t * \"3 dagen te laat\" in the danger tone, \"Vandaag\", the date or the time\n\t\t * left (\"nog 4 dagen\") otherwise, `emptyText` when the field is empty.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {{text: string, tone: string}|null} The text and tone, or null.\n\t\t * @spec openspec/changes/screens-due-text/specs/due-text/spec.md#requirement-a-due-date-reads-as-text-with-a-tone\n\t\t */\n\t\tdueOf(row) {\n\t\t\tconst due = this.content?.due\n\t\t\tif (!due || typeof due !== 'object' || !due.field) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolveDue(readPath(row, due.field), due, (text) => this.translate(text))\n\t\t},\n\n\t\t/**\n\t\t * Ask every `content.aggregates` figure (`{ key: { register, schema,\n\t\t * op: \"count\" | \"max\", field?, where } }`, `@self.<path>` in `where`\n\t\t * read off the row) for each row shown, as a table's `aggregate`\n\t\t * column does. A failed figure is left out; a stale batch is dropped.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\tasync loadAggregates() {\n\t\t\tconst declared = this.content?.aggregates\n\t\t\tconst entries = declared && typeof declared === 'object' ? Object.entries(declared).filter(([, agg]) => isRowAggregate(agg)) : []\n\t\t\tconst id = (this.aggregateRequestId = (this.aggregateRequestId || 0) + 1)\n\t\t\tif (entries.length === 0) {\n\t\t\t\tthis.aggregateValues = {}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = {}\n\t\t\tconst jobs = []\n\t\t\tfor (const raw of this.rows.slice(0, this.limit)) {\n\t\t\t\tconst row = scalarRow(raw)\n\t\t\t\tconst rowId = row && typeof row === 'object' ? (row.id || row['@self']?.id) : null\n\t\t\t\tif (!rowId) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tnext[rowId] = {}\n\t\t\t\tfor (const [key, agg] of entries) {\n\t\t\t\t\tjobs.push(fetchRowAggregate(agg, row)\n\t\t\t\t\t\t.then((value) => {\n\t\t\t\t\t\t\tnext[rowId][key] = this.aggregateText(agg, value)\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.catch(() => {}))\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (id === this.aggregateRequestId) {\n\t\t\t\tthis.aggregateValues = next\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A count read through the aggregate's `text` forms (`{ zero?, one?,\n\t\t * other }`, `{count}` filled in, translated), else the figure itself.\n\t\t *\n\t\t * @param {object} agg The aggregate declaration.\n\t\t * @param {unknown} value The figure.\n\t\t * @return {unknown} The text, or the figure.\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\taggregateText(agg, value) {\n\t\t\tconst forms = agg && agg.text\n\t\t\tconst count = Number(value)\n\t\t\tif (!forms || typeof forms !== 'object' || !Number.isFinite(count)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst form = (count === 0 && forms.zero) || (count === 1 && forms.one) || forms.other || forms.one\n\t\t\treturn typeof form === 'string' ? this.translate(form).replace(/\\{count\\}/g, String(count)) : value\n\t\t},\n\n\t\t/**\n\t\t * The row with its `aggregates` figures under their keys.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {object} The row, its figures added when it has any.\n\t\t * @spec openspec/changes/record-list-row-aggregates/specs/record-list/spec.md#requirement-a-record-list-row-can-carry-a-figure-over-its-related-objects\n\t\t */\n\t\twithAggregates(row) {\n\t\t\tif (!row || typeof row !== 'object') {\n\t\t\t\treturn row\n\t\t\t}\n\t\t\tconst figures = this.aggregateValues[row.id || row['@self']?.id]\n\t\t\treturn figures ? { ...row, ...figures } : row\n\t\t},\n\n\t\t/**\n\t\t * Whether a checklist row is done: `content.done` (a condition over\n\t\t * the row) holds for it.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/record-list-checklist/specs/record-list/spec.md#requirement-a-record-list-can-draw-its-rows-as-a-checklist\n\t\t */\n\t\tisChecked(row) {\n\t\t\tconst done = this.content?.done\n\t\t\treturn Boolean(done && typeof done === 'object' && row && evaluateVisibleWhenLocal(done, row))\n\t\t},\n\n\t\t/**\n\t\t * A `count` badge: how many entries a row's field holds (a list counts\n\t\t * its items, a number is itself), as `one` or `other` with `{count}`.\n\t\t * Nothing at 0.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {{field: string, one?: string, other?: string, variant?: string}} badge The declaration.\n\t\t * @param {number} index The badge's place, for its key.\n\t\t * @return {object|null} The badge.\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tcountBadgeOf(row, badge, index) {\n\t\t\tconst raw = readPath(row, badge.field)\n\t\t\tconst count = Array.isArray(raw) ? raw.length : Number(raw)\n\t\t\tif (!Number.isFinite(count) || count < 1) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst template = count === 1 ? (badge.one || badge.other) : (badge.other || badge.one)\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `count-${index}`,\n\t\t\t\tkind: 'count',\n\t\t\t\tlabel: this.translate(template).replace(/\\{count\\}/g, String(count)),\n\t\t\t\tvariant: isBadgeVariant(badge.variant) ? badge.variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The badge variant of a `table` cell with a `tone`\n\t\t * (`{ field?, map, default?, override?: { when, tone } }`): the value at\n\t\t * `field` (else the cell text) looked up in `map`, else `default`. While\n\t\t * `override.when` (a condition over the row) holds, the cell takes\n\t\t * `override.tone` instead, so a verdict is never green unless a second\n\t\t * field allows it.\n\t\t *\n\t\t * @param {object} col The column.\n\t\t * @param {object} row The row.\n\t\t * @param {string} text The cell text.\n\t\t * @return {string} A badge variant, or '' for a plain cell.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\tcellToneOf(col, row, text) {\n\t\t\tconst tone = col.tone\n\t\t\tif (!tone || typeof tone !== 'object') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet variant\n\t\t\tif (tone.override && typeof tone.override === 'object' && evaluateVisibleWhenLocal(tone.override.when, row || {})) {\n\t\t\t\tvariant = tone.override.tone\n\t\t\t} else {\n\t\t\t\tconst value = tone.field ? readPath(row, tone.field) : text\n\t\t\t\tconst map = tone.map && typeof tone.map === 'object' ? tone.map : {}\n\t\t\t\tvariant = Object.hasOwn(map, String(value)) ? map[String(value)] : tone.default\n\t\t\t}\n\t\t\treturn isBadgeVariant(variant) ? variant : 'default'\n\t\t},\n\n\t\t/**\n\t\t * The `aria-sort` of a sortable `table` column.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @return {string} `ascending`, `descending` or `none`.\n\t\t */\n\t\tsortStateOf(key) {\n\t\t\treturn this.tableSort.key === key && this.tableSort.dir ? this.tableSort.dir : 'none'\n\t\t},\n\n\t\t/**\n\t\t * The arrow after a sortable column's label.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @return {string} An up or down arrow, or '' while the column is not the sort.\n\t\t */\n\t\tsortMarkOf(key) {\n\t\t\tconst state = this.sortStateOf(key)\n\t\t\tif (state === 'ascending') {\n\t\t\t\treturn '▲'\n\t\t\t}\n\t\t\treturn state === 'descending' ? '▼' : ''\n\t\t},\n\n\t\t/**\n\t\t * Sort the `table` by a column: ascending first, then descending.\n\t\t *\n\t\t * @param {string} key The column key.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\ttoggleTableSort(key) {\n\t\t\tconst dir = this.tableSort.key === key && this.tableSort.dir === 'ascending' ? 'descending' : 'ascending'\n\t\t\tthis.tableSort = { key, dir }\n\t\t},\n\n\t\t/**\n\t\t * The rows of a read with `flattenPath` set: each entry of the list at\n\t\t * that path on a record becomes a row, with the record at `@parent`.\n\t\t * A record without the list adds no row. Without `flattenPath` the\n\t\t * records are the rows.\n\t\t *\n\t\t * @param {Array<object>} records The records read.\n\t\t * @return {Array<object>} The rows.\n\t\t * @spec openspec/changes/record-list-table-shape/specs/record-list-table-shape/spec.md#requirement-a-record-list-table-takes-its-shape-from-the-rows\n\t\t */\n\t\tflattenRows(records) {\n\t\t\tconst path = this.content?.flattenPath\n\t\t\tif (typeof path !== 'string' || path === '') {\n\t\t\t\treturn records\n\t\t\t}\n\t\t\treturn records.flatMap((record) => {\n\t\t\t\tconst list = readPath(record, path)\n\t\t\t\treturn Array.isArray(list)\n\t\t\t\t\t? list.filter((entry) => entry && typeof entry === 'object').map((entry) => ({ ...entry, '@parent': record }))\n\t\t\t\t\t: []\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The row actions shown on one row: those whose `visibleWhen` (a\n\t\t * condition over the row) holds. An `href` action is a template over\n\t\t * the row and shows only when it fills to a web address or an\n\t\t * instance path; a web address opens in a new tab.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{action: object, index: number, href: string, external: boolean}>} The visible actions, with their place in `rowActions`.\n\t\t * @spec openspec/changes/record-list-row-rules/specs/record-list-row-rules/spec.md#requirement-a-row-action-can-depend-on-the-row\n\t\t */\n\t\trowActionsOf(row) {\n\t\t\tconst shown = []\n\t\t\tthis.rowActions.forEach((action, index) => {\n\t\t\t\tif (action.type === 'set-field') {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (action.visibleWhen && !evaluateVisibleWhenLocal(action.visibleWhen, row || {})) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (typeof action.href !== 'string') {\n\t\t\t\t\tshown.push({ action, index, href: '', external: false })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst href = this.fill(action.href, row).trim()\n\t\t\t\tconst external = /^https?:\\/\\//i.test(href)\n\t\t\t\tif (external || (href.startsWith('/') && !href.startsWith('//'))) {\n\t\t\t\t\tshown.push({ action, index, href, external })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn shown\n\t\t},\n\n\t\t/**\n\t\t * A row's `links` line: the ids at `links.field`, each labelled from\n\t\t * `links.labelSource` (`{ register, schema, template }`) once read, else\n\t\t * `links.fallback`, and routed by `links.route` with `{value}` the id.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{id: string, label: string, to: (object|null)}>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tlinksOf(row) {\n\t\t\tconst spec = this.content?.links\n\t\t\tif (!spec || typeof spec !== 'object' || !spec.field) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst list = readPath(row, spec.field)\n\t\t\tif (!Array.isArray(list)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst fallback = typeof spec.fallback === 'string' ? this.translate(spec.fallback) : ''\n\t\t\treturn list.filter((id) => typeof id === 'string' && id !== '').map((id) => {\n\t\t\t\tlet to = null\n\t\t\t\tif (spec.route && typeof spec.route === 'object' && spec.route.name && this.$router) {\n\t\t\t\t\tconst params = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(spec.route.params || {})) {\n\t\t\t\t\t\tparams[key] = value === '{value}' ? id : value\n\t\t\t\t\t}\n\t\t\t\t\tto = { name: spec.route.name, params }\n\t\t\t\t}\n\t\t\t\treturn { id, label: this.linkLabels[id] || fallback || id, to }\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Read the labels of the records the `links` lines name, ten at most.\n\t\t * A record that cannot be read keeps the fallback; its link still opens.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLinkLabels() {\n\t\t\tconst spec = this.content?.links?.labelSource\n\t\t\tif (!spec || !spec.register || !spec.schema || this.linkIdsKey === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst wanted = this.linkIdsKey.split('|').filter((id) => !this.linkLabels[id]).slice(0, 10)\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\tawait Promise.all(wanted.map(async (id) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst { data } = await axios.get(generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}', { register: spec.register, schema: spec.schema, id }))\n\t\t\t\t\tconst label = fillTemplate(this.translate(spec.template || '{title}'), data || {})\n\t\t\t\t\tif (label !== '') {\n\t\t\t\t\t\tthis.linkLabels = { ...this.linkLabels, [id]: label }\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// The link still opens; only its text stays the fallback.\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Fill `{field}` placeholders from a row. A text that is one placeholder\n\t\t * keeps the value's type.\n\t\t *\n\t\t * @param {string} text The template.\n\t\t * @param {object} row The row.\n\t\t * @return {unknown} The filled value.\n\t\t */\n\t\tfillRow(text, row) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst whole = text.match(/^\\{([\\w.@]+)\\}$/)\n\t\t\tif (whole) {\n\t\t\t\treturn readPath(row, whole[1]) ?? ''\n\t\t\t}\n\t\t\treturn text.replace(/\\{([\\w.@]+)\\}/g, (_m, field) => String(readPath(row, field) ?? ''))\n\t\t},\n\n\t\t/**\n\t\t * Whether the page's record already holds the value a `set-field`\n\t\t * action would write for this row.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} row The row.\n\t\t * @return {boolean}\n\t\t */\n\t\tsetFieldDone(action, row) {\n\t\t\tconst object = this.tokenCtx.object || {}\n\t\t\tconst current = readPath(object, action.field)\n\t\t\tconst value = this.fillRow(action.value, row)\n\t\t\treturn Boolean(action.doneLabel) && value !== '' && current !== undefined && current !== null && String(current) === String(value)\n\t\t},\n\n\t\t/**\n\t\t * Write one field of the page's record from a row with one PATCH, hand\n\t\t * the saved record to the page, and read the list again.\n\t\t *\n\t\t * @spec openspec/changes/record-list-set-field/specs/record-list/spec.md#requirement-a-row-can-set-a-field-of-the-page-record\n\t\t * @param {object} action The `set-field` action.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync runSetField(action, row) {\n\t\t\tconst context = this.tokenCtx\n\t\t\tif (this.settingField || !context.register || !context.schema || !context.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.actionError = ''\n\t\t\tthis.settingField = true\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\t\tconst url = generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(context.register)}/${encodeURIComponent(context.schema)}/${encodeURIComponent(context.objectId)}`)\n\t\t\t\tconst { data } = await axios.patch(url, { [action.field]: this.fillRow(action.value, row) })\n\t\t\t\tconst setObject = unwrap(this.cnObjectContext)?.setObject\n\t\t\t\tif (typeof setObject === 'function' && data && typeof data === 'object') {\n\t\t\t\t\tsetObject(data)\n\t\t\t\t}\n\t\t\t\tif (typeof this.epRefetch === 'function' && this.endpointActive) {\n\t\t\t\t\tawait this.epRefetch(true)\n\t\t\t\t\tif (typeof this.footnoteRefetch === 'function' && this.footnoteFromAnswer) {\n\t\t\t\t\t\tawait this.footnoteRefetch(false)\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tawait this.fetchRows()\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst said = error?.response?.data?.error ?? error?.response?.data?.message\n\t\t\t\tthis.actionError = typeof said === 'string' && said !== ''\n\t\t\t\t\t? said\n\t\t\t\t\t: (action.errorText ? this.translate(action.errorText) : t('nextcloud-vue', 'This did not work. Try again.'))\n\t\t\t} finally {\n\t\t\t\tthis.settingField = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one of `rowActions` for a row: an `endpoint` is called with the\n\t\t * row's `{field}` tokens and the page's `@objectId` filled in, then the\n\t\t * list reads again; a refusal shows the server's sentence. Any other\n\t\t * entry is a page action, dispatched as `rowAction` is.\n\t\t *\n\t\t * @param {object} action The entry.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-list-can-act-on-its-rows-and-link-onwards\n\t\t */\n\t\tasync runRowActionEntry(action, row) {\n\t\t\tthis.actionError = ''\n\t\t\tif (typeof action.endpoint !== 'string' || action.endpoint === '') {\n\t\t\t\tconst { label, ...declared } = action\n\t\t\t\tconst type = declared.type || 'handler'\n\t\t\t\tlet wrapped = declared\n\t\t\t\tif (type === 'handler') {\n\t\t\t\t\twrapped = { ...declared, args: [...(declared.args || []), row] }\n\t\t\t\t} else if (type === 'open-modal') {\n\t\t\t\t\twrapped = { ...declared, props: { ...resolveDeepTokens(declared.props || {}, this.tokenCtx), row } }\n\t\t\t\t}\n\t\t\t\tif (typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tthis.cnDispatchAction(wrapped)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tdispatchAction(wrapped, { router: this.$router || null, row, tokenCtx: this.rowTokenCtx(row) })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([import('@nextcloud/axios'), import('@nextcloud/router')])\n\t\t\tconst path = interpolateUrlTokens(action.endpoint, this.tokenCtx).replace(/\\{([\\w.@]+)\\}/g, (_match, field) => encodeURIComponent(String(readPath(row, field) ?? '')))\n\t\t\tconst method = typeof action.method === 'string' ? action.method.toLowerCase() : 'post'\n\t\t\ttry {\n\t\t\t\tawait axios.request({ method, url: generateUrl(path) })\n\t\t\t\tif (typeof this.epRefetch === 'function' && this.endpointActive) {\n\t\t\t\t\tawait this.epRefetch(true)\n\t\t\t\t} else {\n\t\t\t\t\tawait this.fetchRows()\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst said = error?.response?.data?.error ?? error?.response?.data?.message\n\t\t\t\tthis.actionError = typeof said === 'string' && said !== ''\n\t\t\t\t\t? said\n\t\t\t\t\t: (action.errorText ? this.translate(action.errorText) : t('nextcloud-vue', 'This did not work. Try again.'))\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The row's extra badges (`badges`): a coloured badge from a field\n\t\t * (`{ field, labels?, colorMap?, variant?, hideValues? }`, the value\n\t\t * shown unless `hideValues` lists it) and an age badge\n\t\t * (`{ kind: \"stale\", field, afterDays, label?, variant? }`, shown when the\n\t\t * date field is older than `afterDays` whole days; `{days}` in the\n\t\t * label is the age).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{key: string, kind: string, label: string, variant: string}>} The badges that apply.\n\t\t * @spec openspec/changes/screens-record-list-badges/specs/record-list-badges/spec.md#requirement-a-record-list-row-can-carry-badges\n\t\t */\n\t\tbadgesOf(row) {\n\t\t\tconst declared = Array.isArray(this.content?.badges) ? this.content.badges : []\n\t\t\tconst out = []\n\t\t\tdeclared.forEach((badge, index) => {\n\t\t\t\tif (!badge || typeof badge !== 'object' || !badge.field) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (badge.kind === 'count') {\n\t\t\t\t\tconst made = this.countBadgeOf(row, badge, index)\n\t\t\t\t\tif (made) {\n\t\t\t\t\t\tout.push(made)\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tif (badge.kind === 'stale') {\n\t\t\t\t\tconst days = ageInDays(readPath(row, badge.field))\n\t\t\t\t\tconst after = Number(badge.afterDays)\n\t\t\t\t\tif (days === null || !Number.isFinite(after) || days <= after) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tconst template = this.translate(badge.label || 'Stale')\n\t\t\t\t\tout.push({\n\t\t\t\t\t\tkey: `stale-${index}`,\n\t\t\t\t\t\tkind: 'stale',\n\t\t\t\t\t\tlabel: template.replace(/\\{days\\}/g, String(days)),\n\t\t\t\t\t\tvariant: isBadgeVariant(badge.variant) ? badge.variant : 'warning',\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst made = this.pillOf(row, badge)\n\t\t\t\tif (made) {\n\t\t\t\t\tout.push({ key: `field-${index}`, kind: 'field', ...made })\n\t\t\t\t}\n\t\t\t})\n\t\t\treturn out\n\t\t},\n\n\t\t/**\n\t\t * The row's meta line. A string is one template, and one empty token\n\t\t * empties it. `{ parts: [\"{identifier}\", \"{caseTypeName}\", \"{handler}\"],\n\t\t * separator? }` fills each part on its own, drops the empty ones and\n\t\t * joins the rest (default \" · \"), so a row without a handler still\n\t\t * reads \"2026-0082 · Woo-verzoek\".\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} The meta line, '' when nothing fills.\n\t\t * @spec openspec/changes/screens-record-list-meta-parts/specs/record-list-meta-parts/spec.md#requirement-a-meta-line-of-parts-skips-the-empty-ones\n\t\t */\n\t\tmetaOf(row) {\n\t\t\tconst meta = this.content?.meta\n\t\t\tif (!meta || typeof meta !== 'object' || !Array.isArray(meta.parts)) {\n\t\t\t\treturn this.fill(meta, row)\n\t\t\t}\n\t\t\tconst separator = typeof meta.separator === 'string' ? meta.separator : ' · '\n\t\t\treturn meta.parts\n\t\t\t\t.map((part) => this.fill(part, row))\n\t\t\t\t.filter((text) => text !== '')\n\t\t\t\t.join(separator)\n\t\t},\n\n\t\t/**\n\t\t * The row's pill: `{ field, labels?, colorMap?, variant?, hideValues? }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} [config] A pill config; the widget's `pill` by default.\n\t\t * @return {{label: string, variant: string}|null} The pill, or null.\n\t\t */\n\t\tpillOf(row, config) {\n\t\t\tconst pill = config || this.content?.pill\n\t\t\tif (pill && typeof pill === 'object' && Array.isArray(pill.cases)) {\n\t\t\t\treturn this.pillCaseOf(row, pill)\n\t\t\t}\n\t\t\tif (!pill || typeof pill !== 'object' || !pill.field) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(row, pill.field)\n\t\t\tif (raw === null || raw === undefined || raw === '' || typeof raw === 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst key = String(raw)\n\t\t\tif (Array.isArray(pill.hideValues) && pill.hideValues.map(String).includes(key)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst labels = pill.labels && typeof pill.labels === 'object' ? pill.labels : {}\n\t\t\tconst map = pill.colorMap && typeof pill.colorMap === 'object' ? pill.colorMap : {}\n\t\t\tconst found = Object.keys(map).find((k) => k.toLowerCase() === key.toLowerCase())\n\t\t\tconst variant = found ? map[found] : pill.variant\n\t\t\treturn {\n\t\t\t\tlabel: labels[key] ? this.translate(labels[key]) : key,\n\t\t\t\tvariant: isBadgeVariant(variant) ? variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The pill of `{ cases: [{ when, label, variant? }], label?, variant? }`:\n\t\t * the first case whose `when` (a local condition over the row) holds,\n\t\t * else the pill's own `label` and `variant`, else none. For a state that\n\t\t * reads more than one field (Concept, Actief, Vastgezet).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {object} pill The pill config.\n\t\t * @return {{label: string, variant: string}|null} The pill, or null.\n\t\t * @spec openspec/changes/record-list-pill-cases-footer-choice/specs/record-list/spec.md#requirement-a-record-list-row-pill-can-read-a-state-from-several-fields\n\t\t */\n\t\tpillCaseOf(row, pill) {\n\t\t\tconst found = pill.cases.find((entry) => entry && typeof entry === 'object' && entry.when && evaluateVisibleWhenLocal(entry.when, row || {}))\n\t\t\tconst chosen = found || pill\n\t\t\tif (typeof chosen.label !== 'string' || chosen.label === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tlabel: this.translate(chosen.label),\n\t\t\t\tvariant: isBadgeVariant(chosen.variant) ? chosen.variant : 'default',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The feed icon: an icon name, or `{ field, map, default }`.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {string} The MDI icon name.\n\t\t */\n\t\ticonOf(row) {\n\t\t\tconst icon = this.content?.icon\n\t\t\tif (typeof icon === 'string' && icon !== '') {\n\t\t\t\treturn icon\n\t\t\t}\n\t\t\tif (icon && typeof icon === 'object') {\n\t\t\t\tconst raw = icon.field ? readPath(row, icon.field) : undefined\n\t\t\t\tconst map = icon.map && typeof icon.map === 'object' ? icon.map : {}\n\t\t\t\tif (raw !== null && raw !== undefined && map[String(raw)]) {\n\t\t\t\t\treturn map[String(raw)]\n\t\t\t\t}\n\t\t\t\tif (typeof icon.default === 'string' && icon.default !== '') {\n\t\t\t\t\treturn icon.default\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn 'CircleSmall'\n\t\t},\n\n\t\t/** Tell the card around this list what its header shows. */\n\t\temitHeader() {\n\t\t\tconst header = { link: this.headerLink, note: this.headerNote }\n\t\t\t// `headerSubtitle`: the counts as the muted line under the card title.\n\t\t\tconst subtitle = this.content?.headerSubtitle\n\t\t\tif (typeof subtitle === 'string' && subtitle !== '' && !this.error) {\n\t\t\t\theader.subtitle = this.withTotal(subtitle)\n\t\t\t}\n\t\t\t// `headerCount: true`: the card draws the total as a chip after its title.\n\t\t\tif (this.content?.headerCount === true && !this.error) {\n\t\t\t\theader.count = this.total\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event header Emitted after every read with the card header's parts.\n\t\t\t * @type {{link: (object|null), note: string, count: (number|undefined), subtitle: (string|undefined)}} The header link (resolved, with `{total}` filled), the note, with `headerCount` the total, and with `headerSubtitle` the line under the title.\n\t\t\t */\n\t\t\tthis.$emit('header', header)\n\t\t},\n\n\t\t/**\n\t\t * The rank list of a sort (`{ field, rank: [\"urgent\", \"high\", \"normal\", \"low\"], then? }`),\n\t\t * or null when the sort has none or the list's own filter already fixes the field.\n\t\t *\n\t\t * @param {object|null} sort The effective sort.\n\t\t * @return {Array<string>|null} The values in rank order.\n\t\t * @spec openspec/changes/screens-enum-rank-sort/specs/enum-rank-sort/spec.md#requirement-a-record-list-can-sort-by-the-rank-of-an-enum-value\n\t\t */\n\t\trankOf(sort) {\n\t\t\tif (!sort || typeof sort !== 'object' || !sort.field || !Array.isArray(sort.rank)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst rank = sort.rank.filter((value) => typeof value === 'string' && value !== '')\n\t\t\tif (rank.length === 0 || Object.hasOwn(this.resolvedFilter || {}, sort.field)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn rank\n\t\t},\n\n\t\t/**\n\t\t * Read a list in the rank of an enum field. The list endpoint orders a\n\t\t * text field alphabetically (\"high\", \"low\", \"normal\", \"urgent\"), so the\n\t\t * rows are read one rank at a time, best first, each with the rest of the\n\t\t * sort (`then`) inside it, until the page is full; the rows with a value\n\t\t * outside the rank (or none) follow. The result is exact, not a client-side\n\t\t * sort of a partial page. It costs one request for the total, one per rank\n\t\t * value read and one for the remainder.\n\t\t *\n\t\t * @param {(params: object) => Promise<object>} get Reads the list with the given params.\n\t\t * @param {object} base The params without any order.\n\t\t * @param {{field: string, then?: {field: string, dir?: string}}} sort The sort.\n\t\t * @param {Array<string>} rank The values in rank order.\n\t\t * @return {Promise<{rows: Array<object>, total: number}>} The page and the total.\n\t\t * @spec openspec/changes/screens-enum-rank-sort/specs/enum-rank-sort/spec.md#requirement-a-record-list-can-sort-by-the-rank-of-an-enum-value\n\t\t */\n\t\tasync fetchRanked(get, base, sort, rank) {\n\t\t\tconst order = {}\n\t\t\tif (sort.then && typeof sort.then === 'object' && sort.then.field) {\n\t\t\t\torder[`_order[${sort.then.field}]`] = sort.then.dir === 'desc' ? 'desc' : 'asc'\n\t\t\t}\n\t\t\tconst read = async (extra) => {\n\t\t\t\tconst response = await get({ ...base, ...order, ...extra })\n\t\t\t\tconst data = response && response.data ? response.data : {}\n\t\t\t\treturn { results: Array.isArray(data.results) ? data.results : [], total: data.total }\n\t\t\t}\n\t\t\tconst head = await read({ _limit: 1 })\n\t\t\tconst rows = []\n\t\t\tconst seen = new Set()\n\t\t\tconst idOf = (row) => (row && (row.id || row['@self']?.id)) || null\n\t\t\tconst take = (list) => {\n\t\t\t\tfor (const row of list) {\n\t\t\t\t\tconst id = idOf(row)\n\t\t\t\t\tif (id !== null && seen.has(id)) {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif (id !== null) {\n\t\t\t\t\t\tseen.add(id)\n\t\t\t\t\t}\n\t\t\t\t\tif (rows.length < this.limit) {\n\t\t\t\t\t\trows.push(row)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const value of rank) {\n\t\t\t\tif (rows.length >= this.limit) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\ttake((await read({ [sort.field]: value, _limit: this.limit - rows.length })).results)\n\t\t\t}\n\t\t\tif (rows.length < this.limit) {\n\t\t\t\ttake((await read({ _limit: this.limit + rows.length })).results)\n\t\t\t}\n\t\t\treturn { rows, total: typeof head.total === 'number' ? head.total : rows.length }\n\t\t},\n\n\t\t/**\n\t\t * Copy the endpoint read into the list: its payload must be an array of\n\t\t * rows (anything else is an empty list), and a failed read is an error.\n\t\t *\n\t\t * @spec openspec/changes/endpoint-source-card-grid-record-list/specs/dashboard-page/spec.md#requirement-a-record-list-and-a-card-grid-can-read-an-endpoint\n\t\t */\n\t\ttakeEndpointRows() {\n\t\t\tthis.rows = this.flattenRows(Array.isArray(this.epData) ? this.epData : [])\n\t\t\tthis.total = this.rows.length\n\t\t\tthis.loading = this.epLoading === true\n\t\t\tthis.error = Boolean(this.epError)\n\t\t\tthis.lenses = {}\n\t\t\tif (!this.loading) {\n\t\t\t\tthis.emitHeader()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch the list. Sends nothing while a required token is unresolved\n\t\t * or the source is incomplete.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchRows() {\n\t\t\tconst c = this.content || {}\n\t\t\tif (this.absent) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.endpointActive) {\n\t\t\t\tthis.takeEndpointRows()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.objectRowsActive) {\n\t\t\t\tthis.rows = this.flattenRows(this.objectRowsList.map((row, index) => (row.id === undefined ? { id: `row-${index}`, ...row } : row)))\n\t\t\t\tthis.total = this.rows.length\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.error = false\n\t\t\t\tthis.lenses = {}\n\t\t\t\tthis.emitHeader()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!c.register || !c.schema || this.waiting) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = false\n\t\t\t\tthis.emitHeader()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = false\n\t\t\tconst run = this.fetchRun = (this.fetchRun || 0) + 1\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: c.register, schema: c.schema })\n\t\t\t\tconst sort = this.effectiveSort\n\t\t\t\tconst params = { _limit: this.limit }\n\t\t\t\tif (this.offset > 0) {\n\t\t\t\t\tparams._offset = this.offset\n\t\t\t\t}\n\t\t\t\t// A rank sort (`sort.rank`) cannot be one `_order`: the list endpoint\n\t\t\t\t// orders a text field alphabetically. It is read group by group below.\n\t\t\t\tconst rank = this.rankOf(sort)\n\t\t\t\tif (!rank && sort && typeof sort === 'object' && sort.field) {\n\t\t\t\t\tparams[`_order[${sort.field}]`] = sort.dir === 'desc' ? 'desc' : 'asc'\n\t\t\t\t}\n\t\t\t\tif (Array.isArray(c.extend)) {\n\t\t\t\t\tconst extend = c.extend.filter((e) => typeof e === 'string' && e !== '')\n\t\t\t\t\tif (extend.length > 0) {\n\t\t\t\t\t\tparams._extend = extend\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const [key, value] of Object.entries(this.resolvedFilter)) {\n\t\t\t\t\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\t\t\tfor (const [op, operand] of Object.entries(value)) {\n\t\t\t\t\t\t\tparams[`${key}[${op}]`] = operand\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (value !== '' && value !== null && value !== undefined) {\n\t\t\t\t\t\tparams[key] = value\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (rank) {\n\t\t\t\t\t// Several requests: a fetch started later (the sort changed\n\t\t\t\t\t// meanwhile) must not be overwritten by this one.\n\t\t\t\t\tconst ranked = await this.fetchRanked((query) => axios.get(url, { params: query }), params, sort, rank)\n\t\t\t\t\tif (run !== this.fetchRun) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthis.rows = this.flattenRows(ranked.rows)\n\t\t\t\t\tthis.total = this.content?.flattenPath ? this.rows.length : ranked.total\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst response = await axios.get(url, { params })\n\t\t\t\tconst data = response && response.data ? response.data : {}\n\t\t\t\tthis.rows = this.flattenRows(Array.isArray(data.results) ? data.results : [])\n\t\t\t\tthis.total = typeof data.total === 'number' && !this.content?.flattenPath ? data.total : this.rows.length\n\t\t\t\tthis.lenses = readLensReports(data)\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnRecordListWidget] failed to load objects:', e)\n\t\t\t\tthis.lenses = {}\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.total = 0\n\t\t\t\tthis.error = true\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.emitHeader()\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-record-list__checklist-bar {\n\theight: 8px;\n\tmargin-block-end: 16px;\n\tborder-radius: 4px;\n\tbackground: var(--color-background-dark);\n\toverflow: hidden;\n}\n\n.cn-record-list__checklist-fill {\n\tdisplay: block;\n\theight: 100%;\n\tborder-radius: 4px;\n\tbackground: var(--color-primary-element);\n}\n\n.cn-record-list__checklist {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-record-list-columns, 3), minmax(0, 1fr));\n\tgap: 8px 16px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-record-list__check {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmin-height: 28px;\n}\n\n.cn-record-list__check--done {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__check-mark {\n\tdisplay: inline-flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 20px;\n\theight: 20px;\n\tborder: 2px solid var(--color-border-maxcontrast);\n\tborder-radius: 50%;\n}\n\n.cn-record-list__check--done .cn-record-list__check-mark {\n\tborder-color: transparent;\n\tbackground: var(--color-success-hover, var(--color-background-dark));\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n@media (max-width: 640px) {\n\t.cn-record-list__checklist {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n\n.cn-record-list__set-field-done {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tcolor: var(--color-success-text, var(--color-success));\n\tfont-weight: bold;\n}\n\n.cn-record-list__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-record-list__group-heading {\n\tmargin: 6px 0 0;\n\tfont-size: 15px;\n\tfont-weight: 700;\n\tline-height: 1.4;\n}\n\n.cn-record-list__group-head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px;\n\tmargin-top: 6px;\n}\n\n.cn-record-list__group-head .cn-record-list__group-heading {\n\tmargin: 0;\n}\n\n.cn-record-list__action--tonal.button-vue {\n\tmin-height: 34px;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder: 0;\n\tborder-radius: 17px;\n\tbackground-color: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.cn-record-list__action--tonal.button-vue:hover:not(:disabled) {\n\tbackground-color: var(--color-primary-element-light-hover);\n}\n\n.cn-record-list__footer {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 6px;\n\tmargin-top: 10px;\n}\n\n.cn-record-list__footer--wide {\n\talign-items: stretch;\n}\n\n.cn-record-list__footer-note {\n\tmargin: 0 0 6px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__footer-reason {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__empty,\n.cn-record-list__error {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin: 0;\n}\n\n.cn-record-list__notice {\n\tdisplay: flex;\n\tgap: 10px;\n\talign-items: flex-start;\n\tpadding: 12px 14px;\n\tborder-radius: var(--border-radius-large, 10px);\n\tbackground: var(--color-primary-element-light, var(--color-background-dark));\n\tcolor: var(--color-main-text);\n}\n\n.cn-record-list__notice--warning {\n\tbackground: var(--color-warning-light, rgba(255, 196, 0, 0.12));\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-record-list__notice--error {\n\tbackground: var(--color-error-light, rgba(219, 0, 0, 0.08));\n\tcolor: var(--color-error-text, var(--color-main-text));\n}\n\n.cn-record-list__notice--footnote {\n\tmargin-top: 12px;\n}\n\n.cn-record-list__notice-icon {\n\tflex: 0 0 auto;\n\tmargin-top: 1px;\n}\n\n.cn-record-list__notice-text {\n\tmargin: 0;\n\tline-height: 1.5;\n}\n\n.cn-record-list__loading {\n\tdisplay: flex;\n\tjustify-content: center;\n\tpadding: 8px 0;\n}\n\n/* rows */\n.cn-record-list--rows .cn-record-list__item + .cn-record-list__item,\n.cn-record-list--rule-above .cn-record-list__item:first-child {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__pill-start {\n\tdisplay: flex;\n\tflex: none;\n}\n\n.cn-record-list__bar {\n\tbackground: var(--color-border);\n\tborder-radius: 3px;\n\tdisplay: block;\n\theight: 6px;\n\tmargin: -6px 0 12px;\n\toverflow: hidden;\n}\n\n.cn-record-list__bar-fill {\n\tbackground: var(--color-primary-element);\n\tdisplay: block;\n\theight: 100%;\n}\n\n.cn-record-list__bar--over .cn-record-list__bar-fill {\n\tbackground: var(--color-error);\n}\n\n.cn-record-list__row {\n\talign-items: center;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tgap: 16px;\n\tpadding: 12px 0;\n\ttext-decoration: none;\n}\n\n.cn-record-list__row--link:hover .cn-record-list__title,\n.cn-record-list__row--link:focus-visible .cn-record-list__title {\n\ttext-decoration: underline;\n}\n\n.cn-record-list__dot {\n\tflex: 0 0 14px;\n\twidth: 14px;\n\theight: 14px;\n\tborder-radius: 50%;\n}\n\n.cn-record-list__flag {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n/* `avatar.size: 32`: the smaller circle, 12px from the title where the row\n keeps 16px between its other parts (DqZaakBesluiten Adviezen). */\n.cn-record-list__list--avatar-small .cn-record-list__avatar {\n\twidth: 32px;\n\theight: 32px;\n\tmargin-inline-end: -4px;\n}\n\n.cn-record-list__avatar {\n\talign-items: center;\n\tbackground: var(--color-background-hover);\n\tborder-radius: 50%;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex: none;\n\tfont-size: 12px;\n\tfont-weight: 700;\n\theight: 36px;\n\tjustify-content: center;\n\twidth: 36px;\n}\n\n.cn-record-list__main {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-record-list__title {\n\tfont-size: 15px;\n\tfont-weight: 700;\n}\n\n.cn-record-list--compact .cn-record-list__row {\n\tbox-sizing: border-box;\n\tmin-height: 56px;\n\tpadding: 10px 0;\n}\n\n.cn-record-list--compact .cn-record-list__title {\n\tfont-weight: 500;\n}\n\n/* `density: \"stacked\"`: the rows stand 10px apart with no rule and no row\n padding, a short side list (DqDagAfsluiten \"Morgen eerst\"). */\n.cn-record-list--stacked .cn-record-list__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n}\n\n.cn-record-list--stacked .cn-record-list__row {\n\tmin-height: 0;\n\tpadding: 0;\n}\n\n.cn-record-list--stacked .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 0;\n}\n\n.cn-record-list__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__aside {\n\talign-items: center;\n\tdisplay: flex;\n\tflex: none;\n\tgap: 16px;\n}\n\n.cn-record-list__leading {\n\tflex: 0 0 52px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tfont-variant-numeric: tabular-nums;\n}\n\n.cn-record-list__trailing {\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__due {\n\tfont-size: 14px;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__due--danger {\n\tcolor: var(--color-text-error, var(--color-error-text));\n\tfont-weight: 600;\n}\n\n.cn-record-list__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n\tfont-size: 14px;\n}\n\n.cn-record-list__table th {\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: 600;\n\ttext-align: start;\n}\n\n.cn-record-list__table td {\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-record-list__cell-sub {\n\tdisplay: block;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__table .cn-record-list__cell--actions {\n\twidth: 1%;\n\tpadding-inline-start: 12px;\n\ttext-align: end;\n\twhite-space: nowrap;\n}\n\n.cn-record-list__sort {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\talign-items: center;\n\tmin-height: 0;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: none;\n\tbackground: none;\n\tcolor: inherit;\n\tfont: inherit;\n\tcursor: pointer;\n}\n\n.cn-record-list__sort:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-record-list__sort-mark {\n\tfont-size: 10px;\n}\n\n.cn-record-list__table .cn-record-list__cell--end {\n\tpadding-inline-start: 12px;\n\ttext-align: end;\n\tfont-variant-numeric: tabular-nums;\n}\n\n.cn-record-list__table .cn-record-list__cell--alert {\n\tcolor: var(--color-text-error, var(--color-error-text));\n\tfont-weight: 700;\n}\n\n.cn-record-list__intro {\n\tmargin: 0 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__footnote {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-record-list__due--soon {\n\tcolor: var(--color-text-warning, var(--color-warning-text));\n\tfont-weight: 600;\n}\n\n.cn-record-list__due--empty {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-record-list__row--action {\n\tflex-wrap: wrap;\n\tgap: 8px 16px;\n\tpadding: 14px 0;\n}\n\n.cn-record-list__row--action .cn-record-list__main {\n\tflex: 1 1 280px;\n\tgap: 3px;\n}\n\n.cn-record-list__title--link {\n\tcolor: var(--color-main-text);\n\ttext-decoration: underline;\n}\n\n.cn-record-list__pills {\n\tdisplay: flex;\n\tflex: 0 0 120px;\n\tgap: 6px;\n\tjustify-content: flex-end;\n}\n\n.cn-record-list__due--below {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: normal;\n}\n\n.cn-record-list__footer-link {\n\talign-self: flex-start;\n\tpadding-top: 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttext-decoration: underline;\n}\n\n.cn-record-list__due--column {\n\tflex: 0 0 96px;\n\tfont-size: 13px;\n\ttext-align: end;\n}\n\n.cn-record-list__action {\n\talign-items: center;\n\tbackground: var(--color-primary-element-light);\n\tborder: 0;\n\tborder-radius: 17px;\n\tbox-sizing: border-box;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tcursor: pointer;\n\tdisplay: inline-flex;\n\tflex: 0 0 150px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\theight: 34px;\n\tjustify-content: center;\n\tpadding: 0 14px;\n\ttext-decoration: none;\n}\n\n.cn-record-list__action:hover,\n.cn-record-list__action:focus-visible {\n\tbackground: var(--color-primary-element-light-hover, var(--color-primary-element-light));\n}\n\n.cn-record-list__chevron {\n\tcolor: var(--color-text-maxcontrast);\n\tflex: none;\n}\n\n/* tiles (`tiles: true`, DqZaaktypeOverzicht \"Statussen\"): rows as framed\n tiles in a grid, the title at 14px regular. The selectors outrank the board\n look's list row rules. */\n.cn-record-list.cn-record-list--tiles .cn-record-list__list {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(260px, 1fr));\n\tgap: 8px;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item {\n\tborder-top: 0;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item .cn-record-list__row {\n\tbox-sizing: border-box;\n\theight: 100%;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 8px 10px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-radius: 8px;\n}\n\n.cn-record-list.cn-record-list--tiles .cn-record-list__list .cn-record-list__item .cn-record-list__title {\n\tfont-size: 14px;\n\tfont-weight: 400;\n}\n\n/* cards (board ShBank): a grid of framed cards, 240px at the least. */\n.cn-record-list--cards .cn-record-list__list {\n\talign-items: start;\n\tdisplay: grid;\n\tgap: 16px;\n\tgrid-template-columns: repeat(auto-fit, minmax(240px, 1fr));\n}\n\n.cn-record-list__card {\n\tbackground: var(--color-main-background);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 12px;\n\tbox-sizing: border-box;\n\tcolor: var(--color-main-text);\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tpadding: 16px 18px;\n\ttext-decoration: none;\n}\n\n.cn-record-list__card--link:hover,\n.cn-record-list__card--link:focus-visible {\n\tborder-color: var(--color-border-dark, var(--color-border));\n}\n\n.cn-record-list__card--link:hover .cn-record-list__title,\n.cn-record-list__card--link:focus-visible .cn-record-list__title {\n\ttext-decoration: underline;\n}\n\n.cn-record-list__card-head {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: 8px;\n\tjustify-content: space-between;\n}\n\n.cn-record-list__card-title {\n\talign-items: center;\n\tdisplay: flex;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-record-list__card-icon {\n\tcolor: var(--color-primary-element);\n\tflex: none;\n}\n\n.cn-record-list__card-pills {\n\tdisplay: flex;\n\tflex: none;\n\tgap: 6px;\n}\n\n.cn-record-list__card-value {\n\tfont-size: 24px;\n\tfont-weight: 700;\n}\n\n/* feed */\n.cn-record-list--feed .cn-record-list__item + .cn-record-list__item {\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-record-list__feed-row {\n\talign-items: flex-start;\n\tdisplay: flex;\n\tgap: 14px;\n\tpadding: 12px 0;\n}\n\n.cn-record-list__feed-icon {\n\talign-items: center;\n\tbackground: var(--color-primary-element-light);\n\tborder-radius: 50%;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n\tdisplay: flex;\n\tflex: none;\n\theight: 36px;\n\tjustify-content: center;\n\twidth: 36px;\n}\n\n.cn-record-list__text {\n\tfont-size: 15px;\n}\n\n.cn-record-list--feed .cn-record-list__main {\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n/* inline */\n.cn-record-list__inline-row {\n\tpadding: 4px 0;\n}\n\n.cn-record-list__label {\n\tmargin-inline-end: 4px;\n}\n\n.cn-record-list__inline-title {\n\tcolor: var(--color-main-text);\n}\n\na.cn-record-list__inline-title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n</style>\n\n<style>\n/* In a narrow side column a row stacks: title, meta, then pill and date. */\n.cn-detail-page__side .cn-record-list__row {\n\talign-items: flex-start;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-detail-page__side .cn-record-list__row .cn-record-list__title {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: underline;\n}\n\n.cn-detail-page__side .cn-record-list__chevron {\n\tdisplay: none;\n}\n\n/* A row is a touch target of at least 44px on a phone. */\n@media (max-width: 640px) {\n\t.cn-record-list__row {\n\t\tmin-height: 44px;\n\t}\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_toDisplayString","_createVNode","_Fragment","_renderList","_createElementVNode","_createTextVNode","_normalizeStyle","_createBlock","_openBlock","_resolveDynamicComponent","_mergeProps","_toHandlers"],"mappings":"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"}
|