@conduction/nextcloud-vue 2.56.0-beta.34 → 2.56.0-beta.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue.js +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js +22 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue2.js.map +1 -1
- package/dist/esm/components/CnBodySections/CnBodySections.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +47 -4
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +239 -3
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +5 -5
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +5 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeltaWidget/CnDeltaWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +203 -4
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +38 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +45 -5
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnGaugeWidget/CnGaugeWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js +29 -6
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnInteractionFormWidget/CnInteractionFormWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +126 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +37 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +135 -2
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +95 -43
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue.js +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +72 -5
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +33 -8
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +17 -2
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +33 -3
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue.js +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +16 -0
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
- package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js +68 -6
- package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js +133 -105
- package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +16 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +38 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +525 -318
- package/dist/esm/utils/buildManifest.js +37 -3
- package/dist/esm/utils/buildManifest.js.map +1 -1
- package/dist/esm/utils/detailWidgetVisibility.js +149 -0
- package/dist/esm/utils/detailWidgetVisibility.js.map +1 -0
- package/dist/esm/utils/formatMetric.js +39 -3
- package/dist/esm/utils/formatMetric.js.map +1 -1
- package/dist/esm/utils/gridStack.js +40 -1
- package/dist/esm/utils/gridStack.js.map +1 -1
- package/dist/esm/utils/humaniseKey.js +41 -0
- package/dist/esm/utils/humaniseKey.js.map +1 -0
- package/dist/esm/utils/notificationRuleLabel.js +6 -23
- package/dist/esm/utils/notificationRuleLabel.js.map +1 -1
- package/dist/esm/utils/resolveManifestTokens.js +1 -0
- package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +9 -0
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2250 -708
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +525 -318
- package/l10n/en.json +16 -1
- package/l10n/nl.json +38 -1
- package/package.json +1 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +1 -1
- package/src/components/CnBodySections/CnBodySections.vue +22 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +47 -4
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +244 -8
- package/src/components/CnDashboardPage/CnDashboardPage.vue +5 -0
- package/src/components/CnDeltaWidget/CnDeltaWidget.vue +1 -1
- package/src/components/CnDetailPage/CnDetailPage.md +2 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +203 -4
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +63 -1
- package/src/components/CnGaugeWidget/CnGaugeWidget.vue +1 -1
- package/src/components/CnInteractionFormWidget/CnInteractionFormWidget.vue +29 -6
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +154 -5
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +37 -2
- package/src/components/CnReportsPage/CnReportsPage.vue +179 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +103 -6
- package/src/components/CnStatWidget/CnStatWidget.vue +1 -1
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +34 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +33 -3
- package/src/components/CnWalkthrough/CnWalkthrough.vue +16 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
- package/src/css/form-field.css +14 -0
- package/src/css/form-widget.css +11 -0
- package/src/css/kpi-card.css +13 -0
- package/src/css/look-board-reports.css +58 -0
- package/src/css/look-board.css +31 -0
- package/src/dialogs/CnTransitionInputDialog.vue +87 -7
- package/src/index.js +2 -0
- package/src/schemas/app-manifest-v2.schema.json +23 -2
- package/src/utils/buildManifest.js +36 -2
- package/src/utils/detailWidgetVisibility.js +145 -0
- package/src/utils/formatMetric.js +38 -2
- package/src/utils/gridStack.js +39 -0
- package/src/utils/humaniseKey.js +38 -0
- package/src/utils/notificationRuleLabel.js +5 -23
- package/src/utils/resolveManifestTokens.js +1 -0
- package/src/utils/sentinelTokens.js +9 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnWeekStripWidget.vue3.js","sources":["../../../../src/components/CnWeekStripWidget/CnWeekStripWidget.vue?vue&type=template&id=b6c5e274&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-week-strip\" :class=\"{ 'cn-week-strip--inset': inset }\" data-testid=\"cn-week-strip\">\n\t\t<div v-if=\"loading\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t<span class=\"cn-week-strip__state-text\">{{ loadingLabel }}</span>\n\t\t</div>\n\t\t<p v-else-if=\"error\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<!-- A scroll container a keyboard user cannot focus cannot be scrolled,\n\t\t so the region is focusable and named. -->\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-week-strip__scroll\"\n\t\t\trole=\"region\"\n\t\t\ttabindex=\"0\"\n\t\t\t:aria-label=\"regionLabel\">\n\t\t\t<ol class=\"cn-week-strip__days\" :style=\"{ '--cn-week-strip-columns': dayColumns.length }\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"day in dayColumns\"\n\t\t\t\t\t:key=\"day.key\"\n\t\t\t\t\tclass=\"cn-week-strip__day\"\n\t\t\t\t\t:class=\"{ 'cn-week-strip__day--today': day.today }\"\n\t\t\t\t\t:aria-current=\"day.today ? 'date' : null\"\n\t\t\t\t\t:data-day=\"day.key\">\n\t\t\t\t\t<span class=\"cn-week-strip__head\">\n\t\t\t\t\t\t<span class=\"cn-week-strip__label\">{{ day.label }}</span>\n\t\t\t\t\t\t<span v-if=\"day.today\" class=\"cn-week-strip__today\">{{ todayLabel }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<ul v-if=\"day.items.length > 0\" class=\"cn-week-strip__items\">\n\t\t\t\t\t\t<li v-for=\"item in day.shown\" :key=\"item.key\" class=\"cn-week-strip__item-row\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.href ? 'a' : 'div'\"\n\t\t\t\t\t\t\t\tclass=\"cn-week-strip__item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-week-strip__item--late': item.late, 'cn-week-strip__item--link': !!item.href }\"\n\t\t\t\t\t\t\t\t:href=\"item.href || null\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-week-strip-item\"\n\t\t\t\t\t\t\t\t@click=\"onItemClick($event, item)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-week-strip__title\">{{ item.title }}</strong>\n\t\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-week-strip__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"item.late\" class=\"cn-week-strip__late\">{{ lateLabel }}</span>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t\t<!-- `maxPerDay`: the rest of a full day sits behind \"+N more\": a link\n\t\t\t\t\t to `moreRoute`, or a button that opens the day in place. -->\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"day.hidden > 0 && moreHref\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:href=\"moreHref\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"onMoreClick($event)\">{{ moreLabel(day.hidden) }}</a>\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-else-if=\"day.hidden > 0 || day.expanded\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:aria-expanded=\"day.expanded ? 'true' : 'false'\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"toggleDay(day.key)\">\n\t\t\t\t\t\t{{ day.expanded ? lessLabel : moreLabel(day.hidden) }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<span v-if=\"day.items.length === 0\" class=\"cn-week-strip__empty\">{{ emptyLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { dayKey, daysUntil, parseDateValue } from '../../utils/dateVariant.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { objectDisplayName, objectFieldValue } from '../../utils/objectName.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { compareVisibleWhen } from '../../utils/visibleWhen.js'\n\nconst DEFAULT_LIMIT = 100\n\n/**\n * CnWeekStripWidget shows the current week as day columns, with the items\n * that fall on each day listed under it. Use it for deadlines, appointments\n * or anything else that has a date and that somebody should see coming.\n *\n * It renders the five working days by default (`days: 7` adds the weekend),\n * highlights today, marks items that are late, and says so when a day has\n * nothing. On a narrow screen the strip scrolls sideways.\n *\n * Items come from an OpenRegister source (one request for the whole week) or\n * from static `items`. Resolved by its registry type key `week-strip`.\n *\n * ```json\n * {\n * \"widgetKey\": \"week-strip\",\n * \"props\": {\n * \"content\": {\n * \"source\": { \"register\": \"dossiq\", \"schema\": \"case\", \"filter\": { \"assignee\": \"@me\" } },\n * \"dateField\": \"deadline\",\n * \"titleField\": \"title\",\n * \"metaFields\": [\"identifier\", \"caseType\"],\n * \"itemRoute\": \"CaseDetail\",\n * \"emptyText\": \"No deadlines\"\n * }\n * }\n * }\n * ```\n */\nexport default {\n\tname: 'CnWeekStripWidget',\n\n\tcomponents: { NcLoadingIcon },\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot. The manifest-authored\n\t\t * `emptyText` and static item texts run through it. Identity by default.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration. `days` is `5` (working days, the\n\t\t * default) or `7`. `source` names the OpenRegister register and schema,\n\t\t * with an optional `filter` (the shared @-token grammar) and `limit`.\n\t\t * `dateField` is the field the items are bucketed by. `titleField` and\n\t\t * `metaFields` pick what each item shows. `itemRoute` is the route name\n\t\t * an item links to (with the record id as `params.id`). `lateWhen` is a\n\t\t * `{ op, value }` rule on the days until the date (default: before\n\t\t * today), `lateField` a boolean field that marks a record late.\n\t\t * `items` are static entries `{ title, meta?, date, route?, href?, late? }`.\n\t\t * `emptyText` is the text of a day without items. `weekOffset` moves\n\t\t * the strip whole weeks from the current one. `inset: true` draws the\n\t\t * strip inside the board's inset (16px above, 24px at the sides, 22px\n\t\t * below) instead of from card edge to card edge. `maxPerDay` caps the\n\t\t * items a day shows; the rest sit behind \"+N more\", a link to\n\t\t * `moreRoute` (a route name or object) or, without one, a button that\n\t\t * opens the day in place. `moreLabel` replaces the text (`{count}` is\n\t\t * the number hidden).\n\t\t *\n\t\t * @type {{maxPerDay?: number, moreRoute?: (string|object), moreLabel?: string, days?: (5|7), inset?: boolean, source?: {register?: string, schema?: string, filter?: object, limit?: number}, dateField?: string, titleField?: string, metaFields?: Array<string>, itemRoute?: string, lateWhen?: {op?: string, value?: number}, lateField?: string, items?: Array<{title: string, meta?: string, date: string, route?: (string|object), href?: string, late?: boolean}>, emptyText?: string, weekOffset?: number}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`. Pass it\n\t\t * when mounting the widget outside a CnAppRoot.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The moment the strip treats as \"now\". Leave empty for the current\n\t\t * time; set it to render another week or to test.\n\t\t *\n\t\t * @type {Date|null}\n\t\t */\n\t\tnow: {\n\t\t\ttype: Date,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\trows: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\t/** The days opened past `maxPerDay`, by day key. */\n\t\t\texpandedDays: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the widget draws the board's inset (`content.inset`). Off\n\t\t * by default, which keeps it edge to edge as before.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-strip-and-a-stacked-bar-can-take-the-board-inset\n\t\t * @return {boolean}\n\t\t */\n\t\tinset() {\n\t\t\treturn Boolean(this.content && this.content.inset === true)\n\t\t},\n\n\t\t/**\n\t\t * The translate function in use.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn this.translate ?? this.cnTranslate\n\t\t},\n\n\t\t/**\n\t\t * The reference moment.\n\t\t *\n\t\t * @return {Date}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\treference() {\n\t\t\treturn this.now instanceof Date ? this.now : new Date()\n\t\t},\n\n\t\t/**\n\t\t * How many day columns render: 7, or 5 for anything else.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayCount() {\n\t\t\treturn Number(this.content.days) === 7 ? 7 : 5\n\t\t},\n\n\t\t/**\n\t\t * The days of the strip, Monday first.\n\t\t *\n\t\t * @return {Array<Date>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tweekDays() {\n\t\t\tconst ref = this.reference\n\t\t\tconst offset = Number.isInteger(this.content.weekOffset) ? this.content.weekOffset : 0\n\t\t\tconst mondayDelta = (ref.getDay() + 6) % 7\n\t\t\tconst days = []\n\t\t\tfor (let i = 0; i < this.dayCount; i++) {\n\t\t\t\tdays.push(new Date(ref.getFullYear(), ref.getMonth(), ref.getDate() - mondayDelta + (offset * 7) + i))\n\t\t\t}\n\t\t\treturn days\n\t\t},\n\n\t\t/**\n\t\t * The field the items are bucketed by.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdateField() {\n\t\t\treturn typeof this.content.dateField === 'string' ? this.content.dateField : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the items come from OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\thasSource() {\n\t\t\tconst s = this.content.source || {}\n\t\t\treturn Boolean(s.register && s.schema && this.dateField)\n\t\t},\n\n\t\t/**\n\t\t * Every item, from the source rows or the static list, in one shape.\n\t\t *\n\t\t * @return {Array<{key: string, title: string, meta: string, date: (Date|null), late: boolean, href: string, target: (object|string|null)}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tnormalizedItems() {\n\t\t\tif (this.hasSource) {\n\t\t\t\treturn this.rows.map((row, index) => this.itemFromRow(row, index))\n\t\t\t}\n\t\t\tconst items = Array.isArray(this.content.items) ? this.content.items : []\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && typeof item === 'object')\n\t\t\t\t.map((item, index) => this.itemFromStatic(item, index))\n\t\t},\n\n\t\t/**\n\t\t * The columns: one per day, each with its items.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, today: boolean, items: Array<object>}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayColumns() {\n\t\t\tconst todayKey = dayKey(this.reference)\n\t\t\tconst buckets = {}\n\t\t\tfor (const item of this.normalizedItems) {\n\t\t\t\tif (item.date === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst key = dayKey(item.date)\n\t\t\t\t;(buckets[key] = buckets[key] || []).push(item)\n\t\t\t}\n\t\t\tconst formatter = this.dayFormatter\n\t\t\treturn this.weekDays.map((day) => {\n\t\t\t\tconst key = dayKey(day)\n\t\t\t\tconst items = buckets[key] || []\n\t\t\t\tconst expanded = this.expandedDays[key] === true\n\t\t\t\tconst cap = this.maxPerDay > 0 && !expanded ? this.maxPerDay : items.length\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\tlabel: formatter.format(day),\n\t\t\t\t\ttoday: key === todayKey,\n\t\t\t\t\titems,\n\t\t\t\t\tshown: items.slice(0, cap),\n\t\t\t\t\thidden: Math.max(0, items.length - cap),\n\t\t\t\t\texpanded: expanded && this.maxPerDay > 0 && items.length > this.maxPerDay,\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The most items a day shows (`content.maxPerDay`), or 0 for no cap.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmaxPerDay() {\n\t\t\tconst value = Number(this.content.maxPerDay)\n\t\t\treturn Number.isInteger(value) && value > 0 ? value : 0\n\t\t},\n\n\t\t/**\n\t\t * Where \"+N more\" leads (`content.moreRoute`), or null to open the day in place.\n\t\t *\n\t\t * @return {object|null}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreTarget() {\n\t\t\tconst route = this.content.moreRoute\n\t\t\tif (typeof route === 'string' && route !== '') {\n\t\t\t\treturn { name: route }\n\t\t\t}\n\t\t\treturn route && typeof route === 'object' ? route : null\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The href of the \"+N more\" link, '' without a target.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreHref() {\n\t\t\treturn this.moreTarget ? (resolveHref(this.moreTarget, this.$router) || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text that closes an opened day.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tlessLabel() {\n\t\t\treturn t('nextcloud-vue', 'Show less')\n\t\t},\n\n\t\t/**\n\t\t * Formats a day as a short weekday and a day number (\"Mon 5\").\n\t\t *\n\t\t * @return {Intl.DateTimeFormat}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayFormatter() {\n\t\t\tlet locale\n\t\t\ttry {\n\t\t\t\tlocale = getCanonicalLocale()\n\t\t\t} catch {\n\t\t\t\tlocale = undefined\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale || undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t} catch {\n\t\t\t\treturn new Intl.DateTimeFormat(undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of a day without items.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\temptyLabel() {\n\t\t\tconst text = this.content.emptyText\n\t\t\treturn (typeof text === 'string' && text !== '')\n\t\t\t\t? this.effectiveTranslate(text)\n\t\t\t\t: t('nextcloud-vue', 'Nothing planned')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The badge on today's column.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\ttodayLabel() {\n\t\t\treturn t('nextcloud-vue', 'today')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The marker on a late item.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tlateLabel() {\n\t\t\treturn t('nextcloud-vue', 'Late')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The accessible name of the scrolling region.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tregionLabel() {\n\t\t\treturn t('nextcloud-vue', 'This week, day by day')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The loading text.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text shown when the items could not be loaded.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\terrorLabel() {\n\t\t\treturn t('nextcloud-vue', 'The items for this week could not be loaded.')\n\t\t},\n\n\t\t/**\n\t\t * Changes whenever a new fetch is needed.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tsourceKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\ts: this.content.source || {},\n\t\t\t\tf: this.dateField,\n\t\t\t\td: this.weekDays.length > 0 ? [dayKey(this.weekDays[0]), this.weekDays.length] : [],\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget */\n\t\tsourceKey() {\n\t\t\tthis.fetchItems()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.fetchItems()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a date counts as late under `content.lateWhen` (default:\n\t\t * before today).\n\t\t *\n\t\t * @param {Date|null} date The item's date.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tisLateDate(date) {\n\t\t\tif (date === null) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst rule = (this.content.lateWhen && typeof this.content.lateWhen === 'object')\n\t\t\t\t? this.content.lateWhen\n\t\t\t\t: { op: 'lt', value: 0 }\n\t\t\treturn compareVisibleWhen(daysUntil(date, this.reference), rule.op || 'lt', rule.value ?? 0)\n\t\t},\n\n\t\t/**\n\t\t * One OpenRegister record as a strip item.\n\t\t *\n\t\t * @param {object} row The record.\n\t\t * @param {number} index Its position, used as a key of last resort.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromRow(row, index) {\n\t\t\tconst c = this.content\n\t\t\tconst id = row && (row.id || (row['@self'] && row['@self'].id))\n\t\t\tconst date = parseDateValue(objectFieldValue(row, this.dateField))\n\t\t\tconst titleValue = c.titleField ? objectFieldValue(row, c.titleField) : undefined\n\t\t\tconst title = (titleValue !== undefined && titleValue !== null && titleValue !== '')\n\t\t\t\t? String(titleValue)\n\t\t\t\t: objectDisplayName(row)\n\t\t\tconst metaFields = Array.isArray(c.metaFields) ? c.metaFields : []\n\t\t\tconst meta = metaFields\n\t\t\t\t.map((field) => objectFieldValue(row, field))\n\t\t\t\t.filter((value) => value !== undefined && value !== null && value !== '' && typeof value !== 'object')\n\t\t\t\t.map(String)\n\t\t\t\t.join(' · ')\n\t\t\tconst flagged = c.lateField ? objectFieldValue(row, c.lateField) === true : false\n\t\t\tconst target = (c.itemRoute && id) ? { name: c.itemRoute, params: { id } } : null\n\t\t\treturn {\n\t\t\t\tkey: String(id || `row-${index}`),\n\t\t\t\ttitle,\n\t\t\t\tmeta,\n\t\t\t\tdate,\n\t\t\t\tlate: flagged || this.isLateDate(date),\n\t\t\t\ttarget,\n\t\t\t\thref: target ? resolveHref(target, this.$router) : '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * One static manifest entry as a strip item.\n\t\t *\n\t\t * @param {object} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromStatic(item, index) {\n\t\t\tconst date = parseDateValue(item.date)\n\t\t\tlet target = null\n\t\t\tlet href = ''\n\t\t\tif (item.route) {\n\t\t\t\ttarget = typeof item.route === 'string' ? { name: item.route } : item.route\n\t\t\t\thref = resolveHref(target, this.$router)\n\t\t\t} else if (typeof item.href === 'string' && item.href !== '') {\n\t\t\t\tconst safe = safeHref(item.href)\n\t\t\t\thref = safe === '#' ? '' : safe\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `item-${index}`,\n\t\t\t\ttitle: typeof item.title === 'string' ? this.effectiveTranslate(item.title) : '',\n\t\t\t\tmeta: typeof item.meta === 'string' ? this.effectiveTranslate(item.meta) : '',\n\t\t\t\tdate,\n\t\t\t\tlate: item.late === true || (item.late !== false && this.isLateDate(date)),\n\t\t\t\ttarget,\n\t\t\t\thref,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load the week's records in one request.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tasync fetchItems() {\n\t\t\tif (!this.hasSource) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.error = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst s = this.content.source\n\t\t\tconst requestKey = this.sourceKey\n\t\t\tconst first = this.weekDays[0]\n\t\t\tconst last = this.weekDays[this.weekDays.length - 1]\n\t\t\tconst dayAfter = new Date(last.getFullYear(), last.getMonth(), last.getDate() + 1)\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/{register}/{schema}',\n\t\t\t\t\t{ register: s.register, schema: s.schema },\n\t\t\t\t)\n\t\t\t\tconst params = {\n\t\t\t\t\t_limit: Number.isInteger(s.limit) && s.limit > 0 ? s.limit : DEFAULT_LIMIT,\n\t\t\t\t\t[`_order[${this.dateField}]`]: 'asc',\n\t\t\t\t}\n\t\t\t\tconst filter = resolveFilterTokens(s.filter || {}, {})\n\t\t\t\tfor (const [k, v] of Object.entries(filter || {})) {\n\t\t\t\t\tif (v && typeof v === 'object') {\n\t\t\t\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\t\t\t\tparams[`${k}[${op}]`] = ov\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The week window goes last, so a manifest filter on the date\n\t\t\t\t// field cannot widen the strip beyond the days it shows.\n\t\t\t\tparams[`${this.dateField}[gte]`] = dayKey(first)\n\t\t\t\tparams[`${this.dateField}[lt]`] = dayKey(dayAfter)\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tif (requestKey !== this.sourceKey) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.rows = (res && res.data && Array.isArray(res.data.results)) ? res.data.results : []\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnWeekStripWidget] failed to load items:', e)\n\t\t\t\tthis.error = (e && e.message) || 'error'\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of the \"+N more\" control: `content.moreLabel` with `{count}`\n\t\t * filled, else \"+N more\" from the library's catalogue.\n\t\t *\n\t\t * @param {number} count The number of hidden items.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreLabel(count) {\n\t\t\tconst own = this.content.moreLabel\n\t\t\tif (typeof own === 'string' && own !== '') {\n\t\t\t\treturn this.effectiveTranslate(own).replace(/\\{count\\}/g, String(count))\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '+{count} more', { count })\n\t\t},\n\n\t\t/**\n\t\t * Open or close a day past its cap.\n\t\t *\n\t\t * @param {string} key The day key.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\ttoggleDay(key) {\n\t\t\tthis.expandedDays = { ...this.expandedDays, [key]: this.expandedDays[key] !== true }\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on the \"+N more\" link.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tonMoreClick(event) {\n\t\t\tif (this.moreTarget) {\n\t\t\t\tfollowLinkClick(event, this.moreTarget, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on an in-app item; the browser handles the rest.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @param {object} item The clicked item.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tonItemClick(event, item) {\n\t\t\tif (item.target) {\n\t\t\t\tfollowLinkClick(event, item.target, this.$router)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-week-strip {\n\twidth: 100%;\n}\n\n/* `content.inset: true`: the board's inset inside the card (zuiddrecht-pixel-\n gaps-3). A dashboard renders its widgets flush, so without it the strip ran\n from card edge to card edge. Theme hook: --cn-widget-board-inset. */\n.cn-week-strip--inset {\n\tbox-sizing: border-box;\n\tpadding: var(--cn-widget-board-inset, 16px 24px 22px);\n}\n\n.cn-week-strip__state {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tpadding: 12px 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-week-strip__scroll {\n\toverflow-x: auto;\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-week-strip__scroll:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-week-strip__days {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-week-strip-columns, 5), minmax(128px, 1fr));\n\tgap: 10px;\n\t/* 5 columns of 128px plus gaps: below this the region scrolls sideways. */\n\tmin-width: calc(var(--cn-week-strip-columns, 5) * 136px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__day {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n\tpadding: 10px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-week-strip__day--today {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-week-strip__head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 6px;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-week-strip__today {\n\tpadding: 1px 8px;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tfont-size: 0.85em;\n\tfont-weight: 700;\n}\n\n.cn-week-strip__items {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-week-strip__item--link:hover {\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-week-strip__item--link:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* The edge is drawn inside the box, so a late item is as wide as the others. */\n.cn-week-strip__item--late {\n\tborder-color: var(--color-element-error, var(--color-error));\n\tbox-shadow: inset 3px 0 0 0 var(--color-element-error, var(--color-error));\n}\n\n.cn-week-strip__title {\n\tfont-size: 0.95em;\n\tline-height: 1.3;\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__meta {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__late {\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-error, var(--color-error-text));\n}\n\n.cn-week-strip__empty {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* \"+N more\" under a capped day: a quiet text control, 24px high to click. */\n.cn-week-strip__more {\n\talign-self: flex-start;\n\tmin-height: 24px;\n\tmargin: 0;\n\tpadding: 2px 4px;\n\tborder: 0;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground: transparent;\n\tcolor: var(--color-primary-element);\n\tfont: inherit;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n\n.cn-week-strip__more:hover {\n\ttext-decoration: underline;\n}\n\n.cn-week-strip__more:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnWeekStripWidget.vue3.js","sources":["../../../../src/components/CnWeekStripWidget/CnWeekStripWidget.vue?vue&type=template&id=27a717bd&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-week-strip\" :class=\"{ 'cn-week-strip--inset': inset }\" data-testid=\"cn-week-strip\">\n\t\t<div v-if=\"loading\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t<span class=\"cn-week-strip__state-text\">{{ loadingLabel }}</span>\n\t\t</div>\n\t\t<p v-else-if=\"error\" class=\"cn-week-strip__state\" role=\"status\">\n\t\t\t{{ errorLabel }}\n\t\t</p>\n\t\t<!-- A scroll container a keyboard user cannot focus cannot be scrolled,\n\t\t so the region is focusable and named. -->\n\t\t<div\n\t\t\tv-else\n\t\t\tclass=\"cn-week-strip__scroll\"\n\t\t\trole=\"region\"\n\t\t\ttabindex=\"0\"\n\t\t\t:aria-label=\"regionLabel\">\n\t\t\t<ol class=\"cn-week-strip__days\" :style=\"{ '--cn-week-strip-columns': dayColumns.length }\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"day in dayColumns\"\n\t\t\t\t\t:key=\"day.key\"\n\t\t\t\t\tclass=\"cn-week-strip__day\"\n\t\t\t\t\t:class=\"{ 'cn-week-strip__day--today': day.today }\"\n\t\t\t\t\t:aria-current=\"day.today ? 'date' : null\"\n\t\t\t\t\t:data-day=\"day.key\">\n\t\t\t\t\t<span class=\"cn-week-strip__head\">\n\t\t\t\t\t\t<span class=\"cn-week-strip__label\">{{ day.label }}</span>\n\t\t\t\t\t\t<span v-if=\"day.today\" class=\"cn-week-strip__today\">{{ todayLabel }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<ul v-if=\"day.items.length > 0\" class=\"cn-week-strip__items\">\n\t\t\t\t\t\t<li v-for=\"item in day.shown\" :key=\"item.key\" class=\"cn-week-strip__item-row\">\n\t\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t\t:is=\"item.href ? 'a' : 'div'\"\n\t\t\t\t\t\t\t\tclass=\"cn-week-strip__item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-week-strip__item--late': item.late, 'cn-week-strip__item--link': !!item.href }\"\n\t\t\t\t\t\t\t\t:href=\"item.href || null\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-week-strip-item\"\n\t\t\t\t\t\t\t\t@click=\"onItemClick($event, item)\">\n\t\t\t\t\t\t\t\t<strong class=\"cn-week-strip__title\">{{ item.title }}</strong>\n\t\t\t\t\t\t\t\t<span v-if=\"item.meta\" class=\"cn-week-strip__meta\">{{ item.meta }}</span>\n\t\t\t\t\t\t\t\t<span v-if=\"item.late\" class=\"cn-week-strip__late\">{{ lateLabel }}</span>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t</ul>\n\t\t\t\t\t<!-- `maxPerDay`: the rest of a full day sits behind \"+N more\": a link\n\t\t\t\t\t to `moreRoute`, or a button that opens the day in place. -->\n\t\t\t\t\t<a\n\t\t\t\t\t\tv-if=\"day.hidden > 0 && moreHref\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:href=\"moreHref\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"onMoreClick($event)\">{{ moreLabel(day.hidden) }}</a>\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-else-if=\"day.hidden > 0 || day.expanded\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-week-strip__more\"\n\t\t\t\t\t\t:aria-expanded=\"day.expanded ? 'true' : 'false'\"\n\t\t\t\t\t\tdata-testid=\"cn-week-strip-more\"\n\t\t\t\t\t\t@click=\"toggleDay(day.key)\">\n\t\t\t\t\t\t{{ day.expanded ? lessLabel : moreLabel(day.hidden) }}\n\t\t\t\t\t</button>\n\t\t\t\t\t<span v-if=\"day.items.length === 0\" class=\"cn-week-strip__empty\">{{ emptyLabel }}</span>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getCanonicalLocale, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { dayKey, daysUntil, parseDateValue } from '../../utils/dateVariant.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { objectDisplayName, objectFieldValue } from '../../utils/objectName.js'\nimport { resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { safeHref } from '../../utils/safeHref.js'\nimport { compareVisibleWhen } from '../../utils/visibleWhen.js'\n\nconst DEFAULT_LIMIT = 100\n\n/**\n * CnWeekStripWidget shows the current week as day columns, with the items\n * that fall on each day listed under it. Use it for deadlines, appointments\n * or anything else that has a date and that somebody should see coming.\n *\n * It renders the five working days by default (`days: 7` adds the weekend),\n * highlights today, marks items that are late, and says so when a day has\n * nothing. On a narrow screen the strip scrolls sideways; under the board\n * look (`.cn-look-board`) the days wrap into rows instead.\n *\n * Items come from an OpenRegister source (one request for the whole week) or\n * from static `items`. Resolved by its registry type key `week-strip`.\n *\n * ```json\n * {\n * \"widgetKey\": \"week-strip\",\n * \"props\": {\n * \"content\": {\n * \"source\": { \"register\": \"dossiq\", \"schema\": \"case\", \"filter\": { \"assignee\": \"@me\" } },\n * \"dateField\": \"deadline\",\n * \"titleField\": \"title\",\n * \"metaFields\": [\"identifier\", \"caseType\"],\n * \"itemRoute\": \"CaseDetail\",\n * \"emptyText\": \"No deadlines\"\n * }\n * }\n * }\n * ```\n */\nexport default {\n\tname: 'CnWeekStripWidget',\n\n\tcomponents: { NcLoadingIcon },\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function provided by CnAppRoot. The manifest-authored\n\t\t * `emptyText` and static item texts run through it. Identity by default.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's configuration. `days` is `5` (working days, the\n\t\t * default) or `7`. `source` names the OpenRegister register and schema,\n\t\t * with an optional `filter` (the shared @-token grammar) and `limit`.\n\t\t * `dateField` is the field the items are bucketed by. `titleField` and\n\t\t * `metaFields` pick what each item shows. `itemRoute` is the route name\n\t\t * an item links to (with the record id as `params.id`). `lateWhen` is a\n\t\t * `{ op, value }` rule on the days until the date (default: before\n\t\t * today), `lateField` a boolean field that marks a record late.\n\t\t * `items` are static entries `{ title, meta?, date, route?, href?, late? }`.\n\t\t * `emptyText` is the text of a day without items. `weekOffset` moves\n\t\t * the strip whole weeks from the current one. `inset: true` draws the\n\t\t * strip inside the board's inset (16px above, 24px at the sides, 22px\n\t\t * below) instead of from card edge to card edge. `maxPerDay` caps the\n\t\t * items a day shows; the rest sit behind \"+N more\", a link to\n\t\t * `moreRoute` (a route name or object) or, without one, a button that\n\t\t * opens the day in place. `moreLabel` replaces the text (`{count}` is\n\t\t * the number hidden).\n\t\t *\n\t\t * @type {{maxPerDay?: number, moreRoute?: (string|object), moreLabel?: string, days?: (5|7), inset?: boolean, source?: {register?: string, schema?: string, filter?: object, limit?: number}, dateField?: string, titleField?: string, metaFields?: Array<string>, itemRoute?: string, lateWhen?: {op?: string, value?: number}, lateField?: string, items?: Array<{title: string, meta?: string, date: string, route?: (string|object), href?: string, late?: boolean}>, emptyText?: string, weekOffset?: number}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`. Pass it\n\t\t * when mounting the widget outside a CnAppRoot.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The moment the strip treats as \"now\". Leave empty for the current\n\t\t * time; set it to render another week or to test.\n\t\t *\n\t\t * @type {Date|null}\n\t\t */\n\t\tnow: {\n\t\t\ttype: Date,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\trows: [],\n\t\t\tloading: false,\n\t\t\terror: '',\n\t\t\t/** The days opened past `maxPerDay`, by day key. */\n\t\t\texpandedDays: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Whether the widget draws the board's inset (`content.inset`). Off\n\t\t * by default, which keeps it edge to edge as before.\n\t\t *\n\t\t * @spec openspec/changes/zuiddrecht-pixel-gaps-3/specs/zuiddrecht-pixel-gaps-3/spec.md#requirement-a-strip-and-a-stacked-bar-can-take-the-board-inset\n\t\t * @return {boolean}\n\t\t */\n\t\tinset() {\n\t\t\treturn Boolean(this.content && this.content.inset === true)\n\t\t},\n\n\t\t/**\n\t\t * The translate function in use.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\teffectiveTranslate() {\n\t\t\treturn this.translate ?? this.cnTranslate\n\t\t},\n\n\t\t/**\n\t\t * The reference moment.\n\t\t *\n\t\t * @return {Date}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\treference() {\n\t\t\treturn this.now instanceof Date ? this.now : new Date()\n\t\t},\n\n\t\t/**\n\t\t * How many day columns render: 7, or 5 for anything else.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayCount() {\n\t\t\treturn Number(this.content.days) === 7 ? 7 : 5\n\t\t},\n\n\t\t/**\n\t\t * The days of the strip, Monday first.\n\t\t *\n\t\t * @return {Array<Date>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tweekDays() {\n\t\t\tconst ref = this.reference\n\t\t\tconst offset = Number.isInteger(this.content.weekOffset) ? this.content.weekOffset : 0\n\t\t\tconst mondayDelta = (ref.getDay() + 6) % 7\n\t\t\tconst days = []\n\t\t\tfor (let i = 0; i < this.dayCount; i++) {\n\t\t\t\tdays.push(new Date(ref.getFullYear(), ref.getMonth(), ref.getDate() - mondayDelta + (offset * 7) + i))\n\t\t\t}\n\t\t\treturn days\n\t\t},\n\n\t\t/**\n\t\t * The field the items are bucketed by.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdateField() {\n\t\t\treturn typeof this.content.dateField === 'string' ? this.content.dateField : ''\n\t\t},\n\n\t\t/**\n\t\t * Whether the items come from OpenRegister.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\thasSource() {\n\t\t\tconst s = this.content.source || {}\n\t\t\treturn Boolean(s.register && s.schema && this.dateField)\n\t\t},\n\n\t\t/**\n\t\t * Every item, from the source rows or the static list, in one shape.\n\t\t *\n\t\t * @return {Array<{key: string, title: string, meta: string, date: (Date|null), late: boolean, href: string, target: (object|string|null)}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tnormalizedItems() {\n\t\t\tif (this.hasSource) {\n\t\t\t\treturn this.rows.map((row, index) => this.itemFromRow(row, index))\n\t\t\t}\n\t\t\tconst items = Array.isArray(this.content.items) ? this.content.items : []\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && typeof item === 'object')\n\t\t\t\t.map((item, index) => this.itemFromStatic(item, index))\n\t\t},\n\n\t\t/**\n\t\t * The columns: one per day, each with its items.\n\t\t *\n\t\t * @return {Array<{key: string, label: string, today: boolean, items: Array<object>}>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayColumns() {\n\t\t\tconst todayKey = dayKey(this.reference)\n\t\t\tconst buckets = {}\n\t\t\tfor (const item of this.normalizedItems) {\n\t\t\t\tif (item.date === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst key = dayKey(item.date)\n\t\t\t\t;(buckets[key] = buckets[key] || []).push(item)\n\t\t\t}\n\t\t\tconst formatter = this.dayFormatter\n\t\t\treturn this.weekDays.map((day) => {\n\t\t\t\tconst key = dayKey(day)\n\t\t\t\tconst items = buckets[key] || []\n\t\t\t\tconst expanded = this.expandedDays[key] === true\n\t\t\t\tconst cap = this.maxPerDay > 0 && !expanded ? this.maxPerDay : items.length\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\tlabel: formatter.format(day),\n\t\t\t\t\ttoday: key === todayKey,\n\t\t\t\t\titems,\n\t\t\t\t\tshown: items.slice(0, cap),\n\t\t\t\t\thidden: Math.max(0, items.length - cap),\n\t\t\t\t\texpanded: expanded && this.maxPerDay > 0 && items.length > this.maxPerDay,\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The most items a day shows (`content.maxPerDay`), or 0 for no cap.\n\t\t *\n\t\t * @return {number}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmaxPerDay() {\n\t\t\tconst value = Number(this.content.maxPerDay)\n\t\t\treturn Number.isInteger(value) && value > 0 ? value : 0\n\t\t},\n\n\t\t/**\n\t\t * Where \"+N more\" leads (`content.moreRoute`), or null to open the day in place.\n\t\t *\n\t\t * @return {object|null}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreTarget() {\n\t\t\tconst route = this.content.moreRoute\n\t\t\tif (typeof route === 'string' && route !== '') {\n\t\t\t\treturn { name: route }\n\t\t\t}\n\t\t\treturn route && typeof route === 'object' ? route : null\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The href of the \"+N more\" link, '' without a target.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreHref() {\n\t\t\treturn this.moreTarget ? (resolveHref(this.moreTarget, this.$router) || '') : ''\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text that closes an opened day.\n\t\t *\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tlessLabel() {\n\t\t\treturn t('nextcloud-vue', 'Show less')\n\t\t},\n\n\t\t/**\n\t\t * Formats a day as a short weekday and a day number (\"Mon 5\").\n\t\t *\n\t\t * @return {Intl.DateTimeFormat}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tdayFormatter() {\n\t\t\tlet locale\n\t\t\ttry {\n\t\t\t\tlocale = getCanonicalLocale()\n\t\t\t} catch {\n\t\t\t\tlocale = undefined\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale || undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t} catch {\n\t\t\t\treturn new Intl.DateTimeFormat(undefined, { weekday: 'short', day: 'numeric' })\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of a day without items.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\temptyLabel() {\n\t\t\tconst text = this.content.emptyText\n\t\t\treturn (typeof text === 'string' && text !== '')\n\t\t\t\t? this.effectiveTranslate(text)\n\t\t\t\t: t('nextcloud-vue', 'Nothing planned')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The badge on today's column.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\ttodayLabel() {\n\t\t\treturn t('nextcloud-vue', 'today')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The marker on a late item.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tlateLabel() {\n\t\t\treturn t('nextcloud-vue', 'Late')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The accessible name of the scrolling region.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tregionLabel() {\n\t\t\treturn t('nextcloud-vue', 'This week, day by day')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The loading text.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/**\n\t\t * @return {string} The text shown when the items could not be loaded.\n\t\t *\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\terrorLabel() {\n\t\t\treturn t('nextcloud-vue', 'The items for this week could not be loaded.')\n\t\t},\n\n\t\t/**\n\t\t * Changes whenever a new fetch is needed.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tsourceKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\ts: this.content.source || {},\n\t\t\t\tf: this.dateField,\n\t\t\t\td: this.weekDays.length > 0 ? [dayKey(this.weekDays[0]), this.weekDays.length] : [],\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\t/** @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget */\n\t\tsourceKey() {\n\t\t\tthis.fetchItems()\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.fetchItems()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a date counts as late under `content.lateWhen` (default:\n\t\t * before today).\n\t\t *\n\t\t * @param {Date|null} date The item's date.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tisLateDate(date) {\n\t\t\tif (date === null) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst rule = (this.content.lateWhen && typeof this.content.lateWhen === 'object')\n\t\t\t\t? this.content.lateWhen\n\t\t\t\t: { op: 'lt', value: 0 }\n\t\t\treturn compareVisibleWhen(daysUntil(date, this.reference), rule.op || 'lt', rule.value ?? 0)\n\t\t},\n\n\t\t/**\n\t\t * One OpenRegister record as a strip item.\n\t\t *\n\t\t * @param {object} row The record.\n\t\t * @param {number} index Its position, used as a key of last resort.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromRow(row, index) {\n\t\t\tconst c = this.content\n\t\t\tconst id = row && (row.id || (row['@self'] && row['@self'].id))\n\t\t\tconst date = parseDateValue(objectFieldValue(row, this.dateField))\n\t\t\tconst titleValue = c.titleField ? objectFieldValue(row, c.titleField) : undefined\n\t\t\tconst title = (titleValue !== undefined && titleValue !== null && titleValue !== '')\n\t\t\t\t? String(titleValue)\n\t\t\t\t: objectDisplayName(row)\n\t\t\tconst metaFields = Array.isArray(c.metaFields) ? c.metaFields : []\n\t\t\tconst meta = metaFields\n\t\t\t\t.map((field) => objectFieldValue(row, field))\n\t\t\t\t.filter((value) => value !== undefined && value !== null && value !== '' && typeof value !== 'object')\n\t\t\t\t.map(String)\n\t\t\t\t.join(' · ')\n\t\t\tconst flagged = c.lateField ? objectFieldValue(row, c.lateField) === true : false\n\t\t\tconst target = (c.itemRoute && id) ? { name: c.itemRoute, params: { id } } : null\n\t\t\treturn {\n\t\t\t\tkey: String(id || `row-${index}`),\n\t\t\t\ttitle,\n\t\t\t\tmeta,\n\t\t\t\tdate,\n\t\t\t\tlate: flagged || this.isLateDate(date),\n\t\t\t\ttarget,\n\t\t\t\thref: target ? resolveHref(target, this.$router) : '',\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * One static manifest entry as a strip item.\n\t\t *\n\t\t * @param {object} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {object} The item.\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\titemFromStatic(item, index) {\n\t\t\tconst date = parseDateValue(item.date)\n\t\t\tlet target = null\n\t\t\tlet href = ''\n\t\t\tif (item.route) {\n\t\t\t\ttarget = typeof item.route === 'string' ? { name: item.route } : item.route\n\t\t\t\thref = resolveHref(target, this.$router)\n\t\t\t} else if (typeof item.href === 'string' && item.href !== '') {\n\t\t\t\tconst safe = safeHref(item.href)\n\t\t\t\thref = safe === '#' ? '' : safe\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tkey: `item-${index}`,\n\t\t\t\ttitle: typeof item.title === 'string' ? this.effectiveTranslate(item.title) : '',\n\t\t\t\tmeta: typeof item.meta === 'string' ? this.effectiveTranslate(item.meta) : '',\n\t\t\t\tdate,\n\t\t\t\tlate: item.late === true || (item.late !== false && this.isLateDate(date)),\n\t\t\t\ttarget,\n\t\t\t\thref,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load the week's records in one request.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tasync fetchItems() {\n\t\t\tif (!this.hasSource) {\n\t\t\t\tthis.rows = []\n\t\t\t\tthis.error = ''\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst s = this.content.source\n\t\t\tconst requestKey = this.sourceKey\n\t\t\tconst first = this.weekDays[0]\n\t\t\tconst last = this.weekDays[this.weekDays.length - 1]\n\t\t\tconst dayAfter = new Date(last.getFullYear(), last.getMonth(), last.getDate() + 1)\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\t\timport('@nextcloud/router'),\n\t\t\t\t])\n\t\t\t\tconst url = generateUrl(\n\t\t\t\t\t'/apps/openregister/api/objects/{register}/{schema}',\n\t\t\t\t\t{ register: s.register, schema: s.schema },\n\t\t\t\t)\n\t\t\t\tconst params = {\n\t\t\t\t\t_limit: Number.isInteger(s.limit) && s.limit > 0 ? s.limit : DEFAULT_LIMIT,\n\t\t\t\t\t[`_order[${this.dateField}]`]: 'asc',\n\t\t\t\t}\n\t\t\t\tconst filter = resolveFilterTokens(s.filter || {}, {})\n\t\t\t\tfor (const [k, v] of Object.entries(filter || {})) {\n\t\t\t\t\tif (v && typeof v === 'object') {\n\t\t\t\t\t\tfor (const [op, ov] of Object.entries(v)) {\n\t\t\t\t\t\t\tparams[`${k}[${op}]`] = ov\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (v !== '' && v !== null && v !== undefined) {\n\t\t\t\t\t\tparams[k] = v\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// The week window goes last, so a manifest filter on the date\n\t\t\t\t// field cannot widen the strip beyond the days it shows.\n\t\t\t\tparams[`${this.dateField}[gte]`] = dayKey(first)\n\t\t\t\tparams[`${this.dateField}[lt]`] = dayKey(dayAfter)\n\t\t\t\tconst res = await axios.get(url, { params })\n\t\t\t\tif (requestKey !== this.sourceKey) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.rows = (res && res.data && Array.isArray(res.data.results)) ? res.data.results : []\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnWeekStripWidget] failed to load items:', e)\n\t\t\t\tthis.error = (e && e.message) || 'error'\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The text of the \"+N more\" control: `content.moreLabel` with `{count}`\n\t\t * filled, else \"+N more\" from the library's catalogue.\n\t\t *\n\t\t * @param {number} count The number of hidden items.\n\t\t * @return {string}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tmoreLabel(count) {\n\t\t\tconst own = this.content.moreLabel\n\t\t\tif (typeof own === 'string' && own !== '') {\n\t\t\t\treturn this.effectiveTranslate(own).replace(/\\{count\\}/g, String(count))\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '+{count} more', { count })\n\t\t},\n\n\t\t/**\n\t\t * Open or close a day past its cap.\n\t\t *\n\t\t * @param {string} key The day key.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\ttoggleDay(key) {\n\t\t\tthis.expandedDays = { ...this.expandedDays, [key]: this.expandedDays[key] !== true }\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on the \"+N more\" link.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/screens-week-strip-max-per-day/specs/week-strip-max-per-day/spec.md#requirement-a-day-shows-at-most-maxperday-items\n\t\t */\n\t\tonMoreClick(event) {\n\t\t\tif (this.moreTarget) {\n\t\t\t\tfollowLinkClick(event, this.moreTarget, this.$router)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on an in-app item; the browser handles the rest.\n\t\t *\n\t\t * @param {MouseEvent} event The click.\n\t\t * @param {object} item The clicked item.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget\n\t\t */\n\t\tonItemClick(event, item) {\n\t\t\tif (item.target) {\n\t\t\t\tfollowLinkClick(event, item.target, this.$router)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-week-strip {\n\twidth: 100%;\n}\n\n/* `content.inset: true`: the board's inset inside the card (zuiddrecht-pixel-\n gaps-3). A dashboard renders its widgets flush, so without it the strip ran\n from card edge to card edge. Theme hook: --cn-widget-board-inset. */\n.cn-week-strip--inset {\n\tbox-sizing: border-box;\n\tpadding: var(--cn-widget-board-inset, 16px 24px 22px);\n}\n\n.cn-week-strip__state {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tpadding: 12px 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-week-strip__scroll {\n\toverflow-x: auto;\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-week-strip__scroll:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-week-strip__days {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--cn-week-strip-columns, 5), minmax(128px, 1fr));\n\tgap: 10px;\n\t/* 5 columns of 128px plus gaps: below this the region scrolls sideways. */\n\tmin-width: calc(var(--cn-week-strip-columns, 5) * 136px);\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__day {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n\tpadding: 10px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-week-strip__day--today {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-week-strip__head {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 6px;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-week-strip__today {\n\tpadding: 1px 8px;\n\tborder-radius: var(--border-radius-pill, 10px);\n\tbackground: var(--color-primary-element);\n\tcolor: var(--color-primary-element-text);\n\tfont-size: 0.85em;\n\tfont-weight: 700;\n}\n\n.cn-week-strip__items {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-week-strip__item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-week-strip__item--link:hover {\n\tborder-color: var(--color-primary-element);\n}\n\n.cn-week-strip__item--link:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n/* The edge is drawn inside the box, so a late item is as wide as the others. */\n.cn-week-strip__item--late {\n\tborder-color: var(--color-element-error, var(--color-error));\n\tbox-shadow: inset 3px 0 0 0 var(--color-element-error, var(--color-error));\n}\n\n.cn-week-strip__title {\n\tfont-size: 0.95em;\n\tline-height: 1.3;\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__meta {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow-wrap: anywhere;\n}\n\n.cn-week-strip__late {\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\tcolor: var(--color-text-error, var(--color-error-text));\n}\n\n.cn-week-strip__empty {\n\tfont-size: 0.9em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* \"+N more\" under a capped day: a quiet text control, 24px high to click. */\n.cn-week-strip__more {\n\talign-self: flex-start;\n\tmin-height: 24px;\n\tmargin: 0;\n\tpadding: 2px 4px;\n\tborder: 0;\n\tborder-radius: var(--border-radius, 4px);\n\tbackground: transparent;\n\tcolor: var(--color-primary-element);\n\tfont: inherit;\n\tfont-size: 0.85em;\n\tfont-weight: 600;\n\ttext-decoration: none;\n\tcursor: pointer;\n}\n\n.cn-week-strip__more:hover {\n\ttext-decoration: underline;\n}\n\n.cn-week-strip__more:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n</style>\n"],"names":["_normalizeClass","_openBlock","_createElementBlock","_createVNode","_createElementVNode","_toDisplayString","_normalizeStyle","_Fragment","_renderList","_resolveDynamicComponent"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnTransitionInputDialog.vue2.js';
|
|
|
2
2
|
import { render } from './CnTransitionInputDialog.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-457532e4";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { translate } from '@nextcloud/l10n';
|
|
2
|
-
import { NcButton, NcTextField, NcTextArea, NcCheckboxRadioSwitch } from '@nextcloud/vue';
|
|
2
|
+
import { NcButton, NcLoadingIcon, NcTextField, NcTextArea, NcCheckboxRadioSwitch, NcSelect } from '@nextcloud/vue';
|
|
3
3
|
import __sfc_main$1 from '../components/CnDialog/CnDialog.vue.js';
|
|
4
4
|
import __sfc_main from '../components/CnResourceSelect/CnResourceSelect.vue.js';
|
|
5
5
|
import { dialogBoardMixin } from '../mixins/dialogBoard.js';
|
|
@@ -22,7 +22,13 @@ import { fieldsFromSchema } from '../utils/schema.js';
|
|
|
22
22
|
* from the property `title`, booleans render as a switch, numbers as a number
|
|
23
23
|
* field, and long text (`maxLength > 255` or a `textarea`/`markdown` format)
|
|
24
24
|
* as a textarea. Anything else — including a field the schema does not
|
|
25
|
-
* declare — falls back to a plain labelled text input.
|
|
25
|
+
* declare — falls back to a plain labelled text input.
|
|
26
|
+
*
|
|
27
|
+
* An input may also say how it is asked for, which matters when the choices
|
|
28
|
+
* depend on the record rather than on its schema: `label` names the field,
|
|
29
|
+
* and `options: [{ value, label }]` turns it into a picker that shows each
|
|
30
|
+
* `label` and sends the chosen `value`. An input that declares neither is
|
|
31
|
+
* rendered from the schema as before. Deliberately minimal:
|
|
26
32
|
* text, textarea, number and checkbox cover transition inputs; this is not a
|
|
27
33
|
* form engine (use `CnFormDialog` for full object forms).
|
|
28
34
|
*
|
|
@@ -44,9 +50,11 @@ var script = {
|
|
|
44
50
|
CnResourceSelect: __sfc_main,
|
|
45
51
|
CnDialog: __sfc_main$1,
|
|
46
52
|
NcButton,
|
|
53
|
+
NcLoadingIcon,
|
|
47
54
|
NcTextField,
|
|
48
55
|
NcTextArea,
|
|
49
56
|
NcCheckboxRadioSwitch,
|
|
57
|
+
NcSelect,
|
|
50
58
|
},
|
|
51
59
|
|
|
52
60
|
mixins: [dialogBoardMixin],
|
|
@@ -57,7 +65,11 @@ var script = {
|
|
|
57
65
|
* `x-openregister-lifecycle.transitions.<action>.inputs` (server-derived
|
|
58
66
|
* or config-declared); `label` doubles as dialog title + confirm label.
|
|
59
67
|
*
|
|
60
|
-
*
|
|
68
|
+
* An input may carry a `label` for its field and `options` to pick
|
|
69
|
+
* from, each `{ value, label }`; the picker shows the label and sends
|
|
70
|
+
* the value.
|
|
71
|
+
*
|
|
72
|
+
* @type {{action?: string, label?: string, inputs?: Array<{field: string, required?: boolean, label?: string, options?: Array<{value: string, label?: string}>}>}}
|
|
61
73
|
*/
|
|
62
74
|
transition: {
|
|
63
75
|
type: Object,
|
|
@@ -154,6 +166,8 @@ var script = {
|
|
|
154
166
|
required: input.required === true,
|
|
155
167
|
picker: input.picker && typeof input.picker === 'object' ? input.picker : null,
|
|
156
168
|
fields: Array.isArray(input.fields) ? input.fields.filter((f) => typeof f === 'string') : null,
|
|
169
|
+
label: typeof input.label === 'string' && input.label.trim() !== '' ? input.label.trim() : null,
|
|
170
|
+
options: this.declaredOptions(input.options),
|
|
157
171
|
}))
|
|
158
172
|
},
|
|
159
173
|
|
|
@@ -163,26 +177,40 @@ var script = {
|
|
|
163
177
|
* widget from the type/format); the widget is then clamped to the minimal
|
|
164
178
|
* set this dialog renders (text / textarea / number / checkbox). Fields
|
|
165
179
|
* the schema does not declare fall back to a plain text input.
|
|
180
|
+
*
|
|
181
|
+
* An input that declares `options` is a picker whatever the schema
|
|
182
|
+
* says, because its choices are the ones this transition offers on
|
|
183
|
+
* this record. A declared `label` names the field over the schema's.
|
|
166
184
|
*/
|
|
167
185
|
fields() {
|
|
168
186
|
const keys = this.inputs.map((input) => input.field);
|
|
169
187
|
const resolved = fieldsFromSchema(this.schema, { include: keys, includeReadOnly: true });
|
|
170
188
|
return this.inputs.map((input) => {
|
|
171
189
|
const field = resolved.find((f) => f.key === input.field);
|
|
190
|
+
if (input.options) {
|
|
191
|
+
return {
|
|
192
|
+
key: input.field,
|
|
193
|
+
label: input.label || (field && field.label) || input.field,
|
|
194
|
+
description: (field && field.description) || '',
|
|
195
|
+
widget: 'select',
|
|
196
|
+
options: input.options,
|
|
197
|
+
required: input.required,
|
|
198
|
+
}
|
|
199
|
+
}
|
|
172
200
|
const prop = (this.schema && this.schema.properties && this.schema.properties[input.field]) || null;
|
|
173
201
|
if (prop && prop.type === 'object' && prop.properties && typeof prop.properties === 'object') {
|
|
174
202
|
return this.objectField(input, prop)
|
|
175
203
|
}
|
|
176
204
|
if (!field) {
|
|
177
|
-
return { key: input.field, label: input.field, description: '', widget: 'text', required: input.required }
|
|
205
|
+
return { key: input.field, label: input.label || input.field, description: '', widget: 'text', required: input.required }
|
|
178
206
|
}
|
|
179
207
|
if (field.reference && field.reference.multiple !== true) {
|
|
180
208
|
const register = field.reference.register || this.register;
|
|
181
209
|
if (register !== '') {
|
|
182
|
-
return { ...field, widget: 'reference', referenceRegister: register, picker: input.picker, required: input.required }
|
|
210
|
+
return { ...field, label: input.label || field.label, widget: 'reference', referenceRegister: register, picker: input.picker, required: input.required }
|
|
183
211
|
}
|
|
184
212
|
}
|
|
185
|
-
return { ...field, widget: this.clampWidget(field.widget), required: input.required }
|
|
213
|
+
return { ...field, label: input.label || field.label, widget: this.clampWidget(field.widget), required: input.required }
|
|
186
214
|
})
|
|
187
215
|
},
|
|
188
216
|
|
|
@@ -296,6 +324,40 @@ var script = {
|
|
|
296
324
|
}
|
|
297
325
|
},
|
|
298
326
|
|
|
327
|
+
/**
|
|
328
|
+
* The choices an input declares, as `[{ value, label }]`, or null when
|
|
329
|
+
* it declares none. An option without a value is dropped, because it
|
|
330
|
+
* cannot be sent; one without a label shows its value.
|
|
331
|
+
*
|
|
332
|
+
* @param {unknown} options The input's declared `options`.
|
|
333
|
+
* @return {Array<{value: string, label: string}>|null}
|
|
334
|
+
*/
|
|
335
|
+
declaredOptions(options) {
|
|
336
|
+
if (!Array.isArray(options)) {
|
|
337
|
+
return null
|
|
338
|
+
}
|
|
339
|
+
const usable = options
|
|
340
|
+
.filter((option) => option && typeof option === 'object'
|
|
341
|
+
&& (typeof option.value === 'string' || typeof option.value === 'number')
|
|
342
|
+
&& String(option.value).trim() !== '')
|
|
343
|
+
.map((option) => ({
|
|
344
|
+
value: String(option.value),
|
|
345
|
+
label: typeof option.label === 'string' && option.label.trim() !== '' ? option.label.trim() : String(option.value),
|
|
346
|
+
}));
|
|
347
|
+
return usable.length > 0 ? usable : null
|
|
348
|
+
},
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The option a picker field currently holds, or null.
|
|
352
|
+
*
|
|
353
|
+
* @param {object} field The select field descriptor.
|
|
354
|
+
* @return {{value: string, label: string}|null}
|
|
355
|
+
*/
|
|
356
|
+
selectedOption(field) {
|
|
357
|
+
const value = this.values[field.key];
|
|
358
|
+
return field.options.find((option) => option.value === String(value ?? '')) || null
|
|
359
|
+
},
|
|
360
|
+
|
|
299
361
|
/**
|
|
300
362
|
* Ids a reference picker must not offer: the current record, when the
|
|
301
363
|
* input's `picker.excludeSelf` says so.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTransitionInputDialog.vue2.js","sources":["../../../src/dialogs/CnTransitionInputDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\tdefaultWidth=\"form\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:name=\"dialogTitle\"\n\t\tsize=\"normal\"\n\t\t@closing=\"$emit('close')\">\n\t\t<div\n\t\t\tclass=\"cn-transition-input\"\n\t\t\tdata-testid=\"cn-modal\"\n\t\t\tdata-testid-modal=\"cn-transition-input-dialog\">\n\t\t\t<!-- A refusal keeps this dialog open with what was typed still in\n\t\t\t it. Closing first and reporting behind it loses the work and\n\t\t\t asks the person to retype it from memory. -->\n\t\t\t<p v-if=\"error\"\n\t\t\t\tclass=\"cn-transition-input__error\"\n\t\t\t\tdata-testid=\"cn-transition-input-error\">\n\t\t\t\t{{ error }}\n\t\t\t</p>\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-transition-input__field\"\n\t\t\t\t:class=\"{ 'cn-transition-input__field--refused': isRefused(field.key) }\"\n\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}`\">\n\t\t\t\t<!-- An input that points at another record is picked, never typed. -->\n\t\t\t\t<div v-if=\"field.widget === 'reference'\" class=\"cn-transition-input__reference\">\n\t\t\t\t\t<label class=\"cn-transition-input__label\">{{ requiredLabel(field) }}</label>\n\t\t\t\t\t<CnResourceSelect\n\t\t\t\t\t\t:register=\"field.referenceRegister\"\n\t\t\t\t\t\t:schema=\"String(field.reference.schema)\"\n\t\t\t\t\t\t:labelField=\"(field.picker && field.picker.labelField) || field.reference.labelField || 'name'\"\n\t\t\t\t\t\t:filter=\"(field.picker && field.picker.filter) || {}\"\n\t\t\t\t\t\t:exclude=\"excludedIds(field)\"\n\t\t\t\t\t\t:allowCreate=\"false\"\n\t\t\t\t\t\t:preload=\"true\"\n\t\t\t\t\t\t:inputLabel=\"requiredLabel(field)\"\n\t\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-picker-${field.key}`\"\n\t\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- An object input: its sub-properties, one field at a time. -->\n\t\t\t\t<fieldset v-else-if=\"field.widget === 'object'\" class=\"cn-transition-input__object\">\n\t\t\t\t\t<legend>{{ requiredLabel(field) }}</legend>\n\t\t\t\t\t<div v-for=\"sub in field.subFields\"\n\t\t\t\t\t\t:key=\"sub.key\"\n\t\t\t\t\t\tclass=\"cn-transition-input__subfield\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}-${sub.key}`\">\n\t\t\t\t\t\t<NcTextArea v-if=\"sub.widget === 'textarea'\"\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\trows=\"3\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"sub.widget === 'checkbox'\"\n\t\t\t\t\t\t\t:modelValue=\"subValue(field.key, sub.key) === true\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event === true)\">\n\t\t\t\t\t\t\t{{ subLabel(sub) }}\n\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t<NcTextField v-else\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:type=\"sub.widget === 'number' ? 'number' : 'text'\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<p v-if=\"isSubRefused(field.key, sub.key)\"\n\t\t\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}.${sub.key}`\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'This value was not accepted.') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</fieldset>\n\n\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"field.widget === 'checkbox'\"\n\t\t\t\t\t:modelValue=\"values[field.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event === true)\">\n\t\t\t\t\t{{ requiredLabel(field) }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcTextArea v-else-if=\"field.widget === 'textarea'\"\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\trows=\"4\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<NcTextField v-else-if=\"field.widget === 'number'\"\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<NcTextField v-else\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<p v-if=\"isRefused(field.key)\"\n\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}`\">\n\t\t\t\t\t{{ refusalFor(field.key) }}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<!-- A key the refusal names that this dialog never offered is not a\n\t\t\t field anybody can correct here. Saying so beats saying nothing:\n\t\t\t the request sent something the transition does not accept. -->\n\t\t\t<p v-for=\"key in unofferedRefusals\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t:data-testid=\"`cn-transition-input-error-${key}`\">\n\t\t\t\t{{ undeclaredMessage(key) }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<template #actions>\n\t\t\t<NcButton\n\t\t\t\tdata-testid=\"cn-transition-input-cancel\"\n\t\t\t\t@click=\"$emit('close')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-transition-input-confirm\"\n\t\t\t\t@click=\"onConfirm\">\n\t\t\t\t{{ confirmLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\nimport CnResourceSelect from '../components/CnResourceSelect/CnResourceSelect.vue'\nimport { dialogBoardMixin } from '../mixins/dialogBoard.js'\nimport { fieldsFromSchema } from '../utils/schema.js'\n\n/**\n * CnTransitionInputDialog — collects a lifecycle transition's declared\n * `inputs` before the transition is applied.\n *\n * A schema's `x-openregister-lifecycle.transitions.<action>` block may declare\n * `inputs: [{ field, required }]`; the transition endpoint then accepts\n * `{ action, data: { <field>: <value> } }`. This dialog renders one input per\n * declared field, disables the confirm button until every `required: true`\n * field is filled, and emits the collected values — the parent\n * (`CnLifecycleActions`) performs the actual POST. Cancel emits `close`\n * without any confirm, so no request is made.\n *\n * Field rendering resolves each declared field against the object's JSON\n * Schema via `fieldsFromSchema()` when a `schema` is given: the label comes\n * from the property `title`, booleans render as a switch, numbers as a number\n * field, and long text (`maxLength > 255` or a `textarea`/`markdown` format)\n * as a textarea. Anything else — including a field the schema does not\n * declare — falls back to a plain labelled text input. Deliberately minimal:\n * text, textarea, number and checkbox cover transition inputs; this is not a\n * form engine (use `CnFormDialog` for full object forms).\n *\n * Lives in its own file under `src/dialogs/` per the modal-isolation rule.\n *\n * ```vue\n * <CnTransitionInputDialog\n * v-if=\"inputTransition\"\n * :transition=\"inputTransition\"\n * :schema=\"schema\"\n * @confirm=\"onInputConfirm\"\n * @close=\"inputTransition = null\" />\n * ```\n */\nexport default {\n\tname: 'CnTransitionInputDialog',\n\n\tcomponents: {\n\t\tCnResourceSelect,\n\t\tCnDialog,\n\t\tNcButton,\n\t\tNcTextField,\n\t\tNcTextArea,\n\t\tNcCheckboxRadioSwitch,\n\t},\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/**\n\t\t * The transition being applied. `inputs` is the declared input list from\n\t\t * `x-openregister-lifecycle.transitions.<action>.inputs` (server-derived\n\t\t * or config-declared); `label` doubles as dialog title + confirm label.\n\t\t *\n\t\t * @type {{action?: string, label?: string, inputs?: Array<{field: string, required?: boolean}>}}\n\t\t */\n\t\ttransition: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The object's JSON Schema (with `properties`), used to resolve each\n\t\t * input's label, widget and helper text. Optional — undeclared fields\n\t\t * render as plain text inputs labelled by their field name.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The record the transition runs on. Gives `picker.excludeSelf` its id\n\t\t * to leave out, and the current value an object input is merged over.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tcurrentObject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Register slug the reference pickers look in when the schema property\n\t\t * names none of its own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The sentence a refused transition answered with. Present means the\n\t\t * dialog stayed open BECAUSE the attempt was refused, with everything\n\t\t * typed still in it.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The input keys the refusal named (`fields` in the 400 body). Each one\n\t\t * that this dialog offers is marked on its own field; each one it does\n\t\t * not is reported as a key the transition does not accept.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\tfieldErrors: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Whether the parent is mid-POST. Keeps the confirm button from firing\n\t\t * a second attempt while the first is in flight.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tbusy: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['confirm', 'close'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** @type {{[key: string]: unknown}} Collected input values, keyed by declared field name. */\n\t\t\tvalues: this.initialValues(),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** The declared inputs, normalised to `{ field, required }`. */\n\t\tinputs() {\n\t\t\tconst declared = Array.isArray(this.transition.inputs) ? this.transition.inputs : []\n\t\t\treturn declared\n\t\t\t\t.filter((input) => input && typeof input.field === 'string' && input.field !== '')\n\t\t\t\t.map((input) => ({\n\t\t\t\t\tfield: input.field,\n\t\t\t\t\trequired: input.required === true,\n\t\t\t\t\tpicker: input.picker && typeof input.picker === 'object' ? input.picker : null,\n\t\t\t\t\tfields: Array.isArray(input.fields) ? input.fields.filter((f) => typeof f === 'string') : null,\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * One renderable field descriptor per declared input. Schema-declared\n\t\t * fields come from `fieldsFromSchema()` (label from the property title,\n\t\t * widget from the type/format); the widget is then clamped to the minimal\n\t\t * set this dialog renders (text / textarea / number / checkbox). Fields\n\t\t * the schema does not declare fall back to a plain text input.\n\t\t */\n\t\tfields() {\n\t\t\tconst keys = this.inputs.map((input) => input.field)\n\t\t\tconst resolved = fieldsFromSchema(this.schema, { include: keys, includeReadOnly: true })\n\t\t\treturn this.inputs.map((input) => {\n\t\t\t\tconst field = resolved.find((f) => f.key === input.field)\n\t\t\t\tconst prop = (this.schema && this.schema.properties && this.schema.properties[input.field]) || null\n\t\t\t\tif (prop && prop.type === 'object' && prop.properties && typeof prop.properties === 'object') {\n\t\t\t\t\treturn this.objectField(input, prop)\n\t\t\t\t}\n\t\t\t\tif (!field) {\n\t\t\t\t\treturn { key: input.field, label: input.field, description: '', widget: 'text', required: input.required }\n\t\t\t\t}\n\t\t\t\tif (field.reference && field.reference.multiple !== true) {\n\t\t\t\t\tconst register = field.reference.register || this.register\n\t\t\t\t\tif (register !== '') {\n\t\t\t\t\t\treturn { ...field, widget: 'reference', referenceRegister: register, picker: input.picker, required: input.required }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ...field, widget: this.clampWidget(field.widget), required: input.required }\n\t\t\t})\n\t\t},\n\n\t\t/** Dialog title — the transition's label, with a generic fallback. */\n\t\tdialogTitle() {\n\t\t\treturn this.transition.label || t('nextcloud-vue', 'Provide details')\n\t\t},\n\n\t\t/** Confirm button label — the transition's label per the contract. */\n\t\tconfirmLabel() {\n\t\t\treturn this.transition.label || t('nextcloud-vue', 'Confirm')\n\t\t},\n\n\t\t/** True when every `required: true` input holds a non-empty value. */\n\t\tcanConfirm() {\n\t\t\tif (this.busy === true) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.fields.every((field) => (field.widget === 'object'\n\t\t\t\t? field.subFields.every((sub) => !sub.required || this.isSubFilled(field.key, sub))\n\t\t\t\t: (!field.required || this.isFilled(field))))\n\t\t},\n\n\t\t/** The refused keys this dialog offers no field for. */\n\t\tunofferedRefusals() {\n\t\t\tconst offered = this.fields.map((field) => field.key)\n\t\t\treturn this.refusedKeys.filter((key) => !offered.includes(key))\n\t\t},\n\n\t\t/** The refusal's field keys, normalised to strings. */\n\t\trefusedKeys() {\n\t\t\tif (!Array.isArray(this.fieldErrors)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.fieldErrors.filter((key) => typeof key === 'string' && key !== '')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t// Exposed to the template for the static button labels — the same\n\t\t// `methods: { t }` pattern the other dialogs in this folder use.\n\t\tt,\n\n\t\t/**\n\t\t * Whether the refusal named this field.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisRefused(key) {\n\t\t\treturn this.refusedKeys.includes(key)\n\t\t},\n\n\t\t/**\n\t\t * What to say beside a refused field.\n\t\t *\n\t\t * The KIND is decided here rather than read out of the refusal's\n\t\t * sentence. A field this dialog offers and the person left empty is a\n\t\t * missing required input; one it offers that carries a value was\n\t\t * refused for what is in it. Parsing the server's prose to tell those\n\t\t * apart would break the first time the sentence is reworded, and a\n\t\t * reworded sentence is not a contract change.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {string}\n\t\t */\n\t\trefusalFor(key) {\n\t\t\tconst field = this.fields.find((candidate) => candidate.key === key)\n\t\t\tif (field && !this.isFilled(field)) {\n\t\t\t\treturn t('nextcloud-vue', 'This field is required.')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'This value was not accepted.')\n\t\t},\n\n\t\t/**\n\t\t * What to say about a refused key this dialog does not offer.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {string}\n\t\t */\n\t\tundeclaredMessage(key) {\n\t\t\treturn t('nextcloud-vue', 'This action does not accept the field \"{field}\".', { field: key })\n\t\t},\n\n\t\t/**\n\t\t * The descriptor of an object input: its sub-properties (narrowed to the\n\t\t * input's `fields` when it names them), each with its own widget.\n\t\t * A sub-field is required when the input names it in `fields` and the\n\t\t * sub-schema lists it as required, or when the whole input is required\n\t\t * and it is the only one asked.\n\t\t *\n\t\t * @param {object} input The normalised input.\n\t\t * @param {object} prop The object property's schema.\n\t\t * @return {object} The field descriptor.\n\t\t */\n\t\tobjectField(input, prop) {\n\t\t\tconst subs = fieldsFromSchema(prop, { includeReadOnly: true, ...(input.fields ? { include: input.fields } : {}) })\n\t\t\tconst required = Array.isArray(prop.required) ? prop.required : []\n\t\t\tconst only = subs.length === 1\n\t\t\treturn {\n\t\t\t\tkey: input.field,\n\t\t\t\tlabel: prop.title || input.field,\n\t\t\t\tdescription: prop.description || '',\n\t\t\t\twidget: 'object',\n\t\t\t\trequired: input.required,\n\t\t\t\tsubFields: subs.map((sub) => ({\n\t\t\t\t\t...sub,\n\t\t\t\t\twidget: this.clampWidget(sub.widget),\n\t\t\t\t\trequired: (input.fields ? required.includes(sub.key) : sub.required === true) || (input.required && only),\n\t\t\t\t})),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Ids a reference picker must not offer: the current record, when the\n\t\t * input's `picker.excludeSelf` says so.\n\t\t *\n\t\t * @param {object} field The reference field descriptor.\n\t\t * @return {string[]} The ids to leave out.\n\t\t */\n\t\texcludedIds(field) {\n\t\t\tif (!field.picker || field.picker.excludeSelf !== true || !this.currentObject) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst self = this.currentObject\n\t\t\treturn [self.id, self.uuid, self['@self'] && self['@self'].id].filter((id) => id !== undefined && id !== null).map(String)\n\t\t},\n\n\t\t/**\n\t\t * Label of a sub-field, with the required marker.\n\t\t *\n\t\t * @param {object} sub The sub-field descriptor.\n\t\t * @return {string}\n\t\t */\n\t\tsubLabel(sub) {\n\t\t\treturn sub.required ? `${sub.label} *` : sub.label\n\t\t},\n\n\t\t/**\n\t\t * A typed sub-value.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {unknown}\n\t\t */\n\t\tsubValue(key, sub) {\n\t\t\tconst group = this.values[key]\n\t\t\treturn group && typeof group === 'object' ? group[sub] : undefined\n\t\t},\n\n\t\t/**\n\t\t * Store one sub-value, keeping the rest of the object input's values.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetSubValue(key, sub, value) {\n\t\t\tconst group = this.values[key] && typeof this.values[key] === 'object' ? this.values[key] : {}\n\t\t\tthis.setValue(key, { ...group, [sub]: value })\n\t\t},\n\n\t\t/**\n\t\t * Whether a required sub-field holds a value.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {object} sub The sub-field descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisSubFilled(key, sub) {\n\t\t\tconst value = this.subValue(key, sub.key)\n\t\t\treturn sub.widget === 'checkbox' ? value === true : String(value ?? '').trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a refusal named `<input>.<sub>`.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisSubRefused(key, sub) {\n\t\t\treturn this.refusedKeys.includes(`${key}.${sub}`)\n\t\t},\n\n\t\t/** Seed each declared input from its schema default (booleans start false). */\n\t\tinitialValues() {\n\t\t\tconst values = {}\n\t\t\tconst declared = Array.isArray(this.transition?.inputs) ? this.transition.inputs : []\n\t\t\tconst properties = (this.schema && this.schema.properties) || {}\n\t\t\tfor (const input of declared) {\n\t\t\t\tif (!input || typeof input.field !== 'string' || input.field === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prop = properties[input.field] || {}\n\t\t\t\tif (prop.type === 'object' && prop.properties && typeof prop.properties === 'object') {\n\t\t\t\t\t// An object input starts from the record's present value, so\n\t\t\t\t\t// the sub-fields it asks for show what is there.\n\t\t\t\t\tconst present = this.currentObject ? this.currentObject[input.field] : null\n\t\t\t\t\tvalues[input.field] = present && typeof present === 'object' ? { ...present } : {}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalues[input.field] = prop.default !== undefined\n\t\t\t\t\t? prop.default\n\t\t\t\t\t: (prop.type === 'boolean' ? false : '')\n\t\t\t}\n\t\t\treturn values\n\t\t},\n\n\t\t/**\n\t\t * Clamp a `fieldsFromSchema()` widget to the minimal set this dialog\n\t\t * renders. Anything richer (select, date, user picker, …) degrades to a\n\t\t * plain text input rather than pulling a form engine into the dialog.\n\t\t *\n\t\t * @param {string} widget The resolved widget name.\n\t\t * @return {'text'|'textarea'|'number'|'checkbox'}\n\t\t */\n\t\tclampWidget(widget) {\n\t\t\tif (widget === 'checkbox' || widget === 'switch') {\n\t\t\t\treturn 'checkbox'\n\t\t\t}\n\t\t\tif (widget === 'textarea') {\n\t\t\t\treturn 'textarea'\n\t\t\t}\n\t\t\tif (widget === 'number') {\n\t\t\t\treturn 'number'\n\t\t\t}\n\t\t\treturn 'text'\n\t\t},\n\n\t\t/**\n\t\t * The field's visible label, with a `*` marker on required inputs so the\n\t\t * confirm-gating is visually explained.\n\t\t *\n\t\t * @param {object} field The field descriptor.\n\t\t * @return {string}\n\t\t */\n\t\trequiredLabel(field) {\n\t\t\treturn field.required ? `${field.label} *` : field.label\n\t\t},\n\n\t\t/**\n\t\t * Store one input's value.\n\t\t *\n\t\t * @param {string} key The declared field name.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetValue(key, value) {\n\t\t\tthis.values = { ...this.values, [key]: value }\n\t\t},\n\n\t\t/**\n\t\t * Whether a required field counts as filled: a checked switch for\n\t\t * booleans, a non-blank string otherwise.\n\t\t *\n\t\t * @param {object} field The field descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisFilled(field) {\n\t\t\tconst value = this.values[field.key]\n\t\t\tif (field.widget === 'checkbox') {\n\t\t\t\treturn value === true\n\t\t\t}\n\t\t\treturn String(value ?? '').trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * The object an object input sends: the record's current value with the\n\t\t * asked sub-fields merged over it, so a sub-field that was not asked for\n\t\t * keeps its value. A shown field left empty over an empty current value\n\t\t * is not written. Never a dotted key.\n\t\t *\n\t\t * @param {object} field The object field descriptor.\n\t\t * @return {object}\n\t\t */\n\t\tmergedObject(field) {\n\t\t\tconst present = this.currentObject ? this.currentObject[field.key] : null\n\t\t\tconst base = present && typeof present === 'object' ? { ...present } : {}\n\t\t\tfor (const sub of field.subFields) {\n\t\t\t\tlet value = this.subValue(field.key, sub.key)\n\t\t\t\tconst empty = sub.widget === 'checkbox' ? value === undefined : String(value ?? '').trim() === ''\n\t\t\t\tconst had = base[sub.key]\n\t\t\t\tif (empty && (had === undefined || had === null || had === '')) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (sub.widget === 'number' && !empty && !Number.isNaN(Number(value))) {\n\t\t\t\t\tvalue = Number(value)\n\t\t\t\t}\n\t\t\t\tbase[sub.key] = value\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Confirm: emit exactly the declared keys (numbers cast) and let the parent POST. */\n\t\tonConfirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.widget === 'object') {\n\t\t\t\t\tdata[field.key] = this.mergedObject(field)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tlet value = this.values[field.key]\n\t\t\t\tif (field.widget === 'number' && String(value ?? '').trim() !== '') {\n\t\t\t\t\tconst parsed = Number(value)\n\t\t\t\t\tif (!Number.isNaN(parsed)) {\n\t\t\t\t\t\tvalue = parsed\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdata[field.key] = value\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event confirm Emitted when the user confirms with all required\n\t\t\t * inputs filled. Payload holds exactly the declared input keys; the\n\t\t\t * parent POSTs `{ action, data }`.\n\t\t\t * @type {{[key: string]: unknown}}\n\t\t\t */\n\t\t\tthis.$emit('confirm', data)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-transition-input {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tpadding: 4px 0;\n}\n\n.cn-transition-input__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-transition-input__field-error {\n\tmargin: 4px 0 0;\n\tfont-size: 0.9em;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-transition-input__object {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 8px 12px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-transition-input__label {\n\tdisplay: block;\n\tmargin-bottom: 4px;\n}\n\n.cn-transition-input__field--refused {\n\tborder-inline-start: 2px solid var(--color-error);\n\tpadding-inline-start: 8px;\n}\n</style>\n"],"names":["CnResourceSelect","CnDialog","t"],"mappings":";;;;;;;AAqJA;AACC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;;;AAIA;;AAEA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,yBAAyB;;CAE/B,UAAU,EAAE;AACX,oBAAAA,UAAgB;AAChB,YAAAC,YAAQ;AACR,EAAA,QAAQ;EACR,WAAW;EACX,UAAU;AACV,EAAA,qBAAqB;EACrB;;CAED,MAAM,EAAE,CAAC,gBAAgB,CAAC;;AAE1B,CAAA,KAAK,EAAE;AACN;;AAEC;;AAEA;AACA;;EAED,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;;;;AAIC;AACA;;AAED,EAAA,MAAM,EAAE;GACP,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;AAED;;;AAGC;AACA;;AAED,EAAA,aAAa,EAAE;GACd,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;AAED;;AAEC;AACA;;;AAGD,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;AAGC;AACA;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;AAIC;AACA;;EAED,WAAW,EAAE;GACZ,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;;AAEC;AACA;AACA;;EAED,IAAI,EAAE;GACL,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;EACD;;CAED,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC;;AAE3B,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN;GACA,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE;AAC7B,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;;AAET,EAAA,MAAM,GAAG;AACR,GAAA,MAAM,QAAO,GAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAE,GAAE,IAAI,CAAC,UAAU,CAAC,MAAK,GAAI,GAAC;GACnF,OAAO,QAAO;AACb,KAAC,MAAM,CAAC,CAAC,KAAK,KAAK,KAAM,IAAG,OAAO,KAAK,CAAC,KAAI,KAAM,QAAS,IAAG,KAAK,CAAC,KAAM,KAAI,EAAE,CAAA;AACjF,KAAC,GAAG,CAAC,CAAC,KAAK,MAAM;AAChB,KAAA,KAAK,EAAE,KAAK,CAAC,KAAK;AAClB,KAAA,QAAQ,EAAE,KAAK,CAAC,QAAO,KAAM,IAAI;AACjC,KAAA,MAAM,EAAE,KAAK,CAAC,MAAO,IAAG,OAAO,KAAK,CAAC,MAAO,KAAI,QAAS,GAAE,KAAK,CAAC,MAAO,GAAE,IAAI;AAC9E,KAAA,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,CAAE,KAAI,QAAQ,CAAA,GAAI,IAAI;AAC/F,KAAC,CAAC,CAAA;GACH;;AAED;;;;;;;AAOA,EAAA,MAAM,GAAG;GACR,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,EAAA;AACnD,GAAA,MAAM,QAAS,GAAE,gBAAgB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAA;AACvF,GAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK;IACjC,MAAM,KAAM,GAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAE,KAAM,KAAK,CAAC,KAAK,EAAA;AACxD,IAAA,MAAM,IAAK,GAAE,CAAC,IAAI,CAAC,MAAO,IAAG,IAAI,CAAC,MAAM,CAAC,UAAS,IAAK,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAG;AAClG,IAAA,IAAI,QAAQ,IAAI,CAAC,IAAK,KAAI,QAAO,IAAK,IAAI,CAAC,UAAW,IAAG,OAAO,IAAI,CAAC,eAAe,QAAQ,EAAE;AAC7F,KAAA,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,CAAA;AACpC,KAAA;IACA,IAAI,CAAC,KAAK,EAAE;AACX,KAAA,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAS,EAAA;AAC1G,KAAA;IACA,IAAI,KAAK,CAAC,SAAU,IAAG,KAAK,CAAC,SAAS,CAAC,QAAO,KAAM,IAAI,EAAE;KACzD,MAAM,WAAW,KAAK,CAAC,SAAS,CAAC,QAAS,IAAG,IAAI,CAAC,SAAO;AACzD,KAAA,IAAI,aAAa,EAAE,EAAE;MACpB,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAS,EAAA;AACrH,MAAA;AACD,KAAA;AACA,IAAA,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAS,EAAA;IACpF,CAAA;GACD;;;EAGD,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,UAAU,CAAC,KAAI,IAAKC,SAAC,CAAC,eAAe,EAAE,iBAAiB,CAAA;GACpE;;;AAGD,EAAA,YAAY,GAAG;GACd,OAAO,IAAI,CAAC,UAAU,CAAC,KAAM,IAAGA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAA;GAC5D;;;EAGD,UAAU,GAAG;AACZ,GAAA,IAAI,IAAI,CAAC,IAAG,KAAM,IAAI,EAAE;IACvB,OAAO,KAAI;AACZ,IAAA;GACA,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,MAAM,KAAK,CAAC,MAAO,KAAI,QAAO;AAC5D,MAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,QAAS,IAAG,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAClF,OAAG,CAAC,KAAK,CAAC,QAAO,IAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;GAC7C;;AAED;AACA,EAAA,iBAAiB,GAAG;GACnB,MAAM,UAAU,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,GAAG,EAAA;GACpD,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;GAC9D;;;EAGD,WAAW,GAAG;AACb,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;AACrC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,OAAO,GAAI,KAAI,YAAY,GAAI,KAAI,EAAE,CAAA;GAC7E;EACD;;AAED,CAAA,OAAO,EAAE;;;KAGRA,SAAC;;AAED;AACC;AACA;;AAEA;;AAED,EAAA,SAAS,CAAC,GAAG,EAAE;AACd,GAAA,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAA;GACpC;;AAED;;AAEC;;;;;;AAMA;AACA;;AAEA;;AAED,EAAA,UAAU,CAAC,GAAG,EAAE;GACf,MAAM,KAAI,GAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,GAAI,KAAI,GAAG,EAAA;AACnE,GAAA,IAAI,KAAM,IAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;IACnC,OAAOA,SAAC,CAAC,eAAe,EAAE,yBAAyB,CAAA;AACpD,IAAA;GACA,OAAOA,SAAC,CAAC,eAAe,EAAE,8BAA8B,CAAA;GACxD;;AAED;;AAEC;;AAEA;;EAED,iBAAiB,CAAC,GAAG,EAAE;AACtB,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,kDAAkD,EAAE,EAAE,KAAK,EAAE,KAAK,CAAA;GAC5F;;AAED;;;;;;AAMC;AACA;AACA;AACA;;EAED,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE;GACxB,MAAM,OAAO,gBAAgB,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,IAAI,KAAK,CAAC,MAAK,GAAI,EAAE,OAAO,EAAE,KAAK,CAAC,MAAK,KAAM,EAAE,CAAA,EAAG,EAAA;GACjH,MAAM,QAAS,GAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAA,GAAI,IAAI,CAAC,QAAS,GAAE,GAAC;GACjE,MAAM,IAAK,GAAE,IAAI,CAAC,MAAK,KAAM,EAAA;AAC7B,GAAA,OAAO;AACN,IAAA,GAAG,EAAE,KAAK,CAAC,KAAK;IAChB,KAAK,EAAE,IAAI,CAAC,KAAI,IAAK,KAAK,CAAC,KAAK;AAChC,IAAA,WAAW,EAAE,IAAI,CAAC,WAAU,IAAK,EAAE;AACnC,IAAA,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;IACxB,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM;AAC7B,KAAA,GAAG,GAAG;AACN,KAAA,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC;KACpC,QAAQ,EAAE,CAAC,KAAK,CAAC,MAAO,GAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAE,GAAE,GAAG,CAAC,QAAO,KAAM,IAAI,MAAM,KAAK,CAAC,YAAY,IAAI,CAAC;AAC1G,KAAC,CAAC,CAAC;AACJ,IAAA;GACA;;AAED;;AAEC;AACA;;AAEA;;AAED,EAAA,WAAW,CAAC,KAAK,EAAE;AAClB,GAAA,IAAI,CAAC,KAAK,CAAC,MAAO,IAAG,KAAK,CAAC,MAAM,CAAC,gBAAgB,IAAK,IAAG,CAAC,IAAI,CAAC,aAAa,EAAE;AAC9E,IAAA,OAAO,EAAC;AACT,IAAA;GACA,MAAM,IAAG,GAAI,IAAI,CAAC,cAAY;GAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAA,IAAK,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAG,KAAI,SAAU,IAAG,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAA;GACzH;;AAED;AACC;AACA;AACA;AACA;;EAED,QAAQ,CAAC,GAAG,EAAE;AACb,GAAA,OAAO,GAAG,CAAC,QAAO,GAAI,CAAC,EAAE,GAAG,CAAC,KAAK,CAAA,EAAG,CAAE,GAAE,GAAG,CAAC,KAAI;GACjD;;AAED;AACC;AACA;;AAEA;AACA;;AAED,EAAA,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;GAClB,MAAM,KAAM,GAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAA;GAC7B,OAAO,KAAI,IAAK,OAAO,KAAM,KAAI,WAAW,KAAK,CAAC,GAAG,CAAA,GAAI,SAAQ;GACjE;;AAED;;AAEC;;AAEA;AACA;;EAED,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE;AAC5B,GAAA,MAAM,KAAM,GAAE,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAE,KAAI,QAAS,GAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAA,GAAI,GAAC;AAC7F,GAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,OAAO,EAAA;GAC7C;;AAED;AACC;AACA;;AAEA;AACA;;AAED,EAAA,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE;AACrB,GAAA,MAAM,KAAI,GAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAA;AACxC,GAAA,OAAO,GAAG,CAAC,MAAO,KAAI,UAAW,GAAE,KAAI,KAAM,OAAO,MAAM,CAAC,KAAI,IAAK,EAAE,CAAC,CAAC,IAAI,EAAC,KAAM,EAAC;GACpF;;AAED;AACC;AACA;;AAEA;AACA;;AAED,EAAA,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE;GACtB,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAA;GAChD;;AAED;AACA,EAAA,aAAa,GAAG;GACf,MAAM,MAAO,GAAE,GAAC;AAChB,GAAA,MAAM,QAAO,GAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAE,GAAE,IAAI,CAAC,UAAU,CAAC,MAAK,GAAI,GAAC;GACpF,MAAM,UAAW,GAAE,CAAC,IAAI,CAAC,MAAK,IAAK,IAAI,CAAC,MAAM,CAAC,UAAU,KAAK,GAAC;GAC/D,KAAK,MAAM,KAAM,IAAG,QAAQ,EAAE;IAC7B,IAAI,CAAC,KAAM,IAAG,OAAO,KAAK,CAAC,KAAM,KAAI,QAAS,IAAG,KAAK,CAAC,KAAM,KAAI,EAAE,EAAE;AACpE,KAAA,QAAO;AACR,KAAA;AACA,IAAA,MAAM,IAAK,GAAE,UAAU,CAAC,KAAK,CAAC,KAAK,CAAE,IAAG,GAAC;AACzC,IAAA,IAAI,IAAI,CAAC,IAAK,KAAI,QAAS,IAAG,IAAI,CAAC,UAAW,IAAG,OAAO,IAAI,CAAC,UAAS,KAAM,QAAQ,EAAE;;AAErF;AACA,KAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,gBAAgB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAA,GAAI,KAAG;AAC1E,KAAA,MAAM,CAAC,KAAK,CAAC,KAAK,CAAE,GAAE,OAAM,IAAK,OAAO,OAAM,KAAM,QAAO,GAAI,EAAE,GAAG,OAAQ,EAAA,GAAI,GAAC;AACjF,KAAA,QAAO;AACR,KAAA;AACA,IAAA,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,OAAM,KAAM,SAAQ;OAC5C,IAAI,CAAC,OAAM;AACb,QAAG,IAAI,CAAC,IAAG,KAAM,SAAU,GAAE,KAAM,GAAE,EAAE,EAAA;AACzC,IAAA;GACA,OAAO,MAAK;GACZ;;AAED;;;;AAIC;AACA;;;AAGD,EAAA,WAAW,CAAC,MAAM,EAAE;AACnB,GAAA,IAAI,MAAO,KAAI,UAAW,IAAG,WAAW,QAAQ,EAAE;AACjD,IAAA,OAAO,UAAS;AACjB,IAAA;GACA,IAAI,WAAW,UAAU,EAAE;AAC1B,IAAA,OAAO,UAAS;AACjB,IAAA;AACA,GAAA,IAAI,MAAO,KAAI,QAAQ,EAAE;IACxB,OAAO,QAAO;AACf,IAAA;GACA,OAAO,MAAK;GACZ;;AAED;;AAEC;AACA;AACA;AACA;;AAED,EAAA,aAAa,CAAC,KAAK,EAAE;GACpB,OAAO,KAAK,CAAC,QAAO,GAAI,CAAC,EAAE,KAAK,CAAC,KAAK,CAAE,EAAC,IAAI,KAAK,CAAC,KAAI;GACvD;;AAED;AACC;AACA;AACA;AACA;;AAED,EAAA,QAAQ,CAAC,GAAG,EAAE,KAAK,EAAE;AACpB,GAAA,IAAI,CAAC,MAAK,GAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,GAAG,KAAM,GAAA;GAC7C;;AAED;;AAEC;AACA;AACA;AACA;;AAED,EAAA,QAAQ,CAAC,KAAK,EAAE;AACf,GAAA,MAAM,KAAM,GAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAA;GACnC,IAAI,KAAK,CAAC,MAAO,KAAI,UAAU,EAAE;AAChC,IAAA,OAAO,UAAU,IAAG;AACrB,IAAA;AACA,GAAA,OAAO,MAAM,CAAC,KAAM,IAAG,EAAE,CAAC,CAAC,IAAI,EAAC,KAAM,EAAC;GACvC;;AAED;;;;;AAKC;AACA;AACA;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;AACnB,GAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,aAAc,GAAE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAA,GAAI,KAAG;GACxE,MAAM,IAAK,GAAE,OAAM,IAAK,OAAO,OAAM,KAAM,QAAS,GAAE,EAAE,GAAG,OAAM,EAAI,GAAE,GAAC;AACxE,GAAA,KAAK,MAAM,GAAI,IAAG,KAAK,CAAC,SAAS,EAAE;AAClC,IAAA,IAAI,KAAM,GAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAA;AAC5C,IAAA,MAAM,KAAM,GAAE,GAAG,CAAC,MAAK,KAAM,UAAS,GAAI,KAAI,KAAM,SAAQ,GAAI,MAAM,CAAC,KAAM,IAAG,EAAE,CAAC,CAAC,IAAI,OAAO,GAAC;AAChG,IAAA,MAAM,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAA;IACxB,IAAI,KAAI,KAAM,GAAI,KAAI,aAAa,GAAE,KAAM,IAAG,IAAK,GAAI,KAAI,EAAE,CAAC,EAAE;AAC/D,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,GAAG,CAAC,MAAK,KAAM,QAAS,IAAG,CAAC,KAAM,IAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE;AACtE,KAAA,KAAM,GAAE,MAAM,CAAC,KAAK,EAAA;AACrB,KAAA;AACA,IAAA,IAAI,CAAC,GAAG,CAAC,GAAG,CAAE,GAAE,MAAI;AACrB,IAAA;AACA,GAAA,OAAO,IAAG;GACV;;AAED;EACA,SAAS,GAAG;AACX,GAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;IACrB,MAAK;AACN,IAAA;GACA,MAAM,IAAK,GAAE,GAAC;GACd,KAAK,MAAM,KAAI,IAAK,IAAI,CAAC,MAAM,EAAE;IAChC,IAAI,KAAK,CAAC,MAAO,KAAI,QAAQ,EAAE;AAC9B,KAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,GAAE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAA;AACzC,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,KAAM,GAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAA;IACjC,IAAI,KAAK,CAAC,WAAW,QAAS,IAAG,MAAM,CAAC,KAAI,IAAK,EAAE,CAAC,CAAC,IAAI,EAAG,KAAI,EAAE,EAAE;KACnE,MAAM,MAAO,GAAE,MAAM,CAAC,KAAK,EAAA;KAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;MAC1B,KAAI,GAAI,OAAK;AACd,MAAA;AACD,KAAA;AACA,IAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAA,GAAI,MAAI;AACvB,IAAA;AACA;;;;;;GAMA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAA;GAC1B;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnTransitionInputDialog.vue2.js","sources":["../../../src/dialogs/CnTransitionInputDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\tdefaultWidth=\"form\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:name=\"dialogTitle\"\n\t\tsize=\"normal\"\n\t\t@closing=\"$emit('close')\">\n\t\t<div\n\t\t\tclass=\"cn-transition-input\"\n\t\t\t:aria-busy=\"busy ? 'true' : null\"\n\t\t\tdata-testid=\"cn-modal\"\n\t\t\tdata-testid-modal=\"cn-transition-input-dialog\">\n\t\t\t<!-- A refusal keeps this dialog open with what was typed still in\n\t\t\t it. Closing first and reporting behind it loses the work and\n\t\t\t asks the person to retype it from memory. -->\n\t\t\t<p v-if=\"error\"\n\t\t\t\tclass=\"cn-transition-input__error\"\n\t\t\t\tdata-testid=\"cn-transition-input-error\">\n\t\t\t\t{{ error }}\n\t\t\t</p>\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-transition-input__field\"\n\t\t\t\t:class=\"{ 'cn-transition-input__field--refused': isRefused(field.key) }\"\n\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}`\">\n\t\t\t\t<!-- An input that declares its choices is picked from them. -->\n\t\t\t\t<NcSelect v-if=\"field.widget === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"requiredLabel(field)\"\n\t\t\t\t\t:clearable=\"!field.required\"\n\t\t\t\t\t:data-testid=\"`cn-transition-input-select-${field.key}`\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event && $event.value !== undefined ? $event.value : '')\" />\n\n\t\t\t\t<!-- An input that points at another record is picked, never typed. -->\n\t\t\t\t<div v-else-if=\"field.widget === 'reference'\" class=\"cn-transition-input__reference\">\n\t\t\t\t\t<label class=\"cn-transition-input__label\">{{ requiredLabel(field) }}</label>\n\t\t\t\t\t<CnResourceSelect\n\t\t\t\t\t\t:register=\"field.referenceRegister\"\n\t\t\t\t\t\t:schema=\"String(field.reference.schema)\"\n\t\t\t\t\t\t:labelField=\"(field.picker && field.picker.labelField) || field.reference.labelField || 'name'\"\n\t\t\t\t\t\t:filter=\"(field.picker && field.picker.filter) || {}\"\n\t\t\t\t\t\t:exclude=\"excludedIds(field)\"\n\t\t\t\t\t\t:allowCreate=\"false\"\n\t\t\t\t\t\t:preload=\"true\"\n\t\t\t\t\t\t:inputLabel=\"requiredLabel(field)\"\n\t\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-picker-${field.key}`\"\n\t\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- An object input: its sub-properties, one field at a time. -->\n\t\t\t\t<fieldset v-else-if=\"field.widget === 'object'\" class=\"cn-transition-input__object\">\n\t\t\t\t\t<legend>{{ requiredLabel(field) }}</legend>\n\t\t\t\t\t<div v-for=\"sub in field.subFields\"\n\t\t\t\t\t\t:key=\"sub.key\"\n\t\t\t\t\t\tclass=\"cn-transition-input__subfield\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}-${sub.key}`\">\n\t\t\t\t\t\t<NcTextArea v-if=\"sub.widget === 'textarea'\"\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\trows=\"3\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"sub.widget === 'checkbox'\"\n\t\t\t\t\t\t\t:modelValue=\"subValue(field.key, sub.key) === true\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event === true)\">\n\t\t\t\t\t\t\t{{ subLabel(sub) }}\n\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t<NcTextField v-else\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:type=\"sub.widget === 'number' ? 'number' : 'text'\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<p v-if=\"isSubRefused(field.key, sub.key)\"\n\t\t\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}.${sub.key}`\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'This value was not accepted.') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</fieldset>\n\n\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"field.widget === 'checkbox'\"\n\t\t\t\t\t:modelValue=\"values[field.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event === true)\">\n\t\t\t\t\t{{ requiredLabel(field) }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<NcTextArea v-else-if=\"field.widget === 'textarea'\"\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\trows=\"4\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<NcTextField v-else-if=\"field.widget === 'number'\"\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<NcTextField v-else\n\t\t\t\t\t:modelValue=\"String(values[field.key] ?? '')\"\n\t\t\t\t\t:label=\"requiredLabel(field)\"\n\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\n\t\t\t\t<p v-if=\"isRefused(field.key)\"\n\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}`\">\n\t\t\t\t\t{{ refusalFor(field.key) }}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<!-- A key the refusal names that this dialog never offered is not a\n\t\t\t field anybody can correct here. Saying so beats saying nothing:\n\t\t\t the request sent something the transition does not accept. -->\n\t\t\t<p v-for=\"key in unofferedRefusals\"\n\t\t\t\t:key=\"key\"\n\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t:data-testid=\"`cn-transition-input-error-${key}`\">\n\t\t\t\t{{ undeclaredMessage(key) }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<template #actions>\n\t\t\t<NcButton\n\t\t\t\tdata-testid=\"cn-transition-input-cancel\"\n\t\t\t\t@click=\"$emit('close')\">\n\t\t\t\t{{ t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<!-- Busy while the parent's POST runs: a transition can take\n\t\t\t seconds, and a confirm button that only greys out reads as one\n\t\t\t that did nothing. -->\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\t:aria-busy=\"busy ? 'true' : null\"\n\t\t\t\tdata-testid=\"cn-transition-input-confirm\"\n\t\t\t\t@click=\"onConfirm\">\n\t\t\t\t<template v-if=\"busy\" #icon>\n\t\t\t\t\t<NcLoadingIcon :size=\"20\" data-testid=\"cn-transition-input-busy\" />\n\t\t\t\t</template>\n\t\t\t\t{{ confirmLabel }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\nimport CnResourceSelect from '../components/CnResourceSelect/CnResourceSelect.vue'\nimport { dialogBoardMixin } from '../mixins/dialogBoard.js'\nimport { fieldsFromSchema } from '../utils/schema.js'\n\n/**\n * CnTransitionInputDialog — collects a lifecycle transition's declared\n * `inputs` before the transition is applied.\n *\n * A schema's `x-openregister-lifecycle.transitions.<action>` block may declare\n * `inputs: [{ field, required }]`; the transition endpoint then accepts\n * `{ action, data: { <field>: <value> } }`. This dialog renders one input per\n * declared field, disables the confirm button until every `required: true`\n * field is filled, and emits the collected values — the parent\n * (`CnLifecycleActions`) performs the actual POST. Cancel emits `close`\n * without any confirm, so no request is made.\n *\n * Field rendering resolves each declared field against the object's JSON\n * Schema via `fieldsFromSchema()` when a `schema` is given: the label comes\n * from the property `title`, booleans render as a switch, numbers as a number\n * field, and long text (`maxLength > 255` or a `textarea`/`markdown` format)\n * as a textarea. Anything else — including a field the schema does not\n * declare — falls back to a plain labelled text input.\n *\n * An input may also say how it is asked for, which matters when the choices\n * depend on the record rather than on its schema: `label` names the field,\n * and `options: [{ value, label }]` turns it into a picker that shows each\n * `label` and sends the chosen `value`. An input that declares neither is\n * rendered from the schema as before. Deliberately minimal:\n * text, textarea, number and checkbox cover transition inputs; this is not a\n * form engine (use `CnFormDialog` for full object forms).\n *\n * Lives in its own file under `src/dialogs/` per the modal-isolation rule.\n *\n * ```vue\n * <CnTransitionInputDialog\n * v-if=\"inputTransition\"\n * :transition=\"inputTransition\"\n * :schema=\"schema\"\n * @confirm=\"onInputConfirm\"\n * @close=\"inputTransition = null\" />\n * ```\n */\nexport default {\n\tname: 'CnTransitionInputDialog',\n\n\tcomponents: {\n\t\tCnResourceSelect,\n\t\tCnDialog,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tNcTextField,\n\t\tNcTextArea,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcSelect,\n\t},\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/**\n\t\t * The transition being applied. `inputs` is the declared input list from\n\t\t * `x-openregister-lifecycle.transitions.<action>.inputs` (server-derived\n\t\t * or config-declared); `label` doubles as dialog title + confirm label.\n\t\t *\n\t\t * An input may carry a `label` for its field and `options` to pick\n\t\t * from, each `{ value, label }`; the picker shows the label and sends\n\t\t * the value.\n\t\t *\n\t\t * @type {{action?: string, label?: string, inputs?: Array<{field: string, required?: boolean, label?: string, options?: Array<{value: string, label?: string}>}>}}\n\t\t */\n\t\ttransition: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The object's JSON Schema (with `properties`), used to resolve each\n\t\t * input's label, widget and helper text. Optional — undeclared fields\n\t\t * render as plain text inputs labelled by their field name.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The record the transition runs on. Gives `picker.excludeSelf` its id\n\t\t * to leave out, and the current value an object input is merged over.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tcurrentObject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Register slug the reference pickers look in when the schema property\n\t\t * names none of its own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The sentence a refused transition answered with. Present means the\n\t\t * dialog stayed open BECAUSE the attempt was refused, with everything\n\t\t * typed still in it.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The input keys the refusal named (`fields` in the 400 body). Each one\n\t\t * that this dialog offers is marked on its own field; each one it does\n\t\t * not is reported as a key the transition does not accept.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\tfieldErrors: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Whether the parent is mid-POST. Keeps the confirm button from firing\n\t\t * a second attempt while the first is in flight.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tbusy: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['confirm', 'close'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** @type {{[key: string]: unknown}} Collected input values, keyed by declared field name. */\n\t\t\tvalues: this.initialValues(),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** The declared inputs, normalised to `{ field, required }`. */\n\t\tinputs() {\n\t\t\tconst declared = Array.isArray(this.transition.inputs) ? this.transition.inputs : []\n\t\t\treturn declared\n\t\t\t\t.filter((input) => input && typeof input.field === 'string' && input.field !== '')\n\t\t\t\t.map((input) => ({\n\t\t\t\t\tfield: input.field,\n\t\t\t\t\trequired: input.required === true,\n\t\t\t\t\tpicker: input.picker && typeof input.picker === 'object' ? input.picker : null,\n\t\t\t\t\tfields: Array.isArray(input.fields) ? input.fields.filter((f) => typeof f === 'string') : null,\n\t\t\t\t\tlabel: typeof input.label === 'string' && input.label.trim() !== '' ? input.label.trim() : null,\n\t\t\t\t\toptions: this.declaredOptions(input.options),\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * One renderable field descriptor per declared input. Schema-declared\n\t\t * fields come from `fieldsFromSchema()` (label from the property title,\n\t\t * widget from the type/format); the widget is then clamped to the minimal\n\t\t * set this dialog renders (text / textarea / number / checkbox). Fields\n\t\t * the schema does not declare fall back to a plain text input.\n\t\t *\n\t\t * An input that declares `options` is a picker whatever the schema\n\t\t * says, because its choices are the ones this transition offers on\n\t\t * this record. A declared `label` names the field over the schema's.\n\t\t */\n\t\tfields() {\n\t\t\tconst keys = this.inputs.map((input) => input.field)\n\t\t\tconst resolved = fieldsFromSchema(this.schema, { include: keys, includeReadOnly: true })\n\t\t\treturn this.inputs.map((input) => {\n\t\t\t\tconst field = resolved.find((f) => f.key === input.field)\n\t\t\t\tif (input.options) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey: input.field,\n\t\t\t\t\t\tlabel: input.label || (field && field.label) || input.field,\n\t\t\t\t\t\tdescription: (field && field.description) || '',\n\t\t\t\t\t\twidget: 'select',\n\t\t\t\t\t\toptions: input.options,\n\t\t\t\t\t\trequired: input.required,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst prop = (this.schema && this.schema.properties && this.schema.properties[input.field]) || null\n\t\t\t\tif (prop && prop.type === 'object' && prop.properties && typeof prop.properties === 'object') {\n\t\t\t\t\treturn this.objectField(input, prop)\n\t\t\t\t}\n\t\t\t\tif (!field) {\n\t\t\t\t\treturn { key: input.field, label: input.label || input.field, description: '', widget: 'text', required: input.required }\n\t\t\t\t}\n\t\t\t\tif (field.reference && field.reference.multiple !== true) {\n\t\t\t\t\tconst register = field.reference.register || this.register\n\t\t\t\t\tif (register !== '') {\n\t\t\t\t\t\treturn { ...field, label: input.label || field.label, widget: 'reference', referenceRegister: register, picker: input.picker, required: input.required }\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { ...field, label: input.label || field.label, widget: this.clampWidget(field.widget), required: input.required }\n\t\t\t})\n\t\t},\n\n\t\t/** Dialog title — the transition's label, with a generic fallback. */\n\t\tdialogTitle() {\n\t\t\treturn this.transition.label || t('nextcloud-vue', 'Provide details')\n\t\t},\n\n\t\t/** Confirm button label — the transition's label per the contract. */\n\t\tconfirmLabel() {\n\t\t\treturn this.transition.label || t('nextcloud-vue', 'Confirm')\n\t\t},\n\n\t\t/** True when every `required: true` input holds a non-empty value. */\n\t\tcanConfirm() {\n\t\t\tif (this.busy === true) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn this.fields.every((field) => (field.widget === 'object'\n\t\t\t\t? field.subFields.every((sub) => !sub.required || this.isSubFilled(field.key, sub))\n\t\t\t\t: (!field.required || this.isFilled(field))))\n\t\t},\n\n\t\t/** The refused keys this dialog offers no field for. */\n\t\tunofferedRefusals() {\n\t\t\tconst offered = this.fields.map((field) => field.key)\n\t\t\treturn this.refusedKeys.filter((key) => !offered.includes(key))\n\t\t},\n\n\t\t/** The refusal's field keys, normalised to strings. */\n\t\trefusedKeys() {\n\t\t\tif (!Array.isArray(this.fieldErrors)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.fieldErrors.filter((key) => typeof key === 'string' && key !== '')\n\t\t},\n\t},\n\n\tmethods: {\n\t\t// Exposed to the template for the static button labels — the same\n\t\t// `methods: { t }` pattern the other dialogs in this folder use.\n\t\tt,\n\n\t\t/**\n\t\t * Whether the refusal named this field.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisRefused(key) {\n\t\t\treturn this.refusedKeys.includes(key)\n\t\t},\n\n\t\t/**\n\t\t * What to say beside a refused field.\n\t\t *\n\t\t * The KIND is decided here rather than read out of the refusal's\n\t\t * sentence. A field this dialog offers and the person left empty is a\n\t\t * missing required input; one it offers that carries a value was\n\t\t * refused for what is in it. Parsing the server's prose to tell those\n\t\t * apart would break the first time the sentence is reworded, and a\n\t\t * reworded sentence is not a contract change.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {string}\n\t\t */\n\t\trefusalFor(key) {\n\t\t\tconst field = this.fields.find((candidate) => candidate.key === key)\n\t\t\tif (field && !this.isFilled(field)) {\n\t\t\t\treturn t('nextcloud-vue', 'This field is required.')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'This value was not accepted.')\n\t\t},\n\n\t\t/**\n\t\t * What to say about a refused key this dialog does not offer.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {string}\n\t\t */\n\t\tundeclaredMessage(key) {\n\t\t\treturn t('nextcloud-vue', 'This action does not accept the field \"{field}\".', { field: key })\n\t\t},\n\n\t\t/**\n\t\t * The descriptor of an object input: its sub-properties (narrowed to the\n\t\t * input's `fields` when it names them), each with its own widget.\n\t\t * A sub-field is required when the input names it in `fields` and the\n\t\t * sub-schema lists it as required, or when the whole input is required\n\t\t * and it is the only one asked.\n\t\t *\n\t\t * @param {object} input The normalised input.\n\t\t * @param {object} prop The object property's schema.\n\t\t * @return {object} The field descriptor.\n\t\t */\n\t\tobjectField(input, prop) {\n\t\t\tconst subs = fieldsFromSchema(prop, { includeReadOnly: true, ...(input.fields ? { include: input.fields } : {}) })\n\t\t\tconst required = Array.isArray(prop.required) ? prop.required : []\n\t\t\tconst only = subs.length === 1\n\t\t\treturn {\n\t\t\t\tkey: input.field,\n\t\t\t\tlabel: prop.title || input.field,\n\t\t\t\tdescription: prop.description || '',\n\t\t\t\twidget: 'object',\n\t\t\t\trequired: input.required,\n\t\t\t\tsubFields: subs.map((sub) => ({\n\t\t\t\t\t...sub,\n\t\t\t\t\twidget: this.clampWidget(sub.widget),\n\t\t\t\t\trequired: (input.fields ? required.includes(sub.key) : sub.required === true) || (input.required && only),\n\t\t\t\t})),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The choices an input declares, as `[{ value, label }]`, or null when\n\t\t * it declares none. An option without a value is dropped, because it\n\t\t * cannot be sent; one without a label shows its value.\n\t\t *\n\t\t * @param {unknown} options The input's declared `options`.\n\t\t * @return {Array<{value: string, label: string}>|null}\n\t\t */\n\t\tdeclaredOptions(options) {\n\t\t\tif (!Array.isArray(options)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst usable = options\n\t\t\t\t.filter((option) => option && typeof option === 'object'\n\t\t\t\t\t&& (typeof option.value === 'string' || typeof option.value === 'number')\n\t\t\t\t\t&& String(option.value).trim() !== '')\n\t\t\t\t.map((option) => ({\n\t\t\t\t\tvalue: String(option.value),\n\t\t\t\t\tlabel: typeof option.label === 'string' && option.label.trim() !== '' ? option.label.trim() : String(option.value),\n\t\t\t\t}))\n\t\t\treturn usable.length > 0 ? usable : null\n\t\t},\n\n\t\t/**\n\t\t * The option a picker field currently holds, or null.\n\t\t *\n\t\t * @param {object} field The select field descriptor.\n\t\t * @return {{value: string, label: string}|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\tconst value = this.values[field.key]\n\t\t\treturn field.options.find((option) => option.value === String(value ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Ids a reference picker must not offer: the current record, when the\n\t\t * input's `picker.excludeSelf` says so.\n\t\t *\n\t\t * @param {object} field The reference field descriptor.\n\t\t * @return {string[]} The ids to leave out.\n\t\t */\n\t\texcludedIds(field) {\n\t\t\tif (!field.picker || field.picker.excludeSelf !== true || !this.currentObject) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst self = this.currentObject\n\t\t\treturn [self.id, self.uuid, self['@self'] && self['@self'].id].filter((id) => id !== undefined && id !== null).map(String)\n\t\t},\n\n\t\t/**\n\t\t * Label of a sub-field, with the required marker.\n\t\t *\n\t\t * @param {object} sub The sub-field descriptor.\n\t\t * @return {string}\n\t\t */\n\t\tsubLabel(sub) {\n\t\t\treturn sub.required ? `${sub.label} *` : sub.label\n\t\t},\n\n\t\t/**\n\t\t * A typed sub-value.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {unknown}\n\t\t */\n\t\tsubValue(key, sub) {\n\t\t\tconst group = this.values[key]\n\t\t\treturn group && typeof group === 'object' ? group[sub] : undefined\n\t\t},\n\n\t\t/**\n\t\t * Store one sub-value, keeping the rest of the object input's values.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetSubValue(key, sub, value) {\n\t\t\tconst group = this.values[key] && typeof this.values[key] === 'object' ? this.values[key] : {}\n\t\t\tthis.setValue(key, { ...group, [sub]: value })\n\t\t},\n\n\t\t/**\n\t\t * Whether a required sub-field holds a value.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {object} sub The sub-field descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisSubFilled(key, sub) {\n\t\t\tconst value = this.subValue(key, sub.key)\n\t\t\treturn sub.widget === 'checkbox' ? value === true : String(value ?? '').trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a refusal named `<input>.<sub>`.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisSubRefused(key, sub) {\n\t\t\treturn this.refusedKeys.includes(`${key}.${sub}`)\n\t\t},\n\n\t\t/** Seed each declared input from its schema default (booleans start false). */\n\t\tinitialValues() {\n\t\t\tconst values = {}\n\t\t\tconst declared = Array.isArray(this.transition?.inputs) ? this.transition.inputs : []\n\t\t\tconst properties = (this.schema && this.schema.properties) || {}\n\t\t\tfor (const input of declared) {\n\t\t\t\tif (!input || typeof input.field !== 'string' || input.field === '') {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst prop = properties[input.field] || {}\n\t\t\t\tif (prop.type === 'object' && prop.properties && typeof prop.properties === 'object') {\n\t\t\t\t\t// An object input starts from the record's present value, so\n\t\t\t\t\t// the sub-fields it asks for show what is there.\n\t\t\t\t\tconst present = this.currentObject ? this.currentObject[input.field] : null\n\t\t\t\t\tvalues[input.field] = present && typeof present === 'object' ? { ...present } : {}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tvalues[input.field] = prop.default !== undefined\n\t\t\t\t\t? prop.default\n\t\t\t\t\t: (prop.type === 'boolean' ? false : '')\n\t\t\t}\n\t\t\treturn values\n\t\t},\n\n\t\t/**\n\t\t * Clamp a `fieldsFromSchema()` widget to the minimal set this dialog\n\t\t * renders. Anything richer (select, date, user picker, …) degrades to a\n\t\t * plain text input rather than pulling a form engine into the dialog.\n\t\t *\n\t\t * @param {string} widget The resolved widget name.\n\t\t * @return {'text'|'textarea'|'number'|'checkbox'}\n\t\t */\n\t\tclampWidget(widget) {\n\t\t\tif (widget === 'checkbox' || widget === 'switch') {\n\t\t\t\treturn 'checkbox'\n\t\t\t}\n\t\t\tif (widget === 'textarea') {\n\t\t\t\treturn 'textarea'\n\t\t\t}\n\t\t\tif (widget === 'number') {\n\t\t\t\treturn 'number'\n\t\t\t}\n\t\t\treturn 'text'\n\t\t},\n\n\t\t/**\n\t\t * The field's visible label, with a `*` marker on required inputs so the\n\t\t * confirm-gating is visually explained.\n\t\t *\n\t\t * @param {object} field The field descriptor.\n\t\t * @return {string}\n\t\t */\n\t\trequiredLabel(field) {\n\t\t\treturn field.required ? `${field.label} *` : field.label\n\t\t},\n\n\t\t/**\n\t\t * Store one input's value.\n\t\t *\n\t\t * @param {string} key The declared field name.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetValue(key, value) {\n\t\t\tthis.values = { ...this.values, [key]: value }\n\t\t},\n\n\t\t/**\n\t\t * Whether a required field counts as filled: a checked switch for\n\t\t * booleans, a non-blank string otherwise.\n\t\t *\n\t\t * @param {object} field The field descriptor.\n\t\t * @return {boolean}\n\t\t */\n\t\tisFilled(field) {\n\t\t\tconst value = this.values[field.key]\n\t\t\tif (field.widget === 'checkbox') {\n\t\t\t\treturn value === true\n\t\t\t}\n\t\t\treturn String(value ?? '').trim() !== ''\n\t\t},\n\n\t\t/**\n\t\t * The object an object input sends: the record's current value with the\n\t\t * asked sub-fields merged over it, so a sub-field that was not asked for\n\t\t * keeps its value. A shown field left empty over an empty current value\n\t\t * is not written. Never a dotted key.\n\t\t *\n\t\t * @param {object} field The object field descriptor.\n\t\t * @return {object}\n\t\t */\n\t\tmergedObject(field) {\n\t\t\tconst present = this.currentObject ? this.currentObject[field.key] : null\n\t\t\tconst base = present && typeof present === 'object' ? { ...present } : {}\n\t\t\tfor (const sub of field.subFields) {\n\t\t\t\tlet value = this.subValue(field.key, sub.key)\n\t\t\t\tconst empty = sub.widget === 'checkbox' ? value === undefined : String(value ?? '').trim() === ''\n\t\t\t\tconst had = base[sub.key]\n\t\t\t\tif (empty && (had === undefined || had === null || had === '')) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (sub.widget === 'number' && !empty && !Number.isNaN(Number(value))) {\n\t\t\t\t\tvalue = Number(value)\n\t\t\t\t}\n\t\t\t\tbase[sub.key] = value\n\t\t\t}\n\t\t\treturn base\n\t\t},\n\n\t\t/** Confirm: emit exactly the declared keys (numbers cast) and let the parent POST. */\n\t\tonConfirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.widget === 'object') {\n\t\t\t\t\tdata[field.key] = this.mergedObject(field)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tlet value = this.values[field.key]\n\t\t\t\tif (field.widget === 'number' && String(value ?? '').trim() !== '') {\n\t\t\t\t\tconst parsed = Number(value)\n\t\t\t\t\tif (!Number.isNaN(parsed)) {\n\t\t\t\t\t\tvalue = parsed\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdata[field.key] = value\n\t\t\t}\n\t\t\t/**\n\t\t\t * @event confirm Emitted when the user confirms with all required\n\t\t\t * inputs filled. Payload holds exactly the declared input keys; the\n\t\t\t * parent POSTs `{ action, data }`.\n\t\t\t * @type {{[key: string]: unknown}}\n\t\t\t */\n\t\t\tthis.$emit('confirm', data)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-transition-input {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tpadding: 4px 0;\n}\n\n.cn-transition-input__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-transition-input__field-error {\n\tmargin: 4px 0 0;\n\tfont-size: 0.9em;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-transition-input__object {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 8px 12px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-transition-input__label {\n\tdisplay: block;\n\tmargin-bottom: 4px;\n}\n\n.cn-transition-input__field--refused {\n\tborder-inline-start: 2px solid var(--color-error);\n\tpadding-inline-start: 8px;\n}\n</style>\n"],"names":["CnResourceSelect","CnDialog","t"],"mappings":"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"}
|