@conduction/nextcloud-vue 2.56.0-beta.65 → 2.56.0-beta.67
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/CnActionButtons/CnActionButtons.vue.js +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js +4 -6
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +3 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +4 -2
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +3 -2
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +2 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +54 -5
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +16 -2
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +10 -0
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +2 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +22 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +17 -3
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +18 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +52 -13
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +31 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +48 -11
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +160 -97
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +2 -2
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +222 -15
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +24 -7
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue.js +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js +21 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js.map +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +36 -2
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +44 -5
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js +1 -0
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js +22 -2
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js +36 -16
- package/dist/esm/components/CnPartyPicker/CnPartyPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +29 -12
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +3 -1
- package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue.js +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue2.js.map +1 -1
- package/dist/esm/components/CnSearchSelect/CnSearchSelect.vue3.js.map +1 -1
- package/dist/esm/composables/useRefLabels.js +26 -6
- package/dist/esm/composables/useRefLabels.js.map +1 -1
- package/dist/esm/integrations/registry.js +4 -0
- package/dist/esm/integrations/registry.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +3 -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 +680 -449
- package/dist/esm/store/plugins/liveUpdates.js +3 -1
- package/dist/esm/store/plugins/liveUpdates.js.map +1 -1
- package/dist/esm/store/plugins/logs.js +2 -1
- package/dist/esm/store/plugins/logs.js.map +1 -1
- package/dist/esm/utils/actionLink.js +104 -1
- package/dist/esm/utils/actionLink.js.map +1 -1
- package/dist/esm/utils/detailActionModel.js +28 -1
- package/dist/esm/utils/detailActionModel.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +13 -5
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/headerFieldChips.js +21 -2
- package/dist/esm/utils/headerFieldChips.js.map +1 -1
- package/dist/esm/utils/mapList.js +26 -11
- package/dist/esm/utils/mapList.js.map +1 -1
- package/dist/esm/utils/savedViewMenu.js +12 -5
- package/dist/esm/utils/savedViewMenu.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 +2800 -1933
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +680 -449
- package/l10n/en.json +3 -1
- package/l10n/nl.json +3 -1
- package/package.json +1 -1
- package/src/components/CnActionButtons/CnActionButtons.vue +4 -6
- package/src/components/CnActionDialog/CnActionDialog.vue +32 -9
- package/src/components/CnAssignDialog/CnAssignDialog.vue +4 -2
- package/src/components/CnBoardView/CnBoardView.vue +58 -5
- package/src/components/CnCardGrid/CnCardGrid.md +1 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +11 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +27 -3
- package/src/components/CnChartWidget/CnChartWidget.vue +6 -0
- package/src/components/CnChoiceCards/CnChoiceCards.vue +0 -3
- package/src/components/CnDashboardPage/CnDashboardPage.vue +20 -5
- package/src/components/CnDetailPage/CnDetailPage.vue +62 -14
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +100 -5
- package/src/components/CnFormDialog/CnFormDialog.vue +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +233 -18
- package/src/components/CnNcDashboardList/CnNcDashboardList.vue +21 -1
- package/src/components/CnObjectCard/CnObjectCard.md +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +51 -5
- package/src/components/CnPartyPicker/CnPartyPicker.vue +62 -16
- package/src/components/CnReportsPage/CnReportsPage.vue +31 -12
- package/src/components/CnSearchSelect/CnSearchSelect.vue +8 -0
- package/src/composables/useRefLabels.js +25 -5
- package/src/css/badge.css +15 -13
- package/src/css/board.css +0 -1
- package/src/css/dialog.css +53 -3
- package/src/css/index-page.css +26 -1
- package/src/css/look-board-detail.css +36 -15
- package/src/css/look-board-index.css +67 -15
- package/src/css/look-board.css +32 -18
- package/src/integrations/registry.js +4 -0
- package/src/schemas/app-manifest-v2.schema.json +61 -13
- package/src/store/plugins/liveUpdates.js +3 -1
- package/src/store/plugins/logs.js +2 -1
- package/src/utils/actionLink.js +103 -0
- package/src/utils/detailActionModel.js +27 -0
- package/src/utils/fillTemplate.js +13 -5
- package/src/utils/headerFieldChips.js +21 -2
- package/src/utils/mapList.js +26 -11
- package/src/utils/savedViewMenu.js +12 -5
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnActionDialog.vue3.js","sources":["../../../../src/components/CnActionDialog/CnActionDialog.vue?vue&type=template&id=0bb28fd1&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Confirm')\"\n\t\t:eyebrow=\"eyebrowText\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-action-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-action-dialog\">\n\t\t\t<!-- The record the action is about: its title, a meta line, a badge. -->\n\t\t\t<div v-if=\"summary\" class=\"cn-action-dialog__summary\" data-testid=\"cn-action-dialog-summary\">\n\t\t\t\t<CnIcon :name=\"config.summary.icon || 'FolderOutline'\" :size=\"20\" class=\"cn-action-dialog__summary-icon\" />\n\t\t\t\t<span class=\"cn-action-dialog__summary-text\">\n\t\t\t\t\t<strong>{{ summary.title }}</strong>\n\t\t\t\t\t<span v-if=\"summary.meta\" class=\"cn-action-dialog__muted\">{{ summary.meta }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span v-if=\"summary.badge\" class=\"cn-action-dialog__badge\">{{ summary.badge }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- Facts about the record, in titled groups (\"Retention under the case type\"). -->\n\t\t\t<section v-for=\"(section, index) in factSections\"\n\t\t\t\t:key=\"`facts-${index}`\"\n\t\t\t\tclass=\"cn-action-dialog__section\"\n\t\t\t\tdata-testid=\"cn-action-dialog-facts\">\n\t\t\t\t<h3 v-if=\"section.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<dl class=\"cn-action-dialog__facts\">\n\t\t\t\t\t<div v-for=\"fact in section.facts\" :key=\"fact.label\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t</section>\n\n\t\t\t<!-- The checklist, read from an endpoint: each item met, not met or\n\t\t\t unknown. Items named in `required` decide whether the action may\n\t\t\t run; the others inform. -->\n\t\t\t<section v-if=\"config.checklist\" class=\"cn-action-dialog__section\" data-testid=\"cn-action-dialog-checklist\">\n\t\t\t\t<h3 v-if=\"config.checklist.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ text(config.checklist.title) }}\n\t\t\t\t</h3>\n\t\t\t\t<p v-if=\"checklistError\" class=\"cn-action-dialog__muted\" role=\"status\">\n\t\t\t\t\t{{ checklistError }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-action-dialog__checks\">\n\t\t\t\t\t<li v-for=\"item in checklist\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-action-dialog__check\"\n\t\t\t\t\t\t:data-testid=\"`cn-action-dialog-check-${item.id}`\"\n\t\t\t\t\t\t:data-met=\"String(item.met)\">\n\t\t\t\t\t\t<CheckCircle v-if=\"item.met === true\" :size=\"20\" class=\"cn-action-dialog__check-icon cn-action-dialog__check-icon--met\" />\n\t\t\t\t\t\t<HelpCircleOutline v-else-if=\"item.met === null\" :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<CircleOutline v-else :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__check-label\">{{ item.label }}</strong>\n\t\t\t\t\t\t<span v-if=\"item.detail\" class=\"cn-action-dialog__muted\">{{ item.detail }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<!-- Fields the action asks for, sent beside the reason. -->\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.field\"\n\t\t\t\tclass=\"cn-action-dialog__field\"\n\t\t\t\t:data-testid=\"`cn-action-dialog-field-${field.field}`\">\n\t\t\t\t<NcSelect v-if=\"field.type === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"optionsOf(field)\"\n\t\t\t\t\t:inputLabel=\"text(field.label) || field.field\"\n\t\t\t\t\t:clearable=\"field.required === false\"\n\t\t\t\t\t@update:modelValue=\"(option) => pick(field, option)\" />\n\t\t\t\t<NcTextField v-else\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\t:type=\"field.type === 'datetime' ? 'datetime-local' : (field.type === 'date' ? 'date' : 'text')\"\n\t\t\t\t\t:label=\"text(field.label) || field.field\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.reason\" class=\"cn-action-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"reasonId\"\n\t\t\t\t\tv-model=\"reason\"\n\t\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-action-dialog-reason\" />\n\t\t\t\t<span v-if=\"config.reason.hint\" class=\"cn-action-dialog__muted\">{{ text(config.reason.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<NcNoteCard v-if=\"config.note\"\n\t\t\t\t:type=\"noteType\"\n\t\t\t\t:heading=\"text(config.note.title)\"\n\t\t\t\tdata-testid=\"cn-action-dialog-note\">\n\t\t\t\t{{ text(config.note.text) }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-action-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-action-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-action-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-action-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-action-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template v-if=\"confirmConfig.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Confirm') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport CircleOutline from 'vue-material-design-icons/CircleOutline.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** Gives each dialog's reason field its own id. */\nlet reasonSeq = 0\n\n/**\n * CnActionDialog — the generic \"summary, checklist, reason, confirm\" dialog\n * for an act on a record, configured from the manifest (an `open-modal`\n * action's props), so an app does not hand-build each one. dossiq's archive\n * dialog (board DqArchiveren) is the first: the case, what its case type\n * keeps, a readiness checklist read from an endpoint, a reason, a read-only\n * note and Archive it.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record (\"Close off · {identifier}\").\n * - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from\n * the record (`source` an endpointSource to read it from, else `object`).\n * - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template.\n * - `checklist`: `{ title?, source, itemsPath?, labels?, required? }`: items\n * `{ id, met, label?, detail? }` read from `source`; `labels[id]` gives an\n * item's `{ label, detail?, unmetDetail? }`; the ids in `required` must be\n * met before the action can run. `met: null` reads as unknown.\n * - `permission`: `{ source, listPath?, match?, allowedPath, reasonPath? }`:\n * the action runs only while `allowedPath` reads true; `reasonPath` says\n * why not. With `listPath` the paths read the entry of that list whose\n * fields equal `match` (`{ act: \"archive\" }`).\n * - `fields`: `[{ field, type?: \"text\"|\"date\"|\"datetime\"|\"select\", label?,\n * required?, options?: [{ value, label, fills? }] }]`: inputs sent beside\n * the reason, required by default; a select option's `fills` sets other\n * fields that are still empty.\n * - `reason`: `{ label?, hint?, required?, field? }`: a text area; required by\n * default; sent as `field` (default `reason`).\n * - `note`: `{ variant?, title?, text }`: a read-only note.\n * - `confirm`: `{ label, icon?, request?: { method?, url, body? }, action? }`.\n * `request` posts itself (`body` templates filled with the record and\n * `{reason}`); `action` dispatches a manifest action through the page.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url.\n */\nexport default {\n\tname: 'CnActionDialog',\n\n\tcomponents: { CheckCircle, CircleOutline, CnDialog, CnIcon, HelpCircleOutline, NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it: the summary and facts read it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\titems: [],\n\t\t\tchecklistError: '',\n\t\t\tallowed: true,\n\t\t\treason: '',\n\t\t\tvalues: {},\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\treasonId: `cn-action-dialog-reason-${++reasonSeq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/**\n\t\t * The summary row, or null without one or before the record is known.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {{title: string, meta: string, badge: string}|null}\n\t\t */\n\t\tsummary() {\n\t\t\tconst def = this.config.summary\n\t\t\tif (!def || !this.record) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst title = this.fill(def.title)\n\t\t\treturn title ? { title, meta: this.fill(def.meta), badge: this.fill(def.badge) } : null\n\t\t},\n\n\t\t/** @return {Array<{title: string, facts: Array<{label: string, value: string}>}>} The fact groups. */\n\t\tfactSections() {\n\t\t\tif (!Array.isArray(this.config.facts) || !this.record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst empty = t('nextcloud-vue', 'Not set')\n\t\t\treturn this.config.facts.map((section) => ({\n\t\t\t\ttitle: this.text(section.title),\n\t\t\t\tfacts: (Array.isArray(section.items) ? section.items : []).map((fact) => ({ label: this.text(fact.label), value: this.fill(fact.value) || empty })),\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The checklist rows: label and detail from `labels` by id, else the item's own.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Array<{id: string, met: (boolean|null), label: string, detail: string}>}\n\t\t */\n\t\tchecklist() {\n\t\t\tconst labels = (this.config.checklist && this.config.checklist.labels) || {}\n\t\t\treturn this.items.map((item) => {\n\t\t\t\tconst met = item.met === null || item.met === undefined ? null : item.met === true\n\t\t\t\tconst own = labels[item.id] || {}\n\t\t\t\tconst detail = met === false && own.unmetDetail ? own.unmetDetail : (own.detail || item.detail || '')\n\t\t\t\treturn {\n\t\t\t\t\tid: String(item.id),\n\t\t\t\t\tmet,\n\t\t\t\t\tlabel: this.fill(own.label || item.label || String(item.id), item),\n\t\t\t\t\tdetail: met === null && !item.detail ? t('nextcloud-vue', 'Could not be read') : this.fill(detail, item),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether every required item is met. */\n\t\trequiredMet() {\n\t\t\tconst required = (this.config.checklist && Array.isArray(this.config.checklist.required)) ? this.config.checklist.required.map(String) : []\n\t\t\treturn required.every((id) => this.items.some((item) => String(item.id) === id && item.met === true))\n\t\t},\n\n\t\t/** @return {boolean} Whether a reason is asked and needed. */\n\t\treasonNeeded() {\n\t\t\treturn Boolean(this.config.reason) && this.config.reason.required !== false\n\t\t},\n\n\t\t/** @return {string} The reason field's label. */\n\t\treasonLabel() {\n\t\t\treturn this.text(this.config.reason && this.config.reason.label) || t('nextcloud-vue', 'Reason')\n\t\t},\n\n\t\t/** @return {string} The note's NcNoteCard type. */\n\t\tnoteType() {\n\t\t\tconst variant = this.config.note && this.config.note.variant\n\t\t\treturn ['info', 'warning', 'error', 'success'].includes(variant) ? variant : 'info'\n\t\t},\n\n\t\t/**\n\t\t * Whether the action may run: allowed, required items met, a reason\n\t\t * when one is needed, and nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.allowed && this.requiredMet && this.fieldsFilled && (!this.reasonNeeded || this.reason.trim() !== '')\n\t\t},\n\n\t\t/** @return {string} The eyebrow, filled from the record once it is known. */\n\t\teyebrowText() {\n\t\t\treturn this.record ? this.fill(this.config.eyebrow) || this.text(this.config.eyebrow) : this.text(this.config.eyebrow)\n\t\t},\n\n\t\t/** @return {Array<object>} The fields with a name. */\n\t\tfields() {\n\t\t\treturn (Array.isArray(this.config.fields) ? this.config.fields : []).filter((f) => f && f.field)\n\t\t},\n\n\t\t/**\n\t\t * Whether every required field has a value.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-fields-and-acts/specs/action-dialog/spec.md#requirement-an-action-dialog-asks-for-fields-and-reads-a-permission-from-a-list\n\t\t * @return {boolean}\n\t\t */\n\t\tfieldsFilled() {\n\t\t\treturn this.fields.every((f) => f.required === false || String(this.values[f.field] ?? '').trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tawait Promise.all([this.loadRecord(), this.loadChecklist(), this.loadPermission()])\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from a row (the record by default), translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @param {object} [row] The row.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, row) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), row || this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Read an endpoint, fresh.\n\t\t *\n\t\t * @param {object} source An endpointSource block.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tread(source) {\n\t\t\treturn fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadRecord() {\n\t\t\tconst source = this.config.summary && this.config.summary.source\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(source)\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The summary stays empty; the checklist and the action still work.\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadChecklist() {\n\t\t\tconst def = this.config.checklist\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst list = def.itemsPath ? readPath(data, def.itemsPath) : data\n\t\t\t\tthis.items = Array.isArray(list) ? list.filter((item) => item && item.id !== undefined) : []\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.checklistError = t('nextcloud-vue', 'Whether this is ready could not be read.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entry of a list whose fields equal `match`, or null.\n\t\t *\n\t\t * @param {unknown} list The list.\n\t\t * @param {object} [match] The fields to match.\n\t\t * @return {object|null}\n\t\t */\n\t\tmatchIn(list, match) {\n\t\t\tconst wanted = Object.entries(match || {})\n\t\t\treturn (Array.isArray(list) ? list : []).find((entry) => entry && wanted.every(([key, value]) => String(entry[key]) === String(value))) || null\n\t\t},\n\n\t\t/**\n\t\t * A select field's options, labels translated.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{id: string, label: string, fills?: object}>}\n\t\t */\n\t\toptionsOf(field) {\n\t\t\treturn (Array.isArray(field.options) ? field.options : []).map((o) => ({ id: String(o.value), label: this.text(o.label) || String(o.value), fills: o.fills }))\n\t\t},\n\n\t\t/**\n\t\t * A select field's chosen option.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\treturn this.optionsOf(field).find((o) => o.id === String(this.values[field.field] ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Set a field's value.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\tsetValue(name, value) {\n\t\t\tthis.values = { ...this.values, [name]: value === null || value === undefined ? '' : String(value) }\n\t\t},\n\n\t\t/**\n\t\t * Choose a select option; its `fills` set the fields still empty.\n\t\t *\n\t\t * @param {object} field The select field.\n\t\t * @param {{id: string, fills?: object}|null} option The option.\n\t\t */\n\t\tpick(field, option) {\n\t\t\tthis.setValue(field.field, option ? option.id : '')\n\t\t\tfor (const [name, value] of Object.entries((option && option.fills) || {})) {\n\t\t\t\tif (String(this.values[name] ?? '').trim() === '') {\n\t\t\t\t\tthis.setValue(name, this.text(value) || value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadPermission() {\n\t\t\tconst def = this.config.permission\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst entry = def.listPath ? this.matchIn(readPath(data, def.listPath), def.match) : data\n\t\t\t\tthis.allowed = readPath(entry, def.allowedPath || 'allowed') === true\n\t\t\t\tthis.refusal = this.allowed || !def.reasonPath ? '' : String(readPath(entry, def.reasonPath) || '')\n\t\t\t} catch {\n\t\t\t\tthis.allowed = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the action once: post `confirm.request`, or dispatch\n\t\t * `confirm.action`, then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst reason = this.reason.trim()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, { ...(this.record || {}), reason }) : value\n\t\t\t\t\t}\n\t\t\t\t\tif (this.config.reason) {\n\t\t\t\t\t\tbody[this.config.reason.field || 'reason'] = reason\n\t\t\t\t\t}\n\t\t\t\t\tfor (const field of this.fields) {\n\t\t\t\t\t\tbody[field.field] = this.values[field.field] ?? ''\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch', 'delete'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), body)\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { ...this.values, reason }] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The action ran. Payload: the field values and `reason`. */\n\t\t\t\tthis.$emit('done', { ...this.values, reason })\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'The action could not be completed.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the action is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-action-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-action-dialog__summary {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-action-dialog__summary-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-action-dialog__badge {\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-action-dialog__title {\n\tmargin: 0 0 8px;\n\tfont-size: 15px;\n\tfont-weight: 700;\n}\n\n.cn-action-dialog__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n\tgap: 8px 16px;\n\tmargin: 0;\n}\n\n.cn-action-dialog__facts dt {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__facts dd {\n\tmargin: 0;\n}\n\n.cn-action-dialog__checks {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-action-dialog__check {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-action-dialog__check-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-action-dialog__check-icon--met {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n.cn-action-dialog__muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-action-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-action-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnActionDialog.vue3.js","sources":["../../../../src/components/CnActionDialog/CnActionDialog.vue?vue&type=template&id=5293ec77&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Confirm')\"\n\t\t:eyebrow=\"eyebrowText\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-action-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-action-dialog\">\n\t\t\t<!-- The record the action is about: its title, a meta line, a badge. -->\n\t\t\t<div v-if=\"summary\" class=\"cn-action-dialog__summary\" data-testid=\"cn-action-dialog-summary\">\n\t\t\t\t<CnIcon :name=\"config.summary.icon || 'FolderOutline'\" :size=\"20\" class=\"cn-action-dialog__summary-icon\" />\n\t\t\t\t<span class=\"cn-action-dialog__summary-text\">\n\t\t\t\t\t<strong>{{ summary.title }}</strong>\n\t\t\t\t\t<span v-if=\"summary.meta\" class=\"cn-action-dialog__muted\">{{ summary.meta }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span v-if=\"summary.badge\" class=\"cn-action-dialog__badge\">{{ summary.badge }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- Facts about the record, in titled groups (\"Retention under the case type\"). -->\n\t\t\t<section v-for=\"(section, index) in factSections\"\n\t\t\t\t:key=\"`facts-${index}`\"\n\t\t\t\tclass=\"cn-action-dialog__section\"\n\t\t\t\tdata-testid=\"cn-action-dialog-facts\">\n\t\t\t\t<h3 v-if=\"section.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<dl class=\"cn-action-dialog__facts\">\n\t\t\t\t\t<div v-for=\"fact in section.facts\" :key=\"fact.label\" class=\"cn-action-dialog__fact\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t</section>\n\n\t\t\t<!-- The checklist, read from an endpoint: each item met, not met or\n\t\t\t unknown. Items named in `required` decide whether the action may\n\t\t\t run; the others inform. -->\n\t\t\t<section v-if=\"config.checklist\" class=\"cn-action-dialog__section\" data-testid=\"cn-action-dialog-checklist\">\n\t\t\t\t<h3 v-if=\"config.checklist.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ text(config.checklist.title) }}\n\t\t\t\t</h3>\n\t\t\t\t<p v-if=\"checklistError\" class=\"cn-action-dialog__muted\" role=\"status\">\n\t\t\t\t\t{{ checklistError }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-action-dialog__checks\">\n\t\t\t\t\t<li v-for=\"item in checklist\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-action-dialog__check\"\n\t\t\t\t\t\t:data-testid=\"`cn-action-dialog-check-${item.id}`\"\n\t\t\t\t\t\t:data-met=\"String(item.met)\">\n\t\t\t\t\t\t<CheckCircle v-if=\"item.met === true\" :size=\"20\" class=\"cn-action-dialog__check-icon cn-action-dialog__check-icon--met\" />\n\t\t\t\t\t\t<HelpCircleOutline v-else-if=\"item.met === null\" :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<CircleOutline v-else :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__check-label\">{{ item.label }}</strong>\n\t\t\t\t\t\t<span v-if=\"item.detail\" class=\"cn-action-dialog__muted\">{{ item.detail }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<!-- Fields the action asks for, sent beside the reason. -->\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.field\"\n\t\t\t\tclass=\"cn-action-dialog__field\"\n\t\t\t\t:data-testid=\"`cn-action-dialog-field-${field.field}`\">\n\t\t\t\t<NcSelect v-if=\"field.type === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"optionsOf(field)\"\n\t\t\t\t\t:inputLabel=\"text(field.label) || field.field\"\n\t\t\t\t\t:clearable=\"field.required === false\"\n\t\t\t\t\t@update:modelValue=\"(option) => pick(field, option)\" />\n\t\t\t\t<NcTextField v-else\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\t:type=\"field.type === 'datetime' ? 'datetime-local' : (field.type === 'date' ? 'date' : 'text')\"\n\t\t\t\t\t:label=\"text(field.label) || field.field\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.reason\" class=\"cn-action-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"reasonId\"\n\t\t\t\t\tv-model=\"reason\"\n\t\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\t:rows=\"config.reason.rows || 2\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-action-dialog-reason\" />\n\t\t\t\t<span v-if=\"config.reason.hint\" class=\"cn-action-dialog__muted\">{{ text(config.reason.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<NcNoteCard v-if=\"config.note\"\n\t\t\t\t:type=\"noteType\"\n\t\t\t\t:heading=\"text(config.note.title)\"\n\t\t\t\tdata-testid=\"cn-action-dialog-note\">\n\t\t\t\t{{ text(config.note.text) }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-action-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-action-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-action-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-action-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-action-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template v-if=\"confirmConfig.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Confirm') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport CircleOutline from 'vue-material-design-icons/CircleOutline.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** Gives each dialog's reason field its own id. */\nlet reasonSeq = 0\n\n/**\n * CnActionDialog — the generic \"summary, checklist, reason, confirm\" dialog\n * for an act on a record, configured from the manifest (an `open-modal`\n * action's props), so an app does not hand-build each one. dossiq's archive\n * dialog (board DqArchiveren) is the first: the case, what its case type\n * keeps, a readiness checklist read from an endpoint, a reason, a read-only\n * note and Archive it.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record (\"Close off · {identifier}\").\n * - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from\n * the record (`source` an endpointSource to read it from, else `object`).\n * - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template.\n * - `checklist`: `{ title?, source, itemsPath?, labels?, required? }`: items\n * `{ id, met, label?, detail? }` read from `source`; `labels[id]` gives an\n * item's `{ label, detail?, unmetDetail? }`; the ids in `required` must be\n * met before the action can run. `met: null` reads as unknown.\n * - `permission`: `{ source, listPath?, match?, allowedPath, reasonPath? }`:\n * the action runs only while `allowedPath` reads true; `reasonPath` says\n * why not. With `listPath` the paths read the entry of that list whose\n * fields equal `match` (`{ act: \"archive\" }`).\n * - `fields`: `[{ field, type?: \"text\"|\"date\"|\"datetime\"|\"select\", label?,\n * required?, options?: [{ value, label, fills? }] }]`: inputs sent beside\n * the reason, required by default; a select option's `fills` sets other\n * fields that are still empty.\n * - `reason`: `{ label?, hint?, required?, field?, rows? }`: a text area; required by\n * default; sent as `field` (default `reason`). `rows` is its height in lines\n * (default 2; board DqBesluit draws 4).\n * - `note`: `{ variant?, title?, text }`: a read-only note.\n * - `confirm`: `{ label, icon?, request?: { method?, url, body? }, action? }`.\n * `request` posts itself (`body` templates filled with the record and\n * `{reason}`); `action` dispatches a manifest action through the page.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url.\n */\nexport default {\n\tname: 'CnActionDialog',\n\n\tcomponents: { CheckCircle, CircleOutline, CnDialog, CnIcon, HelpCircleOutline, NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it: the summary and facts read it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\titems: [],\n\t\t\tchecklistError: '',\n\t\t\tallowed: true,\n\t\t\treason: '',\n\t\t\tvalues: {},\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\treasonId: `cn-action-dialog-reason-${++reasonSeq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/**\n\t\t * The summary row, or null without one or before the record is known.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {{title: string, meta: string, badge: string}|null}\n\t\t */\n\t\tsummary() {\n\t\t\tconst def = this.config.summary\n\t\t\tif (!def || !this.record) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst title = this.fill(def.title)\n\t\t\treturn title ? { title, meta: this.fill(def.meta), badge: this.fill(def.badge) } : null\n\t\t},\n\n\t\t/** @return {Array<{title: string, facts: Array<{label: string, value: string}>}>} The fact groups. */\n\t\tfactSections() {\n\t\t\tif (!Array.isArray(this.config.facts) || !this.record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst empty = t('nextcloud-vue', 'Not set')\n\t\t\treturn this.config.facts.map((section) => ({\n\t\t\t\ttitle: this.text(section.title),\n\t\t\t\tfacts: (Array.isArray(section.items) ? section.items : []).map((fact) => ({ label: this.text(fact.label), value: this.fill(fact.value) || empty })),\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The checklist rows: label and detail from `labels` by id, else the item's own.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Array<{id: string, met: (boolean|null), label: string, detail: string}>}\n\t\t */\n\t\tchecklist() {\n\t\t\tconst labels = (this.config.checklist && this.config.checklist.labels) || {}\n\t\t\treturn this.items.map((item) => {\n\t\t\t\tconst met = item.met === null || item.met === undefined ? null : item.met === true\n\t\t\t\tconst own = labels[item.id] || {}\n\t\t\t\tconst detail = met === false && own.unmetDetail ? own.unmetDetail : (own.detail || item.detail || '')\n\t\t\t\treturn {\n\t\t\t\t\tid: String(item.id),\n\t\t\t\t\tmet,\n\t\t\t\t\tlabel: this.fill(own.label || item.label || String(item.id), item),\n\t\t\t\t\tdetail: met === null && !item.detail ? t('nextcloud-vue', 'Could not be read') : this.fill(detail, item),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether every required item is met. */\n\t\trequiredMet() {\n\t\t\tconst required = (this.config.checklist && Array.isArray(this.config.checklist.required)) ? this.config.checklist.required.map(String) : []\n\t\t\treturn required.every((id) => this.items.some((item) => String(item.id) === id && item.met === true))\n\t\t},\n\n\t\t/** @return {boolean} Whether a reason is asked and needed. */\n\t\treasonNeeded() {\n\t\t\treturn Boolean(this.config.reason) && this.config.reason.required !== false\n\t\t},\n\n\t\t/** @return {string} The reason field's label. */\n\t\treasonLabel() {\n\t\t\treturn this.text(this.config.reason && this.config.reason.label) || t('nextcloud-vue', 'Reason')\n\t\t},\n\n\t\t/** @return {string} The note's NcNoteCard type. */\n\t\tnoteType() {\n\t\t\tconst variant = this.config.note && this.config.note.variant\n\t\t\treturn ['info', 'warning', 'error', 'success'].includes(variant) ? variant : 'info'\n\t\t},\n\n\t\t/**\n\t\t * Whether the action may run: allowed, required items met, a reason\n\t\t * when one is needed, and nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.allowed && this.requiredMet && this.fieldsFilled && (!this.reasonNeeded || this.reason.trim() !== '')\n\t\t},\n\n\t\t/** @return {string} The eyebrow, filled from the record once it is known. */\n\t\teyebrowText() {\n\t\t\treturn this.record ? this.fill(this.config.eyebrow) || this.text(this.config.eyebrow) : this.text(this.config.eyebrow)\n\t\t},\n\n\t\t/** @return {Array<object>} The fields with a name. */\n\t\tfields() {\n\t\t\treturn (Array.isArray(this.config.fields) ? this.config.fields : []).filter((f) => f && f.field)\n\t\t},\n\n\t\t/**\n\t\t * Whether every required field has a value.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-fields-and-acts/specs/action-dialog/spec.md#requirement-an-action-dialog-asks-for-fields-and-reads-a-permission-from-a-list\n\t\t * @return {boolean}\n\t\t */\n\t\tfieldsFilled() {\n\t\t\treturn this.fields.every((f) => f.required === false || String(this.values[f.field] ?? '').trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tawait Promise.all([this.loadRecord(), this.loadChecklist(), this.loadPermission()])\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from a row (the record by default), translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @param {object} [row] The row.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, row) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), row || this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Read an endpoint, fresh.\n\t\t *\n\t\t * @param {object} source An endpointSource block.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tread(source) {\n\t\t\treturn fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadRecord() {\n\t\t\tconst source = this.config.summary && this.config.summary.source\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(source)\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The summary stays empty; the checklist and the action still work.\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadChecklist() {\n\t\t\tconst def = this.config.checklist\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst list = def.itemsPath ? readPath(data, def.itemsPath) : data\n\t\t\t\tthis.items = Array.isArray(list) ? list.filter((item) => item && item.id !== undefined) : []\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.checklistError = t('nextcloud-vue', 'Whether this is ready could not be read.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entry of a list whose fields equal `match`, or null.\n\t\t *\n\t\t * @param {unknown} list The list.\n\t\t * @param {object} [match] The fields to match.\n\t\t * @return {object|null}\n\t\t */\n\t\tmatchIn(list, match) {\n\t\t\tconst wanted = Object.entries(match || {})\n\t\t\treturn (Array.isArray(list) ? list : []).find((entry) => entry && wanted.every(([key, value]) => String(entry[key]) === String(value))) || null\n\t\t},\n\n\t\t/**\n\t\t * A select field's options, labels translated.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{id: string, label: string, fills?: object}>}\n\t\t */\n\t\toptionsOf(field) {\n\t\t\treturn (Array.isArray(field.options) ? field.options : []).map((o) => ({ id: String(o.value), label: this.text(o.label) || String(o.value), fills: o.fills }))\n\t\t},\n\n\t\t/**\n\t\t * A select field's chosen option.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\treturn this.optionsOf(field).find((o) => o.id === String(this.values[field.field] ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Set a field's value.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\tsetValue(name, value) {\n\t\t\tthis.values = { ...this.values, [name]: value === null || value === undefined ? '' : String(value) }\n\t\t},\n\n\t\t/**\n\t\t * Choose a select option; its `fills` set the fields still empty.\n\t\t *\n\t\t * @param {object} field The select field.\n\t\t * @param {{id: string, fills?: object}|null} option The option.\n\t\t */\n\t\tpick(field, option) {\n\t\t\tthis.setValue(field.field, option ? option.id : '')\n\t\t\tfor (const [name, value] of Object.entries((option && option.fills) || {})) {\n\t\t\t\tif (String(this.values[name] ?? '').trim() === '') {\n\t\t\t\t\tthis.setValue(name, this.text(value) || value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadPermission() {\n\t\t\tconst def = this.config.permission\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst entry = def.listPath ? this.matchIn(readPath(data, def.listPath), def.match) : data\n\t\t\t\tthis.allowed = readPath(entry, def.allowedPath || 'allowed') === true\n\t\t\t\tthis.refusal = this.allowed || !def.reasonPath ? '' : String(readPath(entry, def.reasonPath) || '')\n\t\t\t} catch {\n\t\t\t\tthis.allowed = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the action once: post `confirm.request`, or dispatch\n\t\t * `confirm.action`, then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst reason = this.reason.trim()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, { ...(this.record || {}), reason }) : value\n\t\t\t\t\t}\n\t\t\t\t\tif (this.config.reason) {\n\t\t\t\t\t\tbody[this.config.reason.field || 'reason'] = reason\n\t\t\t\t\t}\n\t\t\t\t\tfor (const field of this.fields) {\n\t\t\t\t\t\tbody[field.field] = this.values[field.field] ?? ''\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch', 'delete'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), body)\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { ...this.values, reason }] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The action ran. Payload: the field values and `reason`. */\n\t\t\t\tthis.$emit('done', { ...this.values, reason })\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'The action could not be completed.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the action is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-action-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-action-dialog__summary {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-action-dialog__summary-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-action-dialog__badge {\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-action-dialog__title {\n\tmargin: 0 0 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n/* Facts in columns of at least 200px, each a label over its value above a\n hairline (DqArchiveren \"Bewaring volgens het zaaktype\"). */\n.cn-action-dialog__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\tgap: 12px 24px;\n\tmargin: 0;\n}\n\n.cn-action-dialog__fact {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding-bottom: 10px;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-action-dialog__facts dt {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__facts dd {\n\tmargin: 0;\n\tfont-size: 15px;\n\tfont-weight: 500;\n}\n\n/* Checklist rows divided by hairlines, the detail at the row's end\n (DqArchiveren \"Klaar om te archiveren\"). */\n.cn-action-dialog__checks {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-action-dialog__check {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 2px 12px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n\tfont-size: 15px;\n}\n\n.cn-action-dialog__check-label {\n\tflex: 1 1 auto;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__check-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-action-dialog__check-icon--met {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n.cn-action-dialog__muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-action-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-action-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ export { withTypedAssignee } from './CnAssignDialog.vue2.js';
|
|
|
3
3
|
import { render } from './CnAssignDialog.vue3.js';
|
|
4
4
|
|
|
5
5
|
script.render = render;
|
|
6
|
-
script.__scopeId = "data-v-
|
|
6
|
+
script.__scopeId = "data-v-45153be8";
|
|
7
7
|
const __sfc_main = script;
|
|
8
8
|
|
|
9
9
|
export { __sfc_main as default };
|
|
@@ -56,8 +56,9 @@ function withTypedAssignee(found, typed, label) {
|
|
|
56
56
|
* by `currentAs`) says so, in place of `hint`; `allowTyped`
|
|
57
57
|
* offers what was typed as a choice; the id is sent as `field` (default
|
|
58
58
|
* `assignee`) and its kind as `kindField` when set.
|
|
59
|
-
* - `note`: `{ label?, hint?, required?, field? }`, required by default and
|
|
60
|
-
* sent as `field` (default `note`); `false` drops it.
|
|
59
|
+
* - `note`: `{ label?, hint?, required?, field?, rows? }`, required by default and
|
|
60
|
+
* sent as `field` (default `note`); `false` drops it. `rows` is the text
|
|
61
|
+
* area's height in lines (default 3, as board DqOverdragen draws it).
|
|
61
62
|
* - `toggles`: `[{ field, label, note? }]`: switches that start off and are
|
|
62
63
|
* sent as booleans.
|
|
63
64
|
* - `confirm`: `{ label?, icon?, request?: { method?, url, body? }, action? }`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAssignDialog.vue2.js","sources":["../../../../src/components/CnAssignDialog/CnAssignDialog.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:name=\"text(config.title) || t('nextcloud-vue', 'Assign')\"\n\t\t:eyebrow=\"fill(config.eyebrow)\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-assign-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-assign-dialog\">\n\t\t\t<div class=\"cn-assign-dialog__field\">\n\t\t\t\t<CnSearchSelect\n\t\t\t\t\t:modelValue=\"picked ? picked.id : null\"\n\t\t\t\t\t:inputId=\"assigneeId\"\n\t\t\t\t\t:inputLabel=\"assigneeLabel\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:options=\"shownOptions\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"text(assigneeConfig.placeholder)\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-assignee\"\n\t\t\t\t\t@search=\"onSearch\"\n\t\t\t\t\t@update:modelValue=\"onPick\" />\n\t\t\t\t<span v-if=\"assigneeHint\" class=\"cn-assign-dialog__hint\">{{ assigneeHint }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.note !== false\" class=\"cn-assign-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"noteId\"\n\t\t\t\t\tv-model=\"note\"\n\t\t\t\t\t:label=\"noteLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-note\" />\n\t\t\t\t<span v-if=\"noteConfig.hint\" class=\"cn-assign-dialog__hint\">{{ text(noteConfig.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-for=\"toggle in toggles\"\n\t\t\t\t:key=\"toggle.field\"\n\t\t\t\tclass=\"cn-assign-dialog__toggle\"\n\t\t\t\t:class=\"{ 'cn-assign-dialog__toggle--on': flags[toggle.field] }\"\n\t\t\t\t:data-testid=\"`cn-assign-dialog-toggle-${toggle.field}`\">\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"flags[toggle.field] === true\" @update:modelValue=\"flags[toggle.field] = $event\">\n\t\t\t\t\t<span class=\"cn-assign-dialog__toggle-title\">{{ text(toggle.label) }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"toggle.note\" class=\"cn-assign-dialog__hint cn-assign-dialog__toggle-note\">{{ text(toggle.note) }}</span>\n\t\t\t</div>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-assign-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-assign-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-assign-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon || 'SwapHorizontal'\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Assign') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcTextArea } from '@nextcloud/vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { searchNextcloudGroups, searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** How long typing rests before a search runs, in ms. */\nconst SEARCH_DELAY = 250\n\n/** Gives each dialog's fields their own ids. */\nlet fieldSeq = 0\n\n/**\n * The found rows, with what was typed offered as an assignee of its own when\n * no row carries that id or name: where sharing is restricted the search\n * answers nothing, and an endpoint may still take the name.\n *\n * @param {Array<object>} found The rows found.\n * @param {string} typed What was typed.\n * @param {string} label The typed row's label.\n * @return {Array<object>} The rows.\n */\nexport function withTypedAssignee(found, typed, label) {\n\tconst lower = typed.toLowerCase()\n\tif (typed === '' || found.some((row) => String(row.id) === typed || String(row.label).toLowerCase() === lower)) {\n\t\treturn found\n\t}\n\treturn [...found, { id: typed, label, icon: 'AccountGroupOutline', kind: 'typed' }]\n}\n\n/**\n * CnAssignDialog — hand a record to another user or team, with a note and\n * optional switches, configured from the manifest (an `open-modal` action's\n * props). dossiq's case handover (board DqOverdragen: new team, why it moves,\n * \"this is a doorzending (Awb 2:3)\") is the first; pipelinq tickets and bulk\n * reassignment use the same dialog.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record.\n * - `source`: an endpointSource to read the record from, else `object`.\n * - `assignee`: `{ kinds?, label?, placeholder?, hint?, currentPath?,\n * currentHint?, currentAs?, allowTyped?, field?, kindField? }`. `kinds` is `[\"group\"]`\n * (default), `[\"user\"]` or both; `currentPath` reads who has it now from the\n * record and `currentHint` (\"Now with {current}.\", the placeholder named\n * by `currentAs`) says so, in place of `hint`; `allowTyped`\n * offers what was typed as a choice; the id is sent as `field` (default\n * `assignee`) and its kind as `kindField` when set.\n * - `note`: `{ label?, hint?, required?, field? }`, required by default and\n * sent as `field` (default `note`); `false` drops it.\n * - `toggles`: `[{ field, label, note? }]`: switches that start off and are\n * sent as booleans.\n * - `confirm`: `{ label?, icon?, request?: { method?, url, body? }, action? }`.\n * `request` sends the choice itself (`body` templates filled from the\n * record); `action` dispatches a manifest action with the choice as its\n * last argument.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url. A refusal is\n * shown in the server's own words and the dialog stays open.\n */\nexport default {\n\tname: 'CnAssignDialog',\n\n\tcomponents: { CnDialog, CnIcon, CnSearchSelect, NcButton, NcCheckboxRadioSwitch, NcTextArea },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\tconst seq = ++fieldSeq\n\t\tconst flags = {}\n\t\tfor (const toggle of Array.isArray(this.config.toggles) ? this.config.toggles : []) {\n\t\t\tif (toggle && toggle.field) {\n\t\t\t\tflags[toggle.field] = false\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\toptions: [],\n\t\t\tpicked: null,\n\t\t\tsearching: false,\n\t\t\ttimer: null,\n\t\t\tsearchSeq: 0,\n\t\t\tnote: '',\n\t\t\tflags,\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\tassigneeId: `cn-assign-dialog-assignee-${seq}`,\n\t\t\tnoteId: `cn-assign-dialog-note-${seq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The assignee config. */\n\t\tassigneeConfig() {\n\t\t\treturn this.config.assignee && typeof this.config.assignee === 'object' ? this.config.assignee : {}\n\t\t},\n\n\t\t/** @return {object} The note config. */\n\t\tnoteConfig() {\n\t\t\treturn this.config.note && typeof this.config.note === 'object' ? this.config.note : {}\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/** @return {Array<object>} The switches with a field. */\n\t\ttoggles() {\n\t\t\treturn (Array.isArray(this.config.toggles) ? this.config.toggles : []).filter((toggle) => toggle && toggle.field)\n\t\t},\n\n\t\t/** @return {string[]} The kinds searched: `group`, `user`. */\n\t\tkinds() {\n\t\t\tconst kinds = Array.isArray(this.assigneeConfig.kinds) ? this.assigneeConfig.kinds.filter((k) => k === 'group' || k === 'user') : []\n\t\t\treturn kinds.length ? kinds : ['group']\n\t\t},\n\n\t\t/** @return {string} The assignee field's label. */\n\t\tassigneeLabel() {\n\t\t\tif (this.assigneeConfig.label) {\n\t\t\t\treturn this.text(this.assigneeConfig.label)\n\t\t\t}\n\t\t\treturn this.kinds.length === 1 && this.kinds[0] === 'user' ? t('nextcloud-vue', 'New handler') : t('nextcloud-vue', 'New team')\n\t\t},\n\n\t\t/** @return {string} Who has the record now, read from it. */\n\t\tcurrent() {\n\t\t\tconst path = this.assigneeConfig.currentPath\n\t\t\tconst value = path && this.record ? readPath(this.record, path) : ''\n\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The hint under the assignee field: who has it now, else the configured hint.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {string}\n\t\t */\n\t\tassigneeHint() {\n\t\t\tconst name = this.assigneeConfig.currentAs || 'current'\n\t\t\tconst now = this.current && this.assigneeConfig.currentHint ? fillTemplate(this.cnTranslate(this.assigneeConfig.currentHint), { [name]: this.current }) : ''\n\t\t\treturn now || this.text(this.assigneeConfig.hint)\n\t\t},\n\n\t\t/** @return {Array<object>} The rows, keeping the picked one listed. */\n\t\tshownOptions() {\n\t\t\tif (this.picked && !this.options.some((o) => String(o.id) === String(this.picked.id))) {\n\t\t\t\treturn [this.picked, ...this.options]\n\t\t\t}\n\t\t\treturn this.options\n\t\t},\n\n\t\t/** @return {boolean} Whether a note is asked and needed. */\n\t\tnoteNeeded() {\n\t\t\treturn this.config.note !== false && this.noteConfig.required !== false\n\t\t},\n\n\t\t/** @return {string} The note field's label. */\n\t\tnoteLabel() {\n\t\t\treturn this.text(this.noteConfig.label) || t('nextcloud-vue', 'Why it is moving')\n\t\t},\n\n\t\t/**\n\t\t * Whether the assignment may run: an assignee, a note when needed, nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.picked !== null && (!this.noteNeeded || this.note.trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tconst source = this.config.source\n\t\tif (source && source.url) {\n\t\t\ttry {\n\t\t\t\tconst data = await fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The hint stays without the current assignee; the dialog still works.\n\t\t\t}\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.timer)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from the record, translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Search after typing rests.\n\t\t *\n\t\t * @param {string} query What was typed.\n\t\t */\n\t\tonSearch(query) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tconst typed = String(query ?? '').trim()\n\t\t\tif (typed === '') {\n\t\t\t\tthis.options = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.timer = setTimeout(() => this.search(typed), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Search the configured kinds; offer what was typed when allowed.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @param {string} typed What was typed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync search(typed) {\n\t\t\tconst seq = ++this.searchSeq\n\t\t\tthis.searching = true\n\t\t\tconst [groups, users] = await Promise.all([\n\t\t\t\tthis.kinds.includes('group') ? searchNextcloudGroups(typed, { limit: 20 }) : [],\n\t\t\t\tthis.kinds.includes('user') ? searchNextcloudUsers(typed, { limit: 20 }) : [],\n\t\t\t])\n\t\t\tif (seq !== this.searchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst found = [\n\t\t\t\t...groups.map((g) => ({ id: g.id, label: g.label, secondary: g.subline || '', icon: 'AccountGroupOutline', kind: 'group' })),\n\t\t\t\t...users.map((u) => ({ id: u.id, label: u.label, secondary: u.subline || '', avatar: true, kind: 'user' })),\n\t\t\t]\n\t\t\tthis.options = this.assigneeConfig.allowTyped ? withTypedAssignee(found, typed, t('nextcloud-vue', 'Use \"{name}\"', { name: typed })) : found\n\t\t\tthis.searching = false\n\t\t},\n\n\t\t/**\n\t\t * Take the picked row.\n\t\t *\n\t\t * @param {string|null} id The picked id.\n\t\t */\n\t\tonPick(id) {\n\t\t\tthis.picked = id === null ? null : (this.shownOptions.find((o) => String(o.id) === String(id)) || null)\n\t\t},\n\n\t\t/**\n\t\t * The choice as sent: assignee, its kind, the note and the switches.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tchoice() {\n\t\t\tconst out = { [this.assigneeConfig.field || 'assignee']: String(this.picked.id) }\n\t\t\tif (this.assigneeConfig.kindField) {\n\t\t\t\tout[this.assigneeConfig.kindField] = this.picked.kind === 'typed' ? this.kinds[0] : this.picked.kind\n\t\t\t}\n\t\t\tif (this.config.note !== false) {\n\t\t\t\tout[this.noteConfig.field || 'note'] = this.note.trim()\n\t\t\t}\n\t\t\treturn { ...out, ...this.flags }\n\t\t},\n\n\t\t/**\n\t\t * Assign once: send `confirm.request`, or dispatch `confirm.action`,\n\t\t * then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst choice = this.choice()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, this.record || {}) : value\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), { ...body, ...choice })\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), choice] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The assignment ran. Payload: the choice as sent. */\n\t\t\t\tthis.$emit('done', choice)\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'It was not handed over.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the assignment is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-assign-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 18px;\n}\n\n.cn-assign-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-assign-dialog__hint {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-assign-dialog__toggle {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-assign-dialog__toggle--on {\n\tborder: 2px solid var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-assign-dialog__toggle-title {\n\tfont-weight: 600;\n}\n\n.cn-assign-dialog__toggle-note {\n\tpadding-inline-start: 44px;\n}\n\n.cn-assign-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["CnDialog","CnIcon","CnSearchSelect","t","axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAssignDialog.vue2.js","sources":["../../../../src/components/CnAssignDialog/CnAssignDialog.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:name=\"text(config.title) || t('nextcloud-vue', 'Assign')\"\n\t\t:eyebrow=\"fill(config.eyebrow)\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-assign-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-assign-dialog\">\n\t\t\t<div class=\"cn-assign-dialog__field\">\n\t\t\t\t<CnSearchSelect\n\t\t\t\t\t:modelValue=\"picked ? picked.id : null\"\n\t\t\t\t\t:inputId=\"assigneeId\"\n\t\t\t\t\t:inputLabel=\"assigneeLabel\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:options=\"shownOptions\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"text(assigneeConfig.placeholder)\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-assignee\"\n\t\t\t\t\t@search=\"onSearch\"\n\t\t\t\t\t@update:modelValue=\"onPick\" />\n\t\t\t\t<span v-if=\"assigneeHint\" class=\"cn-assign-dialog__hint\">{{ assigneeHint }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.note !== false\" class=\"cn-assign-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"noteId\"\n\t\t\t\t\tv-model=\"note\"\n\t\t\t\t\t:label=\"noteLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\t:rows=\"noteConfig.rows || 3\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-note\" />\n\t\t\t\t<span v-if=\"noteConfig.hint\" class=\"cn-assign-dialog__hint\">{{ text(noteConfig.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-for=\"toggle in toggles\"\n\t\t\t\t:key=\"toggle.field\"\n\t\t\t\tclass=\"cn-assign-dialog__toggle\"\n\t\t\t\t:class=\"{ 'cn-assign-dialog__toggle--on': flags[toggle.field] }\"\n\t\t\t\t:data-testid=\"`cn-assign-dialog-toggle-${toggle.field}`\">\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"flags[toggle.field] === true\" @update:modelValue=\"flags[toggle.field] = $event\">\n\t\t\t\t\t<span class=\"cn-assign-dialog__toggle-title\">{{ text(toggle.label) }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"toggle.note\" class=\"cn-assign-dialog__hint cn-assign-dialog__toggle-note\">{{ text(toggle.note) }}</span>\n\t\t\t</div>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-assign-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-assign-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-assign-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon || 'SwapHorizontal'\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Assign') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcTextArea } from '@nextcloud/vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { searchNextcloudGroups, searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** How long typing rests before a search runs, in ms. */\nconst SEARCH_DELAY = 250\n\n/** Gives each dialog's fields their own ids. */\nlet fieldSeq = 0\n\n/**\n * The found rows, with what was typed offered as an assignee of its own when\n * no row carries that id or name: where sharing is restricted the search\n * answers nothing, and an endpoint may still take the name.\n *\n * @param {Array<object>} found The rows found.\n * @param {string} typed What was typed.\n * @param {string} label The typed row's label.\n * @return {Array<object>} The rows.\n */\nexport function withTypedAssignee(found, typed, label) {\n\tconst lower = typed.toLowerCase()\n\tif (typed === '' || found.some((row) => String(row.id) === typed || String(row.label).toLowerCase() === lower)) {\n\t\treturn found\n\t}\n\treturn [...found, { id: typed, label, icon: 'AccountGroupOutline', kind: 'typed' }]\n}\n\n/**\n * CnAssignDialog — hand a record to another user or team, with a note and\n * optional switches, configured from the manifest (an `open-modal` action's\n * props). dossiq's case handover (board DqOverdragen: new team, why it moves,\n * \"this is a doorzending (Awb 2:3)\") is the first; pipelinq tickets and bulk\n * reassignment use the same dialog.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record.\n * - `source`: an endpointSource to read the record from, else `object`.\n * - `assignee`: `{ kinds?, label?, placeholder?, hint?, currentPath?,\n * currentHint?, currentAs?, allowTyped?, field?, kindField? }`. `kinds` is `[\"group\"]`\n * (default), `[\"user\"]` or both; `currentPath` reads who has it now from the\n * record and `currentHint` (\"Now with {current}.\", the placeholder named\n * by `currentAs`) says so, in place of `hint`; `allowTyped`\n * offers what was typed as a choice; the id is sent as `field` (default\n * `assignee`) and its kind as `kindField` when set.\n * - `note`: `{ label?, hint?, required?, field?, rows? }`, required by default and\n * sent as `field` (default `note`); `false` drops it. `rows` is the text\n * area's height in lines (default 3, as board DqOverdragen draws it).\n * - `toggles`: `[{ field, label, note? }]`: switches that start off and are\n * sent as booleans.\n * - `confirm`: `{ label?, icon?, request?: { method?, url, body? }, action? }`.\n * `request` sends the choice itself (`body` templates filled from the\n * record); `action` dispatches a manifest action with the choice as its\n * last argument.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url. A refusal is\n * shown in the server's own words and the dialog stays open.\n */\nexport default {\n\tname: 'CnAssignDialog',\n\n\tcomponents: { CnDialog, CnIcon, CnSearchSelect, NcButton, NcCheckboxRadioSwitch, NcTextArea },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\tconst seq = ++fieldSeq\n\t\tconst flags = {}\n\t\tfor (const toggle of Array.isArray(this.config.toggles) ? this.config.toggles : []) {\n\t\t\tif (toggle && toggle.field) {\n\t\t\t\tflags[toggle.field] = false\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\toptions: [],\n\t\t\tpicked: null,\n\t\t\tsearching: false,\n\t\t\ttimer: null,\n\t\t\tsearchSeq: 0,\n\t\t\tnote: '',\n\t\t\tflags,\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\tassigneeId: `cn-assign-dialog-assignee-${seq}`,\n\t\t\tnoteId: `cn-assign-dialog-note-${seq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The assignee config. */\n\t\tassigneeConfig() {\n\t\t\treturn this.config.assignee && typeof this.config.assignee === 'object' ? this.config.assignee : {}\n\t\t},\n\n\t\t/** @return {object} The note config. */\n\t\tnoteConfig() {\n\t\t\treturn this.config.note && typeof this.config.note === 'object' ? this.config.note : {}\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/** @return {Array<object>} The switches with a field. */\n\t\ttoggles() {\n\t\t\treturn (Array.isArray(this.config.toggles) ? this.config.toggles : []).filter((toggle) => toggle && toggle.field)\n\t\t},\n\n\t\t/** @return {string[]} The kinds searched: `group`, `user`. */\n\t\tkinds() {\n\t\t\tconst kinds = Array.isArray(this.assigneeConfig.kinds) ? this.assigneeConfig.kinds.filter((k) => k === 'group' || k === 'user') : []\n\t\t\treturn kinds.length ? kinds : ['group']\n\t\t},\n\n\t\t/** @return {string} The assignee field's label. */\n\t\tassigneeLabel() {\n\t\t\tif (this.assigneeConfig.label) {\n\t\t\t\treturn this.text(this.assigneeConfig.label)\n\t\t\t}\n\t\t\treturn this.kinds.length === 1 && this.kinds[0] === 'user' ? t('nextcloud-vue', 'New handler') : t('nextcloud-vue', 'New team')\n\t\t},\n\n\t\t/** @return {string} Who has the record now, read from it. */\n\t\tcurrent() {\n\t\t\tconst path = this.assigneeConfig.currentPath\n\t\t\tconst value = path && this.record ? readPath(this.record, path) : ''\n\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The hint under the assignee field: who has it now, else the configured hint.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {string}\n\t\t */\n\t\tassigneeHint() {\n\t\t\tconst name = this.assigneeConfig.currentAs || 'current'\n\t\t\tconst now = this.current && this.assigneeConfig.currentHint ? fillTemplate(this.cnTranslate(this.assigneeConfig.currentHint), { [name]: this.current }) : ''\n\t\t\treturn now || this.text(this.assigneeConfig.hint)\n\t\t},\n\n\t\t/** @return {Array<object>} The rows, keeping the picked one listed. */\n\t\tshownOptions() {\n\t\t\tif (this.picked && !this.options.some((o) => String(o.id) === String(this.picked.id))) {\n\t\t\t\treturn [this.picked, ...this.options]\n\t\t\t}\n\t\t\treturn this.options\n\t\t},\n\n\t\t/** @return {boolean} Whether a note is asked and needed. */\n\t\tnoteNeeded() {\n\t\t\treturn this.config.note !== false && this.noteConfig.required !== false\n\t\t},\n\n\t\t/** @return {string} The note field's label. */\n\t\tnoteLabel() {\n\t\t\treturn this.text(this.noteConfig.label) || t('nextcloud-vue', 'Why it is moving')\n\t\t},\n\n\t\t/**\n\t\t * Whether the assignment may run: an assignee, a note when needed, nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.picked !== null && (!this.noteNeeded || this.note.trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tconst source = this.config.source\n\t\tif (source && source.url) {\n\t\t\ttry {\n\t\t\t\tconst data = await fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The hint stays without the current assignee; the dialog still works.\n\t\t\t}\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.timer)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from the record, translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Search after typing rests.\n\t\t *\n\t\t * @param {string} query What was typed.\n\t\t */\n\t\tonSearch(query) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tconst typed = String(query ?? '').trim()\n\t\t\tif (typed === '') {\n\t\t\t\tthis.options = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.timer = setTimeout(() => this.search(typed), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Search the configured kinds; offer what was typed when allowed.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @param {string} typed What was typed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync search(typed) {\n\t\t\tconst seq = ++this.searchSeq\n\t\t\tthis.searching = true\n\t\t\tconst [groups, users] = await Promise.all([\n\t\t\t\tthis.kinds.includes('group') ? searchNextcloudGroups(typed, { limit: 20 }) : [],\n\t\t\t\tthis.kinds.includes('user') ? searchNextcloudUsers(typed, { limit: 20 }) : [],\n\t\t\t])\n\t\t\tif (seq !== this.searchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst found = [\n\t\t\t\t...groups.map((g) => ({ id: g.id, label: g.label, secondary: g.subline || '', icon: 'AccountGroupOutline', kind: 'group' })),\n\t\t\t\t...users.map((u) => ({ id: u.id, label: u.label, secondary: u.subline || '', avatar: true, kind: 'user' })),\n\t\t\t]\n\t\t\tthis.options = this.assigneeConfig.allowTyped ? withTypedAssignee(found, typed, t('nextcloud-vue', 'Use \"{name}\"', { name: typed })) : found\n\t\t\tthis.searching = false\n\t\t},\n\n\t\t/**\n\t\t * Take the picked row.\n\t\t *\n\t\t * @param {string|null} id The picked id.\n\t\t */\n\t\tonPick(id) {\n\t\t\tthis.picked = id === null ? null : (this.shownOptions.find((o) => String(o.id) === String(id)) || null)\n\t\t},\n\n\t\t/**\n\t\t * The choice as sent: assignee, its kind, the note and the switches.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tchoice() {\n\t\t\tconst out = { [this.assigneeConfig.field || 'assignee']: String(this.picked.id) }\n\t\t\tif (this.assigneeConfig.kindField) {\n\t\t\t\tout[this.assigneeConfig.kindField] = this.picked.kind === 'typed' ? this.kinds[0] : this.picked.kind\n\t\t\t}\n\t\t\tif (this.config.note !== false) {\n\t\t\t\tout[this.noteConfig.field || 'note'] = this.note.trim()\n\t\t\t}\n\t\t\treturn { ...out, ...this.flags }\n\t\t},\n\n\t\t/**\n\t\t * Assign once: send `confirm.request`, or dispatch `confirm.action`,\n\t\t * then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst choice = this.choice()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, this.record || {}) : value\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), { ...body, ...choice })\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), choice] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The assignment ran. Payload: the choice as sent. */\n\t\t\t\tthis.$emit('done', choice)\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'It was not handed over.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the assignment is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-assign-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 18px;\n}\n\n.cn-assign-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-assign-dialog__hint {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-assign-dialog__toggle {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-assign-dialog__toggle--on {\n\tborder: 2px solid var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-assign-dialog__toggle-title {\n\tfont-weight: 600;\n}\n\n.cn-assign-dialog__toggle-note {\n\tpadding-inline-start: 44px;\n}\n\n.cn-assign-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["CnDialog","CnIcon","CnSearchSelect","t","axios"],"mappings":"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"}
|
|
@@ -113,9 +113,10 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
113
113
|
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => (($data.note) = $event)),
|
|
114
114
|
label: $options.noteLabel,
|
|
115
115
|
labelOutside: false,
|
|
116
|
+
rows: $options.noteConfig.rows || 3,
|
|
116
117
|
resize: "vertical",
|
|
117
118
|
"data-testid": "cn-assign-dialog-note"
|
|
118
|
-
}, null, 8 /* PROPS */, ["id", "modelValue", "label"]),
|
|
119
|
+
}, null, 8 /* PROPS */, ["id", "modelValue", "label", "rows"]),
|
|
119
120
|
($options.noteConfig.hint)
|
|
120
121
|
? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString($options.text($options.noteConfig.hint)), 1 /* TEXT */))
|
|
121
122
|
: createCommentVNode("v-if", true)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAssignDialog.vue3.js","sources":["../../../../src/components/CnAssignDialog/CnAssignDialog.vue?vue&type=template&id=9921b726&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Assign')\"\n\t\t:eyebrow=\"fill(config.eyebrow)\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-assign-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-assign-dialog\">\n\t\t\t<div class=\"cn-assign-dialog__field\">\n\t\t\t\t<CnSearchSelect\n\t\t\t\t\t:modelValue=\"picked ? picked.id : null\"\n\t\t\t\t\t:inputId=\"assigneeId\"\n\t\t\t\t\t:inputLabel=\"assigneeLabel\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:options=\"shownOptions\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"text(assigneeConfig.placeholder)\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-assignee\"\n\t\t\t\t\t@search=\"onSearch\"\n\t\t\t\t\t@update:modelValue=\"onPick\" />\n\t\t\t\t<span v-if=\"assigneeHint\" class=\"cn-assign-dialog__hint\">{{ assigneeHint }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.note !== false\" class=\"cn-assign-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"noteId\"\n\t\t\t\t\tv-model=\"note\"\n\t\t\t\t\t:label=\"noteLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-note\" />\n\t\t\t\t<span v-if=\"noteConfig.hint\" class=\"cn-assign-dialog__hint\">{{ text(noteConfig.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-for=\"toggle in toggles\"\n\t\t\t\t:key=\"toggle.field\"\n\t\t\t\tclass=\"cn-assign-dialog__toggle\"\n\t\t\t\t:class=\"{ 'cn-assign-dialog__toggle--on': flags[toggle.field] }\"\n\t\t\t\t:data-testid=\"`cn-assign-dialog-toggle-${toggle.field}`\">\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"flags[toggle.field] === true\" @update:modelValue=\"flags[toggle.field] = $event\">\n\t\t\t\t\t<span class=\"cn-assign-dialog__toggle-title\">{{ text(toggle.label) }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"toggle.note\" class=\"cn-assign-dialog__hint cn-assign-dialog__toggle-note\">{{ text(toggle.note) }}</span>\n\t\t\t</div>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-assign-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-assign-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-assign-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon || 'SwapHorizontal'\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Assign') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcTextArea } from '@nextcloud/vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { searchNextcloudGroups, searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** How long typing rests before a search runs, in ms. */\nconst SEARCH_DELAY = 250\n\n/** Gives each dialog's fields their own ids. */\nlet fieldSeq = 0\n\n/**\n * The found rows, with what was typed offered as an assignee of its own when\n * no row carries that id or name: where sharing is restricted the search\n * answers nothing, and an endpoint may still take the name.\n *\n * @param {Array<object>} found The rows found.\n * @param {string} typed What was typed.\n * @param {string} label The typed row's label.\n * @return {Array<object>} The rows.\n */\nexport function withTypedAssignee(found, typed, label) {\n\tconst lower = typed.toLowerCase()\n\tif (typed === '' || found.some((row) => String(row.id) === typed || String(row.label).toLowerCase() === lower)) {\n\t\treturn found\n\t}\n\treturn [...found, { id: typed, label, icon: 'AccountGroupOutline', kind: 'typed' }]\n}\n\n/**\n * CnAssignDialog — hand a record to another user or team, with a note and\n * optional switches, configured from the manifest (an `open-modal` action's\n * props). dossiq's case handover (board DqOverdragen: new team, why it moves,\n * \"this is a doorzending (Awb 2:3)\") is the first; pipelinq tickets and bulk\n * reassignment use the same dialog.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record.\n * - `source`: an endpointSource to read the record from, else `object`.\n * - `assignee`: `{ kinds?, label?, placeholder?, hint?, currentPath?,\n * currentHint?, currentAs?, allowTyped?, field?, kindField? }`. `kinds` is `[\"group\"]`\n * (default), `[\"user\"]` or both; `currentPath` reads who has it now from the\n * record and `currentHint` (\"Now with {current}.\", the placeholder named\n * by `currentAs`) says so, in place of `hint`; `allowTyped`\n * offers what was typed as a choice; the id is sent as `field` (default\n * `assignee`) and its kind as `kindField` when set.\n * - `note`: `{ label?, hint?, required?, field? }`, required by default and\n * sent as `field` (default `note`); `false` drops it.\n * - `toggles`: `[{ field, label, note? }]`: switches that start off and are\n * sent as booleans.\n * - `confirm`: `{ label?, icon?, request?: { method?, url, body? }, action? }`.\n * `request` sends the choice itself (`body` templates filled from the\n * record); `action` dispatches a manifest action with the choice as its\n * last argument.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url. A refusal is\n * shown in the server's own words and the dialog stays open.\n */\nexport default {\n\tname: 'CnAssignDialog',\n\n\tcomponents: { CnDialog, CnIcon, CnSearchSelect, NcButton, NcCheckboxRadioSwitch, NcTextArea },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\tconst seq = ++fieldSeq\n\t\tconst flags = {}\n\t\tfor (const toggle of Array.isArray(this.config.toggles) ? this.config.toggles : []) {\n\t\t\tif (toggle && toggle.field) {\n\t\t\t\tflags[toggle.field] = false\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\toptions: [],\n\t\t\tpicked: null,\n\t\t\tsearching: false,\n\t\t\ttimer: null,\n\t\t\tsearchSeq: 0,\n\t\t\tnote: '',\n\t\t\tflags,\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\tassigneeId: `cn-assign-dialog-assignee-${seq}`,\n\t\t\tnoteId: `cn-assign-dialog-note-${seq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The assignee config. */\n\t\tassigneeConfig() {\n\t\t\treturn this.config.assignee && typeof this.config.assignee === 'object' ? this.config.assignee : {}\n\t\t},\n\n\t\t/** @return {object} The note config. */\n\t\tnoteConfig() {\n\t\t\treturn this.config.note && typeof this.config.note === 'object' ? this.config.note : {}\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/** @return {Array<object>} The switches with a field. */\n\t\ttoggles() {\n\t\t\treturn (Array.isArray(this.config.toggles) ? this.config.toggles : []).filter((toggle) => toggle && toggle.field)\n\t\t},\n\n\t\t/** @return {string[]} The kinds searched: `group`, `user`. */\n\t\tkinds() {\n\t\t\tconst kinds = Array.isArray(this.assigneeConfig.kinds) ? this.assigneeConfig.kinds.filter((k) => k === 'group' || k === 'user') : []\n\t\t\treturn kinds.length ? kinds : ['group']\n\t\t},\n\n\t\t/** @return {string} The assignee field's label. */\n\t\tassigneeLabel() {\n\t\t\tif (this.assigneeConfig.label) {\n\t\t\t\treturn this.text(this.assigneeConfig.label)\n\t\t\t}\n\t\t\treturn this.kinds.length === 1 && this.kinds[0] === 'user' ? t('nextcloud-vue', 'New handler') : t('nextcloud-vue', 'New team')\n\t\t},\n\n\t\t/** @return {string} Who has the record now, read from it. */\n\t\tcurrent() {\n\t\t\tconst path = this.assigneeConfig.currentPath\n\t\t\tconst value = path && this.record ? readPath(this.record, path) : ''\n\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The hint under the assignee field: who has it now, else the configured hint.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {string}\n\t\t */\n\t\tassigneeHint() {\n\t\t\tconst name = this.assigneeConfig.currentAs || 'current'\n\t\t\tconst now = this.current && this.assigneeConfig.currentHint ? fillTemplate(this.cnTranslate(this.assigneeConfig.currentHint), { [name]: this.current }) : ''\n\t\t\treturn now || this.text(this.assigneeConfig.hint)\n\t\t},\n\n\t\t/** @return {Array<object>} The rows, keeping the picked one listed. */\n\t\tshownOptions() {\n\t\t\tif (this.picked && !this.options.some((o) => String(o.id) === String(this.picked.id))) {\n\t\t\t\treturn [this.picked, ...this.options]\n\t\t\t}\n\t\t\treturn this.options\n\t\t},\n\n\t\t/** @return {boolean} Whether a note is asked and needed. */\n\t\tnoteNeeded() {\n\t\t\treturn this.config.note !== false && this.noteConfig.required !== false\n\t\t},\n\n\t\t/** @return {string} The note field's label. */\n\t\tnoteLabel() {\n\t\t\treturn this.text(this.noteConfig.label) || t('nextcloud-vue', 'Why it is moving')\n\t\t},\n\n\t\t/**\n\t\t * Whether the assignment may run: an assignee, a note when needed, nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.picked !== null && (!this.noteNeeded || this.note.trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tconst source = this.config.source\n\t\tif (source && source.url) {\n\t\t\ttry {\n\t\t\t\tconst data = await fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The hint stays without the current assignee; the dialog still works.\n\t\t\t}\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.timer)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from the record, translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Search after typing rests.\n\t\t *\n\t\t * @param {string} query What was typed.\n\t\t */\n\t\tonSearch(query) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tconst typed = String(query ?? '').trim()\n\t\t\tif (typed === '') {\n\t\t\t\tthis.options = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.timer = setTimeout(() => this.search(typed), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Search the configured kinds; offer what was typed when allowed.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @param {string} typed What was typed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync search(typed) {\n\t\t\tconst seq = ++this.searchSeq\n\t\t\tthis.searching = true\n\t\t\tconst [groups, users] = await Promise.all([\n\t\t\t\tthis.kinds.includes('group') ? searchNextcloudGroups(typed, { limit: 20 }) : [],\n\t\t\t\tthis.kinds.includes('user') ? searchNextcloudUsers(typed, { limit: 20 }) : [],\n\t\t\t])\n\t\t\tif (seq !== this.searchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst found = [\n\t\t\t\t...groups.map((g) => ({ id: g.id, label: g.label, secondary: g.subline || '', icon: 'AccountGroupOutline', kind: 'group' })),\n\t\t\t\t...users.map((u) => ({ id: u.id, label: u.label, secondary: u.subline || '', avatar: true, kind: 'user' })),\n\t\t\t]\n\t\t\tthis.options = this.assigneeConfig.allowTyped ? withTypedAssignee(found, typed, t('nextcloud-vue', 'Use \"{name}\"', { name: typed })) : found\n\t\t\tthis.searching = false\n\t\t},\n\n\t\t/**\n\t\t * Take the picked row.\n\t\t *\n\t\t * @param {string|null} id The picked id.\n\t\t */\n\t\tonPick(id) {\n\t\t\tthis.picked = id === null ? null : (this.shownOptions.find((o) => String(o.id) === String(id)) || null)\n\t\t},\n\n\t\t/**\n\t\t * The choice as sent: assignee, its kind, the note and the switches.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tchoice() {\n\t\t\tconst out = { [this.assigneeConfig.field || 'assignee']: String(this.picked.id) }\n\t\t\tif (this.assigneeConfig.kindField) {\n\t\t\t\tout[this.assigneeConfig.kindField] = this.picked.kind === 'typed' ? this.kinds[0] : this.picked.kind\n\t\t\t}\n\t\t\tif (this.config.note !== false) {\n\t\t\t\tout[this.noteConfig.field || 'note'] = this.note.trim()\n\t\t\t}\n\t\t\treturn { ...out, ...this.flags }\n\t\t},\n\n\t\t/**\n\t\t * Assign once: send `confirm.request`, or dispatch `confirm.action`,\n\t\t * then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst choice = this.choice()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, this.record || {}) : value\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), { ...body, ...choice })\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), choice] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The assignment ran. Payload: the choice as sent. */\n\t\t\t\tthis.$emit('done', choice)\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'It was not handed over.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the assignment is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-assign-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 18px;\n}\n\n.cn-assign-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-assign-dialog__hint {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-assign-dialog__toggle {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-assign-dialog__toggle--on {\n\tborder: 2px solid var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-assign-dialog__toggle-title {\n\tfont-weight: 600;\n}\n\n.cn-assign-dialog__toggle-note {\n\tpadding-inline-start: 44px;\n}\n\n.cn-assign-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAssignDialog.vue3.js","sources":["../../../../src/components/CnAssignDialog/CnAssignDialog.vue?vue&type=template&id=45153be8&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Assign')\"\n\t\t:eyebrow=\"fill(config.eyebrow)\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-assign-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-assign-dialog\">\n\t\t\t<div class=\"cn-assign-dialog__field\">\n\t\t\t\t<CnSearchSelect\n\t\t\t\t\t:modelValue=\"picked ? picked.id : null\"\n\t\t\t\t\t:inputId=\"assigneeId\"\n\t\t\t\t\t:inputLabel=\"assigneeLabel\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:options=\"shownOptions\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"text(assigneeConfig.placeholder)\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-assignee\"\n\t\t\t\t\t@search=\"onSearch\"\n\t\t\t\t\t@update:modelValue=\"onPick\" />\n\t\t\t\t<span v-if=\"assigneeHint\" class=\"cn-assign-dialog__hint\">{{ assigneeHint }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.note !== false\" class=\"cn-assign-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"noteId\"\n\t\t\t\t\tv-model=\"note\"\n\t\t\t\t\t:label=\"noteLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\t:rows=\"noteConfig.rows || 3\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-assign-dialog-note\" />\n\t\t\t\t<span v-if=\"noteConfig.hint\" class=\"cn-assign-dialog__hint\">{{ text(noteConfig.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-for=\"toggle in toggles\"\n\t\t\t\t:key=\"toggle.field\"\n\t\t\t\tclass=\"cn-assign-dialog__toggle\"\n\t\t\t\t:class=\"{ 'cn-assign-dialog__toggle--on': flags[toggle.field] }\"\n\t\t\t\t:data-testid=\"`cn-assign-dialog-toggle-${toggle.field}`\">\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"flags[toggle.field] === true\" @update:modelValue=\"flags[toggle.field] = $event\">\n\t\t\t\t\t<span class=\"cn-assign-dialog__toggle-title\">{{ text(toggle.label) }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<span v-if=\"toggle.note\" class=\"cn-assign-dialog__hint cn-assign-dialog__toggle-note\">{{ text(toggle.note) }}</span>\n\t\t\t</div>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-assign-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-assign-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-assign-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-assign-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon || 'SwapHorizontal'\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Assign') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcTextArea } from '@nextcloud/vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { searchNextcloudGroups, searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** How long typing rests before a search runs, in ms. */\nconst SEARCH_DELAY = 250\n\n/** Gives each dialog's fields their own ids. */\nlet fieldSeq = 0\n\n/**\n * The found rows, with what was typed offered as an assignee of its own when\n * no row carries that id or name: where sharing is restricted the search\n * answers nothing, and an endpoint may still take the name.\n *\n * @param {Array<object>} found The rows found.\n * @param {string} typed What was typed.\n * @param {string} label The typed row's label.\n * @return {Array<object>} The rows.\n */\nexport function withTypedAssignee(found, typed, label) {\n\tconst lower = typed.toLowerCase()\n\tif (typed === '' || found.some((row) => String(row.id) === typed || String(row.label).toLowerCase() === lower)) {\n\t\treturn found\n\t}\n\treturn [...found, { id: typed, label, icon: 'AccountGroupOutline', kind: 'typed' }]\n}\n\n/**\n * CnAssignDialog — hand a record to another user or team, with a note and\n * optional switches, configured from the manifest (an `open-modal` action's\n * props). dossiq's case handover (board DqOverdragen: new team, why it moves,\n * \"this is a doorzending (Awb 2:3)\") is the first; pipelinq tickets and bulk\n * reassignment use the same dialog.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record.\n * - `source`: an endpointSource to read the record from, else `object`.\n * - `assignee`: `{ kinds?, label?, placeholder?, hint?, currentPath?,\n * currentHint?, currentAs?, allowTyped?, field?, kindField? }`. `kinds` is `[\"group\"]`\n * (default), `[\"user\"]` or both; `currentPath` reads who has it now from the\n * record and `currentHint` (\"Now with {current}.\", the placeholder named\n * by `currentAs`) says so, in place of `hint`; `allowTyped`\n * offers what was typed as a choice; the id is sent as `field` (default\n * `assignee`) and its kind as `kindField` when set.\n * - `note`: `{ label?, hint?, required?, field?, rows? }`, required by default and\n * sent as `field` (default `note`); `false` drops it. `rows` is the text\n * area's height in lines (default 3, as board DqOverdragen draws it).\n * - `toggles`: `[{ field, label, note? }]`: switches that start off and are\n * sent as booleans.\n * - `confirm`: `{ label?, icon?, request?: { method?, url, body? }, action? }`.\n * `request` sends the choice itself (`body` templates filled from the\n * record); `action` dispatches a manifest action with the choice as its\n * last argument.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url. A refusal is\n * shown in the server's own words and the dialog stays open.\n */\nexport default {\n\tname: 'CnAssignDialog',\n\n\tcomponents: { CnDialog, CnIcon, CnSearchSelect, NcButton, NcCheckboxRadioSwitch, NcTextArea },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\tconst seq = ++fieldSeq\n\t\tconst flags = {}\n\t\tfor (const toggle of Array.isArray(this.config.toggles) ? this.config.toggles : []) {\n\t\t\tif (toggle && toggle.field) {\n\t\t\t\tflags[toggle.field] = false\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\toptions: [],\n\t\t\tpicked: null,\n\t\t\tsearching: false,\n\t\t\ttimer: null,\n\t\t\tsearchSeq: 0,\n\t\t\tnote: '',\n\t\t\tflags,\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\tassigneeId: `cn-assign-dialog-assignee-${seq}`,\n\t\t\tnoteId: `cn-assign-dialog-note-${seq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The assignee config. */\n\t\tassigneeConfig() {\n\t\t\treturn this.config.assignee && typeof this.config.assignee === 'object' ? this.config.assignee : {}\n\t\t},\n\n\t\t/** @return {object} The note config. */\n\t\tnoteConfig() {\n\t\t\treturn this.config.note && typeof this.config.note === 'object' ? this.config.note : {}\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/** @return {Array<object>} The switches with a field. */\n\t\ttoggles() {\n\t\t\treturn (Array.isArray(this.config.toggles) ? this.config.toggles : []).filter((toggle) => toggle && toggle.field)\n\t\t},\n\n\t\t/** @return {string[]} The kinds searched: `group`, `user`. */\n\t\tkinds() {\n\t\t\tconst kinds = Array.isArray(this.assigneeConfig.kinds) ? this.assigneeConfig.kinds.filter((k) => k === 'group' || k === 'user') : []\n\t\t\treturn kinds.length ? kinds : ['group']\n\t\t},\n\n\t\t/** @return {string} The assignee field's label. */\n\t\tassigneeLabel() {\n\t\t\tif (this.assigneeConfig.label) {\n\t\t\t\treturn this.text(this.assigneeConfig.label)\n\t\t\t}\n\t\t\treturn this.kinds.length === 1 && this.kinds[0] === 'user' ? t('nextcloud-vue', 'New handler') : t('nextcloud-vue', 'New team')\n\t\t},\n\n\t\t/** @return {string} Who has the record now, read from it. */\n\t\tcurrent() {\n\t\t\tconst path = this.assigneeConfig.currentPath\n\t\t\tconst value = path && this.record ? readPath(this.record, path) : ''\n\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The hint under the assignee field: who has it now, else the configured hint.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {string}\n\t\t */\n\t\tassigneeHint() {\n\t\t\tconst name = this.assigneeConfig.currentAs || 'current'\n\t\t\tconst now = this.current && this.assigneeConfig.currentHint ? fillTemplate(this.cnTranslate(this.assigneeConfig.currentHint), { [name]: this.current }) : ''\n\t\t\treturn now || this.text(this.assigneeConfig.hint)\n\t\t},\n\n\t\t/** @return {Array<object>} The rows, keeping the picked one listed. */\n\t\tshownOptions() {\n\t\t\tif (this.picked && !this.options.some((o) => String(o.id) === String(this.picked.id))) {\n\t\t\t\treturn [this.picked, ...this.options]\n\t\t\t}\n\t\t\treturn this.options\n\t\t},\n\n\t\t/** @return {boolean} Whether a note is asked and needed. */\n\t\tnoteNeeded() {\n\t\t\treturn this.config.note !== false && this.noteConfig.required !== false\n\t\t},\n\n\t\t/** @return {string} The note field's label. */\n\t\tnoteLabel() {\n\t\t\treturn this.text(this.noteConfig.label) || t('nextcloud-vue', 'Why it is moving')\n\t\t},\n\n\t\t/**\n\t\t * Whether the assignment may run: an assignee, a note when needed, nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.picked !== null && (!this.noteNeeded || this.note.trim() !== '')\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tconst source = this.config.source\n\t\tif (source && source.url) {\n\t\t\ttry {\n\t\t\t\tconst data = await fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The hint stays without the current assignee; the dialog still works.\n\t\t\t}\n\t\t}\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.timer)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from the record, translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Search after typing rests.\n\t\t *\n\t\t * @param {string} query What was typed.\n\t\t */\n\t\tonSearch(query) {\n\t\t\tclearTimeout(this.timer)\n\t\t\tconst typed = String(query ?? '').trim()\n\t\t\tif (typed === '') {\n\t\t\t\tthis.options = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.timer = setTimeout(() => this.search(typed), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Search the configured kinds; offer what was typed when allowed.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @param {string} typed What was typed.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync search(typed) {\n\t\t\tconst seq = ++this.searchSeq\n\t\t\tthis.searching = true\n\t\t\tconst [groups, users] = await Promise.all([\n\t\t\t\tthis.kinds.includes('group') ? searchNextcloudGroups(typed, { limit: 20 }) : [],\n\t\t\t\tthis.kinds.includes('user') ? searchNextcloudUsers(typed, { limit: 20 }) : [],\n\t\t\t])\n\t\t\tif (seq !== this.searchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst found = [\n\t\t\t\t...groups.map((g) => ({ id: g.id, label: g.label, secondary: g.subline || '', icon: 'AccountGroupOutline', kind: 'group' })),\n\t\t\t\t...users.map((u) => ({ id: u.id, label: u.label, secondary: u.subline || '', avatar: true, kind: 'user' })),\n\t\t\t]\n\t\t\tthis.options = this.assigneeConfig.allowTyped ? withTypedAssignee(found, typed, t('nextcloud-vue', 'Use \"{name}\"', { name: typed })) : found\n\t\t\tthis.searching = false\n\t\t},\n\n\t\t/**\n\t\t * Take the picked row.\n\t\t *\n\t\t * @param {string|null} id The picked id.\n\t\t */\n\t\tonPick(id) {\n\t\t\tthis.picked = id === null ? null : (this.shownOptions.find((o) => String(o.id) === String(id)) || null)\n\t\t},\n\n\t\t/**\n\t\t * The choice as sent: assignee, its kind, the note and the switches.\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\tchoice() {\n\t\t\tconst out = { [this.assigneeConfig.field || 'assignee']: String(this.picked.id) }\n\t\t\tif (this.assigneeConfig.kindField) {\n\t\t\t\tout[this.assigneeConfig.kindField] = this.picked.kind === 'typed' ? this.kinds[0] : this.picked.kind\n\t\t\t}\n\t\t\tif (this.config.note !== false) {\n\t\t\t\tout[this.noteConfig.field || 'note'] = this.note.trim()\n\t\t\t}\n\t\t\treturn { ...out, ...this.flags }\n\t\t},\n\n\t\t/**\n\t\t * Assign once: send `confirm.request`, or dispatch `confirm.action`,\n\t\t * then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/assign-dialog/specs/assign-dialog/spec.md#requirement-a-manifest-configures-an-assign-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst choice = this.choice()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, this.record || {}) : value\n\t\t\t\t\t}\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), { ...body, ...choice })\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), choice] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The assignment ran. Payload: the choice as sent. */\n\t\t\t\tthis.$emit('done', choice)\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'It was not handed over.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/** Close the dialog, unless the assignment is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-assign-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 18px;\n}\n\n.cn-assign-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-assign-dialog__hint {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-assign-dialog__toggle {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-assign-dialog__toggle--on {\n\tborder: 2px solid var(--color-primary-element);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-assign-dialog__toggle-title {\n\tfont-weight: 600;\n}\n\n.cn-assign-dialog__toggle-note {\n\tpadding-inline-start: 44px;\n}\n\n.cn-assign-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_toDisplayString","_Fragment","_renderList"],"mappings":";;;;AAiBoB,EAAA,KAAK,EAAA,kBAAA;;AACjB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,yBAAiB,GAAA;;;AAajB,EAAA,KAAA,EAAA,wBAAA;;;;AAGQ,EAAA,KAAA,EAAA,yBAAA;;;;AASA,EAAA,KAAA,EAAA,wBAAA;;;;;;AAWO,EAAA,KAAK,EAAA,sDAAA;;;;AAI9B,EAAA,KAAE,EAAA,yBAAA;AACF,EAAA,IAAG,EAAA,OAAA;;;;;AAMK,EAAA,IAAI,EAAC,QAAG;AAAA,EAAA,aAAA,EAAA,uBAAA;;;;;;;;;;;;AAvDjB,IAAA,IAAI,EAAE,QAAI,CAAA,IAAA,CAAC,aAAE,CAAA,KAAA,KAAA,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,QAAA,CAAA;AACb,IAAA,OAAO,EAAE,QAAA,CAAA,IAAI,CAAC,MAAA,CAAA,MAAM,CAAC,OAAO,CAAA;AAC5B,IAAA,QAAQ,EAAE,QAAA,CAAA,IAAI,CAAC,MAAA,CAAA,MAAA,CAAA,QAAA,CAAA;AAChB,IAAA,KAAK,EAAC,MAAM;AACX,IAAA,OAAO,EAAE,KAAI,CAAA,IAAA;AACZ,IAAA,aAAS,EAAC,kBAAI;AACb,IAAA,SAAK,EAAE,QAAK,CAAA,KAAA;;AAqDJ,IAAA,OAAO,UAChB,MAEU;MAFVA,WAEU,CAAA,mBAAA,EAAA;AAFA,QAAA,QAAM,EAAA,KAAA,CAAA,IAAA;AAAA,QAAA,aAAA,EAAA,yBAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,KAAA;;yBAChB,MAAsB;0CAAnB,KAAI,CAAA,IAAA,GAAG,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,OAAA,CAAA,GAAW,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,QAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;QAEN,KAAA,CAAA,IAAA;wBAAhBC;;AACA,YAAA,OAAO,EAAC,SAAO;AACd,YAAA,QAAQ,GAAG,QAAU,CAAA,UAAA;AACtB,YAAA,aAAU,EAAA,0BAAA;AACT,YAAA,OAAK,EAAE,QAAO,CAAA,OAAA;;AACN,YAAA,IAAA,UACR,MAAO;cAAPD,WAAO,CAAA,iBAAA,EAAA;gBAAA,IAAA,EAAA,QAAA,CAAA,aAAA,CAAA,IAAA,IAAA,gBAAA;AAAA,gBAAA,IAAA,EAAA,EAAA;;;6BACD;AAAA,cAAAE,eAAA,CAAA;;;;;;qBA/DN,MA8CA;QA9CS,KAAI,CAAA,IAAA;AAAb,WAAAC,SAAA,EAAA,EAAAC,kBAAA,CA8CA,OA9CA,UA8CA,EAAA;+BA/BI,iBAAA,EAAA;cAbJJ,WAW8B,CAAA,yBAAA,EAAA;AAV7B,gBAAA,UAAU,EAAE,KAAA,CAAA,MAAM,GAAG,KAAA,CAAA,MAAA,CAAA,EAAA,GAAA,IAAA;AACrB,gBAAA,OAAO,EAAE,KAAS,CAAA,UAAA;AAClB,gBAAA,UAAU,EAAE,QAAK,CAAA,aAAA;AACjB,gBAAA,YAAY,EAAE,IAAI;AAClB,gBAAA,OAAO,EAAE,QAAY,CAAA,YAAA;AACrB,gBAAA,OAAO,EAAE,KAAO,CAAA,SAAA;AAChB,gBAAA,UAAU,EAAE,KAAK;AACjB,gBAAA,WAAW,EAAE,QAAA,CAAA,IAAI,CAAC,QAAA,CAAA,cAAc,CAAC,WAAW,CAAA;AAC7C,gBAAA,aAAG,EAAA,2BAAA;;AAEF,gBAAA,qBAAiB,EAAG,QAAK,CAAA,MAAA;;eACjB,QAAA,CAAA,YAAA;gCAAVI,kBAAU,CAAA,MAAA,EAAV,UAAU,EAAAC,eAAA,CAAA,QAAA,CAAA,YAAA,CAAA,EAAA,CAAA,YAAA;;;AAGA,YAAA,CAAA,MAAA,CAAA,MAAM,CAAC,IAAC,KAAA,KAAA;AAAjB,iBAAAF,SAAA,EAAA,EAAAC,kBAAA,CAUI,OAVJ,UAUI,EAAA;kBATJJ,WAO2B,CAAA,qBAAA,EAAA;AAN1B,oBAAA,EAAE,EAAE,KAAM,CAAA,MAAA;gCACF,KAAI,CAAA,IAAA;iFAAJ,KAAI,CAAA,IAAA,IAAA,MAAA,CAAA,CAAA;AACZ,oBAAA,KAAK,EAAE,QAAS,CAAA,SAAA;AAChB,oBAAA,YAAY,EAAE,KAAK;oBACnB,IAAE,EAAA,QAAA,CAAA,UAAA,CAAA,IAAA,IAAA,CAAA;;AAEH,oBAAA,aAAW,EAAC,uBAAe;;AAChB,kBAAA,CAAA,QAAA,CAAA,UAAM,CAAA,IAAA;AAAlB,uBAAAG,SAAA,EAAA,EAAAC,kBAAA,CAAkB,QAAlB,UAAkB,EAAAC,eAAA,CAAA,aAAA,CAAA,QAAA,CAAA,UAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;gDAYb,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CATgB,QAAO,CAAA,OAAA,EAAA,CAAjB,MAAM,KAAA;qDASZ,CAAA,KAAA,EAAA;gBARJ,GAAG,EAAE,MAAM,CAAC,KAAK;AACjB,gBAAA,KAAI,kBAAA,0BAA2B,EAAA,EAAA,8BAAA,EACT,WAAA,CAAA,MAAA,CAAA,KAAA,CAAA,EAAA,CAAA,CAAA;gBACtB,aAAW,EAAA,CAAA,wBAAA,EAA6B,MAAM,CAAC,KAAK,CAAA,CAAA;;gBACrDP,WAEe,CAAA,gCAAA,EAAA;AAFX,kBAAA,UAAA,EAAA,KAAA,CAAA,KAAA,CAAA,MAAA,CAAA,KAAA,CAAA,KAAA,IAAA;AAAA,kBAAA,qBAAA,aAAA,KAAA,CAAA,KAAA,CAAA,MAAA,CAAA,KAAA,IAAA,MAAA,CAAA;;;;;;;AAGQ,gBAAA,CAAA,MAAM,CAAC,IAAI;AAAvB,qBAAAG,SAAA,EAAA,EAAAC,kBAAA,CAA8B,QAA9B,UAA8B,EAAAC,eAAA,CAAA,aAAA,CAAA,MAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;aAGtB,KAAI,CAAA,OAAA;gDAKT,CAAA,GAAA,YAAA,EAAAA,eAAA,CADA,KAAO,CAAA,OAAA,CAAA,EAAA,CAAA,YAAA;;;wBAIZD,kBAEK,CAAA,GAAA,EAFL,WAEK,EADDC,eAAA,CAAA,QAAA,CAAA,IAAI,CAAC,MAAM,CAAA,MAAA,CAAC,QAAQ,CAAA,IAAK,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,MAAA,CAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnBoardView.vue2.js';
|
|
|
2
2
|
import { render } from './CnBoardView.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-45db9bd1";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { translate } from '@nextcloud/l10n';
|
|
2
|
-
import __sfc_main from '../
|
|
2
|
+
import __sfc_main from '../CnIcon/CnIcon.vue.js';
|
|
3
|
+
import __sfc_main$1 from '../CnStatusBadge/CnStatusBadge.vue.js';
|
|
3
4
|
import { normalizeLook } from '../../composables/useLook.js';
|
|
4
5
|
import { isBadgeVariant } from '../../utils/badgeVariants.js';
|
|
5
6
|
import { buildBoardColumns, normalizeAllowed, resolveStageColor } from '../../utils/boardColumns.js';
|
|
6
7
|
import { buildSwimlanes } from '../../utils/boardSwimlanes.js';
|
|
7
8
|
import { runBoardDrop, DROP_OUTCOMES } from '../../utils/boardTransition.js';
|
|
9
|
+
import { pillLook } from '../../utils/detailActionModel.js';
|
|
8
10
|
import { dueStateForRow } from '../../utils/dueRule.js';
|
|
9
11
|
import { formatMetricValue } from '../../utils/formatMetric.js';
|
|
10
12
|
import { readPath } from '../../utils/readPath.js';
|
|
@@ -39,7 +41,7 @@ import { daysUntil } from '../../utils/dateVariant.js';
|
|
|
39
41
|
var script = {
|
|
40
42
|
name: 'CnBoardView',
|
|
41
43
|
|
|
42
|
-
components: { CnStatusBadge: __sfc_main },
|
|
44
|
+
components: { CnIcon: __sfc_main, CnStatusBadge: __sfc_main$1 },
|
|
43
45
|
|
|
44
46
|
inject: {
|
|
45
47
|
/**
|
|
@@ -135,9 +137,10 @@ var script = {
|
|
|
135
137
|
|
|
136
138
|
/**
|
|
137
139
|
* The board look's card roles (manifest `config.board.card`):
|
|
138
|
-
* `{ title, sub, pill, due, owner, pillColors? }`. `sub` is a
|
|
139
|
-
* a list of fields joined by a middle dot; `pillColors` maps a
|
|
140
|
-
* value to a badge variant
|
|
140
|
+
* `{ title, sub, pill, due, owner, pillColors?, resolve? }`. `sub` is a
|
|
141
|
+
* field or a list of fields joined by a middle dot; `pillColors` maps a
|
|
142
|
+
* pill value to a badge variant; `resolve: { colorField?, iconField? }`
|
|
143
|
+
* takes the pill's tone and icon from the record it points at. Missing, the first of `cardFields` is the
|
|
141
144
|
* title and the rest form the sub line. The Nextcloud look ignores it.
|
|
142
145
|
*
|
|
143
146
|
* @type {{title?: string, sub?: string|Array<string>, pill?: string, due?: string, owner?: string, pillColors?: object}|null}
|
|
@@ -148,6 +151,20 @@ var script = {
|
|
|
148
151
|
default: null,
|
|
149
152
|
},
|
|
150
153
|
|
|
154
|
+
/**
|
|
155
|
+
* The referenced records' colour and icon names, by field and id
|
|
156
|
+
* (`{ [field]: { [id]: { color, icon } } }`, CnIndexPage reads them).
|
|
157
|
+
* With `cardRoles.resolve: { colorField?, iconField? }` the card's pill
|
|
158
|
+
* takes its record's tone and icon from here.
|
|
159
|
+
*
|
|
160
|
+
* @type {object}
|
|
161
|
+
* @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record
|
|
162
|
+
*/
|
|
163
|
+
pillLooks: {
|
|
164
|
+
type: Object,
|
|
165
|
+
default: () => ({}),
|
|
166
|
+
},
|
|
167
|
+
|
|
151
168
|
/**
|
|
152
169
|
* The field on a column's state that holds its dot colour (manifest
|
|
153
170
|
* `config.board.colorField`). Empty, the lifecycle state's declared
|
|
@@ -710,11 +727,43 @@ var script = {
|
|
|
710
727
|
* @return {string} A CnStatusBadge variant.
|
|
711
728
|
*/
|
|
712
729
|
pillVariant(card) {
|
|
730
|
+
const look = this.pillLookOf(card);
|
|
731
|
+
if (look.variant) {
|
|
732
|
+
return look.variant
|
|
733
|
+
}
|
|
713
734
|
const raw = this.fieldText(card, this.roles.pill);
|
|
714
735
|
const variant = this.roles.pillColors[raw] ?? this.roles.pillColors[raw.toLowerCase()];
|
|
715
736
|
return isBadgeVariant(variant) ? variant : 'default'
|
|
716
737
|
},
|
|
717
738
|
|
|
739
|
+
/**
|
|
740
|
+
* The pill's icon, from the record it points at (`cardRoles.resolve`).
|
|
741
|
+
*
|
|
742
|
+
* @param {object} card The card's row.
|
|
743
|
+
* @return {string} An icon name, or ''.
|
|
744
|
+
* @spec openspec/changes/pill-color-field/specs/pill-color-field/spec.md#requirement-a-card-pill-takes-its-tone-and-icon-from-the-referenced-record
|
|
745
|
+
*/
|
|
746
|
+
pillIcon(card) {
|
|
747
|
+
return this.pillLookOf(card).icon || ''
|
|
748
|
+
},
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* The tone and icon of the record the card's pill points at, when
|
|
752
|
+
* `cardRoles.resolve` asks for them; empty otherwise.
|
|
753
|
+
*
|
|
754
|
+
* @param {object} card The card's row.
|
|
755
|
+
* @return {{variant?: string, icon?: string}} The look.
|
|
756
|
+
*/
|
|
757
|
+
pillLookOf(card) {
|
|
758
|
+
const given = this.cardRoles && typeof this.cardRoles === 'object' ? this.cardRoles : null;
|
|
759
|
+
if (!given || !given.resolve || !this.roles.pill || !this.pillLooks) {
|
|
760
|
+
return {}
|
|
761
|
+
}
|
|
762
|
+
const raw = readPath(card, this.roles.pill);
|
|
763
|
+
const looks = this.pillLooks[this.roles.pill];
|
|
764
|
+
return pillLook(looks && raw !== null && raw !== undefined && typeof raw !== 'object' ? looks[String(raw)] : null)
|
|
765
|
+
},
|
|
766
|
+
|
|
718
767
|
/**
|
|
719
768
|
* The footer's due text: "Due today", "Due 2 Nov", or "Overdue 2 Nov"
|
|
720
769
|
* for a date in the past. Words, so the late tone is not colour alone.
|