@conduction/nextcloud-vue 2.114.0 → 2.115.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/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +6 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
- package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +2 -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 +19 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +2 -2
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +37 -1
- 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/CnIndexPage/rowsToCsv.js +90 -0
- package/dist/esm/components/CnIndexPage/rowsToCsv.js.map +1 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue.js +9 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue.js.map +1 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue2.js +161 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue3.js +97 -0
- package/dist/esm/components/CnMacrosWidget/CnMacrosWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue.js +9 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue2.js +63 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue2.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue3.js +54 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue3.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js +15 -9
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js +55 -63
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +2 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +13 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +2 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnStepper/CnStepper.vue.js +1 -1
- package/dist/esm/components/CnStepper/CnStepper.vue2.js.map +1 -1
- package/dist/esm/components/CnStepper/CnStepper.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +10 -5
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue.js +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +2 -2
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +32 -20
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/composables/indexSources.js +43 -11
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useTaskInboxStore.js +41 -0
- package/dist/esm/composables/useTaskInboxStore.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +4 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +9 -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 +482 -330
- package/dist/esm/utils/contentHeaderLink.js +37 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/declaredMacros.js +31 -0
- package/dist/esm/utils/declaredMacros.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +2673 -1977
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +482 -330
- package/l10n/en.json +4 -1
- package/l10n/nl.json +9 -1
- package/package.json +1 -1
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +1 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +6 -2
- package/src/components/CnChoiceCards/CnChoiceCards.vue +2 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +45 -3
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +37 -1
- package/src/components/CnIndexPage/rowsToCsv.js +87 -0
- package/src/components/CnMacrosWidget/CnMacrosWidget.md +30 -0
- package/src/components/CnMacrosWidget/CnMacrosWidget.vue +266 -0
- package/src/components/CnMacrosWidget/index.js +6 -0
- package/src/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue +104 -0
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +53 -38
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +2 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +28 -4
- package/src/components/CnStepper/CnStepper.vue +2 -1
- package/src/components/CnTabsWidget/CnTabsWidget.vue +11 -6
- package/src/components/CnTasksWidget/CnTasksWidget.vue +2 -2
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/src/components/index.js +1 -0
- package/src/composables/indexSources.js +43 -11
- package/src/composables/useTaskInboxStore.js +41 -0
- package/src/css/look-board-detail.css +4 -3
- package/src/css/look-board-index.css +62 -0
- package/src/css/look-board.css +20 -0
- package/src/index.js +1 -0
- package/src/utils/contentHeaderLink.js +35 -0
- package/src/utils/declaredMacros.js +28 -0
- package/src/utils/libraryWidgetKeys.js +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* The rows a list shows, as a CSV file: one column per table column, headed by
|
|
6
|
+
* its label. Used by an index page whose rows come from a named or endpoint
|
|
7
|
+
* source, which has no server export of its own.
|
|
8
|
+
*
|
|
9
|
+
* @spec openspec/changes/index-named-source-export/specs/index-named-source-export/spec.md#requirement-a-named-source-list-downloads-its-rows
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A value as the text of one CSV cell. A list joins its items, a record reads
|
|
14
|
+
* its name, an empty value is an empty cell.
|
|
15
|
+
*
|
|
16
|
+
* @param {unknown} value The cell value.
|
|
17
|
+
* @return {string} The cell text.
|
|
18
|
+
*/
|
|
19
|
+
function cellText(value) {
|
|
20
|
+
if (value === null || value === undefined) {
|
|
21
|
+
return ''
|
|
22
|
+
}
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
return value.map(cellText).filter((item) => item !== '').join('; ')
|
|
25
|
+
}
|
|
26
|
+
if (typeof value === 'object') {
|
|
27
|
+
for (const key of ['title', 'name', 'label', 'displayName', 'id']) {
|
|
28
|
+
if (value[key] !== undefined && value[key] !== null && typeof value[key] !== 'object') {
|
|
29
|
+
return String(value[key])
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return JSON.stringify(value)
|
|
33
|
+
}
|
|
34
|
+
return String(value)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* One CSV field: quoted when it holds a separator, a quote or a line break,
|
|
39
|
+
* and a leading `=`, `+`, `-` or `@` is neutralised with a `'` so a
|
|
40
|
+
* spreadsheet does not read the cell as a formula.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} text The cell text.
|
|
43
|
+
* @return {string} The field.
|
|
44
|
+
*/
|
|
45
|
+
function csvField(text) {
|
|
46
|
+
let out = String(text);
|
|
47
|
+
if (/^[=+\-@\t\r]/.test(out)) {
|
|
48
|
+
out = `'${out}`;
|
|
49
|
+
}
|
|
50
|
+
return /[",\r\n]/.test(out) ? `"${out.replace(/"/g, '""')}"` : out
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The value of a column in a row: a dotted key reads a nested field, a flat
|
|
55
|
+
* key falls back to the row's `@self`, as the table reads it.
|
|
56
|
+
*
|
|
57
|
+
* @param {object} row The row.
|
|
58
|
+
* @param {string} key The column key.
|
|
59
|
+
* @return {unknown} The value.
|
|
60
|
+
*/
|
|
61
|
+
function columnValue(row, key) {
|
|
62
|
+
if (key.includes('.')) {
|
|
63
|
+
return key.split('.').reduce((obj, part) => obj?.[part], row)
|
|
64
|
+
}
|
|
65
|
+
if (row?.[key] === undefined && row?.['@self'] && typeof row['@self'] === 'object') {
|
|
66
|
+
return row['@self'][key]
|
|
67
|
+
}
|
|
68
|
+
return row?.[key]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The rows as CSV text, a header line of the column labels first. Columns
|
|
73
|
+
* without a key (selection, row actions) are left out.
|
|
74
|
+
*
|
|
75
|
+
* @param {Array<object>} rows The rows.
|
|
76
|
+
* @param {Array<{key: string, label?: string}>} columns The table columns.
|
|
77
|
+
* @return {string} The CSV text, lines ended with CRLF.
|
|
78
|
+
*/
|
|
79
|
+
function rowsToCsv(rows, columns) {
|
|
80
|
+
const cols = (Array.isArray(columns) ? columns : [])
|
|
81
|
+
.filter((col) => col && typeof col.key === 'string' && col.key !== '' && col.widget !== 'actions');
|
|
82
|
+
const lines = [cols.map((col) => csvField(col.label || col.key)).join(',')];
|
|
83
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
84
|
+
lines.push(cols.map((col) => csvField(cellText(columnValue(row, col.key)))).join(','));
|
|
85
|
+
}
|
|
86
|
+
return lines.join('\r\n') + '\r\n'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export { cellText, csvField, rowsToCsv };
|
|
90
|
+
//# sourceMappingURL=rowsToCsv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rowsToCsv.js","sources":["../../../../src/components/CnIndexPage/rowsToCsv.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * The rows a list shows, as a CSV file: one column per table column, headed by\n * its label. Used by an index page whose rows come from a named or endpoint\n * source, which has no server export of its own.\n *\n * @spec openspec/changes/index-named-source-export/specs/index-named-source-export/spec.md#requirement-a-named-source-list-downloads-its-rows\n */\n\n/**\n * A value as the text of one CSV cell. A list joins its items, a record reads\n * its name, an empty value is an empty cell.\n *\n * @param {unknown} value The cell value.\n * @return {string} The cell text.\n */\nexport function cellText(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn value.map(cellText).filter((item) => item !== '').join('; ')\n\t}\n\tif (typeof value === 'object') {\n\t\tfor (const key of ['title', 'name', 'label', 'displayName', 'id']) {\n\t\t\tif (value[key] !== undefined && value[key] !== null && typeof value[key] !== 'object') {\n\t\t\t\treturn String(value[key])\n\t\t\t}\n\t\t}\n\t\treturn JSON.stringify(value)\n\t}\n\treturn String(value)\n}\n\n/**\n * One CSV field: quoted when it holds a separator, a quote or a line break,\n * and a leading `=`, `+`, `-` or `@` is neutralised with a `'` so a\n * spreadsheet does not read the cell as a formula.\n *\n * @param {string} text The cell text.\n * @return {string} The field.\n */\nexport function csvField(text) {\n\tlet out = String(text)\n\tif (/^[=+\\-@\\t\\r]/.test(out)) {\n\t\tout = `'${out}`\n\t}\n\treturn /[\",\\r\\n]/.test(out) ? `\"${out.replace(/\"/g, '\"\"')}\"` : out\n}\n\n/**\n * The value of a column in a row: a dotted key reads a nested field, a flat\n * key falls back to the row's `@self`, as the table reads it.\n *\n * @param {object} row The row.\n * @param {string} key The column key.\n * @return {unknown} The value.\n */\nfunction columnValue(row, key) {\n\tif (key.includes('.')) {\n\t\treturn key.split('.').reduce((obj, part) => obj?.[part], row)\n\t}\n\tif (row?.[key] === undefined && row?.['@self'] && typeof row['@self'] === 'object') {\n\t\treturn row['@self'][key]\n\t}\n\treturn row?.[key]\n}\n\n/**\n * The rows as CSV text, a header line of the column labels first. Columns\n * without a key (selection, row actions) are left out.\n *\n * @param {Array<object>} rows The rows.\n * @param {Array<{key: string, label?: string}>} columns The table columns.\n * @return {string} The CSV text, lines ended with CRLF.\n */\nexport function rowsToCsv(rows, columns) {\n\tconst cols = (Array.isArray(columns) ? columns : [])\n\t\t.filter((col) => col && typeof col.key === 'string' && col.key !== '' && col.widget !== 'actions')\n\tconst lines = [cols.map((col) => csvField(col.label || col.key)).join(',')]\n\tfor (const row of Array.isArray(rows) ? rows : []) {\n\t\tlines.push(cols.map((col) => csvField(cellText(columnValue(row, col.key)))).join(','))\n\t}\n\treturn lines.join('\\r\\n') + '\\r\\n'\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnMacrosWidget.vue2.js';
|
|
2
|
+
import { render } from './CnMacrosWidget.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-982c6094";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnMacrosWidget.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnMacrosWidget.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import axios__default from '@nextcloud/axios';
|
|
2
|
+
import { emit } from '@nextcloud/event-bus';
|
|
3
|
+
import { translate } from '@nextcloud/l10n';
|
|
4
|
+
import { generateUrl } from '@nextcloud/router';
|
|
5
|
+
import { NcButton, NcNoteCard } from '@nextcloud/vue';
|
|
6
|
+
import { declaredMacros } from '../../utils/declaredMacros.js';
|
|
7
|
+
|
|
8
|
+
var script = {
|
|
9
|
+
name: 'CnMacrosWidget',
|
|
10
|
+
|
|
11
|
+
components: {
|
|
12
|
+
NcButton,
|
|
13
|
+
NcNoteCard,
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
inject: {
|
|
17
|
+
cnTranslate: { default: null },
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
props: {
|
|
21
|
+
/**
|
|
22
|
+
* The widget's content: `description` (the line under the title),
|
|
23
|
+
* `emptyText`, both translated.
|
|
24
|
+
*/
|
|
25
|
+
content: {
|
|
26
|
+
type: Object,
|
|
27
|
+
default: () => ({}),
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
/** The bound record. */
|
|
31
|
+
objectData: {
|
|
32
|
+
type: Object,
|
|
33
|
+
default: null,
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/** The bound record's id. */
|
|
37
|
+
objectId: {
|
|
38
|
+
type: [String, Number],
|
|
39
|
+
default: '',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
data() {
|
|
44
|
+
return {
|
|
45
|
+
macros: [],
|
|
46
|
+
loading: false,
|
|
47
|
+
running: '',
|
|
48
|
+
error: '',
|
|
49
|
+
lastRun: null,
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
computed: {
|
|
54
|
+
/** @return {{register: string, schema: string, id: string}} Where the record lives. */
|
|
55
|
+
target() {
|
|
56
|
+
const self = this.objectData?.['@self'] || {};
|
|
57
|
+
return {
|
|
58
|
+
register: String(self.register ?? ''),
|
|
59
|
+
schema: String(self.schema ?? ''),
|
|
60
|
+
id: String(this.objectId || self.id || this.objectData?.id || ''),
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
watch: {
|
|
66
|
+
'target.schema': {
|
|
67
|
+
immediate: true,
|
|
68
|
+
handler() {
|
|
69
|
+
this.load();
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
methods: {
|
|
75
|
+
t: translate,
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Translate an app-supplied text through the host app when it offers it.
|
|
79
|
+
*
|
|
80
|
+
* @param {string} text The text.
|
|
81
|
+
* @return {string} The translated text.
|
|
82
|
+
*/
|
|
83
|
+
tr(text) {
|
|
84
|
+
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read the schema's macros and the record's last macro run.
|
|
89
|
+
*
|
|
90
|
+
* @return {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
async load() {
|
|
93
|
+
const { register, schema, id } = this.target;
|
|
94
|
+
if (schema === '' || id === '') {
|
|
95
|
+
this.macros = [];
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
this.loading = true;
|
|
99
|
+
try {
|
|
100
|
+
const res = await axios__default.get(generateUrl('/apps/openregister/api/schemas/{schema}', { schema }), register ? { params: { register } } : undefined);
|
|
101
|
+
this.macros = declaredMacros(res?.data || null);
|
|
102
|
+
} catch {
|
|
103
|
+
this.macros = [];
|
|
104
|
+
} finally {
|
|
105
|
+
this.loading = false;
|
|
106
|
+
}
|
|
107
|
+
if (this.macros.length > 0) {
|
|
108
|
+
await this.loadLastRun();
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* The record's most recent macro run, from its audit trail. Left empty
|
|
114
|
+
* when the trail cannot be read: it is a convenience, not a fact the
|
|
115
|
+
* widget may invent.
|
|
116
|
+
*
|
|
117
|
+
* @return {Promise<void>}
|
|
118
|
+
*/
|
|
119
|
+
async loadLastRun() {
|
|
120
|
+
const { register, schema, id } = this.target;
|
|
121
|
+
try {
|
|
122
|
+
const res = await axios__default.get(
|
|
123
|
+
generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/audit-trails', { register, schema, id }),
|
|
124
|
+
{ params: { action: 'action.macro', _limit: 1, '_sort[created]': 'DESC' } },
|
|
125
|
+
);
|
|
126
|
+
const entry = (res?.data?.results || [])[0];
|
|
127
|
+
const key = entry?.changed?.declaredAction;
|
|
128
|
+
const macro = this.macros.find((candidate) => candidate.key === key);
|
|
129
|
+
this.lastRun = macro && entry.created
|
|
130
|
+
? { name: macro.name, date: new Date(entry.created).toLocaleString() }
|
|
131
|
+
: null;
|
|
132
|
+
} catch {
|
|
133
|
+
this.lastRun = null;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Run one macro as the person, then ask the page to refresh.
|
|
139
|
+
*
|
|
140
|
+
* @param {{key: string, name: string}} macro The macro.
|
|
141
|
+
* @return {Promise<void>}
|
|
142
|
+
*/
|
|
143
|
+
async run(macro) {
|
|
144
|
+
const { register, schema, id } = this.target;
|
|
145
|
+
this.running = macro.key;
|
|
146
|
+
this.error = '';
|
|
147
|
+
try {
|
|
148
|
+
await axios__default.post(generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/actions/{action}', { register, schema, id, action: macro.key }));
|
|
149
|
+
this.lastRun = { name: macro.name, date: new Date().toLocaleString() };
|
|
150
|
+
emit('cn:page:refresh', { source: 'cn-macros-widget' });
|
|
151
|
+
} catch (e) {
|
|
152
|
+
this.error = translate('nextcloud-vue', 'The macro did not run: {error}', { error: e?.response?.data?.error || e?.message || '' });
|
|
153
|
+
} finally {
|
|
154
|
+
this.running = '';
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export { script as default };
|
|
161
|
+
//# sourceMappingURL=CnMacrosWidget.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnMacrosWidget.vue2.js","sources":["../../../../src/components/CnMacrosWidget/CnMacrosWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<!--\n CnMacrosWidget — the macros a record's schema declares, each with a button\n that runs it (`type: \"macros\"`, DqZaakAssistent \"Macro's\").\n\n A macro is a declared action (`configuration['x-openregister-action']`) with\n `macro: true` and a bound manual flow; OpenRegister runs it as the person,\n under the action's own right, through\n `POST /api/objects/{register}/{schema}/{id}/actions/{action}`. The widget\n lists what the schema declares and runs what is pressed: it adds no rights and\n no list of its own. The last run comes from the record's audit trail\n (`action.macro`), and after a run the page is asked to refresh.\n-->\n<template>\n\t<div class=\"cn-macros-widget\" data-testid=\"cn-macros-widget\">\n\t\t<p v-if=\"content.description\" class=\"cn-macros-widget__description\">\n\t\t\t{{ tr(content.description) }}\n\t\t</p>\n\t\t<p v-if=\"loading\" class=\"cn-macros-widget__muted\">\n\t\t\t{{ t('nextcloud-vue', 'Loading …') }}\n\t\t</p>\n\t\t<p v-else-if=\"macros.length === 0\" class=\"cn-macros-widget__muted\" data-testid=\"cn-macros-widget-empty\">\n\t\t\t{{ content.emptyText ? tr(content.emptyText) : t('nextcloud-vue', 'This record has no macros') }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-macros-widget__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"macro in macros\"\n\t\t\t\t:key=\"macro.key\"\n\t\t\t\tclass=\"cn-macros-widget__row\"\n\t\t\t\t:data-testid=\"`cn-macros-widget-row-${macro.key}`\">\n\t\t\t\t<div class=\"cn-macros-widget__text\">\n\t\t\t\t\t<span class=\"cn-macros-widget__name\">{{ macro.name }}</span>\n\t\t\t\t\t<span v-if=\"macro.description\" class=\"cn-macros-widget__hint\">{{ macro.description }}</span>\n\t\t\t\t</div>\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"running !== ''\"\n\t\t\t\t\t:data-testid=\"`cn-macros-widget-run-${macro.key}`\"\n\t\t\t\t\t@click=\"run(macro)\">\n\t\t\t\t\t{{ running === macro.key ? t('nextcloud-vue', 'Running …') : t('nextcloud-vue', 'Execute') }}\n\t\t\t\t</NcButton>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard\n\t\t\tv-if=\"error\"\n\t\t\ttype=\"error\"\n\t\t\tdata-testid=\"cn-macros-widget-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\t\t<NcNoteCard\n\t\t\tv-else-if=\"lastRun\"\n\t\t\ttype=\"success\"\n\t\t\tdata-testid=\"cn-macros-widget-last-run\">\n\t\t\t{{ t('nextcloud-vue', 'Last run: {name}, {date}', { name: lastRun.name, date: lastRun.date }) }}\n\t\t</NcNoteCard>\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, NcNoteCard } from '@nextcloud/vue'\nimport { declaredMacros } from '../../utils/declaredMacros.js'\n\nexport default {\n\tname: 'CnMacrosWidget',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\tcnTranslate: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's content: `description` (the line under the title),\n\t\t * `emptyText`, both translated.\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The bound record. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tmacros: [],\n\t\t\tloading: false,\n\t\t\trunning: '',\n\t\t\terror: '',\n\t\t\tlastRun: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {{register: string, schema: string, id: string}} Where the record lives. */\n\t\ttarget() {\n\t\t\tconst self = this.objectData?.['@self'] || {}\n\t\t\treturn {\n\t\t\t\tregister: String(self.register ?? ''),\n\t\t\t\tschema: String(self.schema ?? ''),\n\t\t\t\tid: String(this.objectId || self.id || this.objectData?.id || ''),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\t'target.schema': {\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\tt,\n\n\t\t/**\n\t\t * Translate an app-supplied text through the host app when it offers it.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttr(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * Read the schema's macros and the record's last macro run.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\tif (schema === '' || id === '') {\n\t\t\t\tthis.macros = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst res = await axios.get(generateUrl('/apps/openregister/api/schemas/{schema}', { schema }), register ? { params: { register } } : undefined)\n\t\t\t\tthis.macros = declaredMacros(res?.data || null)\n\t\t\t} catch {\n\t\t\t\tthis.macros = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t\tif (this.macros.length > 0) {\n\t\t\t\tawait this.loadLastRun()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The record's most recent macro run, from its audit trail. Left empty\n\t\t * when the trail cannot be read: it is a convenience, not a fact the\n\t\t * widget may invent.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLastRun() {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\ttry {\n\t\t\t\tconst res = await axios.get(\n\t\t\t\t\tgenerateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/audit-trails', { register, schema, id }),\n\t\t\t\t\t{ params: { action: 'action.macro', _limit: 1, '_sort[created]': 'DESC' } },\n\t\t\t\t)\n\t\t\t\tconst entry = (res?.data?.results || [])[0]\n\t\t\t\tconst key = entry?.changed?.declaredAction\n\t\t\t\tconst macro = this.macros.find((candidate) => candidate.key === key)\n\t\t\t\tthis.lastRun = macro && entry.created\n\t\t\t\t\t? { name: macro.name, date: new Date(entry.created).toLocaleString() }\n\t\t\t\t\t: null\n\t\t\t} catch {\n\t\t\t\tthis.lastRun = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one macro as the person, then ask the page to refresh.\n\t\t *\n\t\t * @param {{key: string, name: string}} macro The macro.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync run(macro) {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\tthis.running = macro.key\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tawait axios.post(generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/actions/{action}', { register, schema, id, action: macro.key }))\n\t\t\t\tthis.lastRun = { name: macro.name, date: new Date().toLocaleString() }\n\t\t\t\temit('cn:page:refresh', { source: 'cn-macros-widget' })\n\t\t\t} catch (e) {\n\t\t\t\tthis.error = t('nextcloud-vue', 'The macro did not run: {error}', { error: e?.response?.data?.error || e?.message || '' })\n\t\t\t} finally {\n\t\t\t\tthis.running = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-macros-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-macros-widget__description,\n.cn-macros-widget__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-macros-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-macros-widget__row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tpadding-block: 10px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-macros-widget__text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-macros-widget__name {\n\tfont-weight: 600;\n}\n\n.cn-macros-widget__hint {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, toDisplayString, createCommentVNode, Fragment, renderList, createElementVNode, createVNode, withCtx, createTextVNode, createBlock } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "cn-macros-widget",
|
|
5
|
+
"data-testid": "cn-macros-widget"
|
|
6
|
+
};
|
|
7
|
+
const _hoisted_2 = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "cn-macros-widget__description"
|
|
10
|
+
};
|
|
11
|
+
const _hoisted_3 = {
|
|
12
|
+
key: 1,
|
|
13
|
+
class: "cn-macros-widget__muted"
|
|
14
|
+
};
|
|
15
|
+
const _hoisted_4 = {
|
|
16
|
+
key: 2,
|
|
17
|
+
class: "cn-macros-widget__muted",
|
|
18
|
+
"data-testid": "cn-macros-widget-empty"
|
|
19
|
+
};
|
|
20
|
+
const _hoisted_5 = {
|
|
21
|
+
key: 3,
|
|
22
|
+
class: "cn-macros-widget__list"
|
|
23
|
+
};
|
|
24
|
+
const _hoisted_6 = ["data-testid"];
|
|
25
|
+
const _hoisted_7 = { class: "cn-macros-widget__text" };
|
|
26
|
+
const _hoisted_8 = { class: "cn-macros-widget__name" };
|
|
27
|
+
const _hoisted_9 = {
|
|
28
|
+
key: 0,
|
|
29
|
+
class: "cn-macros-widget__hint"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
33
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
34
|
+
const _component_NcNoteCard = resolveComponent("NcNoteCard");
|
|
35
|
+
|
|
36
|
+
return (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
37
|
+
($props.content.description)
|
|
38
|
+
? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.tr($props.content.description)), 1 /* TEXT */))
|
|
39
|
+
: createCommentVNode("v-if", true),
|
|
40
|
+
($data.loading)
|
|
41
|
+
? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString($options.t('nextcloud-vue', 'Loading …')), 1 /* TEXT */))
|
|
42
|
+
: ($data.macros.length === 0)
|
|
43
|
+
? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($props.content.emptyText ? $options.tr($props.content.emptyText) : $options.t('nextcloud-vue', 'This record has no macros')), 1 /* TEXT */))
|
|
44
|
+
: (openBlock(), createElementBlock("ul", _hoisted_5, [
|
|
45
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($data.macros, (macro) => {
|
|
46
|
+
return (openBlock(), createElementBlock("li", {
|
|
47
|
+
key: macro.key,
|
|
48
|
+
class: "cn-macros-widget__row",
|
|
49
|
+
"data-testid": `cn-macros-widget-row-${macro.key}`
|
|
50
|
+
}, [
|
|
51
|
+
createElementVNode("div", _hoisted_7, [
|
|
52
|
+
createElementVNode("span", _hoisted_8, toDisplayString(macro.name), 1 /* TEXT */),
|
|
53
|
+
(macro.description)
|
|
54
|
+
? (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString(macro.description), 1 /* TEXT */))
|
|
55
|
+
: createCommentVNode("v-if", true)
|
|
56
|
+
]),
|
|
57
|
+
createVNode(_component_NcButton, {
|
|
58
|
+
disabled: $data.running !== '',
|
|
59
|
+
"data-testid": `cn-macros-widget-run-${macro.key}`,
|
|
60
|
+
onClick: $event => ($options.run(macro))
|
|
61
|
+
}, {
|
|
62
|
+
default: withCtx(() => [
|
|
63
|
+
createTextVNode(toDisplayString($data.running === macro.key ? $options.t('nextcloud-vue', 'Running …') : $options.t('nextcloud-vue', 'Execute')), 1 /* TEXT */)
|
|
64
|
+
]),
|
|
65
|
+
_: 2 /* DYNAMIC */
|
|
66
|
+
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"])
|
|
67
|
+
], 8 /* PROPS */, _hoisted_6))
|
|
68
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
69
|
+
])),
|
|
70
|
+
($data.error)
|
|
71
|
+
? (openBlock(), createBlock(_component_NcNoteCard, {
|
|
72
|
+
key: 4,
|
|
73
|
+
type: "error",
|
|
74
|
+
"data-testid": "cn-macros-widget-error"
|
|
75
|
+
}, {
|
|
76
|
+
default: withCtx(() => [
|
|
77
|
+
createTextVNode(toDisplayString($data.error), 1 /* TEXT */)
|
|
78
|
+
]),
|
|
79
|
+
_: 1 /* STABLE */
|
|
80
|
+
}))
|
|
81
|
+
: ($data.lastRun)
|
|
82
|
+
? (openBlock(), createBlock(_component_NcNoteCard, {
|
|
83
|
+
key: 5,
|
|
84
|
+
type: "success",
|
|
85
|
+
"data-testid": "cn-macros-widget-last-run"
|
|
86
|
+
}, {
|
|
87
|
+
default: withCtx(() => [
|
|
88
|
+
createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Last run: {name}, {date}', { name: $data.lastRun.name, date: $data.lastRun.date })), 1 /* TEXT */)
|
|
89
|
+
]),
|
|
90
|
+
_: 1 /* STABLE */
|
|
91
|
+
}))
|
|
92
|
+
: createCommentVNode("v-if", true)
|
|
93
|
+
]))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { render };
|
|
97
|
+
//# sourceMappingURL=CnMacrosWidget.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnMacrosWidget.vue3.js","sources":["../../../../src/components/CnMacrosWidget/CnMacrosWidget.vue?vue&type=template&id=982c6094&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<!--\n CnMacrosWidget — the macros a record's schema declares, each with a button\n that runs it (`type: \"macros\"`, DqZaakAssistent \"Macro's\").\n\n A macro is a declared action (`configuration['x-openregister-action']`) with\n `macro: true` and a bound manual flow; OpenRegister runs it as the person,\n under the action's own right, through\n `POST /api/objects/{register}/{schema}/{id}/actions/{action}`. The widget\n lists what the schema declares and runs what is pressed: it adds no rights and\n no list of its own. The last run comes from the record's audit trail\n (`action.macro`), and after a run the page is asked to refresh.\n-->\n<template>\n\t<div class=\"cn-macros-widget\" data-testid=\"cn-macros-widget\">\n\t\t<p v-if=\"content.description\" class=\"cn-macros-widget__description\">\n\t\t\t{{ tr(content.description) }}\n\t\t</p>\n\t\t<p v-if=\"loading\" class=\"cn-macros-widget__muted\">\n\t\t\t{{ t('nextcloud-vue', 'Loading …') }}\n\t\t</p>\n\t\t<p v-else-if=\"macros.length === 0\" class=\"cn-macros-widget__muted\" data-testid=\"cn-macros-widget-empty\">\n\t\t\t{{ content.emptyText ? tr(content.emptyText) : t('nextcloud-vue', 'This record has no macros') }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-macros-widget__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"macro in macros\"\n\t\t\t\t:key=\"macro.key\"\n\t\t\t\tclass=\"cn-macros-widget__row\"\n\t\t\t\t:data-testid=\"`cn-macros-widget-row-${macro.key}`\">\n\t\t\t\t<div class=\"cn-macros-widget__text\">\n\t\t\t\t\t<span class=\"cn-macros-widget__name\">{{ macro.name }}</span>\n\t\t\t\t\t<span v-if=\"macro.description\" class=\"cn-macros-widget__hint\">{{ macro.description }}</span>\n\t\t\t\t</div>\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"running !== ''\"\n\t\t\t\t\t:data-testid=\"`cn-macros-widget-run-${macro.key}`\"\n\t\t\t\t\t@click=\"run(macro)\">\n\t\t\t\t\t{{ running === macro.key ? t('nextcloud-vue', 'Running …') : t('nextcloud-vue', 'Execute') }}\n\t\t\t\t</NcButton>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard\n\t\t\tv-if=\"error\"\n\t\t\ttype=\"error\"\n\t\t\tdata-testid=\"cn-macros-widget-error\">\n\t\t\t{{ error }}\n\t\t</NcNoteCard>\n\t\t<NcNoteCard\n\t\t\tv-else-if=\"lastRun\"\n\t\t\ttype=\"success\"\n\t\t\tdata-testid=\"cn-macros-widget-last-run\">\n\t\t\t{{ t('nextcloud-vue', 'Last run: {name}, {date}', { name: lastRun.name, date: lastRun.date }) }}\n\t\t</NcNoteCard>\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, NcNoteCard } from '@nextcloud/vue'\nimport { declaredMacros } from '../../utils/declaredMacros.js'\n\nexport default {\n\tname: 'CnMacrosWidget',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\tcnTranslate: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's content: `description` (the line under the title),\n\t\t * `emptyText`, both translated.\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The bound record. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The bound record's id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tmacros: [],\n\t\t\tloading: false,\n\t\t\trunning: '',\n\t\t\terror: '',\n\t\t\tlastRun: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {{register: string, schema: string, id: string}} Where the record lives. */\n\t\ttarget() {\n\t\t\tconst self = this.objectData?.['@self'] || {}\n\t\t\treturn {\n\t\t\t\tregister: String(self.register ?? ''),\n\t\t\t\tschema: String(self.schema ?? ''),\n\t\t\t\tid: String(this.objectId || self.id || this.objectData?.id || ''),\n\t\t\t}\n\t\t},\n\t},\n\n\twatch: {\n\t\t'target.schema': {\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\tt,\n\n\t\t/**\n\t\t * Translate an app-supplied text through the host app when it offers it.\n\t\t *\n\t\t * @param {string} text The text.\n\t\t * @return {string} The translated text.\n\t\t */\n\t\ttr(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * Read the schema's macros and the record's last macro run.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\tif (schema === '' || id === '') {\n\t\t\t\tthis.macros = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst res = await axios.get(generateUrl('/apps/openregister/api/schemas/{schema}', { schema }), register ? { params: { register } } : undefined)\n\t\t\t\tthis.macros = declaredMacros(res?.data || null)\n\t\t\t} catch {\n\t\t\t\tthis.macros = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t\tif (this.macros.length > 0) {\n\t\t\t\tawait this.loadLastRun()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The record's most recent macro run, from its audit trail. Left empty\n\t\t * when the trail cannot be read: it is a convenience, not a fact the\n\t\t * widget may invent.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLastRun() {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\ttry {\n\t\t\t\tconst res = await axios.get(\n\t\t\t\t\tgenerateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/audit-trails', { register, schema, id }),\n\t\t\t\t\t{ params: { action: 'action.macro', _limit: 1, '_sort[created]': 'DESC' } },\n\t\t\t\t)\n\t\t\t\tconst entry = (res?.data?.results || [])[0]\n\t\t\t\tconst key = entry?.changed?.declaredAction\n\t\t\t\tconst macro = this.macros.find((candidate) => candidate.key === key)\n\t\t\t\tthis.lastRun = macro && entry.created\n\t\t\t\t\t? { name: macro.name, date: new Date(entry.created).toLocaleString() }\n\t\t\t\t\t: null\n\t\t\t} catch {\n\t\t\t\tthis.lastRun = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run one macro as the person, then ask the page to refresh.\n\t\t *\n\t\t * @param {{key: string, name: string}} macro The macro.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync run(macro) {\n\t\t\tconst { register, schema, id } = this.target\n\t\t\tthis.running = macro.key\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tawait axios.post(generateUrl('/apps/openregister/api/objects/{register}/{schema}/{id}/actions/{action}', { register, schema, id, action: macro.key }))\n\t\t\t\tthis.lastRun = { name: macro.name, date: new Date().toLocaleString() }\n\t\t\t\temit('cn:page:refresh', { source: 'cn-macros-widget' })\n\t\t\t} catch (e) {\n\t\t\t\tthis.error = t('nextcloud-vue', 'The macro did not run: {error}', { error: e?.response?.data?.error || e?.message || '' })\n\t\t\t} finally {\n\t\t\t\tthis.running = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-macros-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-macros-widget__description,\n.cn-macros-widget__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-macros-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-macros-widget__row {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n\tpadding-block: 10px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-macros-widget__text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-macros-widget__name {\n\tfont-weight: 600;\n}\n\n.cn-macros-widget__hint {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createElementVNode","_createVNode"],"mappings":";;;AAmCM,EAAA,KAAK,EAAC,kBAAkB;AAAC,EAAA,aAAW,EAAC,kBAAkB;;;;AAC7B,EAAA,KAAK,EAAC,+BAA8B;;;;AAGhD,EAAA,KAAK,EAAC,yBAAI;;;;AAGO,EAAA,KAAK,EAAC,yBAAyB;AAAC,EAAA,aAAW,EAAC,wBAAgB;;;;AAG3F,EAAA,KAAA,EAAA,wBAAA;;;AAMG,MAAA,UAAA,GAAA,EAAA,KAAK,EAAA,wBAAA,GAAA;AACH,MAAA,UAAA,GAAA,EAAA,KAAC,EAAA,wBAAA,GAAA;;;AACS,EAAA,KAAA,EAAA,wBAAA;;;;;;;;AAjBV,IAAA,CAAA,MAAA,CAAA,OAAO,CAAC,WAAW;AAAzB,SAAAA,SAAA,EAAA,EAAAC,kBAAA,CAEC,KAFD,UAEC,EAAAC,eAAA,CADA,WAAE,CAAC,MAAA,CAAA,OAAA,CAAA,WAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;KAEE,KAAO,CAAA,OAAA;wCAEZ,CAAA,GAAA,YAAA,EAAAA,eAAA,CADA,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,WAAA,CAAA,CAAA,EAAA,CAAA,YAAA;AAES,QAAA,CAAA,KAAA,CAAA,MAAM,CAAC,MAAK,KAAA,CAAA;AAAvB,WAAAF,SAAA,EAAA,EAAAC,kBAAA,CAEC,GAFD,EAAA,UAEC,EADAC,eAAA,CAAA,MAAA,CAAA,OAAO,CAAC,SAAA,GAAA,QAAA,CAAA,EAAA,CAAA,MAAA,CAAA,OAAA,CAAA,SAAA,IAAA,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,2BAAA,CAAA,CAAA,EAAA,CAAA,YAAA;AAEZ,WAAAF,SAAA,EAAA,EAAAC,kBAAA,OAAA;8BACCA,8CACW,KAAA,CAAA,MAAA,EAAA,CAAH,KAAG,KAAA;mCADXA;gBAEE,GAAG,EAAE,KAAI,CAAA,GAAA;AACV,gBAAA,KAAK,EAAC,uBAAuB;6BACpB,EAAA,CAAA,qBAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA;;AACT,gBAAAE,kBAAA,CAGM,OAHN,UAGM,EAAA;AAFL,kBAAAA,kBAAA,CAAO,MAAP,EAAA,UAAO,EAAAD,eAAA,CAAA,KAAA,CAAA,IAAA,CAAA,EAAA,CAAA,YAAA;AACK,kBAAA,CAAA,KAAI,CAAA,WAAA;AAAhB,uBAAAF,SAAA,EAAA,EAAAC,kBAAA,CAAgB,MAAhB,EAAA,UAAgB,EAAAC,eAAA,CAAA,KAAA,CAAA,WAAA,CAAA,EAAA,CAAA,YAAA;;;gBAEjBE;AACE,kBAAA,QAAQ,EAAE,KAAO,CAAA,OAAA,KAAA,EAAA;kBACjB,aAAQ,EAAA,CAAA,qBAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA;kBACR,OAAA,EAAA,MAAA,KAAA,QAAA,CAAA,GAAA,CAAA,KAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnRetentionRecomputeDialog.vue2.js';
|
|
2
|
+
import { render } from './CnRetentionRecomputeDialog.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-0e56b9bb";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnRetentionRecomputeDialog.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnRetentionRecomputeDialog.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { translate } from '@nextcloud/l10n';
|
|
2
|
+
import { NcButton, NcTextField } from '@nextcloud/vue';
|
|
3
|
+
import __sfc_main from '../CnDialog/CnDialog.vue.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CnRetentionRecomputeDialog — asks why a record's archival nomination is
|
|
7
|
+
* recomputed, the reason OpenRegister records with it. The retention widget
|
|
8
|
+
* opens it from its card header (board DqZaakArchivering, "Nominatie
|
|
9
|
+
* herberekenen") and posts the recompute itself.
|
|
10
|
+
*
|
|
11
|
+
* @event close The dialog is closed without recomputing.
|
|
12
|
+
* @event confirm The person confirmed, with the reason (trimmed, never empty).
|
|
13
|
+
* @spec openspec/changes/retention-recompute-header/specs/retention-recompute-header/spec.md#requirement-recomputing-the-nomination-starts-in-the-card-header-and-asks-for-a-reason
|
|
14
|
+
*/
|
|
15
|
+
var script = {
|
|
16
|
+
name: 'CnRetentionRecomputeDialog',
|
|
17
|
+
|
|
18
|
+
components: { CnDialog: __sfc_main, NcButton, NcTextField },
|
|
19
|
+
|
|
20
|
+
inject: {
|
|
21
|
+
/** The host app's translate (CnAppRoot `cnTranslate`). */
|
|
22
|
+
cnTranslate: { default: () => (key) => key },
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
props: {
|
|
26
|
+
/** The user the recompute is recorded against. */
|
|
27
|
+
user: { type: String, default: '' },
|
|
28
|
+
/** Whether the recompute is being posted. */
|
|
29
|
+
busy: { type: Boolean, default: false },
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
emits: ['close', 'confirm'],
|
|
33
|
+
|
|
34
|
+
data() {
|
|
35
|
+
return { reason: '' }
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
computed: {
|
|
39
|
+
/**
|
|
40
|
+
* The line naming who the recompute is recorded against.
|
|
41
|
+
*
|
|
42
|
+
* @return {string} The line.
|
|
43
|
+
*/
|
|
44
|
+
recordedAgainst() {
|
|
45
|
+
return translate('nextcloud-vue', 'This is recorded against {user}.', { user: this.user })
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
methods: {
|
|
50
|
+
/**
|
|
51
|
+
* A library string in the reader's language.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} key The English text.
|
|
54
|
+
* @return {string} The text.
|
|
55
|
+
*/
|
|
56
|
+
tr(key) {
|
|
57
|
+
return translate('nextcloud-vue', key)
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { script as default };
|
|
63
|
+
//# sourceMappingURL=CnRetentionRecomputeDialog.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnRetentionRecomputeDialog.vue2.js","sources":["../../../../src/components/CnRetentionWidget/CnRetentionRecomputeDialog.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=\"tr('Recompute the nomination')\"\n\t\twidth=\"confirm\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-retention-recompute-dialog\"\n\t\t@closing=\"$emit('close')\">\n\t\t<NcTextField\n\t\t\t:modelValue=\"reason\"\n\t\t\t:label=\"tr('Why are you recomputing this?')\"\n\t\t\tdata-testid=\"cn-retention-reason\"\n\t\t\t@update:modelValue=\"(value) => (reason = String(value ?? ''))\" />\n\t\t<p class=\"cn-retention-recompute__muted\">\n\t\t\t{{ recordedAgainst }}\n\t\t</p>\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-retention-recompute-cancel\" @click=\"$emit('close')\">\n\t\t\t\t{{ tr('Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\tdata-testid=\"cn-retention-recompute\"\n\t\t\t\t@click=\"$emit('confirm', reason.trim())\">\n\t\t\t\t{{ tr('Recompute') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcTextField } from '@nextcloud/vue'\nimport { CnDialog } from '../CnDialog/index.js'\n\n/**\n * CnRetentionRecomputeDialog — asks why a record's archival nomination is\n * recomputed, the reason OpenRegister records with it. The retention widget\n * opens it from its card header (board DqZaakArchivering, \"Nominatie\n * herberekenen\") and posts the recompute itself.\n *\n * @event close The dialog is closed without recomputing.\n * @event confirm The person confirmed, with the reason (trimmed, never empty).\n * @spec openspec/changes/retention-recompute-header/specs/retention-recompute-header/spec.md#requirement-recomputing-the-nomination-starts-in-the-card-header-and-asks-for-a-reason\n */\nexport default {\n\tname: 'CnRetentionRecomputeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The user the recompute is recorded against. */\n\t\tuser: { type: String, default: '' },\n\t\t/** Whether the recompute is being posted. */\n\t\tbusy: { type: Boolean, default: false },\n\t},\n\n\temits: ['close', 'confirm'],\n\n\tdata() {\n\t\treturn { reason: '' }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The line naming who the recompute is recorded against.\n\t\t *\n\t\t * @return {string} The line.\n\t\t */\n\t\trecordedAgainst() {\n\t\t\treturn t('nextcloud-vue', 'This is recorded against {user}.', { user: this.user })\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A library string in the reader's language.\n\t\t *\n\t\t * @param {string} key The English text.\n\t\t * @return {string} The text.\n\t\t */\n\t\ttr(key) {\n\t\t\treturn t('nextcloud-vue', key)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-retention-recompute__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n</style>\n"],"names":["CnDialog","t"],"mappings":";;;;AAuCA;AACC;AACA;;AAEA;AACA;;AAEA;AACA;;AAED,aAAe;AACd,CAAA,IAAI,EAAE,4BAA4B;;AAElC,CAAA,UAAU,EAAE,YAAEA,UAAQ,EAAE,QAAQ,EAAE,aAAa;;AAE/C,CAAA,MAAM,EAAE;;AAEP,EAAA,WAAW,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,KAAK,KAAK;EAC5C;;AAED,CAAA,KAAK,EAAE;AACN;EACA,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,EAAG;AACnC;AACA,EAAA,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;EACvC;;CAED,KAAK,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;;AAE3B,CAAA,IAAI,GAAG;AACN,EAAA,OAAO,EAAE,MAAM,EAAE,EAAG,EAAA;EACpB;;AAED,CAAA,QAAQ,EAAE;AACT;;AAEC;;;AAGD,EAAA,eAAe,GAAG;AACjB,GAAA,OAAOC,SAAC,CAAC,eAAe,EAAE,kCAAkC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAA;GACjF;EACD;;AAED,CAAA,OAAO,EAAE;AACR;AACC;AACA;AACA;;;AAGD,EAAA,EAAE,CAAC,GAAG,EAAE;GACP,OAAOA,SAAC,CAAC,eAAe,EAAE,GAAG,CAAA;GAC7B;EACD;AACF;;;;"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createBlock, withCtx, createVNode, createTextVNode, toDisplayString, createElementVNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = { class: "cn-retention-recompute__muted" };
|
|
4
|
+
|
|
5
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
6
|
+
const _component_NcTextField = resolveComponent("NcTextField");
|
|
7
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
8
|
+
const _component_CnDialog = resolveComponent("CnDialog");
|
|
9
|
+
|
|
10
|
+
return (openBlock(), createBlock(_component_CnDialog, {
|
|
11
|
+
name: $options.tr('Recompute the nomination'),
|
|
12
|
+
width: "confirm",
|
|
13
|
+
noClose: $props.busy,
|
|
14
|
+
"data-testid": "cn-retention-recompute-dialog",
|
|
15
|
+
onClosing: _cache[3] || (_cache[3] = $event => (_ctx.$emit('close')))
|
|
16
|
+
}, {
|
|
17
|
+
actions: withCtx(() => [
|
|
18
|
+
createVNode(_component_NcButton, {
|
|
19
|
+
disabled: $props.busy,
|
|
20
|
+
"data-testid": "cn-retention-recompute-cancel",
|
|
21
|
+
onClick: _cache[1] || (_cache[1] = $event => (_ctx.$emit('close')))
|
|
22
|
+
}, {
|
|
23
|
+
default: withCtx(() => [
|
|
24
|
+
createTextVNode(toDisplayString($options.tr('Cancel')), 1 /* TEXT */)
|
|
25
|
+
]),
|
|
26
|
+
_: 1 /* STABLE */
|
|
27
|
+
}, 8 /* PROPS */, ["disabled"]),
|
|
28
|
+
createVNode(_component_NcButton, {
|
|
29
|
+
variant: "primary",
|
|
30
|
+
disabled: $props.busy || $data.reason.trim() === '',
|
|
31
|
+
"data-testid": "cn-retention-recompute",
|
|
32
|
+
onClick: _cache[2] || (_cache[2] = $event => (_ctx.$emit('confirm', $data.reason.trim())))
|
|
33
|
+
}, {
|
|
34
|
+
default: withCtx(() => [
|
|
35
|
+
createTextVNode(toDisplayString($options.tr('Recompute')), 1 /* TEXT */)
|
|
36
|
+
]),
|
|
37
|
+
_: 1 /* STABLE */
|
|
38
|
+
}, 8 /* PROPS */, ["disabled"])
|
|
39
|
+
]),
|
|
40
|
+
default: withCtx(() => [
|
|
41
|
+
createVNode(_component_NcTextField, {
|
|
42
|
+
modelValue: $data.reason,
|
|
43
|
+
label: $options.tr('Why are you recomputing this?'),
|
|
44
|
+
"data-testid": "cn-retention-reason",
|
|
45
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = (value) => ($data.reason = String(value ?? '')))
|
|
46
|
+
}, null, 8 /* PROPS */, ["modelValue", "label"]),
|
|
47
|
+
createElementVNode("p", _hoisted_1, toDisplayString($options.recordedAgainst), 1 /* TEXT */)
|
|
48
|
+
]),
|
|
49
|
+
_: 1 /* STABLE */
|
|
50
|
+
}, 8 /* PROPS */, ["name", "noClose"]))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { render };
|
|
54
|
+
//# sourceMappingURL=CnRetentionRecomputeDialog.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnRetentionRecomputeDialog.vue3.js","sources":["../../../../src/components/CnRetentionWidget/CnRetentionRecomputeDialog.vue?vue&type=template&id=0e56b9bb&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=\"tr('Recompute the nomination')\"\n\t\twidth=\"confirm\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-retention-recompute-dialog\"\n\t\t@closing=\"$emit('close')\">\n\t\t<NcTextField\n\t\t\t:modelValue=\"reason\"\n\t\t\t:label=\"tr('Why are you recomputing this?')\"\n\t\t\tdata-testid=\"cn-retention-reason\"\n\t\t\t@update:modelValue=\"(value) => (reason = String(value ?? ''))\" />\n\t\t<p class=\"cn-retention-recompute__muted\">\n\t\t\t{{ recordedAgainst }}\n\t\t</p>\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-retention-recompute-cancel\" @click=\"$emit('close')\">\n\t\t\t\t{{ tr('Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"busy || reason.trim() === ''\"\n\t\t\t\tdata-testid=\"cn-retention-recompute\"\n\t\t\t\t@click=\"$emit('confirm', reason.trim())\">\n\t\t\t\t{{ tr('Recompute') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcTextField } from '@nextcloud/vue'\nimport { CnDialog } from '../CnDialog/index.js'\n\n/**\n * CnRetentionRecomputeDialog — asks why a record's archival nomination is\n * recomputed, the reason OpenRegister records with it. The retention widget\n * opens it from its card header (board DqZaakArchivering, \"Nominatie\n * herberekenen\") and posts the recompute itself.\n *\n * @event close The dialog is closed without recomputing.\n * @event confirm The person confirmed, with the reason (trimmed, never empty).\n * @spec openspec/changes/retention-recompute-header/specs/retention-recompute-header/spec.md#requirement-recomputing-the-nomination-starts-in-the-card-header-and-asks-for-a-reason\n */\nexport default {\n\tname: 'CnRetentionRecomputeDialog',\n\n\tcomponents: { CnDialog, NcButton, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The user the recompute is recorded against. */\n\t\tuser: { type: String, default: '' },\n\t\t/** Whether the recompute is being posted. */\n\t\tbusy: { type: Boolean, default: false },\n\t},\n\n\temits: ['close', 'confirm'],\n\n\tdata() {\n\t\treturn { reason: '' }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The line naming who the recompute is recorded against.\n\t\t *\n\t\t * @return {string} The line.\n\t\t */\n\t\trecordedAgainst() {\n\t\t\treturn t('nextcloud-vue', 'This is recorded against {user}.', { user: this.user })\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A library string in the reader's language.\n\t\t *\n\t\t * @param {string} key The English text.\n\t\t * @return {string} The text.\n\t\t */\n\t\ttr(key) {\n\t\t\treturn t('nextcloud-vue', key)\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-retention-recompute__muted {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n</style>\n"],"names":["_createBlock","_createVNode","_createElementVNode","_toDisplayString"],"mappings":";;AAoBK,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,+BAA+B,GAAA;;;;;;;uBAXxCA;AACC,IAAA,IAAI,EAAE,QAAE,CAAA,EAAA,CAAA,0BAAA,CAAA;AACT,IAAA,KAAK,EAAC,SAAK;AACV,IAAA,OAAO,EAAE,MAAI,CAAA,IAAA;AACb,IAAA,aAAU,EAAC,+BAA+B;AAC1C,IAAA,SAAO,uCAAE,IAAK,CAAA,KAAA,CAAA,OAAA,CAAA,CAAA,CAAA;;AASN,IAAA,OAAA,UACP,MAEU;MAFVC,WAEU,CAAA,mBAAA,EAAA;AAFA,QAAA,QAAM,EAAA,MAAA,CAAA,IAAA;AAAA,QAAA,aAAA,EAAA,+BAAA;AAAA,QAAA,OAAA,uCAAA,IAAA,CAAA,KAAA,CAAA,OAAA,CAAA,CAAA,CAAA;;yBAChB,MAAiB;0CAAd,QAAE,CAAA,EAAA,CAAA,QAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;MAELA;AACA,QAAA,OAAO,EAAC,SAAS;AAChB,QAAA,QAAQ,EAAA,MAAA,CAAA,IAAA,IAAA,KAAA,CAAA,MAAA,CAAA,IAAA,EAAA,KAAA,EAAA;AACT,QAAA,aAAQ,EAAA,wBAAA;AACP,QAAA,OAAK,EAAC,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,IAAA,CAAA,KAAA,CAAA,SAAA,EAAA,KAAA,CAAA,MAAA,CAAA,IAAA,EAAA,CAAA,CAAA,CAAA;;;;;;;;2BAZS;iBAAA,CAAA,sBAAA,EAAA;kBAHN,EAAE,KAAM,CAAA,MAAA;AAClB,QAAA,KAAK,EAAE,QAAE,CAAA,EAAA,CAAA,+BAAA,CAAA;AACV,QAAA,aAAE,EAAA,qBAAA;AACD,QAAA,qBAAgB,6BAAA,KAAA,MAAA,YAAA,GAAA,MAAA,CAAA,KAAA,IAAA,EAAA,CAAA,CAAA,CAAA;;MACjBC,kBAEG,CAAA,GAAA,EAFH,UAEG,EAAAC,eAAA,CADC,QAAc,CAAA,eAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnRetentionWidget.vue2.js';
|
|
|
2
2
|
import { render } from './CnRetentionWidget.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-170cb650";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|