@conduction/nextcloud-vue 2.122.0 → 2.123.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +1 -0
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue.js +1 -1
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue2.js +18 -4
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue3.js +63 -32
- package/dist/esm/components/CnAttentionFlagWidget/CnAttentionFlagWidget.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/CnDetailPage/CnDetailPage.vue2.js +35 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +11 -5
- 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 +13 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +37 -5
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +40 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +71 -65
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue.js +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue2.js +20 -0
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue3.js +2 -1
- package/dist/esm/components/CnFlowDetail/CnFlowDetail.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +2 -0
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +49 -44
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js +10 -0
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js +2 -1
- package/dist/esm/components/CnFlowsPage/CnFlowEditorPage.vue3.js.map +1 -1
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue2.js +31 -0
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue2.js.map +1 -1
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue3.js +4 -3
- package/dist/esm/components/CnGraphCanvas/CnGraphCanvas.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +34 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +2 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +31 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +14 -4
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -1
- package/dist/esm/composables/flowGraphLayout.js +36 -7
- package/dist/esm/composables/flowGraphLayout.js.map +1 -1
- package/dist/esm/composables/useFlowStore.js +7 -3
- package/dist/esm/composables/useFlowStore.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 +508 -303
- package/dist/esm/utils/manifestTranslate.js +12 -3
- package/dist/esm/utils/manifestTranslate.js.map +1 -1
- package/dist/esm/utils/routeFilters.js +3 -3
- package/dist/esm/utils/routeFilters.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1217 -847
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +508 -303
- package/l10n/en.json +3 -1
- package/l10n/nl.json +3 -1
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +1 -0
- package/src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue +50 -5
- package/src/components/CnChartWidget/CnChartWidget.vue +10 -8
- package/src/components/CnDetailPage/CnDetailPage.md +10 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +42 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +39 -0
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +95 -37
- package/src/components/CnFlowDetail/CnFlowDetail.vue +21 -0
- package/src/components/CnFlowsPage/CnFlowBoard.vue +35 -18
- package/src/components/CnFlowsPage/CnFlowEditorPage.vue +11 -0
- package/src/components/CnGraphCanvas/CnGraphCanvas.vue +34 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +34 -2
- package/src/components/CnObjectSidebar/CnFilesTab.vue +3 -0
- package/src/components/CnSectionsWidget/CnSectionsWidget.vue +53 -2
- package/src/composables/flowGraphLayout.js +35 -6
- package/src/composables/useFlowStore.js +7 -3
- package/src/css/detail-page.css +6 -0
- package/src/css/look-board-detail.css +26 -6
- package/src/css/look-board-index.css +43 -0
- package/src/css/look-board.css +89 -3
- package/src/utils/manifestTranslate.js +12 -3
- package/src/utils/routeFilters.js +3 -3
|
@@ -2,7 +2,7 @@ import script from './CnAttentionFlagWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnAttentionFlagWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-7e3434fc";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -3,6 +3,7 @@ import { emit } from '@nextcloud/event-bus';
|
|
|
3
3
|
import { translate } from '@nextcloud/l10n';
|
|
4
4
|
import { generateUrl } from '@nextcloud/router';
|
|
5
5
|
import { NcButton, NcTextField } from '@nextcloud/vue';
|
|
6
|
+
import FlagOutline from 'vue-material-design-icons/FlagOutline.vue';
|
|
6
7
|
import 'vue';
|
|
7
8
|
import { interpolateUrlTokens } from '../../utils/interpolateUrlTokens.js';
|
|
8
9
|
import { dispatchObjectsChanged } from '../../utils/objectSignals.js';
|
|
@@ -20,6 +21,8 @@ function defaultLabels() {
|
|
|
20
21
|
reviewDue: translate('nextcloud-vue', 'Due for review'),
|
|
21
22
|
reasonRaise: translate('nextcloud-vue', 'Why this needs attention'),
|
|
22
23
|
reasonClear: translate('nextcloud-vue', 'Why it no longer needs attention'),
|
|
24
|
+
hintRaise: translate('nextcloud-vue', 'Flag it with a reason, so it stands out to everyone who works on it.'),
|
|
25
|
+
hintClear: translate('nextcloud-vue', 'Clear the flag with a reason once it no longer needs attention.'),
|
|
23
26
|
raise: translate('nextcloud-vue', 'Flag for attention'),
|
|
24
27
|
clear: translate('nextcloud-vue', 'Clear the flag'),
|
|
25
28
|
raised: translate('nextcloud-vue', 'Raised'),
|
|
@@ -50,7 +53,8 @@ const LEVELS = {
|
|
|
50
53
|
* "clearPath": "/clear",
|
|
51
54
|
* "markersPath": "attentionMarkers",
|
|
52
55
|
* "panelLabels": { "item-files": "Files" },
|
|
53
|
-
* "assessment": { "path": "riskAssessment", "levelMap": { "high": "High" }, "reviewDateField": "reviewDate" }
|
|
56
|
+
* "assessment": { "path": "riskAssessment", "levelMap": { "high": "High" }, "reviewDateField": "reviewDate" },
|
|
57
|
+
* "behindButton": true
|
|
54
58
|
* }
|
|
55
59
|
* }
|
|
56
60
|
* ```
|
|
@@ -62,7 +66,9 @@ const LEVELS = {
|
|
|
62
66
|
* as written. Markers and the assessment are read off the record the page
|
|
63
67
|
* already holds. An assessment the reader may not see is absent from the
|
|
64
68
|
* record, so it is absent here rather than blank. A failed read draws
|
|
65
|
-
* nothing.
|
|
69
|
+
* nothing. With `behindButton` the strip shows the act as a heading, a hint
|
|
70
|
+
* (`labels.hintRaise` / `labels.hintClear`) and one button, and the reason
|
|
71
|
+
* field opens when that button is pressed. After a raise or a clear the widget emits `object-changed`, says
|
|
66
72
|
* so to every list (`dispatchObjectsChanged`) and asks the page to refresh.
|
|
67
73
|
*
|
|
68
74
|
* @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-can-carry-an-attention-flag
|
|
@@ -70,7 +76,7 @@ const LEVELS = {
|
|
|
70
76
|
var script = {
|
|
71
77
|
name: 'CnAttentionFlagWidget',
|
|
72
78
|
|
|
73
|
-
components: { NcButton, NcTextField },
|
|
79
|
+
components: { FlagOutline, NcButton, NcTextField },
|
|
74
80
|
|
|
75
81
|
inject: {
|
|
76
82
|
cnTranslate: { default: () => (key) => key },
|
|
@@ -82,7 +88,8 @@ var script = {
|
|
|
82
88
|
* `raisePath` (default `/raise`), `clearPath` (default `/clear`),
|
|
83
89
|
* `labels` (overrides of the default words), `markersPath`,
|
|
84
90
|
* `panelLabels` (marker tab id to label) and `assessment`
|
|
85
|
-
* (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`)
|
|
91
|
+
* (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`)
|
|
92
|
+
* and `behindButton` (the reason field opens from a button).
|
|
86
93
|
*/
|
|
87
94
|
content: {
|
|
88
95
|
type: Object,
|
|
@@ -125,6 +132,7 @@ var script = {
|
|
|
125
132
|
history: [],
|
|
126
133
|
reason: '',
|
|
127
134
|
refusal: '',
|
|
135
|
+
composing: false,
|
|
128
136
|
}
|
|
129
137
|
},
|
|
130
138
|
|
|
@@ -142,6 +150,11 @@ var script = {
|
|
|
142
150
|
return interpolateUrlTokens(raw, { objectId: this.objectId, object: this.objectData || {} })
|
|
143
151
|
},
|
|
144
152
|
|
|
153
|
+
/** @return {boolean} Whether the reason field waits behind a button. */
|
|
154
|
+
behindButton() {
|
|
155
|
+
return this.content?.behindButton === true
|
|
156
|
+
},
|
|
157
|
+
|
|
145
158
|
/** @return {string} What the raise or clear was for, in the flag's own words. */
|
|
146
159
|
flagReason() {
|
|
147
160
|
return String(this.flag?.reason ?? '')
|
|
@@ -290,6 +303,7 @@ var script = {
|
|
|
290
303
|
const response = await axios__default.post(generateUrl(this.endpoint + tail), { reason });
|
|
291
304
|
this.apply(response?.data);
|
|
292
305
|
this.reason = '';
|
|
306
|
+
this.composing = false;
|
|
293
307
|
this.announce();
|
|
294
308
|
} catch (error) {
|
|
295
309
|
const said = String(error?.response?.data?.error ?? error?.response?.data?.message ?? '');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAttentionFlagWidget.vue2.js","sources":["../../../../src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div v-if=\"loaded\" class=\"cn-attention-flag\" data-testid=\"cn-attention-flag\">\n\t\t<p\n\t\t\tv-if=\"raised\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-raised\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('raisedLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ flagReason }}</span>\n\t\t</p>\n\n\t\t<ul\n\t\t\tv-if=\"markers.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-markers\">\n\t\t\t<li\n\t\t\t\tv-for=\"marker in markers\"\n\t\t\t\t:key=\"marker.marker\"\n\t\t\t\t:data-testid=\"`cn-attention-flag-marker-${marker.marker}`\"\n\t\t\t\t:data-tab=\"marker.tab\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ marker.panelLabel }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ marker.reason }}</span>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p\n\t\t\tv-if=\"assessment\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-assessment\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('assessmentLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__lead\" :data-level=\"assessment.level\">{{ assessment.levelLabel }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ assessment.ground }}</span>\n\t\t\t<span\n\t\t\t\tv-if=\"assessment.dueForReview\"\n\t\t\t\tclass=\"cn-attention-flag__due\"\n\t\t\t\tdata-testid=\"cn-attention-flag-review-due\">{{ label('reviewDue') }}</span>\n\t\t</p>\n\n\t\t<div class=\"cn-attention-flag__act\">\n\t\t\t<NcTextField\n\t\t\t\t:modelValue=\"reason\"\n\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\tdata-testid=\"cn-attention-flag-reason\"\n\t\t\t\t@update:modelValue=\"onReason\" />\n\t\t\t<NcButton\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\t:data-testid=\"raised ? 'cn-attention-flag-clear' : 'cn-attention-flag-raise'\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<p\n\t\t\tv-if=\"refusal\"\n\t\t\tclass=\"cn-attention-flag__refusal\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-attention-flag-refusal\">\n\t\t\t{{ refusal }}\n\t\t</p>\n\n\t\t<ol\n\t\t\tv-if=\"history.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-history\">\n\t\t\t<li\n\t\t\t\tv-for=\"(row, index) in history\"\n\t\t\t\t:key=\"`${row.moment}-${index}`\"\n\t\t\t\t:data-act=\"row.act\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ row.act === 'cleared' ? label('cleared') : label('raised') }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ row.reason }}</span>\n\t\t\t</li>\n\t\t</ol>\n\t</div>\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, NcTextField } from '@nextcloud/vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { dispatchObjectsChanged } from '../../utils/objectSignals.js'\nimport { readPath } from '../../utils/readPath.js'\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\traisedLead: t('nextcloud-vue', 'Flagged as needing attention:'),\n\t\tassessmentLead: t('nextcloud-vue', 'Assessed risk:'),\n\t\treviewDue: t('nextcloud-vue', 'Due for review'),\n\t\treasonRaise: t('nextcloud-vue', 'Why this needs attention'),\n\t\treasonClear: t('nextcloud-vue', 'Why it no longer needs attention'),\n\t\traise: t('nextcloud-vue', 'Flag for attention'),\n\t\tclear: t('nextcloud-vue', 'Clear the flag'),\n\t\traised: t('nextcloud-vue', 'Raised'),\n\t\tcleared: t('nextcloud-vue', 'Cleared'),\n\t\tfailed: t('nextcloud-vue', 'This did not work. Try again.'),\n\t}\n}\n\n/** The assessed levels a record may carry, with their default words. */\nconst LEVELS = {\n\tlow: 'Low',\n\tmedium: 'Medium',\n\thigh: 'High',\n\tcritical: 'Critical',\n}\n\n/**\n * CnAttentionFlagWidget — the `attention-flag` widget: a flag a PERSON raises\n * on a record with a reason, the markers the SYSTEM raised against a part of\n * it, and an assessment the ORGANISATION made, kept apart on one strip.\n *\n * ```json\n * {\n * \"type\": \"attention-flag\",\n * \"content\": {\n * \"endpoint\": \"/apps/myapp/api/item/@objectId/attention\",\n * \"raisePath\": \"/raise\",\n * \"clearPath\": \"/clear\",\n * \"markersPath\": \"attentionMarkers\",\n * \"panelLabels\": { \"item-files\": \"Files\" },\n * \"assessment\": { \"path\": \"riskAssessment\", \"levelMap\": { \"high\": \"High\" }, \"reviewDateField\": \"reviewDate\" }\n * }\n * }\n * ```\n *\n * The endpoint answers `{ raised, flag: { reason }, history: [{ act, reason, moment }] }`\n * on GET, and the same after a POST of `{ reason }` to `raisePath` or\n * `clearPath`. A reason is required in both directions: the button stays\n * disabled without one, and the server's refusal sentence (`error`) is shown\n * as written. Markers and the assessment are read off the record the page\n * already holds. An assessment the reader may not see is absent from the\n * record, so it is absent here rather than blank. A failed read draws\n * nothing. After a raise or a clear the widget emits `object-changed`, says\n * so to every list (`dispatchObjectsChanged`) and asks the page to refresh.\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-can-carry-an-attention-flag\n */\nexport default {\n\tname: 'CnAttentionFlagWidget',\n\n\tcomponents: { NcButton, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `endpoint` (tokens `@objectId`, `@object.<field>`),\n\t\t * `raisePath` (default `/raise`), `clearPath` (default `/clear`),\n\t\t * `labels` (overrides of the default words), `markersPath`,\n\t\t * `panelLabels` (marker tab id to label) and `assessment`\n\t\t * (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail-page host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register, for the changed-objects signal. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema, for the changed-objects signal. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['object-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloaded: false,\n\t\t\tbusy: false,\n\t\t\traised: false,\n\t\t\tflag: {},\n\t\t\thistory: [],\n\t\t\treason: '',\n\t\t\trefusal: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The flag endpoint with its tokens filled, or '' while a token is not known.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tendpoint() {\n\t\t\tconst raw = typeof this.content?.endpoint === 'string' ? this.content.endpoint : ''\n\t\t\tif (raw === '' || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn interpolateUrlTokens(raw, { objectId: this.objectId, object: this.objectData || {} })\n\t\t},\n\n\t\t/** @return {string} What the raise or clear was for, in the flag's own words. */\n\t\tflagReason() {\n\t\t\treturn String(this.flag?.reason ?? '')\n\t\t},\n\n\t\t/** @return {string} The label over the reason field, naming the act it is for. */\n\t\treasonLabel() {\n\t\t\treturn this.raised ? this.label('reasonClear') : this.label('reasonRaise')\n\t\t},\n\n\t\t/**\n\t\t * The markers on the record, each naming the part it points at.\n\t\t *\n\t\t * @return {Array<{marker: string, tab: string, reason: string, panelLabel: string}>}\n\t\t */\n\t\tmarkers() {\n\t\t\tconst path = this.content?.markersPath\n\t\t\tif (typeof path !== 'string' || path === '' || !this.objectData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst raw = readPath(this.objectData, path)\n\t\t\tif (!Array.isArray(raw)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst panelLabels = this.content?.panelLabels && typeof this.content.panelLabels === 'object' ? this.content.panelLabels : {}\n\t\t\treturn raw\n\t\t\t\t.filter((marker) => marker && String(marker.marker ?? '') !== '')\n\t\t\t\t.map((marker) => {\n\t\t\t\t\tconst tab = String(marker.tab ?? '')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmarker: String(marker.marker),\n\t\t\t\t\t\ttab,\n\t\t\t\t\t\treason: String(marker.reason ?? ''),\n\t\t\t\t\t\tpanelLabel: this.cnTranslate(panelLabels[tab] || tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The assessment, or null when the record carries none or the reader\n\t\t * may not see it (OpenRegister leaves the property out).\n\t\t *\n\t\t * @return {{level: string, levelLabel: string, ground: string, dueForReview: boolean}|null}\n\t\t */\n\t\tassessment() {\n\t\t\tconst config = this.content?.assessment\n\t\t\tif (!config || typeof config !== 'object' || typeof config.path !== 'string' || !this.objectData) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst stored = readPath(this.objectData, config.path)\n\t\t\tif (!stored || typeof stored !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst level = String(stored[config.levelField || 'level'] ?? '')\n\t\t\tif (level === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst levelMap = config.levelMap && typeof config.levelMap === 'object' ? config.levelMap : {}\n\t\t\tconst word = levelMap[level] || LEVELS[level]\n\t\t\treturn {\n\t\t\t\tlevel,\n\t\t\t\tlevelLabel: word ? this.cnTranslate(word) : level,\n\t\t\t\tground: String(stored[config.groundField || 'ground'] ?? ''),\n\t\t\t\tdueForReview: hasPassed(String(stored[config.reviewDateField || 'reviewDate'] ?? '')),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tendpoint: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A label: the content's own (through the host translate), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string} The text.\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * Read where the flag stands. A failure draws nothing: an instance that\n\t\t * does not carry the endpoint answers 404, and nothing else depends on it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (this.endpoint === '') {\n\t\t\t\tthis.loaded = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(this.endpoint))\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.loaded = true\n\t\t\t} catch {\n\t\t\t\tthis.loaded = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Take the answer of a read or an act.\n\t\t *\n\t\t * @param {object} state What the endpoint answered.\n\t\t * @return {void}\n\t\t */\n\t\tapply(state) {\n\t\t\tthis.raised = state?.raised === true\n\t\t\tthis.flag = state?.flag ?? {}\n\t\t\tthis.history = Array.isArray(state?.history) ? state.history : []\n\t\t},\n\n\t\t/**\n\t\t * Keep the typed reason, so the button knows whether there is one.\n\t\t *\n\t\t * @param {string} value The field's value.\n\t\t * @return {void}\n\t\t */\n\t\tonReason(value) {\n\t\t\tthis.reason = String(value ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Raise the flag, or clear it, with the reason that was written.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tconst reason = this.reason.trim()\n\t\t\tif (reason === '' || this.endpoint === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst tail = this.raised ? (this.content?.clearPath || '/clear') : (this.content?.raisePath || '/raise')\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(this.endpoint + tail), { reason })\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.reason = ''\n\t\t\t\tthis.announce()\n\t\t\t} catch (error) {\n\t\t\t\tconst said = String(error?.response?.data?.error ?? error?.response?.data?.message ?? '')\n\t\t\t\tthis.refusal = said !== '' ? said : this.label('failed')\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Say the record changed: to the host, to every list showing it, and\n\t\t * to the page so it reads the record again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tannounce() {\n\t\t\tconst id = String(this.objectId || '')\n\t\t\t/** @event object-changed The flag was raised or cleared: `{ register, schema, id }` of the record. */\n\t\t\tthis.$emit('object-changed', { register: this.register, schema: this.schema, id })\n\t\t\tdispatchObjectsChanged({ register: typeof this.register === 'string' ? this.register : '', schema: typeof this.schema === 'string' ? this.schema : '', id })\n\t\t\temit('cn:page:refresh')\n\t\t},\n\t},\n}\n\n/**\n * Whether a date lies before today. The date named is the last day the\n * assessment is still good for, so a review date of today is not yet due.\n *\n * @param {string} date The date.\n * @return {boolean} True when it has passed.\n */\nfunction hasPassed(date) {\n\tif (date === '') {\n\t\treturn false\n\t}\n\tconst moment = new Date(date)\n\tif (Number.isNaN(moment.getTime())) {\n\t\treturn false\n\t}\n\treturn moment.toISOString().slice(0, 10) < new Date().toISOString().slice(0, 10)\n}\n</script>\n\n<style scoped>\n.cn-attention-flag {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 4px 0;\n}\n\n.cn-attention-flag__line,\n.cn-attention-flag__act {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n}\n\n.cn-attention-flag__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-attention-flag__list li {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n.cn-attention-flag__lead {\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-attention-flag__due {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-attention-flag__refusal {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAttentionFlagWidget.vue2.js","sources":["../../../../src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div v-if=\"loaded\" class=\"cn-attention-flag\" data-testid=\"cn-attention-flag\">\n\t\t<p\n\t\t\tv-if=\"raised\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-raised\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('raisedLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ flagReason }}</span>\n\t\t</p>\n\n\t\t<ul\n\t\t\tv-if=\"markers.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-markers\">\n\t\t\t<li\n\t\t\t\tv-for=\"marker in markers\"\n\t\t\t\t:key=\"marker.marker\"\n\t\t\t\t:data-testid=\"`cn-attention-flag-marker-${marker.marker}`\"\n\t\t\t\t:data-tab=\"marker.tab\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ marker.panelLabel }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ marker.reason }}</span>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p\n\t\t\tv-if=\"assessment\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-assessment\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('assessmentLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__lead\" :data-level=\"assessment.level\">{{ assessment.levelLabel }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ assessment.ground }}</span>\n\t\t\t<span\n\t\t\t\tv-if=\"assessment.dueForReview\"\n\t\t\t\tclass=\"cn-attention-flag__due\"\n\t\t\t\tdata-testid=\"cn-attention-flag-review-due\">{{ label('reviewDue') }}</span>\n\t\t</p>\n\n\t\t<template v-if=\"behindButton && !composing\">\n\t\t\t<h4 class=\"cn-attention-flag__heading\" data-testid=\"cn-attention-flag-heading\">\n\t\t\t\t{{ reasonLabel }}\n\t\t\t</h4>\n\t\t\t<p class=\"cn-attention-flag__hint\" data-testid=\"cn-attention-flag-hint\">\n\t\t\t\t{{ raised ? label('hintClear') : label('hintRaise') }}\n\t\t\t</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\twide\n\t\t\t\tdata-testid=\"cn-attention-flag-compose\"\n\t\t\t\t@click=\"composing = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FlagOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<div v-else class=\"cn-attention-flag__act\">\n\t\t\t<NcTextField\n\t\t\t\t:modelValue=\"reason\"\n\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\tdata-testid=\"cn-attention-flag-reason\"\n\t\t\t\t@update:modelValue=\"onReason\" />\n\t\t\t<NcButton\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\t:data-testid=\"raised ? 'cn-attention-flag-clear' : 'cn-attention-flag-raise'\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<p\n\t\t\tv-if=\"refusal\"\n\t\t\tclass=\"cn-attention-flag__refusal\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-attention-flag-refusal\">\n\t\t\t{{ refusal }}\n\t\t</p>\n\n\t\t<ol\n\t\t\tv-if=\"history.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-history\">\n\t\t\t<li\n\t\t\t\tv-for=\"(row, index) in history\"\n\t\t\t\t:key=\"`${row.moment}-${index}`\"\n\t\t\t\t:data-act=\"row.act\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ row.act === 'cleared' ? label('cleared') : label('raised') }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ row.reason }}</span>\n\t\t\t</li>\n\t\t</ol>\n\t</div>\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, NcTextField } from '@nextcloud/vue'\nimport FlagOutline from 'vue-material-design-icons/FlagOutline.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { dispatchObjectsChanged } from '../../utils/objectSignals.js'\nimport { readPath } from '../../utils/readPath.js'\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\traisedLead: t('nextcloud-vue', 'Flagged as needing attention:'),\n\t\tassessmentLead: t('nextcloud-vue', 'Assessed risk:'),\n\t\treviewDue: t('nextcloud-vue', 'Due for review'),\n\t\treasonRaise: t('nextcloud-vue', 'Why this needs attention'),\n\t\treasonClear: t('nextcloud-vue', 'Why it no longer needs attention'),\n\t\thintRaise: t('nextcloud-vue', 'Flag it with a reason, so it stands out to everyone who works on it.'),\n\t\thintClear: t('nextcloud-vue', 'Clear the flag with a reason once it no longer needs attention.'),\n\t\traise: t('nextcloud-vue', 'Flag for attention'),\n\t\tclear: t('nextcloud-vue', 'Clear the flag'),\n\t\traised: t('nextcloud-vue', 'Raised'),\n\t\tcleared: t('nextcloud-vue', 'Cleared'),\n\t\tfailed: t('nextcloud-vue', 'This did not work. Try again.'),\n\t}\n}\n\n/** The assessed levels a record may carry, with their default words. */\nconst LEVELS = {\n\tlow: 'Low',\n\tmedium: 'Medium',\n\thigh: 'High',\n\tcritical: 'Critical',\n}\n\n/**\n * CnAttentionFlagWidget — the `attention-flag` widget: a flag a PERSON raises\n * on a record with a reason, the markers the SYSTEM raised against a part of\n * it, and an assessment the ORGANISATION made, kept apart on one strip.\n *\n * ```json\n * {\n * \"type\": \"attention-flag\",\n * \"content\": {\n * \"endpoint\": \"/apps/myapp/api/item/@objectId/attention\",\n * \"raisePath\": \"/raise\",\n * \"clearPath\": \"/clear\",\n * \"markersPath\": \"attentionMarkers\",\n * \"panelLabels\": { \"item-files\": \"Files\" },\n * \"assessment\": { \"path\": \"riskAssessment\", \"levelMap\": { \"high\": \"High\" }, \"reviewDateField\": \"reviewDate\" },\n * \"behindButton\": true\n * }\n * }\n * ```\n *\n * The endpoint answers `{ raised, flag: { reason }, history: [{ act, reason, moment }] }`\n * on GET, and the same after a POST of `{ reason }` to `raisePath` or\n * `clearPath`. A reason is required in both directions: the button stays\n * disabled without one, and the server's refusal sentence (`error`) is shown\n * as written. Markers and the assessment are read off the record the page\n * already holds. An assessment the reader may not see is absent from the\n * record, so it is absent here rather than blank. A failed read draws\n * nothing. With `behindButton` the strip shows the act as a heading, a hint\n * (`labels.hintRaise` / `labels.hintClear`) and one button, and the reason\n * field opens when that button is pressed. After a raise or a clear the widget emits `object-changed`, says\n * so to every list (`dispatchObjectsChanged`) and asks the page to refresh.\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-can-carry-an-attention-flag\n */\nexport default {\n\tname: 'CnAttentionFlagWidget',\n\n\tcomponents: { FlagOutline, NcButton, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `endpoint` (tokens `@objectId`, `@object.<field>`),\n\t\t * `raisePath` (default `/raise`), `clearPath` (default `/clear`),\n\t\t * `labels` (overrides of the default words), `markersPath`,\n\t\t * `panelLabels` (marker tab id to label) and `assessment`\n\t\t * (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`)\n\t\t * and `behindButton` (the reason field opens from a button).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail-page host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register, for the changed-objects signal. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema, for the changed-objects signal. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['object-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloaded: false,\n\t\t\tbusy: false,\n\t\t\traised: false,\n\t\t\tflag: {},\n\t\t\thistory: [],\n\t\t\treason: '',\n\t\t\trefusal: '',\n\t\t\tcomposing: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The flag endpoint with its tokens filled, or '' while a token is not known.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tendpoint() {\n\t\t\tconst raw = typeof this.content?.endpoint === 'string' ? this.content.endpoint : ''\n\t\t\tif (raw === '' || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn interpolateUrlTokens(raw, { objectId: this.objectId, object: this.objectData || {} })\n\t\t},\n\n\t\t/** @return {boolean} Whether the reason field waits behind a button. */\n\t\tbehindButton() {\n\t\t\treturn this.content?.behindButton === true\n\t\t},\n\n\t\t/** @return {string} What the raise or clear was for, in the flag's own words. */\n\t\tflagReason() {\n\t\t\treturn String(this.flag?.reason ?? '')\n\t\t},\n\n\t\t/** @return {string} The label over the reason field, naming the act it is for. */\n\t\treasonLabel() {\n\t\t\treturn this.raised ? this.label('reasonClear') : this.label('reasonRaise')\n\t\t},\n\n\t\t/**\n\t\t * The markers on the record, each naming the part it points at.\n\t\t *\n\t\t * @return {Array<{marker: string, tab: string, reason: string, panelLabel: string}>}\n\t\t */\n\t\tmarkers() {\n\t\t\tconst path = this.content?.markersPath\n\t\t\tif (typeof path !== 'string' || path === '' || !this.objectData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst raw = readPath(this.objectData, path)\n\t\t\tif (!Array.isArray(raw)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst panelLabels = this.content?.panelLabels && typeof this.content.panelLabels === 'object' ? this.content.panelLabels : {}\n\t\t\treturn raw\n\t\t\t\t.filter((marker) => marker && String(marker.marker ?? '') !== '')\n\t\t\t\t.map((marker) => {\n\t\t\t\t\tconst tab = String(marker.tab ?? '')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmarker: String(marker.marker),\n\t\t\t\t\t\ttab,\n\t\t\t\t\t\treason: String(marker.reason ?? ''),\n\t\t\t\t\t\tpanelLabel: this.cnTranslate(panelLabels[tab] || tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The assessment, or null when the record carries none or the reader\n\t\t * may not see it (OpenRegister leaves the property out).\n\t\t *\n\t\t * @return {{level: string, levelLabel: string, ground: string, dueForReview: boolean}|null}\n\t\t */\n\t\tassessment() {\n\t\t\tconst config = this.content?.assessment\n\t\t\tif (!config || typeof config !== 'object' || typeof config.path !== 'string' || !this.objectData) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst stored = readPath(this.objectData, config.path)\n\t\t\tif (!stored || typeof stored !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst level = String(stored[config.levelField || 'level'] ?? '')\n\t\t\tif (level === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst levelMap = config.levelMap && typeof config.levelMap === 'object' ? config.levelMap : {}\n\t\t\tconst word = levelMap[level] || LEVELS[level]\n\t\t\treturn {\n\t\t\t\tlevel,\n\t\t\t\tlevelLabel: word ? this.cnTranslate(word) : level,\n\t\t\t\tground: String(stored[config.groundField || 'ground'] ?? ''),\n\t\t\t\tdueForReview: hasPassed(String(stored[config.reviewDateField || 'reviewDate'] ?? '')),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tendpoint: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A label: the content's own (through the host translate), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string} The text.\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * Read where the flag stands. A failure draws nothing: an instance that\n\t\t * does not carry the endpoint answers 404, and nothing else depends on it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (this.endpoint === '') {\n\t\t\t\tthis.loaded = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(this.endpoint))\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.loaded = true\n\t\t\t} catch {\n\t\t\t\tthis.loaded = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Take the answer of a read or an act.\n\t\t *\n\t\t * @param {object} state What the endpoint answered.\n\t\t * @return {void}\n\t\t */\n\t\tapply(state) {\n\t\t\tthis.raised = state?.raised === true\n\t\t\tthis.flag = state?.flag ?? {}\n\t\t\tthis.history = Array.isArray(state?.history) ? state.history : []\n\t\t},\n\n\t\t/**\n\t\t * Keep the typed reason, so the button knows whether there is one.\n\t\t *\n\t\t * @param {string} value The field's value.\n\t\t * @return {void}\n\t\t */\n\t\tonReason(value) {\n\t\t\tthis.reason = String(value ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Raise the flag, or clear it, with the reason that was written.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tconst reason = this.reason.trim()\n\t\t\tif (reason === '' || this.endpoint === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst tail = this.raised ? (this.content?.clearPath || '/clear') : (this.content?.raisePath || '/raise')\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(this.endpoint + tail), { reason })\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.reason = ''\n\t\t\t\tthis.composing = false\n\t\t\t\tthis.announce()\n\t\t\t} catch (error) {\n\t\t\t\tconst said = String(error?.response?.data?.error ?? error?.response?.data?.message ?? '')\n\t\t\t\tthis.refusal = said !== '' ? said : this.label('failed')\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Say the record changed: to the host, to every list showing it, and\n\t\t * to the page so it reads the record again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tannounce() {\n\t\t\tconst id = String(this.objectId || '')\n\t\t\t/** @event object-changed The flag was raised or cleared: `{ register, schema, id }` of the record. */\n\t\t\tthis.$emit('object-changed', { register: this.register, schema: this.schema, id })\n\t\t\tdispatchObjectsChanged({ register: typeof this.register === 'string' ? this.register : '', schema: typeof this.schema === 'string' ? this.schema : '', id })\n\t\t\temit('cn:page:refresh')\n\t\t},\n\t},\n}\n\n/**\n * Whether a date lies before today. The date named is the last day the\n * assessment is still good for, so a review date of today is not yet due.\n *\n * @param {string} date The date.\n * @return {boolean} True when it has passed.\n */\nfunction hasPassed(date) {\n\tif (date === '') {\n\t\treturn false\n\t}\n\tconst moment = new Date(date)\n\tif (Number.isNaN(moment.getTime())) {\n\t\treturn false\n\t}\n\treturn moment.toISOString().slice(0, 10) < new Date().toISOString().slice(0, 10)\n}\n</script>\n\n<style scoped>\n.cn-attention-flag {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 4px 0;\n}\n\n.cn-attention-flag__line,\n.cn-attention-flag__act {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n}\n\n.cn-attention-flag__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-attention-flag__list li {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n.cn-attention-flag__lead {\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__heading {\n\tmargin: 0;\n\tfont-size: 14px;\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__hint {\n\tmargin: 0 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-attention-flag__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-attention-flag__due {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-attention-flag__refusal {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["t","axios"],"mappings":";;;;;;;;;;;AA8GA;;AAEC;;;AAGD,SAAS,aAAa,GAAG;AACxB,CAAA,OAAO;EACN,UAAU,EAAEA,SAAC,CAAC,eAAe,EAAE,+BAA+B,CAAC;EAC/D,cAAc,EAAEA,SAAC,CAAC,eAAe,EAAE,gBAAgB,CAAC;AACpD,EAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,gBAAgB,CAAC;EAC/C,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,0BAA0B,CAAC;EAC3D,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,kCAAkC,CAAC;AACnE,EAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,sEAAsE,CAAC;AACrG,EAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,iEAAiE,CAAC;AAChG,EAAA,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,oBAAoB,CAAC;AAC/C,EAAA,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,gBAAgB,CAAC;AAC3C,EAAA,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAC;AACpC,EAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;EACtC,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,+BAA+B,CAAC;AAC5D,EAAA;AACD,CAAA;;AAEA;AACA,MAAM,MAAK,GAAI;AACd,CAAA,GAAG,EAAE,KAAK;AACV,CAAA,MAAM,EAAE,QAAQ;CAChB,IAAI,EAAE,MAAM;AACZ,CAAA,QAAQ,EAAE,UAAU;AACrB,EAAA;;AAEA;AACC;;;AAGA;AACA;;;;;AAKA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;;;AAGA;;;;;AAKA;AACA;AACA;AACA;AACA;;AAED,aAAe;CACd,IAAI,EAAE,uBAAuB;;AAE7B,CAAA,UAAU,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa;;AAElD,CAAA,MAAM,EAAE;AACP,EAAA,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,KAAK,KAAK;EAC5C;;AAED,CAAA,KAAK,EAAE;AACN;AACC;;;;AAIA;;;AAGD,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,OAAO,EAAE,CAAC;GACnB;;AAED;AACA,EAAA,QAAQ,EAAE;AACT,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;;AAED;EACA,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;;AAGD,EAAA,QAAQ,EAAE;AACT,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;;;AAGD,EAAA,MAAM,EAAE;AACP,GAAA,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;GACtB,OAAO,EAAE,EAAE;GACX;EACD;;CAED,KAAK,EAAE,CAAC,gBAAgB,CAAC;;AAEzB,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;GACN,MAAM,EAAE,KAAK;GACb,IAAI,EAAE,KAAK;GACX,MAAM,EAAE,KAAK;AACb,GAAA,IAAI,EAAE,EAAE;GACR,OAAO,EAAE,EAAE;AACX,GAAA,MAAM,EAAE,EAAE;GACV,OAAO,EAAE,EAAE;AACX,GAAA,SAAS,EAAE,KAAK;AACjB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;;AAEC;AACA;;EAED,QAAQ,GAAG;AACV,GAAA,MAAM,GAAE,GAAI,OAAO,IAAI,CAAC,OAAO,EAAE,QAAS,KAAI,QAAS,GAAE,IAAI,CAAC,OAAO,CAAC,QAAO,GAAI,GAAC;GAClF,IAAI,GAAE,KAAM,EAAG,IAAG,CAAC,IAAI,CAAC,QAAQ,EAAE;AACjC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,oBAAoB,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,UAAS,IAAK,IAAI,CAAA;GAC3F;;;AAGD,EAAA,YAAY,GAAG;AACd,GAAA,OAAO,IAAI,CAAC,OAAO,EAAE,iBAAiB,IAAG;GACzC;;AAED;EACA,UAAU,GAAG;AACZ,GAAA,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAK,IAAK,EAAE,CAAA;GACrC;;AAED;EACA,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,MAAO,GAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAE,GAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAA;GACzE;;AAED;;AAEC;AACA;;AAED,EAAA,OAAO,GAAG;AACT,GAAA,MAAM,IAAK,GAAE,IAAI,CAAC,OAAO,EAAE,YAAU;GACrC,IAAI,OAAO,IAAG,KAAM,QAAS,IAAG,IAAG,KAAM,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE;AAChE,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,MAAM,GAAI,GAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAA;GAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACxB,IAAA,OAAO,EAAC;AACT,IAAA;GACA,MAAM,WAAU,GAAI,IAAI,CAAC,OAAO,EAAE,eAAe,OAAO,IAAI,CAAC,OAAO,CAAC,WAAY,KAAI,WAAW,IAAI,CAAC,OAAO,CAAC,WAAY,GAAE,GAAC;AAC5H,GAAA,OAAO,GAAE;KACP,MAAM,CAAC,CAAC,MAAM,KAAK,MAAK,IAAK,MAAM,CAAC,MAAM,CAAC,MAAO,IAAG,EAAE,CAAA,KAAM,EAAE,CAAA;AAChE,KAAC,GAAG,CAAC,CAAC,MAAM,KAAK;AAChB,KAAA,MAAM,GAAI,GAAE,MAAM,CAAC,MAAM,CAAC,GAAI,IAAG,EAAE,EAAA;AACnC,KAAA,OAAO;MACN,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;AAC7B,MAAA,GAAG;AACH,MAAA,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAO,IAAG,EAAE,CAAC;MACnC,UAAU,EAAE,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,CAAA,IAAK,GAAG,CAAC;AACtD,MAAA;KACA,CAAA;GACF;;AAED;;;AAGC;AACA;;EAED,UAAU,GAAG;AACZ,GAAA,MAAM,MAAO,GAAE,IAAI,CAAC,OAAO,EAAE,WAAS;AACtC,GAAA,IAAI,CAAC,MAAO,IAAG,OAAO,MAAO,KAAI,QAAS,IAAG,OAAO,MAAM,CAAC,IAAG,KAAM,QAAO,IAAK,CAAC,IAAI,CAAC,UAAU,EAAE;AACjG,IAAA,OAAO,IAAG;AACX,IAAA;GACA,MAAM,MAAK,GAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,EAAA;AACpD,GAAA,IAAI,CAAC,MAAK,IAAK,OAAO,MAAK,KAAM,QAAQ,EAAE;AAC1C,IAAA,OAAO,IAAG;AACX,IAAA;GACA,MAAM,KAAM,GAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAS,IAAK,OAAO,CAAE,IAAG,EAAE,EAAA;AAC/D,GAAA,IAAI,KAAM,KAAI,EAAE,EAAE;AACjB,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,MAAM,QAAS,GAAE,MAAM,CAAC,QAAO,IAAK,OAAO,MAAM,CAAC,QAAO,KAAM,QAAO,GAAI,MAAM,CAAC,QAAO,GAAI,GAAC;AAC7F,GAAA,MAAM,IAAG,GAAI,QAAQ,CAAC,KAAK,CAAE,IAAG,MAAM,CAAC,KAAK,EAAA;AAC5C,GAAA,OAAO;IACN,KAAK;AACL,IAAA,UAAU,EAAE,IAAK,GAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAE,GAAE,KAAK;IACjD,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,WAAU,IAAK,QAAQ,CAAA,IAAK,EAAE,CAAC;AAC5D,IAAA,YAAY,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,eAAgB,IAAG,YAAY,CAAE,IAAG,EAAE,CAAC,CAAC;AACtF,IAAA;GACA;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,QAAQ,EAAE;AACT,GAAA,SAAS,EAAE,IAAI;AACf,GAAA,OAAO,GAAG;IACT,IAAI,CAAC,IAAI,GAAC;IACV;GACD;EACD;;AAED,CAAA,OAAO,EAAE;AACR;AACC;AACA;;;;EAID,KAAK,CAAC,GAAG,EAAE;GACV,MAAM,GAAE,GAAI,IAAI,CAAC,OAAO,EAAE,MAAO,IAAG,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAA,KAAM,QAAO,GAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAE,GAAE,GAAC;GAC/G,OAAO,GAAE,KAAM,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,IAAI,aAAa,EAAE,CAAC,GAAG,CAAA;GAC/D;;AAED;;;AAGC;;;EAGD,MAAM,IAAI,GAAG;GACZ,IAAI,IAAI,CAAC,QAAS,KAAI,EAAE,EAAE;AACzB,IAAA,IAAI,CAAC,MAAO,GAAE,MAAI;IAClB,MAAK;AACN,IAAA;AACA,GAAA,IAAI;IACH,MAAM,QAAO,GAAI,MAAMC,cAAK,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;IAC3D,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAA;AACzB,IAAA,IAAI,CAAC,MAAK,GAAI,KAAG;AAClB,IAAA,CAAE,MAAM;AACP,IAAA,IAAI,CAAC,MAAO,GAAE,MAAI;AACnB,IAAA;GACA;;AAED;;AAEC;AACA;;;EAGD,KAAK,CAAC,KAAK,EAAE;AACZ,GAAA,IAAI,CAAC,MAAK,GAAI,KAAK,EAAE,MAAK,KAAM,KAAG;GACnC,IAAI,CAAC,IAAK,GAAE,KAAK,EAAE,IAAG,IAAK,GAAC;GAC5B,IAAI,CAAC,OAAM,GAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAA,GAAI,KAAK,CAAC,OAAQ,GAAE,GAAC;GAChE;;AAED;;AAEC;AACA;;;AAGD,EAAA,QAAQ,CAAC,KAAK,EAAE;GACf,IAAI,CAAC,MAAO,GAAE,MAAM,CAAC,KAAM,IAAG,EAAE,EAAA;GAChC;;AAED;;AAEC;;;EAGD,MAAM,MAAM,GAAG;GACd,MAAM,MAAO,GAAE,IAAI,CAAC,MAAM,CAAC,IAAI,GAAC;AAChC,GAAA,IAAI,MAAO,KAAI,EAAC,IAAK,IAAI,CAAC,aAAa,EAAE,EAAE;IAC1C,MAAK;AACN,IAAA;AACA,GAAA,MAAM,IAAK,GAAE,IAAI,CAAC,MAAO,IAAG,IAAI,CAAC,OAAO,EAAE,SAAQ,IAAK,QAAQ,KAAK,IAAI,CAAC,OAAO,EAAE,aAAa,QAAQ,EAAA;GACvG,IAAI,CAAC,IAAK,GAAE,KAAG;AACf,GAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AAChB,GAAA,IAAI;AACH,IAAA,MAAM,QAAS,GAAE,MAAMA,cAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAO,GAAI,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAA;IAC/E,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAA;IACzB,IAAI,CAAC,MAAO,GAAE,GAAC;AACf,IAAA,IAAI,CAAC,SAAQ,GAAI,MAAI;AACrB,IAAA,IAAI,CAAC,QAAQ,GAAC;IACb,CAAA,OAAO,KAAK,EAAE;AACf,IAAA,MAAM,IAAG,GAAI,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAI,IAAK,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,EAAA;IACxF,IAAI,CAAC,UAAU,IAAG,KAAM,EAAG,GAAE,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAA;AACxD,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,IAAG,GAAI,MAAI;AACjB,IAAA;GACA;;AAED;;AAEC;AACA;;;EAGD,QAAQ,GAAG;AACV,GAAA,MAAM,EAAC,GAAI,MAAM,CAAC,IAAI,CAAC,QAAO,IAAK,EAAE,EAAA;AACrC;AACA,GAAA,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAA;AACjF,GAAA,sBAAsB,CAAC,EAAE,QAAQ,EAAE,OAAO,IAAI,CAAC,QAAO,KAAM,QAAS,GAAE,IAAI,CAAC,QAAO,GAAI,EAAE,EAAE,MAAM,EAAE,OAAO,IAAI,CAAC,MAAK,KAAM,WAAW,IAAI,CAAC,MAAO,GAAE,EAAE,EAAE,IAAI,EAAA;GAC3J,IAAI,CAAC,iBAAiB,EAAA;GACtB;EACD;AACF,EAAA;;AAEA;;;AAGC;;AAEA;;AAED,SAAS,SAAS,CAAC,IAAI,EAAE;CACxB,IAAI,IAAK,KAAI,EAAE,EAAE;EAChB,OAAO,KAAI;AACZ,EAAA;CACA,MAAM,MAAO,GAAE,IAAI,IAAI,CAAC,IAAI,EAAA;AAC5B,CAAA,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE;EACnC,OAAO,KAAI;AACZ,EAAA;AACA,CAAA,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAA,GAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAA;AAChF;;;;"}
|
|
@@ -33,25 +33,37 @@ const _hoisted_13 = {
|
|
|
33
33
|
class: "cn-attention-flag__due",
|
|
34
34
|
"data-testid": "cn-attention-flag-review-due"
|
|
35
35
|
};
|
|
36
|
-
const _hoisted_14 = {
|
|
36
|
+
const _hoisted_14 = {
|
|
37
|
+
class: "cn-attention-flag__heading",
|
|
38
|
+
"data-testid": "cn-attention-flag-heading"
|
|
39
|
+
};
|
|
37
40
|
const _hoisted_15 = {
|
|
38
|
-
|
|
41
|
+
class: "cn-attention-flag__hint",
|
|
42
|
+
"data-testid": "cn-attention-flag-hint"
|
|
43
|
+
};
|
|
44
|
+
const _hoisted_16 = {
|
|
45
|
+
key: 4,
|
|
46
|
+
class: "cn-attention-flag__act"
|
|
47
|
+
};
|
|
48
|
+
const _hoisted_17 = {
|
|
49
|
+
key: 5,
|
|
39
50
|
class: "cn-attention-flag__refusal",
|
|
40
51
|
role: "alert",
|
|
41
52
|
"data-testid": "cn-attention-flag-refusal"
|
|
42
53
|
};
|
|
43
|
-
const
|
|
44
|
-
key:
|
|
54
|
+
const _hoisted_18 = {
|
|
55
|
+
key: 6,
|
|
45
56
|
class: "cn-attention-flag__list",
|
|
46
57
|
"data-testid": "cn-attention-flag-history"
|
|
47
58
|
};
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
59
|
+
const _hoisted_19 = ["data-act"];
|
|
60
|
+
const _hoisted_20 = { class: "cn-attention-flag__lead" };
|
|
61
|
+
const _hoisted_21 = { class: "cn-attention-flag__muted" };
|
|
51
62
|
|
|
52
63
|
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
53
|
-
const
|
|
64
|
+
const _component_FlagOutline = resolveComponent("FlagOutline");
|
|
54
65
|
const _component_NcButton = resolveComponent("NcButton");
|
|
66
|
+
const _component_NcTextField = resolveComponent("NcTextField");
|
|
55
67
|
|
|
56
68
|
return ($data.loaded)
|
|
57
69
|
? (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
@@ -88,38 +100,57 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
88
100
|
: createCommentVNode("v-if", true)
|
|
89
101
|
]))
|
|
90
102
|
: createCommentVNode("v-if", true),
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
($options.behindButton && !$data.composing)
|
|
104
|
+
? (openBlock(), createElementBlock(Fragment, { key: 3 }, [
|
|
105
|
+
createElementVNode("h4", _hoisted_14, toDisplayString($options.reasonLabel), 1 /* TEXT */),
|
|
106
|
+
createElementVNode("p", _hoisted_15, toDisplayString($data.raised ? $options.label('hintClear') : $options.label('hintRaise')), 1 /* TEXT */),
|
|
107
|
+
createVNode(_component_NcButton, {
|
|
108
|
+
variant: "secondary",
|
|
109
|
+
wide: "",
|
|
110
|
+
"data-testid": "cn-attention-flag-compose",
|
|
111
|
+
onClick: _cache[0] || (_cache[0] = $event => ($data.composing = true))
|
|
112
|
+
}, {
|
|
113
|
+
icon: withCtx(() => [
|
|
114
|
+
createVNode(_component_FlagOutline, { size: 20 })
|
|
115
|
+
]),
|
|
116
|
+
default: withCtx(() => [
|
|
117
|
+
createTextVNode(" " + toDisplayString($data.raised ? $options.label('clear') : $options.label('raise')), 1 /* TEXT */)
|
|
118
|
+
]),
|
|
119
|
+
_: 1 /* STABLE */
|
|
120
|
+
})
|
|
121
|
+
], 64 /* STABLE_FRAGMENT */))
|
|
122
|
+
: (openBlock(), createElementBlock("div", _hoisted_16, [
|
|
123
|
+
createVNode(_component_NcTextField, {
|
|
124
|
+
modelValue: $data.reason,
|
|
125
|
+
label: $options.reasonLabel,
|
|
126
|
+
"data-testid": "cn-attention-flag-reason",
|
|
127
|
+
"onUpdate:modelValue": $options.onReason
|
|
128
|
+
}, null, 8 /* PROPS */, ["modelValue", "label", "onUpdate:modelValue"]),
|
|
129
|
+
createVNode(_component_NcButton, {
|
|
130
|
+
variant: "tertiary",
|
|
131
|
+
disabled: $data.busy || $data.reason.trim() === '',
|
|
132
|
+
"data-testid": $data.raised ? 'cn-attention-flag-clear' : 'cn-attention-flag-raise',
|
|
133
|
+
onClick: $options.submit
|
|
134
|
+
}, {
|
|
135
|
+
default: withCtx(() => [
|
|
136
|
+
createTextVNode(toDisplayString($data.raised ? $options.label('clear') : $options.label('raise')), 1 /* TEXT */)
|
|
137
|
+
]),
|
|
138
|
+
_: 1 /* STABLE */
|
|
139
|
+
}, 8 /* PROPS */, ["disabled", "data-testid", "onClick"])
|
|
140
|
+
])),
|
|
110
141
|
($data.refusal)
|
|
111
|
-
? (openBlock(), createElementBlock("p",
|
|
142
|
+
? (openBlock(), createElementBlock("p", _hoisted_17, toDisplayString($data.refusal), 1 /* TEXT */))
|
|
112
143
|
: createCommentVNode("v-if", true),
|
|
113
144
|
($data.history.length > 0)
|
|
114
|
-
? (openBlock(), createElementBlock("ol",
|
|
145
|
+
? (openBlock(), createElementBlock("ol", _hoisted_18, [
|
|
115
146
|
(openBlock(true), createElementBlock(Fragment, null, renderList($data.history, (row, index) => {
|
|
116
147
|
return (openBlock(), createElementBlock("li", {
|
|
117
148
|
key: `${row.moment}-${index}`,
|
|
118
149
|
"data-act": row.act
|
|
119
150
|
}, [
|
|
120
|
-
createElementVNode("span",
|
|
121
|
-
createElementVNode("span",
|
|
122
|
-
], 8 /* PROPS */,
|
|
151
|
+
createElementVNode("span", _hoisted_20, toDisplayString(row.act === 'cleared' ? $options.label('cleared') : $options.label('raised')), 1 /* TEXT */),
|
|
152
|
+
createElementVNode("span", _hoisted_21, toDisplayString(row.reason), 1 /* TEXT */)
|
|
153
|
+
], 8 /* PROPS */, _hoisted_19))
|
|
123
154
|
}), 128 /* KEYED_FRAGMENT */))
|
|
124
155
|
]))
|
|
125
156
|
: createCommentVNode("v-if", true)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAttentionFlagWidget.vue3.js","sources":["../../../../src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue?vue&type=template&id=21e92a64&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div v-if=\"loaded\" class=\"cn-attention-flag\" data-testid=\"cn-attention-flag\">\n\t\t<p\n\t\t\tv-if=\"raised\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-raised\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('raisedLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ flagReason }}</span>\n\t\t</p>\n\n\t\t<ul\n\t\t\tv-if=\"markers.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-markers\">\n\t\t\t<li\n\t\t\t\tv-for=\"marker in markers\"\n\t\t\t\t:key=\"marker.marker\"\n\t\t\t\t:data-testid=\"`cn-attention-flag-marker-${marker.marker}`\"\n\t\t\t\t:data-tab=\"marker.tab\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ marker.panelLabel }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ marker.reason }}</span>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p\n\t\t\tv-if=\"assessment\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-assessment\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('assessmentLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__lead\" :data-level=\"assessment.level\">{{ assessment.levelLabel }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ assessment.ground }}</span>\n\t\t\t<span\n\t\t\t\tv-if=\"assessment.dueForReview\"\n\t\t\t\tclass=\"cn-attention-flag__due\"\n\t\t\t\tdata-testid=\"cn-attention-flag-review-due\">{{ label('reviewDue') }}</span>\n\t\t</p>\n\n\t\t<div class=\"cn-attention-flag__act\">\n\t\t\t<NcTextField\n\t\t\t\t:modelValue=\"reason\"\n\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\tdata-testid=\"cn-attention-flag-reason\"\n\t\t\t\t@update:modelValue=\"onReason\" />\n\t\t\t<NcButton\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\t:data-testid=\"raised ? 'cn-attention-flag-clear' : 'cn-attention-flag-raise'\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<p\n\t\t\tv-if=\"refusal\"\n\t\t\tclass=\"cn-attention-flag__refusal\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-attention-flag-refusal\">\n\t\t\t{{ refusal }}\n\t\t</p>\n\n\t\t<ol\n\t\t\tv-if=\"history.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-history\">\n\t\t\t<li\n\t\t\t\tv-for=\"(row, index) in history\"\n\t\t\t\t:key=\"`${row.moment}-${index}`\"\n\t\t\t\t:data-act=\"row.act\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ row.act === 'cleared' ? label('cleared') : label('raised') }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ row.reason }}</span>\n\t\t\t</li>\n\t\t</ol>\n\t</div>\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, NcTextField } from '@nextcloud/vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { dispatchObjectsChanged } from '../../utils/objectSignals.js'\nimport { readPath } from '../../utils/readPath.js'\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\traisedLead: t('nextcloud-vue', 'Flagged as needing attention:'),\n\t\tassessmentLead: t('nextcloud-vue', 'Assessed risk:'),\n\t\treviewDue: t('nextcloud-vue', 'Due for review'),\n\t\treasonRaise: t('nextcloud-vue', 'Why this needs attention'),\n\t\treasonClear: t('nextcloud-vue', 'Why it no longer needs attention'),\n\t\traise: t('nextcloud-vue', 'Flag for attention'),\n\t\tclear: t('nextcloud-vue', 'Clear the flag'),\n\t\traised: t('nextcloud-vue', 'Raised'),\n\t\tcleared: t('nextcloud-vue', 'Cleared'),\n\t\tfailed: t('nextcloud-vue', 'This did not work. Try again.'),\n\t}\n}\n\n/** The assessed levels a record may carry, with their default words. */\nconst LEVELS = {\n\tlow: 'Low',\n\tmedium: 'Medium',\n\thigh: 'High',\n\tcritical: 'Critical',\n}\n\n/**\n * CnAttentionFlagWidget — the `attention-flag` widget: a flag a PERSON raises\n * on a record with a reason, the markers the SYSTEM raised against a part of\n * it, and an assessment the ORGANISATION made, kept apart on one strip.\n *\n * ```json\n * {\n * \"type\": \"attention-flag\",\n * \"content\": {\n * \"endpoint\": \"/apps/myapp/api/item/@objectId/attention\",\n * \"raisePath\": \"/raise\",\n * \"clearPath\": \"/clear\",\n * \"markersPath\": \"attentionMarkers\",\n * \"panelLabels\": { \"item-files\": \"Files\" },\n * \"assessment\": { \"path\": \"riskAssessment\", \"levelMap\": { \"high\": \"High\" }, \"reviewDateField\": \"reviewDate\" }\n * }\n * }\n * ```\n *\n * The endpoint answers `{ raised, flag: { reason }, history: [{ act, reason, moment }] }`\n * on GET, and the same after a POST of `{ reason }` to `raisePath` or\n * `clearPath`. A reason is required in both directions: the button stays\n * disabled without one, and the server's refusal sentence (`error`) is shown\n * as written. Markers and the assessment are read off the record the page\n * already holds. An assessment the reader may not see is absent from the\n * record, so it is absent here rather than blank. A failed read draws\n * nothing. After a raise or a clear the widget emits `object-changed`, says\n * so to every list (`dispatchObjectsChanged`) and asks the page to refresh.\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-can-carry-an-attention-flag\n */\nexport default {\n\tname: 'CnAttentionFlagWidget',\n\n\tcomponents: { NcButton, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `endpoint` (tokens `@objectId`, `@object.<field>`),\n\t\t * `raisePath` (default `/raise`), `clearPath` (default `/clear`),\n\t\t * `labels` (overrides of the default words), `markersPath`,\n\t\t * `panelLabels` (marker tab id to label) and `assessment`\n\t\t * (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail-page host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register, for the changed-objects signal. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema, for the changed-objects signal. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['object-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloaded: false,\n\t\t\tbusy: false,\n\t\t\traised: false,\n\t\t\tflag: {},\n\t\t\thistory: [],\n\t\t\treason: '',\n\t\t\trefusal: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The flag endpoint with its tokens filled, or '' while a token is not known.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tendpoint() {\n\t\t\tconst raw = typeof this.content?.endpoint === 'string' ? this.content.endpoint : ''\n\t\t\tif (raw === '' || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn interpolateUrlTokens(raw, { objectId: this.objectId, object: this.objectData || {} })\n\t\t},\n\n\t\t/** @return {string} What the raise or clear was for, in the flag's own words. */\n\t\tflagReason() {\n\t\t\treturn String(this.flag?.reason ?? '')\n\t\t},\n\n\t\t/** @return {string} The label over the reason field, naming the act it is for. */\n\t\treasonLabel() {\n\t\t\treturn this.raised ? this.label('reasonClear') : this.label('reasonRaise')\n\t\t},\n\n\t\t/**\n\t\t * The markers on the record, each naming the part it points at.\n\t\t *\n\t\t * @return {Array<{marker: string, tab: string, reason: string, panelLabel: string}>}\n\t\t */\n\t\tmarkers() {\n\t\t\tconst path = this.content?.markersPath\n\t\t\tif (typeof path !== 'string' || path === '' || !this.objectData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst raw = readPath(this.objectData, path)\n\t\t\tif (!Array.isArray(raw)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst panelLabels = this.content?.panelLabels && typeof this.content.panelLabels === 'object' ? this.content.panelLabels : {}\n\t\t\treturn raw\n\t\t\t\t.filter((marker) => marker && String(marker.marker ?? '') !== '')\n\t\t\t\t.map((marker) => {\n\t\t\t\t\tconst tab = String(marker.tab ?? '')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmarker: String(marker.marker),\n\t\t\t\t\t\ttab,\n\t\t\t\t\t\treason: String(marker.reason ?? ''),\n\t\t\t\t\t\tpanelLabel: this.cnTranslate(panelLabels[tab] || tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The assessment, or null when the record carries none or the reader\n\t\t * may not see it (OpenRegister leaves the property out).\n\t\t *\n\t\t * @return {{level: string, levelLabel: string, ground: string, dueForReview: boolean}|null}\n\t\t */\n\t\tassessment() {\n\t\t\tconst config = this.content?.assessment\n\t\t\tif (!config || typeof config !== 'object' || typeof config.path !== 'string' || !this.objectData) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst stored = readPath(this.objectData, config.path)\n\t\t\tif (!stored || typeof stored !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst level = String(stored[config.levelField || 'level'] ?? '')\n\t\t\tif (level === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst levelMap = config.levelMap && typeof config.levelMap === 'object' ? config.levelMap : {}\n\t\t\tconst word = levelMap[level] || LEVELS[level]\n\t\t\treturn {\n\t\t\t\tlevel,\n\t\t\t\tlevelLabel: word ? this.cnTranslate(word) : level,\n\t\t\t\tground: String(stored[config.groundField || 'ground'] ?? ''),\n\t\t\t\tdueForReview: hasPassed(String(stored[config.reviewDateField || 'reviewDate'] ?? '')),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tendpoint: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A label: the content's own (through the host translate), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string} The text.\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * Read where the flag stands. A failure draws nothing: an instance that\n\t\t * does not carry the endpoint answers 404, and nothing else depends on it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (this.endpoint === '') {\n\t\t\t\tthis.loaded = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(this.endpoint))\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.loaded = true\n\t\t\t} catch {\n\t\t\t\tthis.loaded = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Take the answer of a read or an act.\n\t\t *\n\t\t * @param {object} state What the endpoint answered.\n\t\t * @return {void}\n\t\t */\n\t\tapply(state) {\n\t\t\tthis.raised = state?.raised === true\n\t\t\tthis.flag = state?.flag ?? {}\n\t\t\tthis.history = Array.isArray(state?.history) ? state.history : []\n\t\t},\n\n\t\t/**\n\t\t * Keep the typed reason, so the button knows whether there is one.\n\t\t *\n\t\t * @param {string} value The field's value.\n\t\t * @return {void}\n\t\t */\n\t\tonReason(value) {\n\t\t\tthis.reason = String(value ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Raise the flag, or clear it, with the reason that was written.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tconst reason = this.reason.trim()\n\t\t\tif (reason === '' || this.endpoint === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst tail = this.raised ? (this.content?.clearPath || '/clear') : (this.content?.raisePath || '/raise')\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(this.endpoint + tail), { reason })\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.reason = ''\n\t\t\t\tthis.announce()\n\t\t\t} catch (error) {\n\t\t\t\tconst said = String(error?.response?.data?.error ?? error?.response?.data?.message ?? '')\n\t\t\t\tthis.refusal = said !== '' ? said : this.label('failed')\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Say the record changed: to the host, to every list showing it, and\n\t\t * to the page so it reads the record again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tannounce() {\n\t\t\tconst id = String(this.objectId || '')\n\t\t\t/** @event object-changed The flag was raised or cleared: `{ register, schema, id }` of the record. */\n\t\t\tthis.$emit('object-changed', { register: this.register, schema: this.schema, id })\n\t\t\tdispatchObjectsChanged({ register: typeof this.register === 'string' ? this.register : '', schema: typeof this.schema === 'string' ? this.schema : '', id })\n\t\t\temit('cn:page:refresh')\n\t\t},\n\t},\n}\n\n/**\n * Whether a date lies before today. The date named is the last day the\n * assessment is still good for, so a review date of today is not yet due.\n *\n * @param {string} date The date.\n * @return {boolean} True when it has passed.\n */\nfunction hasPassed(date) {\n\tif (date === '') {\n\t\treturn false\n\t}\n\tconst moment = new Date(date)\n\tif (Number.isNaN(moment.getTime())) {\n\t\treturn false\n\t}\n\treturn moment.toISOString().slice(0, 10) < new Date().toISOString().slice(0, 10)\n}\n</script>\n\n<style scoped>\n.cn-attention-flag {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 4px 0;\n}\n\n.cn-attention-flag__line,\n.cn-attention-flag__act {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n}\n\n.cn-attention-flag__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-attention-flag__list li {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n.cn-attention-flag__lead {\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-attention-flag__due {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-attention-flag__refusal {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList","_createVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAttentionFlagWidget.vue3.js","sources":["../../../../src/components/CnAttentionFlagWidget/CnAttentionFlagWidget.vue?vue&type=template&id=7e3434fc&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div v-if=\"loaded\" class=\"cn-attention-flag\" data-testid=\"cn-attention-flag\">\n\t\t<p\n\t\t\tv-if=\"raised\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-raised\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('raisedLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ flagReason }}</span>\n\t\t</p>\n\n\t\t<ul\n\t\t\tv-if=\"markers.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-markers\">\n\t\t\t<li\n\t\t\t\tv-for=\"marker in markers\"\n\t\t\t\t:key=\"marker.marker\"\n\t\t\t\t:data-testid=\"`cn-attention-flag-marker-${marker.marker}`\"\n\t\t\t\t:data-tab=\"marker.tab\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ marker.panelLabel }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ marker.reason }}</span>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p\n\t\t\tv-if=\"assessment\"\n\t\t\tclass=\"cn-attention-flag__line\"\n\t\t\tdata-testid=\"cn-attention-flag-assessment\">\n\t\t\t<span class=\"cn-attention-flag__lead\">{{ label('assessmentLead') }}</span>\n\t\t\t<span class=\"cn-attention-flag__lead\" :data-level=\"assessment.level\">{{ assessment.levelLabel }}</span>\n\t\t\t<span class=\"cn-attention-flag__muted\">{{ assessment.ground }}</span>\n\t\t\t<span\n\t\t\t\tv-if=\"assessment.dueForReview\"\n\t\t\t\tclass=\"cn-attention-flag__due\"\n\t\t\t\tdata-testid=\"cn-attention-flag-review-due\">{{ label('reviewDue') }}</span>\n\t\t</p>\n\n\t\t<template v-if=\"behindButton && !composing\">\n\t\t\t<h4 class=\"cn-attention-flag__heading\" data-testid=\"cn-attention-flag-heading\">\n\t\t\t\t{{ reasonLabel }}\n\t\t\t</h4>\n\t\t\t<p class=\"cn-attention-flag__hint\" data-testid=\"cn-attention-flag-hint\">\n\t\t\t\t{{ raised ? label('hintClear') : label('hintRaise') }}\n\t\t\t</p>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\twide\n\t\t\t\tdata-testid=\"cn-attention-flag-compose\"\n\t\t\t\t@click=\"composing = true\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<FlagOutline :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</template>\n\n\t\t<div v-else class=\"cn-attention-flag__act\">\n\t\t\t<NcTextField\n\t\t\t\t:modelValue=\"reason\"\n\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\tdata-testid=\"cn-attention-flag-reason\"\n\t\t\t\t@update:modelValue=\"onReason\" />\n\t\t\t<NcButton\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\t:data-testid=\"raised ? 'cn-attention-flag-clear' : 'cn-attention-flag-raise'\"\n\t\t\t\t@click=\"submit\">\n\t\t\t\t{{ raised ? label('clear') : label('raise') }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<p\n\t\t\tv-if=\"refusal\"\n\t\t\tclass=\"cn-attention-flag__refusal\"\n\t\t\trole=\"alert\"\n\t\t\tdata-testid=\"cn-attention-flag-refusal\">\n\t\t\t{{ refusal }}\n\t\t</p>\n\n\t\t<ol\n\t\t\tv-if=\"history.length > 0\"\n\t\t\tclass=\"cn-attention-flag__list\"\n\t\t\tdata-testid=\"cn-attention-flag-history\">\n\t\t\t<li\n\t\t\t\tv-for=\"(row, index) in history\"\n\t\t\t\t:key=\"`${row.moment}-${index}`\"\n\t\t\t\t:data-act=\"row.act\">\n\t\t\t\t<span class=\"cn-attention-flag__lead\">{{ row.act === 'cleared' ? label('cleared') : label('raised') }}</span>\n\t\t\t\t<span class=\"cn-attention-flag__muted\">{{ row.reason }}</span>\n\t\t\t</li>\n\t\t</ol>\n\t</div>\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, NcTextField } from '@nextcloud/vue'\nimport FlagOutline from 'vue-material-design-icons/FlagOutline.vue'\nimport { interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { dispatchObjectsChanged } from '../../utils/objectSignals.js'\nimport { readPath } from '../../utils/readPath.js'\n\n/**\n * The default words, keyed as `content.labels` overrides them.\n *\n * @return {object} The labels.\n */\nfunction defaultLabels() {\n\treturn {\n\t\traisedLead: t('nextcloud-vue', 'Flagged as needing attention:'),\n\t\tassessmentLead: t('nextcloud-vue', 'Assessed risk:'),\n\t\treviewDue: t('nextcloud-vue', 'Due for review'),\n\t\treasonRaise: t('nextcloud-vue', 'Why this needs attention'),\n\t\treasonClear: t('nextcloud-vue', 'Why it no longer needs attention'),\n\t\thintRaise: t('nextcloud-vue', 'Flag it with a reason, so it stands out to everyone who works on it.'),\n\t\thintClear: t('nextcloud-vue', 'Clear the flag with a reason once it no longer needs attention.'),\n\t\traise: t('nextcloud-vue', 'Flag for attention'),\n\t\tclear: t('nextcloud-vue', 'Clear the flag'),\n\t\traised: t('nextcloud-vue', 'Raised'),\n\t\tcleared: t('nextcloud-vue', 'Cleared'),\n\t\tfailed: t('nextcloud-vue', 'This did not work. Try again.'),\n\t}\n}\n\n/** The assessed levels a record may carry, with their default words. */\nconst LEVELS = {\n\tlow: 'Low',\n\tmedium: 'Medium',\n\thigh: 'High',\n\tcritical: 'Critical',\n}\n\n/**\n * CnAttentionFlagWidget — the `attention-flag` widget: a flag a PERSON raises\n * on a record with a reason, the markers the SYSTEM raised against a part of\n * it, and an assessment the ORGANISATION made, kept apart on one strip.\n *\n * ```json\n * {\n * \"type\": \"attention-flag\",\n * \"content\": {\n * \"endpoint\": \"/apps/myapp/api/item/@objectId/attention\",\n * \"raisePath\": \"/raise\",\n * \"clearPath\": \"/clear\",\n * \"markersPath\": \"attentionMarkers\",\n * \"panelLabels\": { \"item-files\": \"Files\" },\n * \"assessment\": { \"path\": \"riskAssessment\", \"levelMap\": { \"high\": \"High\" }, \"reviewDateField\": \"reviewDate\" },\n * \"behindButton\": true\n * }\n * }\n * ```\n *\n * The endpoint answers `{ raised, flag: { reason }, history: [{ act, reason, moment }] }`\n * on GET, and the same after a POST of `{ reason }` to `raisePath` or\n * `clearPath`. A reason is required in both directions: the button stays\n * disabled without one, and the server's refusal sentence (`error`) is shown\n * as written. Markers and the assessment are read off the record the page\n * already holds. An assessment the reader may not see is absent from the\n * record, so it is absent here rather than blank. A failed read draws\n * nothing. With `behindButton` the strip shows the act as a heading, a hint\n * (`labels.hintRaise` / `labels.hintClear`) and one button, and the reason\n * field opens when that button is pressed. After a raise or a clear the widget emits `object-changed`, says\n * so to every list (`dispatchObjectsChanged`) and asks the page to refresh.\n *\n * @spec openspec/changes/dq-abstract-record-widgets/specs/record-widgets/spec.md#requirement-a-record-can-carry-an-attention-flag\n */\nexport default {\n\tname: 'CnAttentionFlagWidget',\n\n\tcomponents: { FlagOutline, NcButton, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The configuration: `endpoint` (tokens `@objectId`, `@object.<field>`),\n\t\t * `raisePath` (default `/raise`), `clearPath` (default `/clear`),\n\t\t * `labels` (overrides of the default words), `markersPath`,\n\t\t * `panelLabels` (marker tab id to label) and `assessment`\n\t\t * (`{ path, levelMap?, levelField?, groundField?, reviewDateField? }`)\n\t\t * and `behindButton` (the reason field opens from a button).\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, bound by the detail-page host. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The loaded record, or null while it is fetched. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's register, for the changed-objects signal. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The record's schema, for the changed-objects signal. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['object-changed'],\n\n\tdata() {\n\t\treturn {\n\t\t\tloaded: false,\n\t\t\tbusy: false,\n\t\t\traised: false,\n\t\t\tflag: {},\n\t\t\thistory: [],\n\t\t\treason: '',\n\t\t\trefusal: '',\n\t\t\tcomposing: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The flag endpoint with its tokens filled, or '' while a token is not known.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tendpoint() {\n\t\t\tconst raw = typeof this.content?.endpoint === 'string' ? this.content.endpoint : ''\n\t\t\tif (raw === '' || !this.objectId) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn interpolateUrlTokens(raw, { objectId: this.objectId, object: this.objectData || {} })\n\t\t},\n\n\t\t/** @return {boolean} Whether the reason field waits behind a button. */\n\t\tbehindButton() {\n\t\t\treturn this.content?.behindButton === true\n\t\t},\n\n\t\t/** @return {string} What the raise or clear was for, in the flag's own words. */\n\t\tflagReason() {\n\t\t\treturn String(this.flag?.reason ?? '')\n\t\t},\n\n\t\t/** @return {string} The label over the reason field, naming the act it is for. */\n\t\treasonLabel() {\n\t\t\treturn this.raised ? this.label('reasonClear') : this.label('reasonRaise')\n\t\t},\n\n\t\t/**\n\t\t * The markers on the record, each naming the part it points at.\n\t\t *\n\t\t * @return {Array<{marker: string, tab: string, reason: string, panelLabel: string}>}\n\t\t */\n\t\tmarkers() {\n\t\t\tconst path = this.content?.markersPath\n\t\t\tif (typeof path !== 'string' || path === '' || !this.objectData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst raw = readPath(this.objectData, path)\n\t\t\tif (!Array.isArray(raw)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst panelLabels = this.content?.panelLabels && typeof this.content.panelLabels === 'object' ? this.content.panelLabels : {}\n\t\t\treturn raw\n\t\t\t\t.filter((marker) => marker && String(marker.marker ?? '') !== '')\n\t\t\t\t.map((marker) => {\n\t\t\t\t\tconst tab = String(marker.tab ?? '')\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmarker: String(marker.marker),\n\t\t\t\t\t\ttab,\n\t\t\t\t\t\treason: String(marker.reason ?? ''),\n\t\t\t\t\t\tpanelLabel: this.cnTranslate(panelLabels[tab] || tab),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * The assessment, or null when the record carries none or the reader\n\t\t * may not see it (OpenRegister leaves the property out).\n\t\t *\n\t\t * @return {{level: string, levelLabel: string, ground: string, dueForReview: boolean}|null}\n\t\t */\n\t\tassessment() {\n\t\t\tconst config = this.content?.assessment\n\t\t\tif (!config || typeof config !== 'object' || typeof config.path !== 'string' || !this.objectData) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst stored = readPath(this.objectData, config.path)\n\t\t\tif (!stored || typeof stored !== 'object') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst level = String(stored[config.levelField || 'level'] ?? '')\n\t\t\tif (level === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst levelMap = config.levelMap && typeof config.levelMap === 'object' ? config.levelMap : {}\n\t\t\tconst word = levelMap[level] || LEVELS[level]\n\t\t\treturn {\n\t\t\t\tlevel,\n\t\t\t\tlevelLabel: word ? this.cnTranslate(word) : level,\n\t\t\t\tground: String(stored[config.groundField || 'ground'] ?? ''),\n\t\t\t\tdueForReview: hasPassed(String(stored[config.reviewDateField || 'reviewDate'] ?? '')),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\tendpoint: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A label: the content's own (through the host translate), else the default.\n\t\t *\n\t\t * @param {string} key The label key.\n\t\t * @return {string} The text.\n\t\t */\n\t\tlabel(key) {\n\t\t\tconst own = this.content?.labels && typeof this.content.labels[key] === 'string' ? this.content.labels[key] : ''\n\t\t\treturn own !== '' ? this.cnTranslate(own) : defaultLabels()[key]\n\t\t},\n\n\t\t/**\n\t\t * Read where the flag stands. A failure draws nothing: an instance that\n\t\t * does not carry the endpoint answers 404, and nothing else depends on it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (this.endpoint === '') {\n\t\t\t\tthis.loaded = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst response = await axios.get(generateUrl(this.endpoint))\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.loaded = true\n\t\t\t} catch {\n\t\t\t\tthis.loaded = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Take the answer of a read or an act.\n\t\t *\n\t\t * @param {object} state What the endpoint answered.\n\t\t * @return {void}\n\t\t */\n\t\tapply(state) {\n\t\t\tthis.raised = state?.raised === true\n\t\t\tthis.flag = state?.flag ?? {}\n\t\t\tthis.history = Array.isArray(state?.history) ? state.history : []\n\t\t},\n\n\t\t/**\n\t\t * Keep the typed reason, so the button knows whether there is one.\n\t\t *\n\t\t * @param {string} value The field's value.\n\t\t * @return {void}\n\t\t */\n\t\tonReason(value) {\n\t\t\tthis.reason = String(value ?? '')\n\t\t},\n\n\t\t/**\n\t\t * Raise the flag, or clear it, with the reason that was written.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync submit() {\n\t\t\tconst reason = this.reason.trim()\n\t\t\tif (reason === '' || this.endpoint === '') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst tail = this.raised ? (this.content?.clearPath || '/clear') : (this.content?.raisePath || '/raise')\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(generateUrl(this.endpoint + tail), { reason })\n\t\t\t\tthis.apply(response?.data)\n\t\t\t\tthis.reason = ''\n\t\t\t\tthis.composing = false\n\t\t\t\tthis.announce()\n\t\t\t} catch (error) {\n\t\t\t\tconst said = String(error?.response?.data?.error ?? error?.response?.data?.message ?? '')\n\t\t\t\tthis.refusal = said !== '' ? said : this.label('failed')\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Say the record changed: to the host, to every list showing it, and\n\t\t * to the page so it reads the record again.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tannounce() {\n\t\t\tconst id = String(this.objectId || '')\n\t\t\t/** @event object-changed The flag was raised or cleared: `{ register, schema, id }` of the record. */\n\t\t\tthis.$emit('object-changed', { register: this.register, schema: this.schema, id })\n\t\t\tdispatchObjectsChanged({ register: typeof this.register === 'string' ? this.register : '', schema: typeof this.schema === 'string' ? this.schema : '', id })\n\t\t\temit('cn:page:refresh')\n\t\t},\n\t},\n}\n\n/**\n * Whether a date lies before today. The date named is the last day the\n * assessment is still good for, so a review date of today is not yet due.\n *\n * @param {string} date The date.\n * @return {boolean} True when it has passed.\n */\nfunction hasPassed(date) {\n\tif (date === '') {\n\t\treturn false\n\t}\n\tconst moment = new Date(date)\n\tif (Number.isNaN(moment.getTime())) {\n\t\treturn false\n\t}\n\treturn moment.toISOString().slice(0, 10) < new Date().toISOString().slice(0, 10)\n}\n</script>\n\n<style scoped>\n.cn-attention-flag {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tpadding: 4px 0;\n}\n\n.cn-attention-flag__line,\n.cn-attention-flag__act {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n}\n\n.cn-attention-flag__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-attention-flag__list li {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n\n.cn-attention-flag__lead {\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__heading {\n\tmargin: 0;\n\tfont-size: 14px;\n\tfont-weight: bold;\n}\n\n.cn-attention-flag__hint {\n\tmargin: 0 0 8px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-attention-flag__muted {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-attention-flag__due {\n\tcolor: var(--color-warning-text, var(--color-main-text));\n}\n\n.cn-attention-flag__refusal {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList","_createVNode","_createTextVNode"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnChartWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnChartWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-7636430b";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|