@conduction/nextcloud-vue 2.83.0 → 2.85.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 +131 -3
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +54 -18
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +232 -4
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +95 -51
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue.js +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js +22 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +47 -4
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +239 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +5 -5
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +50 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -12
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +226 -8
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -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 +18 -5
- 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/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +38 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +45 -5
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +548 -77
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +191 -82
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +11 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js +29 -6
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +126 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +106 -3
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +67 -5
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +181 -124
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +135 -2
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +95 -43
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +5 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue.js +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +72 -5
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +33 -8
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +135 -11
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +17 -2
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +39 -6
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +140 -7
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +37 -9
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +6 -5
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue.js +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +16 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js +53 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js +3 -2
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +135 -0
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +19 -0
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +37 -19
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/composables/useListView.js +21 -0
- package/dist/esm/composables/useListView.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js +68 -6
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js +133 -105
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +38 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +78 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1030 -533
- package/dist/esm/store/useObjectStore.js +16 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +8 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +278 -0
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -0
- package/dist/esm/utils/buildManifest.js +41 -4
- package/dist/esm/utils/buildManifest.js.map +1 -1
- package/dist/esm/utils/detailWidgetVisibility.js +149 -0
- package/dist/esm/utils/detailWidgetVisibility.js.map +1 -0
- package/dist/esm/utils/formatMetric.js +39 -3
- package/dist/esm/utils/formatMetric.js.map +1 -1
- package/dist/esm/utils/gridStack.js +40 -1
- package/dist/esm/utils/gridStack.js.map +1 -1
- package/dist/esm/utils/humaniseKey.js +41 -0
- package/dist/esm/utils/humaniseKey.js.map +1 -0
- package/dist/esm/utils/notificationRuleLabel.js +6 -23
- package/dist/esm/utils/notificationRuleLabel.js.map +1 -1
- package/dist/esm/utils/resolveManifestTokens.js +1 -0
- package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +9 -0
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/widgetDispatch.js +8 -2
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +17159 -13422
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1030 -533
- package/l10n/en.json +38 -1
- package/l10n/nl.json +78 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +160 -8
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +1 -1
- package/src/components/CnBoardView/CnBoardView.vue +262 -6
- package/src/components/CnBodySections/CnBodySections.vue +22 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +47 -4
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +244 -8
- package/src/components/CnDashboardPage/CnDashboardPage.vue +62 -2
- package/src/components/CnDeltaWidget/CnDeltaWidget.vue +1 -1
- package/src/components/CnDetailPage/CnDetailPage.md +3 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +226 -8
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +3 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -5
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +63 -1
- package/src/components/CnGaugeWidget/CnGaugeWidget.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +586 -25
- package/src/components/CnIndexPage/useSelfFetchList.js +10 -1
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +29 -6
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +154 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +106 -3
- package/src/components/CnRegisterMapping/CnRegisterMapping.md +5 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +231 -96
- package/src/components/CnReportsPage/CnReportsPage.vue +179 -1
- package/src/components/CnSettingsPage/CnSettingsPage.vue +5 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +103 -6
- package/src/components/CnStatWidget/CnStatWidget.vue +137 -12
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +34 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +39 -6
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +140 -7
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.md +2 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +42 -13
- package/src/components/CnWalkthrough/CnWalkthrough.vue +16 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
- package/src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue +55 -2
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +135 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +10 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +44 -1
- package/src/composables/useListView.js +21 -0
- package/src/css/board.css +65 -4
- package/src/css/dialog.css +4 -2
- package/src/css/form-field.css +14 -0
- package/src/css/form-widget.css +11 -0
- package/src/css/index-page.css +49 -0
- package/src/css/kpi-card.css +13 -0
- package/src/css/look-board-reports.css +58 -0
- package/src/css/look-board.css +108 -7
- package/src/dialogs/CnTransitionInputDialog.vue +87 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +137 -6
- package/src/store/useObjectStore.js +16 -2
- package/src/utils/boardColumns.js +8 -1
- package/src/utils/boardReferenceColumns.js +274 -0
- package/src/utils/buildManifest.js +40 -3
- package/src/utils/detailWidgetVisibility.js +145 -0
- package/src/utils/formatMetric.js +38 -2
- package/src/utils/gridStack.js +39 -0
- package/src/utils/humaniseKey.js +38 -0
- package/src/utils/notificationRuleLabel.js +5 -23
- package/src/utils/resolveManifestTokens.js +1 -0
- package/src/utils/sentinelTokens.js +9 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/widgetDispatch.js +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWeekStripWidget.vue3.js","sources":["../../../../src/components/CnWeekStripWidget/CnWeekStripWidget.vue?vue&type=template&id=b6c5e274&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-week-strip\" :class=\"{ 'cn-week-strip--inset': inset }\" data-testid=\"cn-week-strip\">\n\t\t<div v-if=\"loading\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t<span class=\"cn-week-strip__state-text\">{{ loadingLabel }}</span>\n\t\t</div>\n\t\t<p v-else-if=\"error\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<!-- A scroll container a keyboard user cannot focus cannot be scrolled,\n\t\t so the region is focusable and named. -->\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-week-strip__scroll\"\n\t\t\trole=\"region\"\n\t\t\ttabindex=\"0\"\n\t\t\t:aria-label=\"regionLabel\">\n\t\t\t<ol class=\"cn-week-strip__days\" :style=\"{ '--cn-week-strip-columns': dayColumns.length }\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"day in dayColumns\"\n\t\t\t\t\t:key=\"day.key\"\n\t\t\t\t\tclass=\"cn-week-strip__day\"\n\t\t\t\t\t:class=\"{ 'cn-week-strip__day--today': day.today }\"\n\t\t\t\t\t:aria-current=\"day.today ? 'date' : null\"\n\t\t\t\t\t:data-day=\"day.key\">\n\t\t\t\t\t<span class=\"cn-week-strip__head\">\n\t\t\t\t\t\t<span class=\"cn-week-strip__label\">{{ day.label }}</span>\n\t\t\t\t\t\t<span v-if=\"day.today\" class=\"cn-week-strip__today\">{{ todayLabel }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<ul v-if=\"day.items.length > 0\" class=\"cn-week-strip__items\">\n\t\t\t\t\t\t<li v-for=\"item in day.shown\" :key=\"item.key\" class=\"cn-week-strip__item-row\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.href ? 'a' : 'div'\"\n\t\t\t\t\t\t\t\tclass=\"cn-week-strip__item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-week-strip__item--late': item.late, 'cn-week-strip__item--link': !!item.href }\"\n\t\t\t\t\t\t\t\t:href=\"item.href || null\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-week-strip-item\"\n\t\t\t\t\t\t\t\t@click=\"onItemClick($event, item)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-week-strip__title\">{{ item.title }}</strong>\n\t\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-week-strip__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"item.late\" class=\"cn-week-strip__late\">{{ lateLabel }}</span>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t\t<!-- `maxPerDay`: the rest of a full day sits behind \"+N more\": a link\n\t\t\t\t\t to `moreRoute`, or a button that opens the day in place. -->\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"day.hidden > 0 && moreHref\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:href=\"moreHref\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"onMoreClick($event)\">{{ moreLabel(day.hidden) }}</a>\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-else-if=\"day.hidden > 0 || day.expanded\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:aria-expanded=\"day.expanded ? 'true' : 'false'\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"toggleDay(day.key)\">\n\t\t\t\t\t\t{{ day.expanded ? lessLabel : moreLabel(day.hidden) }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<span v-if=\"day.items.length === 0\" class=\"cn-week-strip__empty\">{{ emptyLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { dayKey, daysUntil, parseDateValue } from '../../utils/dateVariant.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { objectDisplayName, objectFieldValue } from '../../utils/objectName.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { compareVisibleWhen } from '../../utils/visibleWhen.js'\n\nconst DEFAULT_LIMIT = 100\n\n/**\n * CnWeekStripWidget shows the current week as day columns, with the items\n * that fall on each day listed under it. Use it for deadlines, appointments\n * or anything else that has a date and that somebody should see coming.\n *\n * It renders the five working days by default (`days: 7` adds the weekend),\n * highlights today, marks items that are late, and says so when a day has\n * nothing. On a narrow screen the strip scrolls sideways.\n *\n * Items come from an OpenRegister source (one request for the whole week) or\n * from static `items`. Resolved by its registry type key `week-strip`.\n *\n * ```json\n * {\n * \"widgetKey\": \"week-strip\",\n * \"props\": {\n * \"content\": {\n * \"source\": { \"register\": \"dossiq\", \"schema\": \"case\", \"filter\": { \"assignee\": \"@me\" } },\n * \"dateField\": \"deadline\",\n * \"titleField\": \"title\",\n * \"metaFields\": [\"identifier\", \"caseType\"],\n * \"itemRoute\": \"CaseDetail\",\n * \"emptyText\": \"No deadlines\"\n * }\n * }\n * }\n * ```\n */\nexport default {\n\tname: 'CnWeekStripWidget',\n\n\tcomponents: { NcLoadingIcon },\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot. The manifest-authored\n\t\t * `emptyText` and static item texts run through it. Identity by default.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration. `days` is `5` (working days, the\n\t\t * default) or `7`. `source` names the OpenRegister register and schema,\n\t\t * with an optional `filter` (the shared @-token grammar) and `limit`.\n\t\t * `dateField` is the field the items are bucketed by. `titleField` and\n\t\t * `metaFields` pick what each item shows. `itemRoute` is the route name\n\t\t * an item links to (with the record id as `params.id`). `lateWhen` is a\n\t\t * `{ op, value }` rule on the days until the date (default: before\n\t\t * today), `lateField` a boolean field that marks a record late.\n\t\t * `items` are static entries `{ title, meta?, date, route?, href?, late? }`.\n\t\t * `emptyText` is the text of a day without items. `weekOffset` moves\n\t\t * the strip whole weeks from the current one. `inset: true` draws the\n\t\t * strip inside the board's inset (16px above, 24px at the sides, 22px\n\t\t * below) instead of from card edge to card edge. `maxPerDay` caps the\n\t\t * items a day shows; the rest sit behind \"+N more\", a link to\n\t\t * `moreRoute` (a route name or object) or, without one, a button that\n\t\t * opens the day in place. `moreLabel` replaces the text (`{count}` is\n\t\t * the number hidden).\n\t\t *\n\t\t * @type {{maxPerDay?: number, moreRoute?: (string|object), moreLabel?: string, days?: (5|7), inset?: boolean, source?: {register?: string, schema?: string, filter?: object, limit?: number}, dateField?: string, titleField?: string, metaFields?: Array<string>, itemRoute?: string, lateWhen?: {op?: string, value?: number}, lateField?: string, items?: Array<{title: string, meta?: string, date: string, route?: (string|object), href?: string, late?: boolean}>, emptyText?: string, weekOffset?: number}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`. Pass it\n\t\t * when mounting the widget outside a CnAppRoot.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The moment the strip treats as \"now\". Leave empty for the current\n\t\t * time; set it to render another week or to test.\n\t\t *\n\t\t * @type {Date|null}\n\t\t */\n\t\tnow: {\n\t\t\ttype: Date,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\trows: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\t/** The days opened past `maxPerDay`, by day key. */\n\t\t\texpandedDays: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the widget draws the board's inset (`content.inset`). Off\n\t\t * by default, which keeps it edge to edge as before.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-strip-and-a-stacked-bar-can-take-the-board-inset\n\t\t * @return {boolean}\n\t\t */\n\t\tinset() {\n\t\t\treturn Boolean(this.content && this.content.inset === true)\n\t\t},\n\n\t\t/**\n\t\t * The translate function in use.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn this.translate ?? this.cnTranslate\n\t\t},\n\n\t\t/**\n\t\t * The reference moment.\n\t\t *\n\t\t * @return {Date}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\treference() {\n\t\t\treturn this.now instanceof Date ? this.now : new Date()\n\t\t},\n\n\t\t/**\n\t\t * How many day columns render: 7, or 5 for anything else.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayCount() {\n\t\t\treturn Number(this.content.days) === 7 ? 7 : 5\n\t\t},\n\n\t\t/**\n\t\t * The days of the strip, Monday first.\n\t\t *\n\t\t * @return {Array<Date>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tweekDays() {\n\t\t\tconst ref = this.reference\n\t\t\tconst offset = Number.isInteger(this.content.weekOffset) ? this.content.weekOffset : 0\n\t\t\tconst mondayDelta = (ref.getDay() + 6) % 7\n\t\t\tconst days = []\n\t\t\tfor (let i = 0; i < this.dayCount; i++) {\n\t\t\t\tdays.push(new Date(ref.getFullYear(), ref.getMonth(), ref.getDate() - mondayDelta + (offset * 7) + i))\n\t\t\t}\n\t\t\treturn days\n\t\t},\n\n\t\t/**\n\t\t * The field the items are bucketed by.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdateField() {\n\t\t\treturn typeof this.content.dateField === 'string' ? this.content.dateField : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the items come from OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\thasSource() {\n\t\t\tconst s = this.content.source || {}\n\t\t\treturn Boolean(s.register && s.schema && this.dateField)\n\t\t},\n\n\t\t/**\n\t\t * Every item, from the source rows or the static list, in one shape.\n\t\t *\n\t\t * @return {Array<{key: string, title: string, meta: string, date: (Date|null), late: boolean, href: string, target: (object|string|null)}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tnormalizedItems() {\n\t\t\tif (this.hasSource) {\n\t\t\t\treturn this.rows.map((row, index) => this.itemFromRow(row, index))\n\t\t\t}\n\t\t\tconst items = Array.isArray(this.content.items) ? this.content.items : []\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && typeof item === 'object')\n\t\t\t\t.map((item, index) => this.itemFromStatic(item, index))\n\t\t},\n\n\t\t/**\n\t\t * The columns: one per day, each with its items.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, today: boolean, items: Array<object>}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayColumns() {\n\t\t\tconst todayKey = dayKey(this.reference)\n\t\t\tconst buckets = {}\n\t\t\tfor (const item of this.normalizedItems) {\n\t\t\t\tif (item.date === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst key = dayKey(item.date)\n\t\t\t\t;(buckets[key] = buckets[key] || []).push(item)\n\t\t\t}\n\t\t\tconst formatter = this.dayFormatter\n\t\t\treturn this.weekDays.map((day) => {\n\t\t\t\tconst key = dayKey(day)\n\t\t\t\tconst items = buckets[key] || []\n\t\t\t\tconst expanded = this.expandedDays[key] === true\n\t\t\t\tconst cap = this.maxPerDay > 0 && !expanded ? this.maxPerDay : items.length\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\tlabel: formatter.format(day),\n\t\t\t\t\ttoday: key === todayKey,\n\t\t\t\t\titems,\n\t\t\t\t\tshown: items.slice(0, cap),\n\t\t\t\t\thidden: Math.max(0, items.length - cap),\n\t\t\t\t\texpanded: expanded && this.maxPerDay > 0 && items.length > this.maxPerDay,\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The most items a day shows (`content.maxPerDay`), or 0 for no cap.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmaxPerDay() {\n\t\t\tconst value = Number(this.content.maxPerDay)\n\t\t\treturn Number.isInteger(value) && value > 0 ? value : 0\n\t\t},\n\n\t\t/**\n\t\t * Where \"+N more\" leads (`content.moreRoute`), or null to open the day in place.\n\t\t *\n\t\t * @return {object|null}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreTarget() {\n\t\t\tconst route = this.content.moreRoute\n\t\t\tif (typeof route === 'string' && route !== '') {\n\t\t\t\treturn { name: route }\n\t\t\t}\n\t\t\treturn route && typeof route === 'object' ? route : null\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The href of the \"+N more\" link, '' without a target.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreHref() {\n\t\t\treturn this.moreTarget ? (resolveHref(this.moreTarget, this.$router) || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text that closes an opened day.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tlessLabel() {\n\t\t\treturn t('nextcloud-vue', 'Show less')\n\t\t},\n\n\t\t/**\n\t\t * Formats a day as a short weekday and a day number (\"Mon 5\").\n\t\t *\n\t\t * @return {Intl.DateTimeFormat}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayFormatter() {\n\t\t\tlet locale\n\t\t\ttry {\n\t\t\t\tlocale = getCanonicalLocale()\n\t\t\t} catch {\n\t\t\t\tlocale = undefined\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale || undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t} catch {\n\t\t\t\treturn new Intl.DateTimeFormat(undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of a day without items.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\temptyLabel() {\n\t\t\tconst text = this.content.emptyText\n\t\t\treturn (typeof text === 'string' && text !== '')\n\t\t\t\t? this.effectiveTranslate(text)\n\t\t\t\t: t('nextcloud-vue', 'Nothing planned')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The badge on today's column.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\ttodayLabel() {\n\t\t\treturn t('nextcloud-vue', 'today')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The marker on a late item.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tlateLabel() {\n\t\t\treturn t('nextcloud-vue', 'Late')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The accessible name of the scrolling region.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tregionLabel() {\n\t\t\treturn t('nextcloud-vue', 'This week, day by day')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The loading text.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text shown when the items could not be loaded.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\terrorLabel() {\n\t\t\treturn t('nextcloud-vue', 'The items for this week could not be loaded.')\n\t\t},\n\n\t\t/**\n\t\t * Changes whenever a new fetch is needed.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tsourceKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\ts: this.content.source || {},\n\t\t\t\tf: this.dateField,\n\t\t\t\td: this.weekDays.length > 0 ? [dayKey(this.weekDays[0]), this.weekDays.length] : [],\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget */\n\t\tsourceKey() {\n\t\t\tthis.fetchItems()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.fetchItems()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a date counts as late under `content.lateWhen` (default:\n\t\t * before today).\n\t\t *\n\t\t * @param {Date|null} date The item's date.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tisLateDate(date) {\n\t\t\tif (date === null) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst rule = (this.content.lateWhen && typeof this.content.lateWhen === 'object')\n\t\t\t\t? this.content.lateWhen\n\t\t\t\t: { op: 'lt', value: 0 }\n\t\t\treturn compareVisibleWhen(daysUntil(date, this.reference), rule.op || 'lt', rule.value ?? 0)\n\t\t},\n\n\t\t/**\n\t\t * One OpenRegister record as a strip item.\n\t\t *\n\t\t * @param {object} row The record.\n\t\t * @param {number} index Its position, used as a key of last resort.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromRow(row, index) {\n\t\t\tconst c = this.content\n\t\t\tconst id = row && (row.id || (row['@self'] && row['@self'].id))\n\t\t\tconst date = parseDateValue(objectFieldValue(row, this.dateField))\n\t\t\tconst titleValue = c.titleField ? objectFieldValue(row, c.titleField) : undefined\n\t\t\tconst title = (titleValue !== undefined && titleValue !== null && titleValue !== '')\n\t\t\t\t? String(titleValue)\n\t\t\t\t: objectDisplayName(row)\n\t\t\tconst metaFields = Array.isArray(c.metaFields) ? c.metaFields : []\n\t\t\tconst meta = metaFields\n\t\t\t\t.map((field) => objectFieldValue(row, field))\n\t\t\t\t.filter((value) => value !== undefined && value !== null && value !== '' && typeof value !== 'object')\n\t\t\t\t.map(String)\n\t\t\t\t.join(' · ')\n\t\t\tconst flagged = c.lateField ? objectFieldValue(row, c.lateField) === true : false\n\t\t\tconst target = (c.itemRoute && id) ? { name: c.itemRoute, params: { id } } : null\n\t\t\treturn {\n\t\t\t\tkey: String(id || `row-${index}`),\n\t\t\t\ttitle,\n\t\t\t\tmeta,\n\t\t\t\tdate,\n\t\t\t\tlate: flagged || this.isLateDate(date),\n\t\t\t\ttarget,\n\t\t\t\thref: target ? resolveHref(target, this.$router) : '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * One static manifest entry as a strip item.\n\t\t *\n\t\t * @param {object} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromStatic(item, index) {\n\t\t\tconst date = parseDateValue(item.date)\n\t\t\tlet target = null\n\t\t\tlet href = ''\n\t\t\tif (item.route) {\n\t\t\t\ttarget = typeof item.route === 'string' ? { name: item.route } : item.route\n\t\t\t\thref = resolveHref(target, this.$router)\n\t\t\t} else if (typeof item.href === 'string' && item.href !== '') {\n\t\t\t\tconst safe = safeHref(item.href)\n\t\t\t\thref = safe === '#' ? '' : safe\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `item-${index}`,\n\t\t\t\ttitle: typeof item.title === 'string' ? this.effectiveTranslate(item.title) : '',\n\t\t\t\tmeta: typeof item.meta === 'string' ? this.effectiveTranslate(item.meta) : '',\n\t\t\t\tdate,\n\t\t\t\tlate: item.late === true || (item.late !== false && this.isLateDate(date)),\n\t\t\t\ttarget,\n\t\t\t\thref,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load the week's records in one request.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tasync fetchItems() {\n\t\t\tif (!this.hasSource) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.error = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst s = this.content.source\n\t\t\tconst requestKey = this.sourceKey\n\t\t\tconst first = this.weekDays[0]\n\t\t\tconst last = this.weekDays[this.weekDays.length - 1]\n\t\t\tconst dayAfter = new Date(last.getFullYear(), last.getMonth(), last.getDate() + 1)\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/{register}/{schema}',\n\t\t\t\t\t{ register: s.register, schema: s.schema },\n\t\t\t\t)\n\t\t\t\tconst params = {\n\t\t\t\t\t_limit: Number.isInteger(s.limit) && s.limit > 0 ? s.limit : DEFAULT_LIMIT,\n\t\t\t\t\t[`_order[${this.dateField}]`]: 'asc',\n\t\t\t\t}\n\t\t\t\tconst filter = resolveFilterTokens(s.filter || {}, {})\n\t\t\t\tfor (const [k, v] of Object.entries(filter || {})) {\n\t\t\t\t\tif (v && typeof v === 'object') {\n\t\t\t\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\t\t\t\tparams[`${k}[${op}]`] = ov\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The week window goes last, so a manifest filter on the date\n\t\t\t\t// field cannot widen the strip beyond the days it shows.\n\t\t\t\tparams[`${this.dateField}[gte]`] = dayKey(first)\n\t\t\t\tparams[`${this.dateField}[lt]`] = dayKey(dayAfter)\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tif (requestKey !== this.sourceKey) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.rows = (res && res.data && Array.isArray(res.data.results)) ? res.data.results : []\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnWeekStripWidget] failed to load items:', e)\n\t\t\t\tthis.error = (e && e.message) || 'error'\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of the \"+N more\" control: `content.moreLabel` with `{count}`\n\t\t * filled, else \"+N more\" from the library's catalogue.\n\t\t *\n\t\t * @param {number} count The number of hidden items.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreLabel(count) {\n\t\t\tconst own = this.content.moreLabel\n\t\t\tif (typeof own === 'string' && own !== '') {\n\t\t\t\treturn this.effectiveTranslate(own).replace(/\\{count\\}/g, String(count))\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '+{count} more', { count })\n\t\t},\n\n\t\t/**\n\t\t * Open or close a day past its cap.\n\t\t *\n\t\t * @param {string} key The day key.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\ttoggleDay(key) {\n\t\t\tthis.expandedDays = { ...this.expandedDays, [key]: this.expandedDays[key] !== true }\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on the \"+N more\" link.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tonMoreClick(event) {\n\t\t\tif (this.moreTarget) {\n\t\t\t\tfollowLinkClick(event, this.moreTarget, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on an in-app item; the browser handles the rest.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @param {object} item The clicked item.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tonItemClick(event, item) {\n\t\t\tif (item.target) {\n\t\t\t\tfollowLinkClick(event, item.target, this.$router)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-week-strip {\n\twidth: 100%;\n}\n\n/* `content.inset: true`: the board's inset inside the card (zuiddrecht-pixel-\n gaps-3). A dashboard renders its widgets flush, so without it the strip ran\n from card edge to card edge. Theme hook: --cn-widget-board-inset. */\n.cn-week-strip--inset {\n\tbox-sizing: border-box;\n\tpadding: var(--cn-widget-board-inset, 16px 24px 22px);\n}\n\n.cn-week-strip__state {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tpadding: 12px 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-week-strip__scroll {\n\toverflow-x: auto;\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-week-strip__scroll:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-week-strip__days {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-week-strip-columns, 5), minmax(128px, 1fr));\n\tgap: 10px;\n\t/* 5 columns of 128px plus gaps: below this the region scrolls sideways. */\n\tmin-width: calc(var(--cn-week-strip-columns, 5) * 136px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__day {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n\tpadding: 10px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-week-strip__day--today {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-week-strip__head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 6px;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-week-strip__today {\n\tpadding: 1px 8px;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tfont-size: 0.85em;\n\tfont-weight: 700;\n}\n\n.cn-week-strip__items {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-week-strip__item--link:hover {\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-week-strip__item--link:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* The edge is drawn inside the box, so a late item is as wide as the others. */\n.cn-week-strip__item--late {\n\tborder-color: var(--color-element-error, var(--color-error));\n\tbox-shadow: inset 3px 0 0 0 var(--color-element-error, var(--color-error));\n}\n\n.cn-week-strip__title {\n\tfont-size: 0.95em;\n\tline-height: 1.3;\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__meta {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__late {\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-error, var(--color-error-text));\n}\n\n.cn-week-strip__empty {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* \"+N more\" under a capped day: a quiet text control, 24px high to click. */\n.cn-week-strip__more {\n\talign-self: flex-start;\n\tmin-height: 24px;\n\tmargin: 0;\n\tpadding: 2px 4px;\n\tborder: 0;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground: transparent;\n\tcolor: var(--color-primary-element);\n\tfont: inherit;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n\n.cn-week-strip__more:hover {\n\ttext-decoration: underline;\n}\n\n.cn-week-strip__more:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnWeekStripWidget.vue3.js","sources":["../../../../src/components/CnWeekStripWidget/CnWeekStripWidget.vue?vue&type=template&id=27a717bd&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-week-strip\" :class=\"{ 'cn-week-strip--inset': inset }\" data-testid=\"cn-week-strip\">\n\t\t<div v-if=\"loading\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t<span class=\"cn-week-strip__state-text\">{{ loadingLabel }}</span>\n\t\t</div>\n\t\t<p v-else-if=\"error\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<!-- A scroll container a keyboard user cannot focus cannot be scrolled,\n\t\t so the region is focusable and named. -->\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-week-strip__scroll\"\n\t\t\trole=\"region\"\n\t\t\ttabindex=\"0\"\n\t\t\t:aria-label=\"regionLabel\">\n\t\t\t<ol class=\"cn-week-strip__days\" :style=\"{ '--cn-week-strip-columns': dayColumns.length }\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"day in dayColumns\"\n\t\t\t\t\t:key=\"day.key\"\n\t\t\t\t\tclass=\"cn-week-strip__day\"\n\t\t\t\t\t:class=\"{ 'cn-week-strip__day--today': day.today }\"\n\t\t\t\t\t:aria-current=\"day.today ? 'date' : null\"\n\t\t\t\t\t:data-day=\"day.key\">\n\t\t\t\t\t<span class=\"cn-week-strip__head\">\n\t\t\t\t\t\t<span class=\"cn-week-strip__label\">{{ day.label }}</span>\n\t\t\t\t\t\t<span v-if=\"day.today\" class=\"cn-week-strip__today\">{{ todayLabel }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<ul v-if=\"day.items.length > 0\" class=\"cn-week-strip__items\">\n\t\t\t\t\t\t<li v-for=\"item in day.shown\" :key=\"item.key\" class=\"cn-week-strip__item-row\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.href ? 'a' : 'div'\"\n\t\t\t\t\t\t\t\tclass=\"cn-week-strip__item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-week-strip__item--late': item.late, 'cn-week-strip__item--link': !!item.href }\"\n\t\t\t\t\t\t\t\t:href=\"item.href || null\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-week-strip-item\"\n\t\t\t\t\t\t\t\t@click=\"onItemClick($event, item)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-week-strip__title\">{{ item.title }}</strong>\n\t\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-week-strip__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"item.late\" class=\"cn-week-strip__late\">{{ lateLabel }}</span>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t\t<!-- `maxPerDay`: the rest of a full day sits behind \"+N more\": a link\n\t\t\t\t\t to `moreRoute`, or a button that opens the day in place. -->\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"day.hidden > 0 && moreHref\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:href=\"moreHref\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"onMoreClick($event)\">{{ moreLabel(day.hidden) }}</a>\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-else-if=\"day.hidden > 0 || day.expanded\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:aria-expanded=\"day.expanded ? 'true' : 'false'\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"toggleDay(day.key)\">\n\t\t\t\t\t\t{{ day.expanded ? lessLabel : moreLabel(day.hidden) }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<span v-if=\"day.items.length === 0\" class=\"cn-week-strip__empty\">{{ emptyLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { dayKey, daysUntil, parseDateValue } from '../../utils/dateVariant.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { objectDisplayName, objectFieldValue } from '../../utils/objectName.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { compareVisibleWhen } from '../../utils/visibleWhen.js'\n\nconst DEFAULT_LIMIT = 100\n\n/**\n * CnWeekStripWidget shows the current week as day columns, with the items\n * that fall on each day listed under it. Use it for deadlines, appointments\n * or anything else that has a date and that somebody should see coming.\n *\n * It renders the five working days by default (`days: 7` adds the weekend),\n * highlights today, marks items that are late, and says so when a day has\n * nothing. On a narrow screen the strip scrolls sideways; under the board\n * look (`.cn-look-board`) the days wrap into rows instead.\n *\n * Items come from an OpenRegister source (one request for the whole week) or\n * from static `items`. Resolved by its registry type key `week-strip`.\n *\n * ```json\n * {\n * \"widgetKey\": \"week-strip\",\n * \"props\": {\n * \"content\": {\n * \"source\": { \"register\": \"dossiq\", \"schema\": \"case\", \"filter\": { \"assignee\": \"@me\" } },\n * \"dateField\": \"deadline\",\n * \"titleField\": \"title\",\n * \"metaFields\": [\"identifier\", \"caseType\"],\n * \"itemRoute\": \"CaseDetail\",\n * \"emptyText\": \"No deadlines\"\n * }\n * }\n * }\n * ```\n */\nexport default {\n\tname: 'CnWeekStripWidget',\n\n\tcomponents: { NcLoadingIcon },\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot. The manifest-authored\n\t\t * `emptyText` and static item texts run through it. Identity by default.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration. `days` is `5` (working days, the\n\t\t * default) or `7`. `source` names the OpenRegister register and schema,\n\t\t * with an optional `filter` (the shared @-token grammar) and `limit`.\n\t\t * `dateField` is the field the items are bucketed by. `titleField` and\n\t\t * `metaFields` pick what each item shows. `itemRoute` is the route name\n\t\t * an item links to (with the record id as `params.id`). `lateWhen` is a\n\t\t * `{ op, value }` rule on the days until the date (default: before\n\t\t * today), `lateField` a boolean field that marks a record late.\n\t\t * `items` are static entries `{ title, meta?, date, route?, href?, late? }`.\n\t\t * `emptyText` is the text of a day without items. `weekOffset` moves\n\t\t * the strip whole weeks from the current one. `inset: true` draws the\n\t\t * strip inside the board's inset (16px above, 24px at the sides, 22px\n\t\t * below) instead of from card edge to card edge. `maxPerDay` caps the\n\t\t * items a day shows; the rest sit behind \"+N more\", a link to\n\t\t * `moreRoute` (a route name or object) or, without one, a button that\n\t\t * opens the day in place. `moreLabel` replaces the text (`{count}` is\n\t\t * the number hidden).\n\t\t *\n\t\t * @type {{maxPerDay?: number, moreRoute?: (string|object), moreLabel?: string, days?: (5|7), inset?: boolean, source?: {register?: string, schema?: string, filter?: object, limit?: number}, dateField?: string, titleField?: string, metaFields?: Array<string>, itemRoute?: string, lateWhen?: {op?: string, value?: number}, lateField?: string, items?: Array<{title: string, meta?: string, date: string, route?: (string|object), href?: string, late?: boolean}>, emptyText?: string, weekOffset?: number}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`. Pass it\n\t\t * when mounting the widget outside a CnAppRoot.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The moment the strip treats as \"now\". Leave empty for the current\n\t\t * time; set it to render another week or to test.\n\t\t *\n\t\t * @type {Date|null}\n\t\t */\n\t\tnow: {\n\t\t\ttype: Date,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\trows: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\t/** The days opened past `maxPerDay`, by day key. */\n\t\t\texpandedDays: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the widget draws the board's inset (`content.inset`). Off\n\t\t * by default, which keeps it edge to edge as before.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-strip-and-a-stacked-bar-can-take-the-board-inset\n\t\t * @return {boolean}\n\t\t */\n\t\tinset() {\n\t\t\treturn Boolean(this.content && this.content.inset === true)\n\t\t},\n\n\t\t/**\n\t\t * The translate function in use.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn this.translate ?? this.cnTranslate\n\t\t},\n\n\t\t/**\n\t\t * The reference moment.\n\t\t *\n\t\t * @return {Date}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\treference() {\n\t\t\treturn this.now instanceof Date ? this.now : new Date()\n\t\t},\n\n\t\t/**\n\t\t * How many day columns render: 7, or 5 for anything else.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayCount() {\n\t\t\treturn Number(this.content.days) === 7 ? 7 : 5\n\t\t},\n\n\t\t/**\n\t\t * The days of the strip, Monday first.\n\t\t *\n\t\t * @return {Array<Date>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tweekDays() {\n\t\t\tconst ref = this.reference\n\t\t\tconst offset = Number.isInteger(this.content.weekOffset) ? this.content.weekOffset : 0\n\t\t\tconst mondayDelta = (ref.getDay() + 6) % 7\n\t\t\tconst days = []\n\t\t\tfor (let i = 0; i < this.dayCount; i++) {\n\t\t\t\tdays.push(new Date(ref.getFullYear(), ref.getMonth(), ref.getDate() - mondayDelta + (offset * 7) + i))\n\t\t\t}\n\t\t\treturn days\n\t\t},\n\n\t\t/**\n\t\t * The field the items are bucketed by.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdateField() {\n\t\t\treturn typeof this.content.dateField === 'string' ? this.content.dateField : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the items come from OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\thasSource() {\n\t\t\tconst s = this.content.source || {}\n\t\t\treturn Boolean(s.register && s.schema && this.dateField)\n\t\t},\n\n\t\t/**\n\t\t * Every item, from the source rows or the static list, in one shape.\n\t\t *\n\t\t * @return {Array<{key: string, title: string, meta: string, date: (Date|null), late: boolean, href: string, target: (object|string|null)}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tnormalizedItems() {\n\t\t\tif (this.hasSource) {\n\t\t\t\treturn this.rows.map((row, index) => this.itemFromRow(row, index))\n\t\t\t}\n\t\t\tconst items = Array.isArray(this.content.items) ? this.content.items : []\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && typeof item === 'object')\n\t\t\t\t.map((item, index) => this.itemFromStatic(item, index))\n\t\t},\n\n\t\t/**\n\t\t * The columns: one per day, each with its items.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, today: boolean, items: Array<object>}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayColumns() {\n\t\t\tconst todayKey = dayKey(this.reference)\n\t\t\tconst buckets = {}\n\t\t\tfor (const item of this.normalizedItems) {\n\t\t\t\tif (item.date === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst key = dayKey(item.date)\n\t\t\t\t;(buckets[key] = buckets[key] || []).push(item)\n\t\t\t}\n\t\t\tconst formatter = this.dayFormatter\n\t\t\treturn this.weekDays.map((day) => {\n\t\t\t\tconst key = dayKey(day)\n\t\t\t\tconst items = buckets[key] || []\n\t\t\t\tconst expanded = this.expandedDays[key] === true\n\t\t\t\tconst cap = this.maxPerDay > 0 && !expanded ? this.maxPerDay : items.length\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\tlabel: formatter.format(day),\n\t\t\t\t\ttoday: key === todayKey,\n\t\t\t\t\titems,\n\t\t\t\t\tshown: items.slice(0, cap),\n\t\t\t\t\thidden: Math.max(0, items.length - cap),\n\t\t\t\t\texpanded: expanded && this.maxPerDay > 0 && items.length > this.maxPerDay,\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The most items a day shows (`content.maxPerDay`), or 0 for no cap.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmaxPerDay() {\n\t\t\tconst value = Number(this.content.maxPerDay)\n\t\t\treturn Number.isInteger(value) && value > 0 ? value : 0\n\t\t},\n\n\t\t/**\n\t\t * Where \"+N more\" leads (`content.moreRoute`), or null to open the day in place.\n\t\t *\n\t\t * @return {object|null}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreTarget() {\n\t\t\tconst route = this.content.moreRoute\n\t\t\tif (typeof route === 'string' && route !== '') {\n\t\t\t\treturn { name: route }\n\t\t\t}\n\t\t\treturn route && typeof route === 'object' ? route : null\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The href of the \"+N more\" link, '' without a target.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreHref() {\n\t\t\treturn this.moreTarget ? (resolveHref(this.moreTarget, this.$router) || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text that closes an opened day.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tlessLabel() {\n\t\t\treturn t('nextcloud-vue', 'Show less')\n\t\t},\n\n\t\t/**\n\t\t * Formats a day as a short weekday and a day number (\"Mon 5\").\n\t\t *\n\t\t * @return {Intl.DateTimeFormat}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayFormatter() {\n\t\t\tlet locale\n\t\t\ttry {\n\t\t\t\tlocale = getCanonicalLocale()\n\t\t\t} catch {\n\t\t\t\tlocale = undefined\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale || undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t} catch {\n\t\t\t\treturn new Intl.DateTimeFormat(undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of a day without items.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\temptyLabel() {\n\t\t\tconst text = this.content.emptyText\n\t\t\treturn (typeof text === 'string' && text !== '')\n\t\t\t\t? this.effectiveTranslate(text)\n\t\t\t\t: t('nextcloud-vue', 'Nothing planned')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The badge on today's column.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\ttodayLabel() {\n\t\t\treturn t('nextcloud-vue', 'today')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The marker on a late item.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tlateLabel() {\n\t\t\treturn t('nextcloud-vue', 'Late')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The accessible name of the scrolling region.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tregionLabel() {\n\t\t\treturn t('nextcloud-vue', 'This week, day by day')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The loading text.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text shown when the items could not be loaded.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\terrorLabel() {\n\t\t\treturn t('nextcloud-vue', 'The items for this week could not be loaded.')\n\t\t},\n\n\t\t/**\n\t\t * Changes whenever a new fetch is needed.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tsourceKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\ts: this.content.source || {},\n\t\t\t\tf: this.dateField,\n\t\t\t\td: this.weekDays.length > 0 ? [dayKey(this.weekDays[0]), this.weekDays.length] : [],\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget */\n\t\tsourceKey() {\n\t\t\tthis.fetchItems()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.fetchItems()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a date counts as late under `content.lateWhen` (default:\n\t\t * before today).\n\t\t *\n\t\t * @param {Date|null} date The item's date.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tisLateDate(date) {\n\t\t\tif (date === null) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst rule = (this.content.lateWhen && typeof this.content.lateWhen === 'object')\n\t\t\t\t? this.content.lateWhen\n\t\t\t\t: { op: 'lt', value: 0 }\n\t\t\treturn compareVisibleWhen(daysUntil(date, this.reference), rule.op || 'lt', rule.value ?? 0)\n\t\t},\n\n\t\t/**\n\t\t * One OpenRegister record as a strip item.\n\t\t *\n\t\t * @param {object} row The record.\n\t\t * @param {number} index Its position, used as a key of last resort.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromRow(row, index) {\n\t\t\tconst c = this.content\n\t\t\tconst id = row && (row.id || (row['@self'] && row['@self'].id))\n\t\t\tconst date = parseDateValue(objectFieldValue(row, this.dateField))\n\t\t\tconst titleValue = c.titleField ? objectFieldValue(row, c.titleField) : undefined\n\t\t\tconst title = (titleValue !== undefined && titleValue !== null && titleValue !== '')\n\t\t\t\t? String(titleValue)\n\t\t\t\t: objectDisplayName(row)\n\t\t\tconst metaFields = Array.isArray(c.metaFields) ? c.metaFields : []\n\t\t\tconst meta = metaFields\n\t\t\t\t.map((field) => objectFieldValue(row, field))\n\t\t\t\t.filter((value) => value !== undefined && value !== null && value !== '' && typeof value !== 'object')\n\t\t\t\t.map(String)\n\t\t\t\t.join(' · ')\n\t\t\tconst flagged = c.lateField ? objectFieldValue(row, c.lateField) === true : false\n\t\t\tconst target = (c.itemRoute && id) ? { name: c.itemRoute, params: { id } } : null\n\t\t\treturn {\n\t\t\t\tkey: String(id || `row-${index}`),\n\t\t\t\ttitle,\n\t\t\t\tmeta,\n\t\t\t\tdate,\n\t\t\t\tlate: flagged || this.isLateDate(date),\n\t\t\t\ttarget,\n\t\t\t\thref: target ? resolveHref(target, this.$router) : '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * One static manifest entry as a strip item.\n\t\t *\n\t\t * @param {object} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromStatic(item, index) {\n\t\t\tconst date = parseDateValue(item.date)\n\t\t\tlet target = null\n\t\t\tlet href = ''\n\t\t\tif (item.route) {\n\t\t\t\ttarget = typeof item.route === 'string' ? { name: item.route } : item.route\n\t\t\t\thref = resolveHref(target, this.$router)\n\t\t\t} else if (typeof item.href === 'string' && item.href !== '') {\n\t\t\t\tconst safe = safeHref(item.href)\n\t\t\t\thref = safe === '#' ? '' : safe\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `item-${index}`,\n\t\t\t\ttitle: typeof item.title === 'string' ? this.effectiveTranslate(item.title) : '',\n\t\t\t\tmeta: typeof item.meta === 'string' ? this.effectiveTranslate(item.meta) : '',\n\t\t\t\tdate,\n\t\t\t\tlate: item.late === true || (item.late !== false && this.isLateDate(date)),\n\t\t\t\ttarget,\n\t\t\t\thref,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load the week's records in one request.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tasync fetchItems() {\n\t\t\tif (!this.hasSource) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.error = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst s = this.content.source\n\t\t\tconst requestKey = this.sourceKey\n\t\t\tconst first = this.weekDays[0]\n\t\t\tconst last = this.weekDays[this.weekDays.length - 1]\n\t\t\tconst dayAfter = new Date(last.getFullYear(), last.getMonth(), last.getDate() + 1)\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/{register}/{schema}',\n\t\t\t\t\t{ register: s.register, schema: s.schema },\n\t\t\t\t)\n\t\t\t\tconst params = {\n\t\t\t\t\t_limit: Number.isInteger(s.limit) && s.limit > 0 ? s.limit : DEFAULT_LIMIT,\n\t\t\t\t\t[`_order[${this.dateField}]`]: 'asc',\n\t\t\t\t}\n\t\t\t\tconst filter = resolveFilterTokens(s.filter || {}, {})\n\t\t\t\tfor (const [k, v] of Object.entries(filter || {})) {\n\t\t\t\t\tif (v && typeof v === 'object') {\n\t\t\t\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\t\t\t\tparams[`${k}[${op}]`] = ov\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The week window goes last, so a manifest filter on the date\n\t\t\t\t// field cannot widen the strip beyond the days it shows.\n\t\t\t\tparams[`${this.dateField}[gte]`] = dayKey(first)\n\t\t\t\tparams[`${this.dateField}[lt]`] = dayKey(dayAfter)\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tif (requestKey !== this.sourceKey) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.rows = (res && res.data && Array.isArray(res.data.results)) ? res.data.results : []\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnWeekStripWidget] failed to load items:', e)\n\t\t\t\tthis.error = (e && e.message) || 'error'\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of the \"+N more\" control: `content.moreLabel` with `{count}`\n\t\t * filled, else \"+N more\" from the library's catalogue.\n\t\t *\n\t\t * @param {number} count The number of hidden items.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreLabel(count) {\n\t\t\tconst own = this.content.moreLabel\n\t\t\tif (typeof own === 'string' && own !== '') {\n\t\t\t\treturn this.effectiveTranslate(own).replace(/\\{count\\}/g, String(count))\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '+{count} more', { count })\n\t\t},\n\n\t\t/**\n\t\t * Open or close a day past its cap.\n\t\t *\n\t\t * @param {string} key The day key.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\ttoggleDay(key) {\n\t\t\tthis.expandedDays = { ...this.expandedDays, [key]: this.expandedDays[key] !== true }\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on the \"+N more\" link.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tonMoreClick(event) {\n\t\t\tif (this.moreTarget) {\n\t\t\t\tfollowLinkClick(event, this.moreTarget, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on an in-app item; the browser handles the rest.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @param {object} item The clicked item.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tonItemClick(event, item) {\n\t\t\tif (item.target) {\n\t\t\t\tfollowLinkClick(event, item.target, this.$router)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-week-strip {\n\twidth: 100%;\n}\n\n/* `content.inset: true`: the board's inset inside the card (zuiddrecht-pixel-\n gaps-3). A dashboard renders its widgets flush, so without it the strip ran\n from card edge to card edge. Theme hook: --cn-widget-board-inset. */\n.cn-week-strip--inset {\n\tbox-sizing: border-box;\n\tpadding: var(--cn-widget-board-inset, 16px 24px 22px);\n}\n\n.cn-week-strip__state {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tpadding: 12px 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-week-strip__scroll {\n\toverflow-x: auto;\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-week-strip__scroll:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-week-strip__days {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-week-strip-columns, 5), minmax(128px, 1fr));\n\tgap: 10px;\n\t/* 5 columns of 128px plus gaps: below this the region scrolls sideways. */\n\tmin-width: calc(var(--cn-week-strip-columns, 5) * 136px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__day {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n\tpadding: 10px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-week-strip__day--today {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-week-strip__head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 6px;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-week-strip__today {\n\tpadding: 1px 8px;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tfont-size: 0.85em;\n\tfont-weight: 700;\n}\n\n.cn-week-strip__items {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-week-strip__item--link:hover {\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-week-strip__item--link:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* The edge is drawn inside the box, so a late item is as wide as the others. */\n.cn-week-strip__item--late {\n\tborder-color: var(--color-element-error, var(--color-error));\n\tbox-shadow: inset 3px 0 0 0 var(--color-element-error, var(--color-error));\n}\n\n.cn-week-strip__title {\n\tfont-size: 0.95em;\n\tline-height: 1.3;\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__meta {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__late {\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-error, var(--color-error-text));\n}\n\n.cn-week-strip__empty {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* \"+N more\" under a capped day: a quiet text control, 24px high to click. */\n.cn-week-strip__more {\n\talign-self: flex-start;\n\tmin-height: 24px;\n\tmargin: 0;\n\tpadding: 2px 4px;\n\tborder: 0;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground: transparent;\n\tcolor: var(--color-primary-element);\n\tfont: inherit;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n\n.cn-week-strip__more:hover {\n\ttext-decoration: underline;\n}\n\n.cn-week-strip__more:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":";;;;AAUuB,EAAA,KAAI,EAAC,sBAAsB;AAAA,EAAA,IAAK,EAAC,QAAQ;;AAE3D,MAAA,UAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;AAEiB,EAAA,KAAM,EAAC,sBAAkB;AAAA,EAAA,IAAA,EAAA,QAAA;;;;AAmBpC,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,qBAAqB,GAAA;AAC1B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;;AACxB,EAAA,KAAA,EAAA,sBAAA;;;;AAEkB,EAAA,KAAA,EAAA,sBAAA;;AASxB,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,sBAAA,GAAA;;;AACD,EAAA,KAAA,EAAA,qBAAA;;;;AACuB,EAAA,KAAG,EAAE,qBAAqB;;;;;;AAqBpD,EAAA,KAAA,EAAA,sBAAA;;;;;;;IA5DA,KAAC,EAAAA,cAAA,CAAA,CAAA,eAAA,EAAA,EAAA,sBAAA,EAAA,QAAA,CAAA,KAAA,EAAA,CAAA,CAAA;AAAA,IAAA,aAAA,EAAA,eAAA;;KACM,KAAO,CAAA,OAAA;AAAlB,SAAAC,SAAA,EAAA,EAAAC,kBAAA,CAGO,OAHP,UAGO,EAAA;UAFNC,WAAe,CAAA,wBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;UACfC,kBAAE,CAAA,MAAA,EAAF,UAAE,EAAAC,eAAA,CAAA,QAAA,CAAA,YAAA,CAAA,EAAA,CAAA,YAAA;;SAEW,KAAK,CAAA,KAAA;wBAAdH,kBAED,CAAA,GAAA,EAFC,UAED,EAAAG,eAAA,CADD,QAAA,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;;;AAMF,YAAA,KAAK,EAAC,uBAAuB;AAC5B,YAAA,IAAE,EAAA,QAAA;oBACK,EAAC,GAAI;wBACF,EAAE,QAAE,CAAA,WAAA;;;AACX,cAAA,KAAK,EAAC,qBAAiB;cAAA,KAAA,EAAAC,cAAA,CAAA,EAAA,yBAAA,EAAA,QAAA,CAAA,UAAA,CAAA,MAAA,EAAA,CAAA;;8EAEX,QAAS,CAAA,UAAA,EAAA,CAAhB,GAAG,KAAA;;kBACT,GAAG,EAAE,GAAG,CAAC,GAAG;AACb,kBAAA,KAAI,EAAEN,cAAA,CAAA,CAAA,oBAAoB,EACa,EAAA,2BAAA,EAAA,GAAG,CAAC,KAAI,EAAA,CAAA,CAAA;kBAC9C,cAAY,EAAE,GAAG,CAAC,KAAK,GAAA,MAAA,GAAA,IAAA;kBACvB,UAAK,EAAA,GAAA,CAAA,GAAA;;AACN,kBAAAI,kBAAA,CAGO,QAHP,UAGO,EAAA;AAFN,oBAAAA,kBAAA,CAAyD,MAAzD,EAAA,UAAyD,EAAnBC,eAAA,CAAA,GAAG,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;AACrC,oBAAA,CAAA,GAAA,CAAA,KAAA;sCAATH,kBAAS,CAAA,MAAA,EAAT,UAAS,EAAAG,eAAA,CAAA,QAAA,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;;;mBAED,GAAG,CAAC,KAAK,CAAC,MAAM,GAAA,CAAA;uDAcrB,gBAAA,EAAA;AAbF,yBAAAJ,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,CAYFK,QAZmB,EAAA,IAAA,EAAAC,UAAA,CAAA,GAAG,CAAC,KAAK,GAAhB,IAAG,KAAA;+CAAbN,kBAYF,CAAA,IAAA,EAAA;4BAZ+B,GAAG,EAAE,IAAG,CAAE,GAAG;AAAE,4BAAA,KAAM,EAAA,yBAAyB;;qDAWhE,CAAAO,uBAAA,CATN,IAAI,CAAC,IAAI,GAAA,GAAA,GAAA,KAAA,CAAA,EAAA;8BACd,KAAK,EAAAT,cAAA,CAAA,CAAC,qBAAoB,EACY,EAAA,2BAAA,EAAA,IAAK,CAAC,IAAI,EAAA,2BAAA,EAAA,CAAA,CAAa,IAAA,CAAA,IAAA,EAAA,CAAA,CAAA;8BAC5D,IAAG,EAAG,IAAI,CAAC,IAAI,IAAA,IAAA;AAChB,8BAAA,aAAW,EAAC,oBAAoB;AAC/B,8BAAA,OAAK,EAAE,MAAA,KAAA,QAAA,CAAA,WAAE,CAAA,MAAA,EAAA,IAAA,CAAA,CAAA;;+CACV,MAAE;AAAF,gCAAAI,kBAAA,CAAE,QAAF,EAAA,WAAE,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AACD,gCAAA,CAAA,IAAA,CAAA,IAAA;AAAD,qCAAAJ,SAAA,EAAA,EAAAC,kBAAA,CAAC,MAAD,EAAA,WAAC,EAAAG,eAAA,CAAA,IAAA,CAAA,IAAA,CAAA,EAAA,CAAA,YAAA;;AACW,gCAAA,CAAA,IAAI,CAAC,IAAI;kDAArBH,kBAAkE,CAAA,MAAA,EAAlE,WAAkE,EAAAG,eAAA,CAAZ,QAAS,CAAA,SAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;mBAO3D,GAAG,CAAC,MAAM,GAAA,CAAA,IAAQ,QAAQ,CAAA,QAAA;oCADhCH,kBAK0B,CAAA,GAAA,EAAA;;AAH1B,wBAAA,KAAK,EAAA,qBAAA;AACJ,wBAAA,IAAI,EAAE,QAAQ,CAAA,QAAA;AACf,wBAAA,aAAW,EAAC,oBAAA;wBACX,OAAK,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,QAAW,CAAA,WAAA,CAAC,MAAM,CAAA,CAAA,CAAA;yCAAA,QAAA,CAAA,SAAA,CAAA,GAAA,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;AAEf,sBAAA,CAAA,GAAG,CAAC,MAAM,GAAQ,CAAA,IAAA,GAAE,CAAA,QAAA;sCAD/BA,kBAQC,CAAA,QAAA,EAAA;;AAND,0BAAA,IAAI,EAAC,QAAQ;AACb,0BAAA,KAAK,EAAC;0BACL,eAAM,EAAA,GAAA,CAAA,QAAA,GAAA,MAAA,GAAA,OAAA;AACP,0BAAA,aAAW,EAAC,oBAAoB;AAC/B,0BAAA,OAAC,EAAA,MAAA,KAAA,QAAA,CAAA,SAAA,CAAA,GAAA,CAAA,GAAA,CAAA,CAAA;2CACD,GAAA,CAAA,QAAA,GAAA,QAAA,CAAA,SAAA,GAAA,QAAA,CAAA,SAAA,CAAA,GAAA,CAAA,MAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;;mBAED,GAAA,CAAA,KAAA,CAAA,MAAA,KAAA,CAAA;oCAADA,kBAAC,CAAA,MAAA,EAAD,WAAC,EAAAG,eAAA,CAAA,QAAA,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { translate } from '@nextcloud/l10n';
|
|
2
|
+
import { inject, ref } from 'vue';
|
|
2
3
|
import __sfc_main from '../CnObjectCard/CnObjectCard.vue.js';
|
|
4
|
+
import { useEndpointSource } from '../../composables/useEndpointSource.js';
|
|
5
|
+
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js';
|
|
3
6
|
import __sfc_main$1 from '../CnWidgetWrapper/CnWidgetWrapper.vue.js';
|
|
4
7
|
|
|
5
8
|
/**
|
|
@@ -8,7 +11,9 @@ import __sfc_main$1 from '../CnWidgetWrapper/CnWidgetWrapper.vue.js';
|
|
|
8
11
|
* Renders the card grid on the shared CnWidgetWrapper chrome, which supplies
|
|
9
12
|
* the widget title and the standard overflow Actions menu (Refresh /
|
|
10
13
|
* Documentation / Request a feature). Each entry in `objects` is rendered as a
|
|
11
|
-
* CnObjectCard.
|
|
14
|
+
* CnObjectCard. Without `objects`, an `endpointSource` (`{ url, method?,
|
|
15
|
+
* params?, responsePath? }`, as on the object table) supplies them: the
|
|
16
|
+
* payload after `responsePath` is the array of objects.
|
|
12
17
|
*/
|
|
13
18
|
var script = {
|
|
14
19
|
name: 'CnWidgetCardGrid',
|
|
@@ -48,6 +53,53 @@ var script = {
|
|
|
48
53
|
type: Array,
|
|
49
54
|
default: () => [],
|
|
50
55
|
},
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Read the objects from an app endpoint: `{ url, method?, params?,
|
|
59
|
+
* responsePath? }`, with the token grammar of widget filters. Ignored
|
|
60
|
+
* while `objects` holds any.
|
|
61
|
+
*
|
|
62
|
+
* @type {object|null}
|
|
63
|
+
*/
|
|
64
|
+
endpointSource: {
|
|
65
|
+
type: Object,
|
|
66
|
+
default: null,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
setup(props) {
|
|
71
|
+
const objectCtxRaw = inject('cnObjectContext', null);
|
|
72
|
+
const detailCtxRaw = inject('cnDetailObjectContext', null);
|
|
73
|
+
const workspaceRaw = inject('cnWorkspaceContext', ref(null));
|
|
74
|
+
const appConfigRaw = inject('cnAppConfig', ref({}));
|
|
75
|
+
const unwrap = (v) => ((v && typeof v === 'object' && 'value' in v) ? v.value : v);
|
|
76
|
+
const { data, loading } = useEndpointSource(
|
|
77
|
+
() => ((props.objects && props.objects.length > 0) ? null : props.endpointSource),
|
|
78
|
+
{
|
|
79
|
+
ctx: () => ({
|
|
80
|
+
...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),
|
|
81
|
+
workspace: unwrap(workspaceRaw) || {},
|
|
82
|
+
config: unwrap(appConfigRaw) || {},
|
|
83
|
+
}),
|
|
84
|
+
widgetId: () => props.widgetId,
|
|
85
|
+
},
|
|
86
|
+
);
|
|
87
|
+
return { epData: data, epLoading: loading }
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
computed: {
|
|
91
|
+
/**
|
|
92
|
+
* The objects drawn: `objects` when given, else the endpoint's array.
|
|
93
|
+
*
|
|
94
|
+
* @return {Array<object>}
|
|
95
|
+
* @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
|
|
96
|
+
*/
|
|
97
|
+
cards() {
|
|
98
|
+
if (this.objects && this.objects.length > 0) {
|
|
99
|
+
return this.objects
|
|
100
|
+
}
|
|
101
|
+
return Array.isArray(this.epData) ? this.epData : []
|
|
102
|
+
},
|
|
51
103
|
},
|
|
52
104
|
};
|
|
53
105
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWidgetCardGrid.vue2.js","sources":["../../../../src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue"],"sourcesContent":["<!--\n CnWidgetCardGrid — built-in v2 widget rendering a grid of CnObjectCard items.\n\n Referenced in v2 manifests via `widgetKey: \"card-grid\"`. Renders the grid on\n the shared CnWidgetWrapper chrome (title + standard overflow Actions menu:\n Refresh / Documentation / Request a feature) and renders each item in\n `objects` as a CnObjectCard, replacing the v1.3.0 `cardComponent` field\n pattern.\n\n Spec: REQ-MVR-010 (manifest-v2-renderer) — built-in widget: card-grid\n-->\n<template>\n\t<CnWidgetWrapper\n\t\t:title=\"title\"\n\t\t:widgetId=\"widgetId\"\n\t\t:documentationUrl=\"documentationUrl\"\n\t\tflush>\n\t\t<div class=\"cn-widget-card-grid\">\n\t\t\t<CnObjectCard\n\t\t\t\tv-for=\"(item, index) in
|
|
1
|
+
{"version":3,"file":"CnWidgetCardGrid.vue2.js","sources":["../../../../src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue"],"sourcesContent":["<!--\n CnWidgetCardGrid — built-in v2 widget rendering a grid of CnObjectCard items.\n\n Referenced in v2 manifests via `widgetKey: \"card-grid\"`. Renders the grid on\n the shared CnWidgetWrapper chrome (title + standard overflow Actions menu:\n Refresh / Documentation / Request a feature) and renders each item in\n `objects` as a CnObjectCard, replacing the v1.3.0 `cardComponent` field\n pattern.\n\n Spec: REQ-MVR-010 (manifest-v2-renderer) — built-in widget: card-grid\n-->\n<template>\n\t<CnWidgetWrapper\n\t\t:title=\"title\"\n\t\t:widgetId=\"widgetId\"\n\t\t:documentationUrl=\"documentationUrl\"\n\t\t:refreshing=\"epLoading\"\n\t\tflush>\n\t\t<div class=\"cn-widget-card-grid\">\n\t\t\t<CnObjectCard\n\t\t\t\tv-for=\"(item, index) in cards\"\n\t\t\t\t:key=\"item.id || index\"\n\t\t\t\t:object=\"item\" />\n\t\t</div>\n\t</CnWidgetWrapper>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { inject, ref } from 'vue'\nimport CnObjectCard from '../CnObjectCard/CnObjectCard.vue'\nimport { useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'\nimport { CnWidgetWrapper } from '../CnWidgetWrapper/index.js'\n\n/**\n * CnWidgetCardGrid — built-in v2 widget rendering a grid of CnObjectCard items.\n *\n * Renders the card grid on the shared CnWidgetWrapper chrome, which supplies\n * the widget title and the standard overflow Actions menu (Refresh /\n * Documentation / Request a feature). Each entry in `objects` is rendered as a\n * CnObjectCard. Without `objects`, an `endpointSource` (`{ url, method?,\n * params?, responsePath? }`, as on the object table) supplies them: the\n * payload after `responsePath` is the array of objects.\n */\nexport default {\n\tname: 'CnWidgetCardGrid',\n\n\tcomponents: { CnObjectCard, CnWidgetWrapper },\n\n\tprops: {\n\t\t/**\n\t\t * Widget title shown in the CnWidgetWrapper header.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Items'),\n\t\t},\n\n\t\t/**\n\t\t * Documentation link surfaced in the widget's overflow Actions menu.\n\t\t * Empty (the default) hides the Documentation item; the Refresh and\n\t\t * Request-a-feature items always render.\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded to the widget chrome for the Refresh /\n\t\t * Request-a-feature payloads.\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Array of object records to render as cards. */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Read the objects from an app endpoint: `{ url, method?, params?,\n\t\t * responsePath? }`, with the token grammar of widget filters. Ignored\n\t\t * while `objects` holds any.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tendpointSource: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tsetup(props) {\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst detailCtxRaw = inject('cnDetailObjectContext', null)\n\t\tconst workspaceRaw = inject('cnWorkspaceContext', ref(null))\n\t\tconst appConfigRaw = inject('cnAppConfig', ref({}))\n\t\tconst unwrap = (v) => ((v && typeof v === 'object' && 'value' in v) ? v.value : v)\n\t\tconst { data, loading } = useEndpointSource(\n\t\t\t() => ((props.objects && props.objects.length > 0) ? null : props.endpointSource),\n\t\t\t{\n\t\t\t\tctx: () => ({\n\t\t\t\t\t...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),\n\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\tconfig: unwrap(appConfigRaw) || {},\n\t\t\t\t}),\n\t\t\t\twidgetId: () => props.widgetId,\n\t\t\t},\n\t\t)\n\t\treturn { epData: data, epLoading: loading }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The objects drawn: `objects` when given, else the endpoint's array.\n\t\t *\n\t\t * @return {Array<object>}\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\tcards() {\n\t\t\tif (this.objects && this.objects.length > 0) {\n\t\t\t\treturn this.objects\n\t\t\t}\n\t\t\treturn Array.isArray(this.epData) ? this.epData : []\n\t\t},\n\t},\n}\n</script>\n\n<style>\n.cn-widget-card-grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n\tgap: calc(2 * var(--default-grid-baseline, 4px));\n}\n</style>\n"],"names":["CnObjectCard","CnWidgetWrapper","t"],"mappings":";;;;;;;AAmCA;AACC;AACA;AACA;;AAEA;AACA;;;;AAID,aAAe;CACd,IAAI,EAAE,kBAAkB;;AAExB,CAAA,UAAU,EAAE,gBAAEA,UAAY,mBAAEC,cAAiB;;AAE7C,CAAA,KAAK,EAAE;AACN;AACC;;AAED,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,OAAO,CAAC;GAC1C;;AAED;;;AAGC;;AAED,EAAA,gBAAgB,EAAE;GACjB,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;AAIA,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;AACA,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;;;;AAIC;AACA;;AAED,EAAA,cAAc,EAAE;GACf,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;EACD;;CAED,KAAK,CAAC,KAAK,EAAE;EACZ,MAAM,YAAW,GAAI,MAAM,CAAC,iBAAiB,EAAE,IAAI,EAAA;EACnD,MAAM,YAAW,GAAI,MAAM,CAAC,uBAAuB,EAAE,IAAI,EAAA;EACzD,MAAM,YAAa,GAAE,MAAM,CAAC,oBAAoB,EAAE,GAAG,CAAC,IAAI,CAAC,EAAA;EAC3D,MAAM,YAAW,GAAI,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,EAAE,CAAC,EAAA;AAClD,EAAA,MAAM,MAAK,GAAI,CAAC,CAAC,MAAM,CAAC,CAAE,IAAG,OAAO,CAAA,KAAM,QAAS,IAAG,OAAM,IAAK,CAAC,IAAI,CAAC,CAAC,KAAI,GAAI,CAAC,EAAA;AACjF,EAAA,MAAM,EAAE,IAAI,EAAE,OAAM,EAAI,GAAE,iBAAiB;AAC1C,GAAA,OAAO,CAAC,KAAK,CAAC,OAAM,IAAK,KAAK,CAAC,OAAO,CAAC,MAAK,GAAI,CAAC,IAAI,IAAK,GAAE,KAAK,CAAC,cAAc,CAAC;AACjF,GAAA;AACC,IAAA,GAAG,EAAE,OAAO;KACX,IAAI,yBAAyB,CAAC,YAAY,EAAE,YAAY,CAAA,IAAK,EAAE,CAAC;AAChE,KAAA,SAAS,EAAE,MAAM,CAAC,YAAY,CAAA,IAAK,EAAE;AACrC,KAAA,MAAM,EAAE,MAAM,CAAC,YAAY,CAAA,IAAK,EAAE;AACnC,KAAC,CAAC;IACF,QAAQ,EAAE,MAAM,KAAK,CAAC,QAAQ;IAC9B;AACF,IAAA;AACA,EAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAQ,EAAA;EAC1C;;AAED,CAAA,QAAQ,EAAE;AACT;;AAEC;;AAEA;;AAED,EAAA,KAAK,GAAG;AACP,GAAA,IAAI,IAAI,CAAC,OAAQ,IAAG,IAAI,CAAC,OAAO,CAAC,MAAO,GAAE,CAAC,EAAE;AAC5C,IAAA,OAAO,IAAI,CAAC,OAAM;AACnB,IAAA;GACA,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAA,GAAI,IAAI,CAAC,MAAK,GAAI,EAAC;GACnD;EACD;AACF;;;;"}
|
|
@@ -10,11 +10,12 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
10
10
|
title: $props.title,
|
|
11
11
|
widgetId: $props.widgetId,
|
|
12
12
|
documentationUrl: $props.documentationUrl,
|
|
13
|
+
refreshing: $setup.epLoading,
|
|
13
14
|
flush: ""
|
|
14
15
|
}, {
|
|
15
16
|
default: withCtx(() => [
|
|
16
17
|
createElementVNode("div", _hoisted_1, [
|
|
17
|
-
(openBlock(true), createElementBlock(Fragment, null, renderList($
|
|
18
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.cards, (item, index) => {
|
|
18
19
|
return (openBlock(), createBlock(_component_CnObjectCard, {
|
|
19
20
|
key: item.id || index,
|
|
20
21
|
object: item
|
|
@@ -23,7 +24,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
23
24
|
])
|
|
24
25
|
]),
|
|
25
26
|
_: 1 /* STABLE */
|
|
26
|
-
}, 8 /* PROPS */, ["title", "widgetId", "documentationUrl"]))
|
|
27
|
+
}, 8 /* PROPS */, ["title", "widgetId", "documentationUrl", "refreshing"]))
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export { render };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWidgetCardGrid.vue3.js","sources":["../../../../src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue?vue&type=template&id=
|
|
1
|
+
{"version":3,"file":"CnWidgetCardGrid.vue3.js","sources":["../../../../src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue?vue&type=template&id=4c7ebb07&lang.js"],"sourcesContent":["<!--\n CnWidgetCardGrid — built-in v2 widget rendering a grid of CnObjectCard items.\n\n Referenced in v2 manifests via `widgetKey: \"card-grid\"`. Renders the grid on\n the shared CnWidgetWrapper chrome (title + standard overflow Actions menu:\n Refresh / Documentation / Request a feature) and renders each item in\n `objects` as a CnObjectCard, replacing the v1.3.0 `cardComponent` field\n pattern.\n\n Spec: REQ-MVR-010 (manifest-v2-renderer) — built-in widget: card-grid\n-->\n<template>\n\t<CnWidgetWrapper\n\t\t:title=\"title\"\n\t\t:widgetId=\"widgetId\"\n\t\t:documentationUrl=\"documentationUrl\"\n\t\t:refreshing=\"epLoading\"\n\t\tflush>\n\t\t<div class=\"cn-widget-card-grid\">\n\t\t\t<CnObjectCard\n\t\t\t\tv-for=\"(item, index) in cards\"\n\t\t\t\t:key=\"item.id || index\"\n\t\t\t\t:object=\"item\" />\n\t\t</div>\n\t</CnWidgetWrapper>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { inject, ref } from 'vue'\nimport CnObjectCard from '../CnObjectCard/CnObjectCard.vue'\nimport { useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'\nimport { CnWidgetWrapper } from '../CnWidgetWrapper/index.js'\n\n/**\n * CnWidgetCardGrid — built-in v2 widget rendering a grid of CnObjectCard items.\n *\n * Renders the card grid on the shared CnWidgetWrapper chrome, which supplies\n * the widget title and the standard overflow Actions menu (Refresh /\n * Documentation / Request a feature). Each entry in `objects` is rendered as a\n * CnObjectCard. Without `objects`, an `endpointSource` (`{ url, method?,\n * params?, responsePath? }`, as on the object table) supplies them: the\n * payload after `responsePath` is the array of objects.\n */\nexport default {\n\tname: 'CnWidgetCardGrid',\n\n\tcomponents: { CnObjectCard, CnWidgetWrapper },\n\n\tprops: {\n\t\t/**\n\t\t * Widget title shown in the CnWidgetWrapper header.\n\t\t */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Items'),\n\t\t},\n\n\t\t/**\n\t\t * Documentation link surfaced in the widget's overflow Actions menu.\n\t\t * Empty (the default) hides the Documentation item; the Refresh and\n\t\t * Request-a-feature items always render.\n\t\t */\n\t\tdocumentationUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Stable id forwarded to the widget chrome for the Refresh /\n\t\t * Request-a-feature payloads.\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Array of object records to render as cards. */\n\t\tobjects: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Read the objects from an app endpoint: `{ url, method?, params?,\n\t\t * responsePath? }`, with the token grammar of widget filters. Ignored\n\t\t * while `objects` holds any.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tendpointSource: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tsetup(props) {\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst detailCtxRaw = inject('cnDetailObjectContext', null)\n\t\tconst workspaceRaw = inject('cnWorkspaceContext', ref(null))\n\t\tconst appConfigRaw = inject('cnAppConfig', ref({}))\n\t\tconst unwrap = (v) => ((v && typeof v === 'object' && 'value' in v) ? v.value : v)\n\t\tconst { data, loading } = useEndpointSource(\n\t\t\t() => ((props.objects && props.objects.length > 0) ? null : props.endpointSource),\n\t\t\t{\n\t\t\t\tctx: () => ({\n\t\t\t\t\t...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),\n\t\t\t\t\tworkspace: unwrap(workspaceRaw) || {},\n\t\t\t\t\tconfig: unwrap(appConfigRaw) || {},\n\t\t\t\t}),\n\t\t\t\twidgetId: () => props.widgetId,\n\t\t\t},\n\t\t)\n\t\treturn { epData: data, epLoading: loading }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The objects drawn: `objects` when given, else the endpoint's array.\n\t\t *\n\t\t * @return {Array<object>}\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\tcards() {\n\t\t\tif (this.objects && this.objects.length > 0) {\n\t\t\t\treturn this.objects\n\t\t\t}\n\t\t\treturn Array.isArray(this.epData) ? this.epData : []\n\t\t},\n\t},\n}\n</script>\n\n<style>\n.cn-widget-card-grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n\tgap: calc(2 * var(--default-grid-baseline, 4px));\n}\n</style>\n"],"names":[],"mappings":";;;;;;;;;AAwBG,IAAA,KAAK,EAAE,MAAK,CAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnWidgetObjectTable.vue2.js';
|
|
|
2
2
|
import { render } from './CnWidgetObjectTable.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-d8f8d15a";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -9,6 +9,7 @@ import { dispatchAction, resolveObjectOpType } from '../../utils/actionsDispatch
|
|
|
9
9
|
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js';
|
|
10
10
|
import { pageFilter, pageSort } from '../../utils/pageControls.js';
|
|
11
11
|
import { dropOptionalUnresolved, resolveFilterTokens, hasUnresolvedTokens } from '../../utils/resolveFilterTokens.js';
|
|
12
|
+
import { fieldsFromSchema } from '../../utils/schema.js';
|
|
12
13
|
import { readVisibleWhenPath, compareVisibleWhen } from '../../utils/visibleWhen.js';
|
|
13
14
|
import __sfc_main$3 from '../CnIcon/CnIcon.vue.js';
|
|
14
15
|
import __sfc_main$2 from '../CnRowActions/CnRowActions.vue.js';
|
|
@@ -150,6 +151,12 @@ var script = {
|
|
|
150
151
|
* the object form (`{ key, label, sortable, width, cellClass,
|
|
151
152
|
* formatter, widget, format, aggregate }`) both pass straight through.
|
|
152
153
|
*
|
|
154
|
+
* A column that holds a reference shows the referenced object's label
|
|
155
|
+
* with `labelField` (the property to show) and/or `resolve`
|
|
156
|
+
* (`{ register, schema, labelField? }`, where the reference points).
|
|
157
|
+
* Without `resolve` the target is read off the source schema's `$ref`
|
|
158
|
+
* for that property. Such a column renders as an `fkResolve` cell.
|
|
159
|
+
*
|
|
153
160
|
* @type {Array<object|string>}
|
|
154
161
|
*/
|
|
155
162
|
columns: {
|
|
@@ -388,6 +395,8 @@ var script = {
|
|
|
388
395
|
confirmAction: null,
|
|
389
396
|
/** @type {object|null} The row the pending confirm-gated action targets. */
|
|
390
397
|
confirmRow: null,
|
|
398
|
+
/** Where each label column's references point, read off the source schema, by column key. */
|
|
399
|
+
refTargets: {},
|
|
391
400
|
}
|
|
392
401
|
},
|
|
393
402
|
|
|
@@ -557,6 +566,57 @@ var script = {
|
|
|
557
566
|
return params
|
|
558
567
|
},
|
|
559
568
|
|
|
569
|
+
/**
|
|
570
|
+
* Columns that ask for the label of the object they reference
|
|
571
|
+
* (`labelField` or `resolve`) and draw no cell widget of their own.
|
|
572
|
+
*
|
|
573
|
+
* @return {Array<object>}
|
|
574
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
575
|
+
*/
|
|
576
|
+
refLabelColumns() {
|
|
577
|
+
return (this.columns || []).filter((col) => col && typeof col === 'object' && !col.widget
|
|
578
|
+
&& ((typeof col.labelField === 'string' && col.labelField !== '') || (col.resolve && typeof col.resolve === 'object')))
|
|
579
|
+
},
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* The columns handed to CnDataTable: a label column whose target is
|
|
583
|
+
* known renders as an `fkResolve` cell; every other column as given.
|
|
584
|
+
*
|
|
585
|
+
* @return {Array<object|string>}
|
|
586
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
587
|
+
*/
|
|
588
|
+
renderedColumns() {
|
|
589
|
+
if (this.refLabelColumns.length === 0) {
|
|
590
|
+
return this.columns
|
|
591
|
+
}
|
|
592
|
+
return this.columns.map((col) => {
|
|
593
|
+
if (!this.refLabelColumns.includes(col)) {
|
|
594
|
+
return col
|
|
595
|
+
}
|
|
596
|
+
const target = this.refTargetOf(col);
|
|
597
|
+
if (!target) {
|
|
598
|
+
return col
|
|
599
|
+
}
|
|
600
|
+
const labelField = (col.resolve && typeof col.resolve.labelField === 'string' && col.resolve.labelField) || col.labelField || 'name';
|
|
601
|
+
return { ...col, widget: 'fkResolve', widgetProps: { ...(col.widgetProps || {}), register: target.register, schema: target.schema, labelField } }
|
|
602
|
+
})
|
|
603
|
+
},
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* The label columns whose target has to be read off the source schema.
|
|
607
|
+
*
|
|
608
|
+
* @return {string[]} Their keys.
|
|
609
|
+
*/
|
|
610
|
+
schemaRefKeys() {
|
|
611
|
+
return this.refLabelColumns.filter((col) => !this.explicitTarget(col)).map((col) => col.key)
|
|
612
|
+
},
|
|
613
|
+
|
|
614
|
+
/** @return {string} The label columns to look up and the source schema, to read again when either changes. */
|
|
615
|
+
refTargetsKey() {
|
|
616
|
+
const src = this.source || {};
|
|
617
|
+
return `${src.register || ''}/${src.schema || ''}:${this.schemaRefKeys.join('|')}`
|
|
618
|
+
},
|
|
619
|
+
|
|
560
620
|
/**
|
|
561
621
|
* `$props` minus the chrome props (`title`, `documentationUrl`,
|
|
562
622
|
* `widgetId`, `hideWrapper`) and the widget-only props (`source`,
|
|
@@ -588,6 +648,9 @@ var script = {
|
|
|
588
648
|
if (this.compiledRowClass) {
|
|
589
649
|
inner.rowClass = this.compiledRowClass;
|
|
590
650
|
}
|
|
651
|
+
if (this.refLabelColumns.length > 0) {
|
|
652
|
+
inner.columns = this.renderedColumns;
|
|
653
|
+
}
|
|
591
654
|
if (this.selfFetchActive) {
|
|
592
655
|
inner.register = this.source.register;
|
|
593
656
|
inner.schemaId = this.source.schema;
|
|
@@ -723,6 +786,16 @@ var script = {
|
|
|
723
786
|
},
|
|
724
787
|
},
|
|
725
788
|
|
|
789
|
+
watch: {
|
|
790
|
+
refTargetsKey() {
|
|
791
|
+
this.loadRefTargets();
|
|
792
|
+
},
|
|
793
|
+
},
|
|
794
|
+
|
|
795
|
+
mounted() {
|
|
796
|
+
this.loadRefTargets();
|
|
797
|
+
},
|
|
798
|
+
|
|
726
799
|
methods: {
|
|
727
800
|
/**
|
|
728
801
|
* Entry point for every declarative action trigger (row menu or
|
|
@@ -833,6 +906,68 @@ var script = {
|
|
|
833
906
|
}
|
|
834
907
|
},
|
|
835
908
|
|
|
909
|
+
/**
|
|
910
|
+
* Where a label column's references point when the column says so
|
|
911
|
+
* itself (`resolve.register` and `resolve.schema`).
|
|
912
|
+
*
|
|
913
|
+
* @param {object} col The column.
|
|
914
|
+
* @return {{register: string, schema: string}|null}
|
|
915
|
+
*/
|
|
916
|
+
explicitTarget(col) {
|
|
917
|
+
const r = col && col.resolve;
|
|
918
|
+
if (r && typeof r === 'object' && typeof r.register === 'string' && r.register !== '' && typeof r.schema === 'string' && r.schema !== '') {
|
|
919
|
+
return { register: r.register, schema: r.schema }
|
|
920
|
+
}
|
|
921
|
+
return null
|
|
922
|
+
},
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* Where a label column's references point: the column's `resolve`, else
|
|
926
|
+
* the source schema's `$ref` for the property, else null (the column
|
|
927
|
+
* then shows the raw value).
|
|
928
|
+
*
|
|
929
|
+
* @param {object} col The column.
|
|
930
|
+
* @return {{register: string, schema: string}|null}
|
|
931
|
+
*/
|
|
932
|
+
refTargetOf(col) {
|
|
933
|
+
return this.explicitTarget(col) || this.refTargets[col.key] || null
|
|
934
|
+
},
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Read the source schema once and note, for each label column without a
|
|
938
|
+
* `resolve`, the register and schema its property's `$ref` names. A
|
|
939
|
+
* failed or missing schema leaves those columns showing raw values.
|
|
940
|
+
*
|
|
941
|
+
* @return {Promise<void>}
|
|
942
|
+
* @spec openspec/changes/dashboard-table-reference-labels/specs/dashboard-page/spec.md#requirement-a-dashboard-table-shows-a-referenced-objects-label
|
|
943
|
+
*/
|
|
944
|
+
async loadRefTargets() {
|
|
945
|
+
const keys = this.schemaRefKeys;
|
|
946
|
+
const src = this.source;
|
|
947
|
+
if (keys.length === 0 || !src || typeof src.register !== 'string' || src.register === '' || src.register.startsWith('@') || typeof src.schema !== 'string' || src.schema === '') {
|
|
948
|
+
return
|
|
949
|
+
}
|
|
950
|
+
const store = this.getObjectStore();
|
|
951
|
+
if (!store || typeof store.fetchSchema !== 'function') {
|
|
952
|
+
return
|
|
953
|
+
}
|
|
954
|
+
const type = resolveObjectOpType(store, { register: src.register, schema: src.schema }, { exactSchema: true });
|
|
955
|
+
const schema = await store.fetchSchema(type).catch(() => null);
|
|
956
|
+
if (!schema || typeof schema !== 'object') {
|
|
957
|
+
return
|
|
958
|
+
}
|
|
959
|
+
const fields = fieldsFromSchema(schema, { includeReadOnly: true });
|
|
960
|
+
const found = {};
|
|
961
|
+
for (const key of keys) {
|
|
962
|
+
const field = fields.find((f) => f.key === key);
|
|
963
|
+
const ref = field && field.reference;
|
|
964
|
+
if (ref && ref.schema !== undefined && ref.schema !== null) {
|
|
965
|
+
found[key] = { register: ref.register || src.register, schema: String(ref.schema) };
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
this.refTargets = { ...this.refTargets, ...found };
|
|
969
|
+
},
|
|
970
|
+
|
|
836
971
|
/**
|
|
837
972
|
* The shared object store instance, or null when no Pinia is active
|
|
838
973
|
* (`dispatchAction` then warns and no-ops).
|