@conduction/nextcloud-vue 2.69.0 → 2.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +25 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +155 -152
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +77 -0
  6. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +8 -8
  8. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +151 -13
  10. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  11. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +3 -1
  12. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  13. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js +1 -0
  14. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js.map +1 -1
  15. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +28 -0
  16. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
  17. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +4 -2
  18. package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
  19. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +25 -1
  20. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
  21. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js +32 -17
  22. package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
  23. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js +14 -1
  24. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue2.js.map +1 -1
  25. package/dist/esm/components/CnCapabilityTable/CnCapabilityTable.vue3.js.map +1 -1
  26. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +43 -2
  27. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  28. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +3 -3
  29. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  30. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -1
  31. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  32. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +40 -43
  33. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  34. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +35 -1
  35. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  36. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  37. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +54 -3
  38. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  39. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +6 -3
  40. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  41. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +28 -0
  42. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  43. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +3 -2
  44. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  45. package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js +12 -0
  46. package/dist/esm/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue2.js.map +1 -1
  47. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +9 -0
  48. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  49. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  50. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +29 -2
  51. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  52. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +71 -34
  53. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  54. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +54 -7
  55. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  56. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +26 -8
  57. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  58. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +165 -0
  59. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  60. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +69 -26
  61. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  62. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -1
  63. package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -1
  64. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +4 -1
  65. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  66. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  67. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +1 -1
  68. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
  69. package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
  70. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  71. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +46 -32
  72. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  73. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +17 -3
  74. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
  75. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +25 -24
  76. package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -1
  77. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  78. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  79. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +27 -0
  80. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  81. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +7 -0
  82. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +24 -1
  84. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
  85. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js +1 -1
  86. package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
  87. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +11 -0
  88. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  89. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +4 -2
  90. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  91. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +30 -9
  92. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
  93. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
  94. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +15 -2
  95. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
  96. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +31 -32
  97. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
  98. package/dist/esm/composables/useWalkthrough.js +11 -3
  99. package/dist/esm/composables/useWalkthrough.js.map +1 -1
  100. package/dist/esm/nextcloud-vue.css +198 -0
  101. package/dist/esm/utils/capabilityComparison.js +29 -1
  102. package/dist/esm/utils/capabilityComparison.js.map +1 -1
  103. package/dist/esm/utils/columnFilters.js +54 -4
  104. package/dist/esm/utils/columnFilters.js.map +1 -1
  105. package/dist/esm/utils/userAutocomplete.js +69 -3
  106. package/dist/esm/utils/userAutocomplete.js.map +1 -1
  107. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  108. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  109. package/dist/nextcloud-vue.cjs.js +2778 -1630
  110. package/dist/nextcloud-vue.cjs.js.map +2 -2
  111. package/dist/nextcloud-vue.css +198 -0
  112. package/package.json +1 -1
  113. package/src/components/CnActionsBar/CnActionsBar.md +2 -0
  114. package/src/components/CnActionsBar/CnActionsBar.vue +28 -2
  115. package/src/components/CnAppNav/CnAppNav.vue +85 -8
  116. package/src/components/CnAppRoot/CnAppRoot.vue +153 -13
  117. package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +45 -0
  118. package/src/components/CnCalendarWidget/CnCalendarWidget.vue +32 -4
  119. package/src/components/CnCapabilityTable/CnCapabilityTable.vue +14 -0
  120. package/src/components/CnDashboardGrid/CnDashboardGrid.md +2 -0
  121. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +54 -2
  122. package/src/components/CnDashboardPage/CnDashboardPage.vue +46 -19
  123. package/src/components/CnDataTable/CnDataTable.vue +35 -1
  124. package/src/components/CnDetailPage/CnDetailPage.md +2 -0
  125. package/src/components/CnDetailPage/CnDetailPage.vue +57 -3
  126. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +30 -1
  127. package/src/components/CnFeaturesAndRoadmapPage/CnFeaturesAndRoadmapPage.vue +12 -0
  128. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +9 -0
  129. package/src/components/CnFormDialog/CnFormDialog.vue +62 -2
  130. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +95 -8
  131. package/src/components/CnIndexPage/CnIndexPage.vue +194 -7
  132. package/src/components/CnNextStepCard/CnNextStepCard.vue +11 -0
  133. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +4 -1
  134. package/src/components/CnObjectSidebar/CnNotesTab.vue +1 -1
  135. package/src/components/CnSetupWizard/CnSetupWizard.vue +7 -0
  136. package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +34 -7
  137. package/src/components/CnStagesWidget/CnStagesWidget.vue +19 -0
  138. package/src/components/CnStatWidget/CnStatWidget.vue +36 -0
  139. package/src/components/CnStatsBlock/CnStatsBlock.md +2 -0
  140. package/src/components/CnStatsBlock/CnStatsBlock.vue +25 -2
  141. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +13 -0
  142. package/src/components/CnWalkthrough/CnWalkthrough.vue +30 -9
  143. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +24 -3
  144. package/src/composables/useWalkthrough.js +11 -3
  145. package/src/css/dashboard.css +44 -0
  146. package/src/css/detail-page.css +10 -0
  147. package/src/css/index-page.css +12 -0
  148. package/src/css/kpi-card.css +15 -0
  149. package/src/schemas/app-manifest-v2.schema.json +47 -5
  150. package/src/utils/capabilityComparison.js +28 -0
  151. package/src/utils/columnFilters.js +54 -4
  152. package/src/utils/userAutocomplete.js +68 -2
  153. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"CnWeekStripWidget.vue3.js","sources":["../../../../src/components/CnWeekStripWidget/CnWeekStripWidget.vue?vue&type=template&id=153dd4cb&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\" 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.items\" :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<span v-else 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.\n\t\t *\n\t\t * @type {{days?: (5|7), 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}\n\t},\n\n\tcomputed: {\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\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: buckets[key] || [],\n\t\t\t\t}\n\t\t\t})\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 * 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.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</style>\n"],"names":["_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_normalizeClass","_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=153dd4cb&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.items\" :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<span v-else 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.\n\t\t *\n\t\t * @type {{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}\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\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: buckets[key] || [],\n\t\t\t\t}\n\t\t\t})\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 * 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</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":"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"}
@@ -217,11 +217,13 @@ function walkthroughProgressKey(configKey) {
217
217
 
218
218
  /**
219
219
  * Normalise stored progress (an object, or the JSON string a preference
220
- * holds) into `{ tourId, stepId, index, version }`, or null.
220
+ * holds) into `{ tourId, stepId, index, version }`, plus `paused: true`
221
+ * when the user paused the tour, or null.
221
222
  *
222
223
  * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md
224
+ * @spec openspec/changes/audit-round-lib-fixes/specs/cn-walkthrough/spec.md
223
225
  * @param {unknown} value The stored value.
224
- * @return {{tourId: string, stepId: string, index: number, version: string}|null} The progress.
226
+ * @return {{tourId: string, stepId: string, index: number, version: string, paused: (boolean|undefined)}|null} The progress.
225
227
  */
226
228
  function normaliseWalkthroughProgress(value) {
227
229
  let data = value;
@@ -238,12 +240,18 @@ function normaliseWalkthroughProgress(value) {
238
240
  if (!isPlainObject(data) || typeof data.tourId !== 'string' || data.tourId === '') {
239
241
  return null
240
242
  }
241
- return {
243
+ const progress = {
242
244
  tourId: data.tourId,
243
245
  stepId: typeof data.stepId === 'string' ? data.stepId : '',
244
246
  index: Number.isInteger(data.index) && data.index >= 0 ? data.index : 0,
245
247
  version: typeof data.version === 'string' ? data.version : '',
248
+ };
249
+ // A paused tour stays hidden on the next visit until the user picks
250
+ // "Continue". Only written when true, so older values read unchanged.
251
+ if (data.paused === true) {
252
+ progress.paused = true;
246
253
  }
254
+ return progress
247
255
  }
248
256
 
249
257
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useWalkthrough.js","sources":["../../../src/composables/useWalkthrough.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\nimport { computed, ref } from 'vue'\n\n/**\n * Per-`appId` cache so all consumers of one app share a single walkthrough\n * machine + persisted progress for the page lifetime (mirrors useSetupStatus).\n */\nconst cache = new Map()\n\n/**\n * localStorage key prefix for the per-browser mirror of the last-seen version.\n * The AUTHORITATIVE store is the per-user server preference addressed by\n * `manifest.walkthrough.completionConfigKey`; this is the synchronous cache /\n * offline fallback so the tour never flashes before the GET resolves.\n */\nexport const WALKTHROUGH_SEEN_STORAGE_PREFIX = 'cn-walkthrough-seen:'\n\n/**\n * Build the per-user preferences endpoint for a walkthrough completion key.\n * Read (`GET`) and write (`PUT`) MUST address the same URL — a persist that\n * lands on a different key reads back as \"never seen\" forever.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey`.\n * @return {string} The generated `/apps/{appId}/api/preferences/{key}` URL.\n */\nexport function walkthroughPreferenceUrl(appId, configKey) {\n\treturn generateUrl('/apps/' + appId + '/api/preferences/' + configKey)\n}\n\n/**\n * Normalise a stored completion value into the string the version engine\n * compares against.\n *\n * Only `null` / `undefined` / `''` mean \"never seen\". Anything else counts as\n * seen — including the JS-falsy scalars `false`, `0` and `'0'`, which a plain\n * truthiness check would misread as a fresh user and re-open the tour on every\n * visit. This is the read-side counterpart of `persistWalkthroughSeenVersion`.\n *\n * @param {unknown} value The raw stored / API value.\n * @return {string} The last-seen version, or `''` when never seen.\n */\nexport function normaliseSeenVersion(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'string') {\n\t\treturn value\n\t}\n\treturn String(value)\n}\n\n/**\n * Resolve the injectable `localStorage` backend (null in SSR / locked-down\n * browsers, where persistence degrades to session-only).\n *\n * @param {Storage} [injected] Test-injected storage.\n * @return {Storage|null} The storage backend or null.\n */\nfunction resolveStorage(injected) {\n\tif (injected) {\n\t\treturn injected\n\t}\n\tif (typeof window === 'undefined') {\n\t\treturn null\n\t}\n\ttry {\n\t\treturn window.localStorage\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Read the per-browser mirror of the last-seen walkthrough version.\n * Synchronous, so callers can seed state before the server GET resolves.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {string} The last-seen version, or `''`.\n */\nexport function readLocalWalkthroughSeenVersion(appId, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn ''\n\t}\n\ttry {\n\t\treturn normaliseSeenVersion(s.getItem(WALKTHROUGH_SEEN_STORAGE_PREFIX + appId))\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * Write the per-browser mirror of the last-seen walkthrough version.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} version The version to record.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {void}\n */\nfunction writeLocalWalkthroughSeenVersion(appId, version, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn\n\t}\n\ttry {\n\t\ts.setItem(WALKTHROUGH_SEEN_STORAGE_PREFIX + appId, version)\n\t} catch {\n\t\t/* quota / private mode — persistence is best-effort */\n\t}\n}\n\n/**\n * Type guard — true for a plain (non-null, non-array) object. Used to reject\n * the SPA index HTML Nextcloud returns (with status 200) when an app does not\n * actually serve `/api/preferences/{key}`.\n *\n * @param {unknown} value Candidate.\n * @return {boolean} True when value is a plain object.\n */\nfunction isPlainObject(value) {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * Load the user's last-seen walkthrough version (ADR-043, REQ-WALK-NV-004).\n *\n * The per-USER server preference addressed by `completionConfigKey` is\n * authoritative (cross-device); the localStorage mirror is the fallback used\n * when no key is declared, the endpoint is absent, or the request fails. A\n * `{ value: null }` response is a definitive \"never seen\" and correctly yields\n * the local mirror (usually `''`).\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<string>} The last-seen version, or `''` for a fresh user.\n */\nexport async function loadWalkthroughSeenVersion(appId, configKey, options = {}) {\n\tconst local = readLocalWalkthroughSeenVersion(appId, options.storage)\n\tif (!configKey) {\n\t\treturn local\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\tconst { data } = await http.get(walkthroughPreferenceUrl(appId, configKey))\n\t\t// Only a real preferences payload counts. An HTML string (SPA fallback\n\t\t// from an app that doesn't serve the route) is NOT a \"never seen\"\n\t\t// signal — fall back to the local mirror instead.\n\t\tif (!isPlainObject(data) || !('value' in data)) {\n\t\t\treturn local\n\t\t}\n\t\tconst seen = normaliseSeenVersion(data.value)\n\t\tif (seen) {\n\t\t\twriteLocalWalkthroughSeenVersion(appId, seen, options.storage)\n\t\t\treturn seen\n\t\t}\n\t\treturn local\n\t} catch {\n\t\t// Unauthenticated / endpoint missing / offline.\n\t\treturn local\n\t}\n}\n\n/**\n * Persist the user's last-seen walkthrough version (ADR-043, REQ-WALK-NV-006).\n *\n * Writes the localStorage mirror synchronously AND `PUT`s the same\n * `completionConfigKey` preference the load path reads, so a returning user —\n * on this browser or any other — is not shown the tour again. Never throws:\n * a failed write only means the tour may re-open elsewhere.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {string} version The app version to record as seen.\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<boolean>} True when the server preference was written.\n */\nexport function persistWalkthroughSeenVersion(appId, configKey, version, options = {}) {\n\tconst value = normaliseSeenVersion(version)\n\twriteLocalWalkthroughSeenVersion(appId, value, options.storage)\n\tif (!configKey) {\n\t\treturn Promise.resolve(false)\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\treturn Promise.resolve(http.put(walkthroughPreferenceUrl(appId, configKey), { value }))\n\t\t\t.then(() => true)\n\t\t\t.catch(() => false)\n\t} catch {\n\t\treturn Promise.resolve(false)\n\t}\n}\n\n/**\n * localStorage key prefix for the per-browser mirror of tour progress.\n */\nexport const WALKTHROUGH_PROGRESS_STORAGE_PREFIX = 'cn-walkthrough-progress:'\n\n/**\n * The preference key that holds tour progress, next to the completion key.\n *\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @return {string} `<configKey>-progress`, or '' when no key is declared.\n */\nexport function walkthroughProgressKey(configKey) {\n\treturn configKey ? configKey + '-progress' : ''\n}\n\n/**\n * Normalise stored progress (an object, or the JSON string a preference\n * holds) into `{ tourId, stepId, index, version }`, or null.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {unknown} value The stored value.\n * @return {{tourId: string, stepId: string, index: number, version: string}|null} The progress.\n */\nexport function normaliseWalkthroughProgress(value) {\n\tlet data = value\n\tif (typeof data === 'string') {\n\t\tif (data === '') {\n\t\t\treturn null\n\t\t}\n\t\ttry {\n\t\t\tdata = JSON.parse(data)\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\tif (!isPlainObject(data) || typeof data.tourId !== 'string' || data.tourId === '') {\n\t\treturn null\n\t}\n\treturn {\n\t\ttourId: data.tourId,\n\t\tstepId: typeof data.stepId === 'string' ? data.stepId : '',\n\t\tindex: Number.isInteger(data.index) && data.index >= 0 ? data.index : 0,\n\t\tversion: typeof data.version === 'string' ? data.version : '',\n\t}\n}\n\n/**\n * Read the per-browser mirror of the tour progress. Synchronous.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {object|null} The progress, or null.\n */\nexport function readLocalWalkthroughProgress(appId, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn null\n\t}\n\ttry {\n\t\treturn normaliseWalkthroughProgress(s.getItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId))\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Load the user's tour progress: the per-user preference\n * `<completionConfigKey>-progress` when declared, else the local mirror.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<object|null>} The progress, or null.\n */\nexport async function loadWalkthroughProgress(appId, configKey, options = {}) {\n\tconst local = readLocalWalkthroughProgress(appId, options.storage)\n\tconst key = walkthroughProgressKey(configKey)\n\tif (!key) {\n\t\treturn local\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\tconst { data } = await http.get(walkthroughPreferenceUrl(appId, key))\n\t\tif (!isPlainObject(data) || !('value' in data)) {\n\t\t\treturn local\n\t\t}\n\t\treturn normaliseWalkthroughProgress(data.value) || local\n\t} catch {\n\t\treturn local\n\t}\n}\n\n/**\n * Persist the user's tour progress, or clear it with `null`. Writes the\n * local mirror and, with a completion key, the per-user preference. Never\n * throws.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object|null} progress `{ tourId, stepId, index, version }`, or null to clear.\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<boolean>} True when the server preference was written.\n */\nexport function persistWalkthroughProgress(appId, configKey, progress, options = {}) {\n\tconst value = progress ? normaliseWalkthroughProgress(progress) : null\n\tconst raw = value ? JSON.stringify(value) : ''\n\tconst s = resolveStorage(options.storage)\n\tif (s) {\n\t\ttry {\n\t\t\tif (raw) {\n\t\t\t\ts.setItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId, raw)\n\t\t\t} else {\n\t\t\t\ts.removeItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId)\n\t\t\t}\n\t\t} catch {\n\t\t\t/* quota / private mode: best-effort */\n\t\t}\n\t}\n\tconst key = walkthroughProgressKey(configKey)\n\tif (!key) {\n\t\treturn Promise.resolve(false)\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\treturn Promise.resolve(http.put(walkthroughPreferenceUrl(appId, key), { value: raw }))\n\t\t\t.then(() => true)\n\t\t\t.catch(() => false)\n\t} catch {\n\t\treturn Promise.resolve(false)\n\t}\n}\n\n/**\n * Whether an `object-created` signal satisfies a step's `advanceOn`.\n *\n * The signal's own `register` / `schema` (the slugs the creating surface\n * knows) are compared first; an object's `@self` values are numeric ids on\n * OpenRegister and only match a step that also uses ids.\n *\n * @param {object} advanceOn The step's `advanceOn`.\n * @param {object} signal `{ register?, schema?, object? }`.\n * @return {boolean} True when it matches.\n */\nfunction objectCreatedMatches(advanceOn, signal) {\n\tconst obj = signal.object || {}\n\tconst self = obj['@self'] || {}\n\tconst same = (want, candidates) => !want || candidates\n\t\t.filter((c) => c !== null && c !== undefined && c !== '')\n\t\t.some((c) => String(c).toLowerCase() === String(want).toLowerCase())\n\treturn same(advanceOn.register, [signal.register, obj.register, self.register])\n\t\t&& same(advanceOn.schema, [signal.schema, obj.schema, self.schema])\n}\n\n/**\n * Compare two semver-ish strings. Missing / unparseable parts sort as 0.\n *\n * @param {string} a Left version.\n * @param {string} b Right version.\n * @return {number} -1 / 0 / 1.\n */\nexport function compareSemver(a, b) {\n\tconst pa = String(a || '0').split('.').map((n) => parseInt(n, 10) || 0)\n\tconst pb = String(b || '0').split('.').map((n) => parseInt(n, 10) || 0)\n\tfor (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n\t\tconst d = (pa[i] || 0) - (pb[i] || 0)\n\t\tif (d !== 0) {\n\t\t\treturn d < 0 ? -1 : 1\n\t\t}\n\t}\n\treturn 0\n}\n\n/**\n * Replace `{{var}}` tokens in a string from a context bag. Unknown keys are\n * left intact (and warned in dev) so a misauthored tour degrades visibly.\n *\n * @param {string} input The template string.\n * @param {object} context The context bag.\n * @return {string} The interpolated string.\n */\nexport function interpolateTokens(input, context) {\n\tif (typeof input !== 'string' || input.indexOf('{{') === -1) {\n\t\treturn input\n\t}\n\treturn input.replace(/\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g, (m, key) => {\n\t\tif (context && Object.hasOwn(context, key) && context[key] !== null && context[key] !== undefined) {\n\t\t\treturn String(context[key])\n\t\t}\n\t\treturn m\n\t})\n}\n\n/**\n * Walkthrough engine (ADR-043). Loads `manifest.walkthrough`, composes the\n * active tour for the current user + app version, and runs a step machine whose\n * advancement is fed declarative *signals* (route change, object created,\n * element appeared, click, delay) by the rendering component — keeping this\n * composable pure and unit-testable. Captured route params / object ids land in\n * a context bag interpolated into later steps via `{{var}}`.\n *\n * Persistence is decoupled: pass `seenVersion` (the user's last-seen app version)\n * and an `onComplete(appVersion)` callback. CnAppRoot wires these to the per-user\n * `manifest.walkthrough.completionConfigKey` preference via\n * {@link loadWalkthroughSeenVersion} / {@link persistWalkthroughSeenVersion}.\n *\n * @param {string} appId The Nextcloud app id (cache key).\n * @param {object} manifest The app manifest (reads `manifest.walkthrough` + `manifest.version`).\n * @param {object} [options] `{ appVersion, seenVersion, resume, onComplete }`.\n * @return {object} The reactive machine + controls (see properties below).\n *\n * @example\n * const wt = useWalkthrough('pipelinq', manifest, { seenVersion: '1.0.0' })\n * wt.start('getting-started')\n * wt.notify({ kind: 'route', route: 'Products', params: { id: '42' } })\n */\nexport function useWalkthrough(appId, manifest, options = {}) {\n\tlet entry = cache.get(appId)\n\tif (!entry) {\n\t\tconst walkthrough = (manifest && manifest.walkthrough) || {}\n\t\tconst appVersion = options.appVersion || (manifest && manifest.version) || '0.0.0'\n\t\t// Normalised, NOT `|| ''`: a completed user whose recorded version is a\n\t\t// JS-falsy scalar (`0` / `false`) must still read as \"has seen it\".\n\t\tconst seenVersion = normaliseSeenVersion(options.seenVersion)\n\t\tconst enabled = walkthrough.enabled !== false && Array.isArray(walkthrough.tours) && walkthrough.tours.length > 0\n\n\t\tconst tours = walkthrough.tours || []\n\t\tconst activeTourId = ref(null)\n\t\tconst currentIndex = ref(0)\n\t\tconst context = ref({})\n\t\tconst running = ref(false)\n\t\t// True while the tour is hidden by ESC or a backdrop click. The tour\n\t\t// and its step stay, so it continues where it was.\n\t\tconst paused = ref(false)\n\t\t// True while a user-initiated replay is active (the \"Restart tutorial\"\n\t\t// entry). A replay shows the FULL tour regardless of the persisted\n\t\t// seen-version — otherwise a returning user, whose seenVersion already\n\t\t// covers every step's sinceVersion, would replay an empty tour.\n\t\tconst replaying = ref(false)\n\n\t\t/**\n\t\t * Compose the step set for a tour, filtered by version: a fresh user\n\t\t * (no seenVersion) gets all steps `<= appVersion`; an upgraded user gets\n\t\t * only steps newer than seenVersion and `<= appVersion`. A user-initiated\n\t\t * replay (`replaying`) ignores seenVersion and shows every step\n\t\t * `<= appVersion`.\n\t\t *\n\t\t * @param {object} tour The tour definition.\n\t\t * @return {Array} The visible steps for this user.\n\t\t */\n\t\tfunction composeSteps(tour) {\n\t\t\tconst all = Array.isArray(tour.steps) ? tour.steps : []\n\t\t\treturn all.filter((s) => {\n\t\t\t\tconst since = s.sinceVersion || '0.0.0'\n\t\t\t\tif (compareSemver(since, appVersion) > 0) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tif (!replaying.value && seenVersion && compareSemver(since, seenVersion) <= 0) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t})\n\t\t}\n\n\t\tconst activeTour = computed(() => {\n\t\t\tif (!activeTourId.value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tour = tours.find((t) => t.id === activeTourId.value)\n\t\t\tif (!tour) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { ...tour, steps: composeSteps(tour) }\n\t\t})\n\n\t\t/**\n\t\t * The tour that should auto-start for this user, or null. A\n\t\t * `version-bump` tour only qualifies when it has a non-empty step delta;\n\t\t * `first-visit` qualifies only when the user has never seen the tour.\n\t\t *\n\t\t * @return {object|null} The auto-start tour (raw definition) or null.\n\t\t */\n\t\tconst autoStartTour = computed(() => {\n\t\t\tif (!enabled) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tfor (const tour of tours) {\n\t\t\t\tif (tour.minAppVersion && compareSemver(appVersion, tour.minAppVersion) < 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst steps = composeSteps(tour)\n\t\t\t\tif (steps.length === 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (tour.trigger === 'first-visit' && !seenVersion) {\n\t\t\t\t\treturn tour\n\t\t\t\t}\n\t\t\t\tif (tour.trigger === 'version-bump' && seenVersion && compareSemver(appVersion, seenVersion) > 0) {\n\t\t\t\t\treturn tour\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t})\n\n\t\tconst currentStep = computed(() => {\n\t\t\tconst t = activeTour.value\n\t\t\tif (!t) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = t.steps[currentIndex.value]\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn interpolateStep(raw, context.value)\n\t\t})\n\t\tconst totalSteps = computed(() => (activeTour.value ? activeTour.value.steps.length : 0))\n\t\tconst isFirst = computed(() => currentIndex.value === 0)\n\t\tconst isLast = computed(() => totalSteps.value > 0 && currentIndex.value === totalSteps.value - 1)\n\n\t\t/**\n\t\t * Apply `{{var}}` interpolation to a step's user-facing + targeting fields.\n\t\t *\n\t\t * @param {object} step The raw step.\n\t\t * @param {object} ctx The context bag.\n\t\t * @return {object} A shallow copy with tokens resolved.\n\t\t */\n\t\tfunction interpolateStep(step, ctx) {\n\t\t\tconst out = { ...step }\n\t\t\tfor (const k of ['title', 'body', 'task']) {\n\t\t\t\tif (out[k]) {\n\t\t\t\t\tout[k] = interpolateTokens(out[k], ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (out.target) {\n\t\t\t\tout.target = { ...out.target }\n\t\t\t\tif (out.target.ref) {\n\t\t\t\t\tout.target.ref = interpolateTokens(out.target.ref, ctx)\n\t\t\t\t}\n\t\t\t\tif (out.target.selector) {\n\t\t\t\t\tout.target.selector = interpolateTokens(out.target.selector, ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (out.advanceOn) {\n\t\t\t\tout.advanceOn = { ...out.advanceOn }\n\t\t\t\tif (out.advanceOn.route) {\n\t\t\t\t\tout.advanceOn.route = interpolateTokens(out.advanceOn.route, ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t}\n\n\t\t/**\n\t\t * Run a step's `advanceOn.capture` against captured values.\n\t\t *\n\t\t * @param {object} step The active (raw) step.\n\t\t * @param {object} source `{ params?, object? }` to read captured values from.\n\t\t * @return {void}\n\t\t */\n\t\tfunction runCapture(step, source) {\n\t\t\tconst cap = step && step.advanceOn && step.advanceOn.capture\n\t\t\tif (!cap) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = { ...context.value }\n\t\t\tfor (const [varName, token] of Object.entries(cap)) {\n\t\t\t\tconst key = String(token).replace(/^:/, '')\n\t\t\t\tlet value\n\t\t\t\tif (source.params && key in source.params) {\n\t\t\t\t\tvalue = source.params[key]\n\t\t\t\t} else if (source.object) {\n\t\t\t\t\tvalue = (key === 'id') ? (source.object.id ?? source.object['@self']?.id ?? source.object.uuid) : source.object[key]\n\t\t\t\t}\n\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\tnext[varName] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontext.value = next\n\t\t}\n\n\t\t/**\n\t\t * Advance to the next step, or complete on the last step. Skips\n\t\t * subsequent `optional` steps whose target ref is empty after interpolation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction next() {\n\t\t\tif (!activeTour.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (currentIndex.value >= totalSteps.value - 1) {\n\t\t\t\tcomplete()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcurrentIndex.value += 1\n\t\t}\n\t\t/**\n\t\t * Step back (no-op on the first step).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction back() {\n\t\t\tif (currentIndex.value > 0) {\n\t\t\t\tcurrentIndex.value -= 1\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t * Skip the active step (advance without satisfying its condition).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction skip() {\n\t\t\tnext()\n\t\t}\n\t\t/**\n\t\t * Jump to a step by id within the active tour.\n\t\t *\n\t\t * @param {string} stepId The target step id.\n\t\t * @return {void}\n\t\t */\n\t\tfunction jumpTo(stepId) {\n\t\t\tif (!activeTour.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst idx = activeTour.value.steps.findIndex((s) => s.id === stepId)\n\t\t\tif (idx >= 0) {\n\t\t\t\tcurrentIndex.value = idx\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t * Start a tour by id at its first (resume) step.\n\t\t *\n\t\t * @param {string} tourId The tour id.\n\t\t * @param {number} [startIndex] Optional resume index.\n\t\t * @return {void}\n\t\t */\n\t\tfunction start(tourId, startIndex = 0) {\n\t\t\treplaying.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = tourId\n\t\t\tcurrentIndex.value = startIndex\n\t\t\tcontext.value = {}\n\t\t\trunning.value = true\n\t\t}\n\t\t/**\n\t\t * Restart a tour from the beginning (used by the \"Restart tutorial\" /\n\t\t * \"Replay\" entry). Runs in replay mode so the FULL tour shows even for a\n\t\t * returning user whose persisted seen-version already covers every step.\n\t\t *\n\t\t * @param {string} tourId The tour id.\n\t\t * @return {void}\n\t\t */\n\t\tfunction restart(tourId) {\n\t\t\tstart(tourId, 0)\n\t\t\treplaying.value = true\n\t\t}\n\t\t/**\n\t\t * Dismiss the active tour without marking it complete.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction dismiss() {\n\t\t\trunning.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = null\n\t\t\treplaying.value = false\n\t\t}\n\t\t/**\n\t\t * Hide the active tour without ending it (ESC, a click on the dim).\n\t\t * The tour and step are kept, so `resumePaused()` continues there.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @return {void}\n\t\t */\n\t\tfunction pause() {\n\t\t\tif (!activeTourId.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\trunning.value = false\n\t\t\tpaused.value = true\n\t\t}\n\t\t/**\n\t\t * Show a paused tour again at the step it was on.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @return {boolean} True when there was a paused tour to show.\n\t\t */\n\t\tfunction resumePaused() {\n\t\t\tif (!paused.value || !activeTourId.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tpaused.value = false\n\t\t\trunning.value = true\n\t\t\treturn true\n\t\t}\n\t\t/**\n\t\t * Start a tour at a remembered step (\"continue where you left off\").\n\t\t * Runs in replay mode so a returning user sees the full tour, and\n\t\t * falls back to the first step when the step no longer exists.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @param {string} tourId The tour id.\n\t\t * @param {string} [stepId] The step to continue at.\n\t\t * @return {boolean} True when the tour exists and started.\n\t\t */\n\t\tfunction resumeAt(tourId, stepId) {\n\t\t\tconst tour = tours.find((t) => t.id === tourId)\n\t\t\tif (!tour) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treplaying.value = true\n\t\t\tconst idx = composeSteps(tour).findIndex((s) => s.id === stepId)\n\t\t\tstart(tourId, Math.max(0, idx))\n\t\t\treplaying.value = true\n\t\t\treturn true\n\t\t}\n\t\t/**\n\t\t * Mark the active tour complete: stop running and invoke the\n\t\t * `onComplete(appVersion)` persistence callback so the seen version is\n\t\t * recorded by the consumer (CnAppRoot).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction complete() {\n\t\t\trunning.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = null\n\t\t\treplaying.value = false\n\t\t\tif (typeof options.onComplete === 'function') {\n\t\t\t\toptions.onComplete(appVersion)\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Feed a declarative advance signal to the active step. When the signal\n\t\t * satisfies the step's `advanceOn`, captures run and the tour advances.\n\t\t *\n\t\t * @param {object} signal `{ kind: 'route'|'object-created'|'element'|'click'|'delay', route?, params?, object? }`.\n\t\t * @return {boolean} Whether the signal advanced the tour.\n\t\t */\n\t\tfunction notify(signal) {\n\t\t\tconst step = activeTour.value && activeTour.value.steps[currentIndex.value]\n\t\t\tif (!step || !step.advanceOn) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = step.advanceOn\n\t\t\tlet match = false\n\t\t\tif (signal.kind === 'route' && a.type === 'route-match') {\n\t\t\t\tmatch = signal.route === a.route\n\t\t\t\tif (match) {\n\t\t\t\t\trunCapture(step, { params: signal.params || {} })\n\t\t\t\t}\n\t\t\t} else if (signal.kind === 'object-created' && a.type === 'object-created') {\n\t\t\t\tmatch = objectCreatedMatches(a, signal)\n\t\t\t\tif (match) {\n\t\t\t\t\trunCapture(step, { object: signal.object || {} })\n\t\t\t\t}\n\t\t\t} else if (signal.kind === 'element' && a.type === 'element-appears') {\n\t\t\t\tmatch = true\n\t\t\t} else if (signal.kind === 'click' && a.type === 'click-target') {\n\t\t\t\tmatch = true\n\t\t\t} else if (signal.kind === 'delay' && a.type === 'delay') {\n\t\t\t\tmatch = true\n\t\t\t}\n\t\t\tif (match) {\n\t\t\t\tnext()\n\t\t\t}\n\t\t\treturn match\n\t\t}\n\n\t\tentry = {\n\t\t\tenabled,\n\t\t\tappVersion,\n\t\t\tseenVersion,\n\t\t\ttours,\n\t\t\tactiveTour,\n\t\t\tautoStartTour,\n\t\t\tcurrentStep,\n\t\t\ttotalSteps,\n\t\t\tisFirst,\n\t\t\tisLast,\n\t\t\tcontext,\n\t\t\trunning,\n\t\t\tpaused,\n\t\t\treplaying,\n\t\t\tstart,\n\t\t\trestart,\n\t\t\tpause,\n\t\t\tresumePaused,\n\t\t\tresumeAt,\n\t\t\tnext,\n\t\t\tback,\n\t\t\tskip,\n\t\t\tjumpTo,\n\t\t\tdismiss,\n\t\t\tcomplete,\n\t\t\tnotify,\n\t\t\tinterpolate: (s) => interpolateTokens(s, context.value),\n\t\t}\n\t\tcache.set(appId, entry)\n\n\t\t// Resume token (cross-app hand-off / refresh) — start at the resume step.\n\t\tif (options.resume && options.resume.tourId) {\n\t\t\tconst tour = tours.find((t) => t.id === options.resume.tourId)\n\t\t\tif (tour) {\n\t\t\t\tconst steps = composeSteps(tour)\n\t\t\t\tconst idx = Math.max(0, steps.findIndex((s) => s.id === options.resume.stepId))\n\t\t\t\tstart(options.resume.tourId, idx)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entry\n}\n\n/**\n * Test-only helper to reset the per-`appId` cache.\n *\n * @internal\n */\nexport function __resetWalkthroughCacheForTests() {\n\tcache.clear()\n}\n"],"names":["axios"],"mappings":"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"}
1
+ {"version":3,"file":"useWalkthrough.js","sources":["../../../src/composables/useWalkthrough.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateUrl } from '@nextcloud/router'\nimport { computed, ref } from 'vue'\n\n/**\n * Per-`appId` cache so all consumers of one app share a single walkthrough\n * machine + persisted progress for the page lifetime (mirrors useSetupStatus).\n */\nconst cache = new Map()\n\n/**\n * localStorage key prefix for the per-browser mirror of the last-seen version.\n * The AUTHORITATIVE store is the per-user server preference addressed by\n * `manifest.walkthrough.completionConfigKey`; this is the synchronous cache /\n * offline fallback so the tour never flashes before the GET resolves.\n */\nexport const WALKTHROUGH_SEEN_STORAGE_PREFIX = 'cn-walkthrough-seen:'\n\n/**\n * Build the per-user preferences endpoint for a walkthrough completion key.\n * Read (`GET`) and write (`PUT`) MUST address the same URL — a persist that\n * lands on a different key reads back as \"never seen\" forever.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey`.\n * @return {string} The generated `/apps/{appId}/api/preferences/{key}` URL.\n */\nexport function walkthroughPreferenceUrl(appId, configKey) {\n\treturn generateUrl('/apps/' + appId + '/api/preferences/' + configKey)\n}\n\n/**\n * Normalise a stored completion value into the string the version engine\n * compares against.\n *\n * Only `null` / `undefined` / `''` mean \"never seen\". Anything else counts as\n * seen — including the JS-falsy scalars `false`, `0` and `'0'`, which a plain\n * truthiness check would misread as a fresh user and re-open the tour on every\n * visit. This is the read-side counterpart of `persistWalkthroughSeenVersion`.\n *\n * @param {unknown} value The raw stored / API value.\n * @return {string} The last-seen version, or `''` when never seen.\n */\nexport function normaliseSeenVersion(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'string') {\n\t\treturn value\n\t}\n\treturn String(value)\n}\n\n/**\n * Resolve the injectable `localStorage` backend (null in SSR / locked-down\n * browsers, where persistence degrades to session-only).\n *\n * @param {Storage} [injected] Test-injected storage.\n * @return {Storage|null} The storage backend or null.\n */\nfunction resolveStorage(injected) {\n\tif (injected) {\n\t\treturn injected\n\t}\n\tif (typeof window === 'undefined') {\n\t\treturn null\n\t}\n\ttry {\n\t\treturn window.localStorage\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Read the per-browser mirror of the last-seen walkthrough version.\n * Synchronous, so callers can seed state before the server GET resolves.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {string} The last-seen version, or `''`.\n */\nexport function readLocalWalkthroughSeenVersion(appId, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn ''\n\t}\n\ttry {\n\t\treturn normaliseSeenVersion(s.getItem(WALKTHROUGH_SEEN_STORAGE_PREFIX + appId))\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * Write the per-browser mirror of the last-seen walkthrough version.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} version The version to record.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {void}\n */\nfunction writeLocalWalkthroughSeenVersion(appId, version, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn\n\t}\n\ttry {\n\t\ts.setItem(WALKTHROUGH_SEEN_STORAGE_PREFIX + appId, version)\n\t} catch {\n\t\t/* quota / private mode — persistence is best-effort */\n\t}\n}\n\n/**\n * Type guard — true for a plain (non-null, non-array) object. Used to reject\n * the SPA index HTML Nextcloud returns (with status 200) when an app does not\n * actually serve `/api/preferences/{key}`.\n *\n * @param {unknown} value Candidate.\n * @return {boolean} True when value is a plain object.\n */\nfunction isPlainObject(value) {\n\treturn value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\n/**\n * Load the user's last-seen walkthrough version (ADR-043, REQ-WALK-NV-004).\n *\n * The per-USER server preference addressed by `completionConfigKey` is\n * authoritative (cross-device); the localStorage mirror is the fallback used\n * when no key is declared, the endpoint is absent, or the request fails. A\n * `{ value: null }` response is a definitive \"never seen\" and correctly yields\n * the local mirror (usually `''`).\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<string>} The last-seen version, or `''` for a fresh user.\n */\nexport async function loadWalkthroughSeenVersion(appId, configKey, options = {}) {\n\tconst local = readLocalWalkthroughSeenVersion(appId, options.storage)\n\tif (!configKey) {\n\t\treturn local\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\tconst { data } = await http.get(walkthroughPreferenceUrl(appId, configKey))\n\t\t// Only a real preferences payload counts. An HTML string (SPA fallback\n\t\t// from an app that doesn't serve the route) is NOT a \"never seen\"\n\t\t// signal — fall back to the local mirror instead.\n\t\tif (!isPlainObject(data) || !('value' in data)) {\n\t\t\treturn local\n\t\t}\n\t\tconst seen = normaliseSeenVersion(data.value)\n\t\tif (seen) {\n\t\t\twriteLocalWalkthroughSeenVersion(appId, seen, options.storage)\n\t\t\treturn seen\n\t\t}\n\t\treturn local\n\t} catch {\n\t\t// Unauthenticated / endpoint missing / offline.\n\t\treturn local\n\t}\n}\n\n/**\n * Persist the user's last-seen walkthrough version (ADR-043, REQ-WALK-NV-006).\n *\n * Writes the localStorage mirror synchronously AND `PUT`s the same\n * `completionConfigKey` preference the load path reads, so a returning user —\n * on this browser or any other — is not shown the tour again. Never throws:\n * a failed write only means the tour may re-open elsewhere.\n *\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {string} version The app version to record as seen.\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<boolean>} True when the server preference was written.\n */\nexport function persistWalkthroughSeenVersion(appId, configKey, version, options = {}) {\n\tconst value = normaliseSeenVersion(version)\n\twriteLocalWalkthroughSeenVersion(appId, value, options.storage)\n\tif (!configKey) {\n\t\treturn Promise.resolve(false)\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\treturn Promise.resolve(http.put(walkthroughPreferenceUrl(appId, configKey), { value }))\n\t\t\t.then(() => true)\n\t\t\t.catch(() => false)\n\t} catch {\n\t\treturn Promise.resolve(false)\n\t}\n}\n\n/**\n * localStorage key prefix for the per-browser mirror of tour progress.\n */\nexport const WALKTHROUGH_PROGRESS_STORAGE_PREFIX = 'cn-walkthrough-progress:'\n\n/**\n * The preference key that holds tour progress, next to the completion key.\n *\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @return {string} `<configKey>-progress`, or '' when no key is declared.\n */\nexport function walkthroughProgressKey(configKey) {\n\treturn configKey ? configKey + '-progress' : ''\n}\n\n/**\n * Normalise stored progress (an object, or the JSON string a preference\n * holds) into `{ tourId, stepId, index, version }`, plus `paused: true`\n * when the user paused the tour, or null.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @spec openspec/changes/audit-round-lib-fixes/specs/cn-walkthrough/spec.md\n * @param {unknown} value The stored value.\n * @return {{tourId: string, stepId: string, index: number, version: string, paused: (boolean|undefined)}|null} The progress.\n */\nexport function normaliseWalkthroughProgress(value) {\n\tlet data = value\n\tif (typeof data === 'string') {\n\t\tif (data === '') {\n\t\t\treturn null\n\t\t}\n\t\ttry {\n\t\t\tdata = JSON.parse(data)\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\tif (!isPlainObject(data) || typeof data.tourId !== 'string' || data.tourId === '') {\n\t\treturn null\n\t}\n\tconst progress = {\n\t\ttourId: data.tourId,\n\t\tstepId: typeof data.stepId === 'string' ? data.stepId : '',\n\t\tindex: Number.isInteger(data.index) && data.index >= 0 ? data.index : 0,\n\t\tversion: typeof data.version === 'string' ? data.version : '',\n\t}\n\t// A paused tour stays hidden on the next visit until the user picks\n\t// \"Continue\". Only written when true, so older values read unchanged.\n\tif (data.paused === true) {\n\t\tprogress.paused = true\n\t}\n\treturn progress\n}\n\n/**\n * Read the per-browser mirror of the tour progress. Synchronous.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {Storage} [storage] Injectable storage backend.\n * @return {object|null} The progress, or null.\n */\nexport function readLocalWalkthroughProgress(appId, storage) {\n\tconst s = resolveStorage(storage)\n\tif (!s) {\n\t\treturn null\n\t}\n\ttry {\n\t\treturn normaliseWalkthroughProgress(s.getItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId))\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Load the user's tour progress: the per-user preference\n * `<completionConfigKey>-progress` when declared, else the local mirror.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<object|null>} The progress, or null.\n */\nexport async function loadWalkthroughProgress(appId, configKey, options = {}) {\n\tconst local = readLocalWalkthroughProgress(appId, options.storage)\n\tconst key = walkthroughProgressKey(configKey)\n\tif (!key) {\n\t\treturn local\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\tconst { data } = await http.get(walkthroughPreferenceUrl(appId, key))\n\t\tif (!isPlainObject(data) || !('value' in data)) {\n\t\t\treturn local\n\t\t}\n\t\treturn normaliseWalkthroughProgress(data.value) || local\n\t} catch {\n\t\treturn local\n\t}\n}\n\n/**\n * Persist the user's tour progress, or clear it with `null`. Writes the\n * local mirror and, with a completion key, the per-user preference. Never\n * throws.\n *\n * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n * @param {string} appId The Nextcloud app id.\n * @param {string} configKey `manifest.walkthrough.completionConfigKey` (may be empty).\n * @param {object|null} progress `{ tourId, stepId, index, version }`, or null to clear.\n * @param {object} [options] `{ http, storage }` injection points for tests.\n * @return {Promise<boolean>} True when the server preference was written.\n */\nexport function persistWalkthroughProgress(appId, configKey, progress, options = {}) {\n\tconst value = progress ? normaliseWalkthroughProgress(progress) : null\n\tconst raw = value ? JSON.stringify(value) : ''\n\tconst s = resolveStorage(options.storage)\n\tif (s) {\n\t\ttry {\n\t\t\tif (raw) {\n\t\t\t\ts.setItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId, raw)\n\t\t\t} else {\n\t\t\t\ts.removeItem(WALKTHROUGH_PROGRESS_STORAGE_PREFIX + appId)\n\t\t\t}\n\t\t} catch {\n\t\t\t/* quota / private mode: best-effort */\n\t\t}\n\t}\n\tconst key = walkthroughProgressKey(configKey)\n\tif (!key) {\n\t\treturn Promise.resolve(false)\n\t}\n\tconst http = options.http || axios\n\ttry {\n\t\treturn Promise.resolve(http.put(walkthroughPreferenceUrl(appId, key), { value: raw }))\n\t\t\t.then(() => true)\n\t\t\t.catch(() => false)\n\t} catch {\n\t\treturn Promise.resolve(false)\n\t}\n}\n\n/**\n * Whether an `object-created` signal satisfies a step's `advanceOn`.\n *\n * The signal's own `register` / `schema` (the slugs the creating surface\n * knows) are compared first; an object's `@self` values are numeric ids on\n * OpenRegister and only match a step that also uses ids.\n *\n * @param {object} advanceOn The step's `advanceOn`.\n * @param {object} signal `{ register?, schema?, object? }`.\n * @return {boolean} True when it matches.\n */\nfunction objectCreatedMatches(advanceOn, signal) {\n\tconst obj = signal.object || {}\n\tconst self = obj['@self'] || {}\n\tconst same = (want, candidates) => !want || candidates\n\t\t.filter((c) => c !== null && c !== undefined && c !== '')\n\t\t.some((c) => String(c).toLowerCase() === String(want).toLowerCase())\n\treturn same(advanceOn.register, [signal.register, obj.register, self.register])\n\t\t&& same(advanceOn.schema, [signal.schema, obj.schema, self.schema])\n}\n\n/**\n * Compare two semver-ish strings. Missing / unparseable parts sort as 0.\n *\n * @param {string} a Left version.\n * @param {string} b Right version.\n * @return {number} -1 / 0 / 1.\n */\nexport function compareSemver(a, b) {\n\tconst pa = String(a || '0').split('.').map((n) => parseInt(n, 10) || 0)\n\tconst pb = String(b || '0').split('.').map((n) => parseInt(n, 10) || 0)\n\tfor (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n\t\tconst d = (pa[i] || 0) - (pb[i] || 0)\n\t\tif (d !== 0) {\n\t\t\treturn d < 0 ? -1 : 1\n\t\t}\n\t}\n\treturn 0\n}\n\n/**\n * Replace `{{var}}` tokens in a string from a context bag. Unknown keys are\n * left intact (and warned in dev) so a misauthored tour degrades visibly.\n *\n * @param {string} input The template string.\n * @param {object} context The context bag.\n * @return {string} The interpolated string.\n */\nexport function interpolateTokens(input, context) {\n\tif (typeof input !== 'string' || input.indexOf('{{') === -1) {\n\t\treturn input\n\t}\n\treturn input.replace(/\\{\\{\\s*([\\w.-]+)\\s*\\}\\}/g, (m, key) => {\n\t\tif (context && Object.hasOwn(context, key) && context[key] !== null && context[key] !== undefined) {\n\t\t\treturn String(context[key])\n\t\t}\n\t\treturn m\n\t})\n}\n\n/**\n * Walkthrough engine (ADR-043). Loads `manifest.walkthrough`, composes the\n * active tour for the current user + app version, and runs a step machine whose\n * advancement is fed declarative *signals* (route change, object created,\n * element appeared, click, delay) by the rendering component — keeping this\n * composable pure and unit-testable. Captured route params / object ids land in\n * a context bag interpolated into later steps via `{{var}}`.\n *\n * Persistence is decoupled: pass `seenVersion` (the user's last-seen app version)\n * and an `onComplete(appVersion)` callback. CnAppRoot wires these to the per-user\n * `manifest.walkthrough.completionConfigKey` preference via\n * {@link loadWalkthroughSeenVersion} / {@link persistWalkthroughSeenVersion}.\n *\n * @param {string} appId The Nextcloud app id (cache key).\n * @param {object} manifest The app manifest (reads `manifest.walkthrough` + `manifest.version`).\n * @param {object} [options] `{ appVersion, seenVersion, resume, onComplete }`.\n * @return {object} The reactive machine + controls (see properties below).\n *\n * @example\n * const wt = useWalkthrough('pipelinq', manifest, { seenVersion: '1.0.0' })\n * wt.start('getting-started')\n * wt.notify({ kind: 'route', route: 'Products', params: { id: '42' } })\n */\nexport function useWalkthrough(appId, manifest, options = {}) {\n\tlet entry = cache.get(appId)\n\tif (!entry) {\n\t\tconst walkthrough = (manifest && manifest.walkthrough) || {}\n\t\tconst appVersion = options.appVersion || (manifest && manifest.version) || '0.0.0'\n\t\t// Normalised, NOT `|| ''`: a completed user whose recorded version is a\n\t\t// JS-falsy scalar (`0` / `false`) must still read as \"has seen it\".\n\t\tconst seenVersion = normaliseSeenVersion(options.seenVersion)\n\t\tconst enabled = walkthrough.enabled !== false && Array.isArray(walkthrough.tours) && walkthrough.tours.length > 0\n\n\t\tconst tours = walkthrough.tours || []\n\t\tconst activeTourId = ref(null)\n\t\tconst currentIndex = ref(0)\n\t\tconst context = ref({})\n\t\tconst running = ref(false)\n\t\t// True while the tour is hidden by ESC or a backdrop click. The tour\n\t\t// and its step stay, so it continues where it was.\n\t\tconst paused = ref(false)\n\t\t// True while a user-initiated replay is active (the \"Restart tutorial\"\n\t\t// entry). A replay shows the FULL tour regardless of the persisted\n\t\t// seen-version — otherwise a returning user, whose seenVersion already\n\t\t// covers every step's sinceVersion, would replay an empty tour.\n\t\tconst replaying = ref(false)\n\n\t\t/**\n\t\t * Compose the step set for a tour, filtered by version: a fresh user\n\t\t * (no seenVersion) gets all steps `<= appVersion`; an upgraded user gets\n\t\t * only steps newer than seenVersion and `<= appVersion`. A user-initiated\n\t\t * replay (`replaying`) ignores seenVersion and shows every step\n\t\t * `<= appVersion`.\n\t\t *\n\t\t * @param {object} tour The tour definition.\n\t\t * @return {Array} The visible steps for this user.\n\t\t */\n\t\tfunction composeSteps(tour) {\n\t\t\tconst all = Array.isArray(tour.steps) ? tour.steps : []\n\t\t\treturn all.filter((s) => {\n\t\t\t\tconst since = s.sinceVersion || '0.0.0'\n\t\t\t\tif (compareSemver(since, appVersion) > 0) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tif (!replaying.value && seenVersion && compareSemver(since, seenVersion) <= 0) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t})\n\t\t}\n\n\t\tconst activeTour = computed(() => {\n\t\t\tif (!activeTourId.value) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst tour = tours.find((t) => t.id === activeTourId.value)\n\t\t\tif (!tour) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn { ...tour, steps: composeSteps(tour) }\n\t\t})\n\n\t\t/**\n\t\t * The tour that should auto-start for this user, or null. A\n\t\t * `version-bump` tour only qualifies when it has a non-empty step delta;\n\t\t * `first-visit` qualifies only when the user has never seen the tour.\n\t\t *\n\t\t * @return {object|null} The auto-start tour (raw definition) or null.\n\t\t */\n\t\tconst autoStartTour = computed(() => {\n\t\t\tif (!enabled) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tfor (const tour of tours) {\n\t\t\t\tif (tour.minAppVersion && compareSemver(appVersion, tour.minAppVersion) < 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst steps = composeSteps(tour)\n\t\t\t\tif (steps.length === 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (tour.trigger === 'first-visit' && !seenVersion) {\n\t\t\t\t\treturn tour\n\t\t\t\t}\n\t\t\t\tif (tour.trigger === 'version-bump' && seenVersion && compareSemver(appVersion, seenVersion) > 0) {\n\t\t\t\t\treturn tour\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t})\n\n\t\tconst currentStep = computed(() => {\n\t\t\tconst t = activeTour.value\n\t\t\tif (!t) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = t.steps[currentIndex.value]\n\t\t\tif (!raw) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn interpolateStep(raw, context.value)\n\t\t})\n\t\tconst totalSteps = computed(() => (activeTour.value ? activeTour.value.steps.length : 0))\n\t\tconst isFirst = computed(() => currentIndex.value === 0)\n\t\tconst isLast = computed(() => totalSteps.value > 0 && currentIndex.value === totalSteps.value - 1)\n\n\t\t/**\n\t\t * Apply `{{var}}` interpolation to a step's user-facing + targeting fields.\n\t\t *\n\t\t * @param {object} step The raw step.\n\t\t * @param {object} ctx The context bag.\n\t\t * @return {object} A shallow copy with tokens resolved.\n\t\t */\n\t\tfunction interpolateStep(step, ctx) {\n\t\t\tconst out = { ...step }\n\t\t\tfor (const k of ['title', 'body', 'task']) {\n\t\t\t\tif (out[k]) {\n\t\t\t\t\tout[k] = interpolateTokens(out[k], ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (out.target) {\n\t\t\t\tout.target = { ...out.target }\n\t\t\t\tif (out.target.ref) {\n\t\t\t\t\tout.target.ref = interpolateTokens(out.target.ref, ctx)\n\t\t\t\t}\n\t\t\t\tif (out.target.selector) {\n\t\t\t\t\tout.target.selector = interpolateTokens(out.target.selector, ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (out.advanceOn) {\n\t\t\t\tout.advanceOn = { ...out.advanceOn }\n\t\t\t\tif (out.advanceOn.route) {\n\t\t\t\t\tout.advanceOn.route = interpolateTokens(out.advanceOn.route, ctx)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn out\n\t\t}\n\n\t\t/**\n\t\t * Run a step's `advanceOn.capture` against captured values.\n\t\t *\n\t\t * @param {object} step The active (raw) step.\n\t\t * @param {object} source `{ params?, object? }` to read captured values from.\n\t\t * @return {void}\n\t\t */\n\t\tfunction runCapture(step, source) {\n\t\t\tconst cap = step && step.advanceOn && step.advanceOn.capture\n\t\t\tif (!cap) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = { ...context.value }\n\t\t\tfor (const [varName, token] of Object.entries(cap)) {\n\t\t\t\tconst key = String(token).replace(/^:/, '')\n\t\t\t\tlet value\n\t\t\t\tif (source.params && key in source.params) {\n\t\t\t\t\tvalue = source.params[key]\n\t\t\t\t} else if (source.object) {\n\t\t\t\t\tvalue = (key === 'id') ? (source.object.id ?? source.object['@self']?.id ?? source.object.uuid) : source.object[key]\n\t\t\t\t}\n\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\tnext[varName] = value\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontext.value = next\n\t\t}\n\n\t\t/**\n\t\t * Advance to the next step, or complete on the last step. Skips\n\t\t * subsequent `optional` steps whose target ref is empty after interpolation.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction next() {\n\t\t\tif (!activeTour.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (currentIndex.value >= totalSteps.value - 1) {\n\t\t\t\tcomplete()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tcurrentIndex.value += 1\n\t\t}\n\t\t/**\n\t\t * Step back (no-op on the first step).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction back() {\n\t\t\tif (currentIndex.value > 0) {\n\t\t\t\tcurrentIndex.value -= 1\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t * Skip the active step (advance without satisfying its condition).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction skip() {\n\t\t\tnext()\n\t\t}\n\t\t/**\n\t\t * Jump to a step by id within the active tour.\n\t\t *\n\t\t * @param {string} stepId The target step id.\n\t\t * @return {void}\n\t\t */\n\t\tfunction jumpTo(stepId) {\n\t\t\tif (!activeTour.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst idx = activeTour.value.steps.findIndex((s) => s.id === stepId)\n\t\t\tif (idx >= 0) {\n\t\t\t\tcurrentIndex.value = idx\n\t\t\t}\n\t\t}\n\t\t/**\n\t\t * Start a tour by id at its first (resume) step.\n\t\t *\n\t\t * @param {string} tourId The tour id.\n\t\t * @param {number} [startIndex] Optional resume index.\n\t\t * @return {void}\n\t\t */\n\t\tfunction start(tourId, startIndex = 0) {\n\t\t\treplaying.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = tourId\n\t\t\tcurrentIndex.value = startIndex\n\t\t\tcontext.value = {}\n\t\t\trunning.value = true\n\t\t}\n\t\t/**\n\t\t * Restart a tour from the beginning (used by the \"Restart tutorial\" /\n\t\t * \"Replay\" entry). Runs in replay mode so the FULL tour shows even for a\n\t\t * returning user whose persisted seen-version already covers every step.\n\t\t *\n\t\t * @param {string} tourId The tour id.\n\t\t * @return {void}\n\t\t */\n\t\tfunction restart(tourId) {\n\t\t\tstart(tourId, 0)\n\t\t\treplaying.value = true\n\t\t}\n\t\t/**\n\t\t * Dismiss the active tour without marking it complete.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction dismiss() {\n\t\t\trunning.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = null\n\t\t\treplaying.value = false\n\t\t}\n\t\t/**\n\t\t * Hide the active tour without ending it (ESC, a click on the dim).\n\t\t * The tour and step are kept, so `resumePaused()` continues there.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @return {void}\n\t\t */\n\t\tfunction pause() {\n\t\t\tif (!activeTourId.value) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\trunning.value = false\n\t\t\tpaused.value = true\n\t\t}\n\t\t/**\n\t\t * Show a paused tour again at the step it was on.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @return {boolean} True when there was a paused tour to show.\n\t\t */\n\t\tfunction resumePaused() {\n\t\t\tif (!paused.value || !activeTourId.value) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tpaused.value = false\n\t\t\trunning.value = true\n\t\t\treturn true\n\t\t}\n\t\t/**\n\t\t * Start a tour at a remembered step (\"continue where you left off\").\n\t\t * Runs in replay mode so a returning user sees the full tour, and\n\t\t * falls back to the first step when the step no longer exists.\n\t\t *\n\t\t * @spec openspec/changes/walkthrough-advance-pause-resume/specs/cn-walkthrough/spec.md\n\t\t * @param {string} tourId The tour id.\n\t\t * @param {string} [stepId] The step to continue at.\n\t\t * @return {boolean} True when the tour exists and started.\n\t\t */\n\t\tfunction resumeAt(tourId, stepId) {\n\t\t\tconst tour = tours.find((t) => t.id === tourId)\n\t\t\tif (!tour) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treplaying.value = true\n\t\t\tconst idx = composeSteps(tour).findIndex((s) => s.id === stepId)\n\t\t\tstart(tourId, Math.max(0, idx))\n\t\t\treplaying.value = true\n\t\t\treturn true\n\t\t}\n\t\t/**\n\t\t * Mark the active tour complete: stop running and invoke the\n\t\t * `onComplete(appVersion)` persistence callback so the seen version is\n\t\t * recorded by the consumer (CnAppRoot).\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tfunction complete() {\n\t\t\trunning.value = false\n\t\t\tpaused.value = false\n\t\t\tactiveTourId.value = null\n\t\t\treplaying.value = false\n\t\t\tif (typeof options.onComplete === 'function') {\n\t\t\t\toptions.onComplete(appVersion)\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Feed a declarative advance signal to the active step. When the signal\n\t\t * satisfies the step's `advanceOn`, captures run and the tour advances.\n\t\t *\n\t\t * @param {object} signal `{ kind: 'route'|'object-created'|'element'|'click'|'delay', route?, params?, object? }`.\n\t\t * @return {boolean} Whether the signal advanced the tour.\n\t\t */\n\t\tfunction notify(signal) {\n\t\t\tconst step = activeTour.value && activeTour.value.steps[currentIndex.value]\n\t\t\tif (!step || !step.advanceOn) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst a = step.advanceOn\n\t\t\tlet match = false\n\t\t\tif (signal.kind === 'route' && a.type === 'route-match') {\n\t\t\t\tmatch = signal.route === a.route\n\t\t\t\tif (match) {\n\t\t\t\t\trunCapture(step, { params: signal.params || {} })\n\t\t\t\t}\n\t\t\t} else if (signal.kind === 'object-created' && a.type === 'object-created') {\n\t\t\t\tmatch = objectCreatedMatches(a, signal)\n\t\t\t\tif (match) {\n\t\t\t\t\trunCapture(step, { object: signal.object || {} })\n\t\t\t\t}\n\t\t\t} else if (signal.kind === 'element' && a.type === 'element-appears') {\n\t\t\t\tmatch = true\n\t\t\t} else if (signal.kind === 'click' && a.type === 'click-target') {\n\t\t\t\tmatch = true\n\t\t\t} else if (signal.kind === 'delay' && a.type === 'delay') {\n\t\t\t\tmatch = true\n\t\t\t}\n\t\t\tif (match) {\n\t\t\t\tnext()\n\t\t\t}\n\t\t\treturn match\n\t\t}\n\n\t\tentry = {\n\t\t\tenabled,\n\t\t\tappVersion,\n\t\t\tseenVersion,\n\t\t\ttours,\n\t\t\tactiveTour,\n\t\t\tautoStartTour,\n\t\t\tcurrentStep,\n\t\t\ttotalSteps,\n\t\t\tisFirst,\n\t\t\tisLast,\n\t\t\tcontext,\n\t\t\trunning,\n\t\t\tpaused,\n\t\t\treplaying,\n\t\t\tstart,\n\t\t\trestart,\n\t\t\tpause,\n\t\t\tresumePaused,\n\t\t\tresumeAt,\n\t\t\tnext,\n\t\t\tback,\n\t\t\tskip,\n\t\t\tjumpTo,\n\t\t\tdismiss,\n\t\t\tcomplete,\n\t\t\tnotify,\n\t\t\tinterpolate: (s) => interpolateTokens(s, context.value),\n\t\t}\n\t\tcache.set(appId, entry)\n\n\t\t// Resume token (cross-app hand-off / refresh) — start at the resume step.\n\t\tif (options.resume && options.resume.tourId) {\n\t\t\tconst tour = tours.find((t) => t.id === options.resume.tourId)\n\t\t\tif (tour) {\n\t\t\t\tconst steps = composeSteps(tour)\n\t\t\t\tconst idx = Math.max(0, steps.findIndex((s) => s.id === options.resume.stepId))\n\t\t\t\tstart(options.resume.tourId, idx)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn entry\n}\n\n/**\n * Test-only helper to reset the per-`appId` cache.\n *\n * @internal\n */\nexport function __resetWalkthroughCacheForTests() {\n\tcache.clear()\n}\n"],"names":["axios"],"mappings":"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"}