@conduction/nextcloud-vue 2.108.0 → 2.110.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/CnActionDialog/CnActionDialog.vue.js +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +115 -12
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +36 -9
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue.js +10 -0
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue.js.map +1 -0
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue2.js +305 -0
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue2.js.map +1 -0
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue3.js +38 -0
- package/dist/esm/components/CnAddressSearch/CnAddressSearch.vue3.js.map +1 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +10 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js.map +1 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +398 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js +155 -0
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue.js +9 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue.js.map +1 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue2.js +281 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue3.js +137 -0
- package/dist/esm/components/CnDecisionListWidget/CnDecisionListWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js +9 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js.map +1 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js +225 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js.map +1 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js +110 -0
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js.map +1 -0
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue.js +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +19 -3
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +513 -481
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue.js +9 -0
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue.js.map +1 -0
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js +181 -0
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue2.js.map +1 -0
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue3.js +50 -0
- package/dist/esm/components/CnNcDashboardList/CnNcDashboardList.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +102 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -6
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue.js +9 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue.js.map +1 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue2.js +190 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue3.js +91 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue.js +9 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue.js.map +1 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js +64 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue2.js.map +1 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js +49 -0
- package/dist/esm/components/CnPlanWidget/CnPlanWidgetRow.vue3.js.map +1 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue.js +9 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue.js.map +1 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue2.js +382 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue2.js.map +1 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue3.js +285 -0
- package/dist/esm/components/CnRedactionEditor/CnRedactionEditor.vue3.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +9 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js +277 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js +183 -0
- package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +53 -22
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue.js +9 -0
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue.js.map +1 -0
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js +253 -0
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js.map +1 -0
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue3.js +197 -0
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue3.js.map +1 -0
- package/dist/esm/index.js +12 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +106 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +105 -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 +510 -76
- package/dist/esm/utils/actionsDispatcher.js +11 -3
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/esm/utils/builtInModals.js +3 -1
- package/dist/esm/utils/builtInModals.js.map +1 -1
- package/dist/esm/utils/duplicateWarning.js +62 -0
- package/dist/esm/utils/duplicateWarning.js.map +1 -0
- package/dist/esm/utils/errors.js +4 -0
- package/dist/esm/utils/errors.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +4 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/openDuplicateWarning.js +39 -0
- package/dist/esm/utils/openDuplicateWarning.js.map +1 -0
- package/dist/esm/utils/optionsFrom.js +69 -2
- package/dist/esm/utils/optionsFrom.js.map +1 -1
- package/dist/esm/utils/planTree.js +57 -0
- package/dist/esm/utils/planTree.js.map +1 -0
- package/dist/esm/utils/redactionSegments.js +53 -0
- package/dist/esm/utils/redactionSegments.js.map +1 -0
- package/dist/esm/utils/registerNcDashboardWidgets.js +61 -0
- package/dist/esm/utils/registerNcDashboardWidgets.js.map +1 -0
- package/dist/esm/utils/searchRefusal.js +62 -0
- package/dist/esm/utils/searchRefusal.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +17560 -12844
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +510 -76
- package/l10n/en.json +106 -1
- package/l10n/nl.json +105 -1
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +134 -13
- package/src/components/CnAddressSearch/CnAddressSearch.vue +343 -0
- package/src/components/CnAddressSearch/index.js +12 -0
- package/src/components/CnAssignDialog/CnAssignDialog.vue +525 -0
- package/src/components/CnAssignDialog/index.js +12 -0
- package/src/components/CnDecisionListWidget/CnDecisionListWidget.vue +388 -0
- package/src/components/CnDecisionListWidget/index.js +12 -0
- package/src/components/CnDuplicateWarning/CnDuplicateWarning.vue +318 -0
- package/src/components/CnDuplicateWarning/index.js +12 -0
- package/src/components/CnFormDialog/CnFormDialog.vue +19 -3
- package/src/components/CnIndexPage/CnIndexPage.vue +52 -0
- package/src/components/CnNcDashboardList/CnNcDashboardList.vue +218 -0
- package/src/components/CnNcDashboardList/index.js +12 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +107 -6
- package/src/components/CnPlanWidget/CnPlanWidget.vue +246 -0
- package/src/components/CnPlanWidget/CnPlanWidgetRow.vue +117 -0
- package/src/components/CnPlanWidget/index.js +12 -0
- package/src/components/CnRedactionEditor/CnRedactionEditor.vue +655 -0
- package/src/components/CnRedactionEditor/index.js +13 -0
- package/src/components/CnRetentionWidget/CnRetentionWidget.vue +413 -0
- package/src/components/CnRetentionWidget/index.js +12 -0
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +31 -0
- package/src/components/CnWorkQueue/CnWorkQueue.vue +463 -0
- package/src/components/CnWorkQueue/index.js +12 -0
- package/src/components/index.js +9 -0
- package/src/css/index-page.css +24 -0
- package/src/index.js +12 -0
- package/src/schemas/app-manifest-v2.schema.json +119 -3
- package/src/utils/actionsDispatcher.js +10 -2
- package/src/utils/builtInModals.js +3 -1
- package/src/utils/duplicateWarning.js +59 -0
- package/src/utils/errors.js +4 -0
- package/src/utils/libraryWidgetKeys.js +4 -0
- package/src/utils/openDuplicateWarning.js +35 -0
- package/src/utils/optionsFrom.js +68 -1
- package/src/utils/planTree.js +54 -0
- package/src/utils/redactionSegments.js +50 -0
- package/src/utils/registerNcDashboardWidgets.js +57 -0
- package/src/utils/searchRefusal.js +59 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import axios__default from '@nextcloud/axios';
|
|
2
|
+
import { subscribe, unsubscribe, emit } from '@nextcloud/event-bus';
|
|
3
|
+
import { translate } from '@nextcloud/l10n';
|
|
4
|
+
import { generateUrl } from '@nextcloud/router';
|
|
5
|
+
import { NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue';
|
|
6
|
+
import __sfc_main from './CnPlanWidgetRow.vue.js';
|
|
7
|
+
import { planTree } from '../../utils/planTree.js';
|
|
8
|
+
|
|
9
|
+
/** The page refresh channel the built-in widgets listen on. */
|
|
10
|
+
const PAGE_REFRESH = 'cn:page:refresh';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* CnPlanWidget — the `plan` detail widget: a record's planned steps (stages,
|
|
14
|
+
* tasks and milestones) as OpenRegister's case layer holds them, read from
|
|
15
|
+
* `/api/cases/{id}`, with the moves OpenRegister allows: start a
|
|
16
|
+
* discretionary item, complete or terminate one. It judges nothing:
|
|
17
|
+
* OpenRegister decides every move and its refusal is shown as it says it.
|
|
18
|
+
* A 404 means the record has no plan; any other failure is an error with a
|
|
19
|
+
* retry, never an empty plan. Any app whose records run on OpenRegister's
|
|
20
|
+
* case layer uses it; dossiq's case plan is the first.
|
|
21
|
+
*
|
|
22
|
+
* `content`: `emptyText`, through the host translate.
|
|
23
|
+
*
|
|
24
|
+
* The record's id comes from `objectId`, else the bound record.
|
|
25
|
+
*/
|
|
26
|
+
var script = {
|
|
27
|
+
name: 'CnPlanWidget',
|
|
28
|
+
|
|
29
|
+
components: { CnPlanWidgetRow: __sfc_main, NcButton, NcEmptyContent, NcLoadingIcon },
|
|
30
|
+
|
|
31
|
+
inject: {
|
|
32
|
+
/** The host app's translate (CnAppRoot `cnTranslate`). */
|
|
33
|
+
cnTranslate: { default: () => (key) => key },
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
props: {
|
|
37
|
+
/**
|
|
38
|
+
* The widget's configuration: `{ emptyText? }`.
|
|
39
|
+
*
|
|
40
|
+
* @type {object}
|
|
41
|
+
*/
|
|
42
|
+
content: {
|
|
43
|
+
type: Object,
|
|
44
|
+
default: () => ({}),
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The bound record, on a detail page.
|
|
49
|
+
*
|
|
50
|
+
* @type {object|null}
|
|
51
|
+
*/
|
|
52
|
+
objectData: {
|
|
53
|
+
type: Object,
|
|
54
|
+
default: null,
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/** The record's id (else the bound record's). */
|
|
58
|
+
objectId: {
|
|
59
|
+
type: [String, Number],
|
|
60
|
+
default: '',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
data() {
|
|
65
|
+
return {
|
|
66
|
+
loading: true,
|
|
67
|
+
busy: false,
|
|
68
|
+
error: '',
|
|
69
|
+
roots: [],
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
computed: {
|
|
74
|
+
/** @return {string} The record id. */
|
|
75
|
+
id() {
|
|
76
|
+
const bound = this.objectData || {};
|
|
77
|
+
return String(this.objectId || bound.id || (bound['@self'] && bound['@self'].id) || '')
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
mounted() {
|
|
82
|
+
subscribe(PAGE_REFRESH, this.load);
|
|
83
|
+
this.load();
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
beforeUnmount() {
|
|
87
|
+
unsubscribe(PAGE_REFRESH, this.load);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
methods: {
|
|
91
|
+
t: translate,
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* A config text through the host translate.
|
|
95
|
+
*
|
|
96
|
+
* @param {unknown} value The text.
|
|
97
|
+
* @return {string}
|
|
98
|
+
*/
|
|
99
|
+
text(value) {
|
|
100
|
+
return typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The server's sentence for a failure.
|
|
105
|
+
*
|
|
106
|
+
* @param {unknown} failure The rejection.
|
|
107
|
+
* @return {string}
|
|
108
|
+
*/
|
|
109
|
+
messageOf(failure) {
|
|
110
|
+
const response = failure && failure.response;
|
|
111
|
+
if (response && response.status === 403) {
|
|
112
|
+
return translate('nextcloud-vue', 'You are not allowed to see this plan.')
|
|
113
|
+
}
|
|
114
|
+
const body = response && response.data;
|
|
115
|
+
const detail = body && (body.error || body.message);
|
|
116
|
+
return typeof detail === 'string' && detail !== '' ? detail : translate('nextcloud-vue', 'The plan could not be loaded. Try again.')
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read the plan; 404 is "no plan", anything else an error.
|
|
121
|
+
*
|
|
122
|
+
* @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps
|
|
123
|
+
* @return {Promise<void>}
|
|
124
|
+
*/
|
|
125
|
+
async load() {
|
|
126
|
+
if (!this.id) {
|
|
127
|
+
this.loading = false;
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
this.loading = true;
|
|
131
|
+
this.error = '';
|
|
132
|
+
try {
|
|
133
|
+
const { data } = await axios__default.get(generateUrl(`/apps/openregister/api/cases/${encodeURIComponent(this.id)}`));
|
|
134
|
+
this.roots = data && Array.isArray(data.items) ? planTree(data.items) : [];
|
|
135
|
+
} catch (failure) {
|
|
136
|
+
this.roots = [];
|
|
137
|
+
if (!(failure && failure.response && failure.response.status === 404)) {
|
|
138
|
+
this.error = this.messageOf(failure);
|
|
139
|
+
}
|
|
140
|
+
} finally {
|
|
141
|
+
this.loading = false;
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Start a discretionary item.
|
|
147
|
+
*
|
|
148
|
+
* @param {object} item The plan item.
|
|
149
|
+
* @return {Promise<void>}
|
|
150
|
+
*/
|
|
151
|
+
enable(item) {
|
|
152
|
+
return this.act(() => axios__default.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/enable`), {}))
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Move an item to a target state.
|
|
157
|
+
*
|
|
158
|
+
* @param {object} item The plan item.
|
|
159
|
+
* @param {string} to The target state.
|
|
160
|
+
* @return {Promise<void>}
|
|
161
|
+
*/
|
|
162
|
+
transition(item, to) {
|
|
163
|
+
return this.act(() => axios__default.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/transition`), { to, reason: '' }))
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Run one move, then read the plan again: a move can cascade, so the
|
|
168
|
+
* next read is the plan, not the write's answer.
|
|
169
|
+
*
|
|
170
|
+
* @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps
|
|
171
|
+
* @param {() => Promise<unknown>} write The move.
|
|
172
|
+
* @return {Promise<void>}
|
|
173
|
+
*/
|
|
174
|
+
async act(write) {
|
|
175
|
+
this.busy = true;
|
|
176
|
+
try {
|
|
177
|
+
await write();
|
|
178
|
+
await this.load();
|
|
179
|
+
emit(PAGE_REFRESH, {});
|
|
180
|
+
} catch (failure) {
|
|
181
|
+
this.error = this.messageOf(failure);
|
|
182
|
+
} finally {
|
|
183
|
+
this.busy = false;
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export { script as default };
|
|
190
|
+
//# sourceMappingURL=CnPlanWidget.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnPlanWidget.vue2.js","sources":["../../../../src/components/CnPlanWidget/CnPlanWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-plan\" data-testid=\"cn-plan\">\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'The plan is unavailable')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-plan-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton data-testid=\"cn-plan-retry\" @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<ul v-else-if=\"roots.length > 0\" class=\"cn-plan__tree\">\n\t\t\t<li v-for=\"node in roots\" :key=\"node.uuid\" class=\"cn-plan__node\">\n\t\t\t\t<CnPlanWidgetRow :item=\"node\"\n\t\t\t\t\t:busy=\"busy\"\n\t\t\t\t\t@enable=\"enable\"\n\t\t\t\t\t@transition=\"transition\" />\n\t\t\t\t<ul v-if=\"node.children.length > 0\" class=\"cn-plan__children\">\n\t\t\t\t\t<li v-for=\"child in node.children\" :key=\"child.uuid\" class=\"cn-plan__node\">\n\t\t\t\t\t\t<CnPlanWidgetRow :item=\"child\"\n\t\t\t\t\t\t\t:busy=\"busy\"\n\t\t\t\t\t\t\t@enable=\"enable\"\n\t\t\t\t\t\t\t@transition=\"transition\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-else class=\"cn-plan__empty\" data-testid=\"cn-plan-empty\">\n\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'This record has no plan') }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'\nimport CnPlanWidgetRow from './CnPlanWidgetRow.vue'\nimport { planTree } from '../../utils/planTree.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/**\n * CnPlanWidget — the `plan` detail widget: a record's planned steps (stages,\n * tasks and milestones) as OpenRegister's case layer holds them, read from\n * `/api/cases/{id}`, with the moves OpenRegister allows: start a\n * discretionary item, complete or terminate one. It judges nothing:\n * OpenRegister decides every move and its refusal is shown as it says it.\n * A 404 means the record has no plan; any other failure is an error with a\n * retry, never an empty plan. Any app whose records run on OpenRegister's\n * case layer uses it; dossiq's case plan is the first.\n *\n * `content`: `emptyText`, through the host translate.\n *\n * The record's id comes from `objectId`, else the bound record.\n */\nexport default {\n\tname: 'CnPlanWidget',\n\n\tcomponents: { CnPlanWidgetRow, NcButton, NcEmptyContent, NcLoadingIcon },\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/**\n\t\t * The widget's configuration: `{ emptyText? }`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The bound record, on a detail page.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's id (else the bound record's). */\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\tloading: true,\n\t\t\tbusy: false,\n\t\t\terror: '',\n\t\t\troots: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The record id. */\n\t\tid() {\n\t\t\tconst bound = this.objectData || {}\n\t\t\treturn String(this.objectId || bound.id || (bound['@self'] && bound['@self'].id) || '')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe(PAGE_REFRESH, this.load)\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(PAGE_REFRESH, this.load)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * The server's sentence for a failure.\n\t\t *\n\t\t * @param {unknown} failure The rejection.\n\t\t * @return {string}\n\t\t */\n\t\tmessageOf(failure) {\n\t\t\tconst response = failure && failure.response\n\t\t\tif (response && response.status === 403) {\n\t\t\t\treturn t('nextcloud-vue', 'You are not allowed to see this plan.')\n\t\t\t}\n\t\t\tconst body = response && response.data\n\t\t\tconst detail = body && (body.error || body.message)\n\t\t\treturn typeof detail === 'string' && detail !== '' ? detail : t('nextcloud-vue', 'The plan could not be loaded. Try again.')\n\t\t},\n\n\t\t/**\n\t\t * Read the plan; 404 is \"no plan\", anything else an error.\n\t\t *\n\t\t * @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.id) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/cases/${encodeURIComponent(this.id)}`))\n\t\t\t\tthis.roots = data && Array.isArray(data.items) ? planTree(data.items) : []\n\t\t\t} catch (failure) {\n\t\t\t\tthis.roots = []\n\t\t\t\tif (!(failure && failure.response && failure.response.status === 404)) {\n\t\t\t\t\tthis.error = this.messageOf(failure)\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Start a discretionary item.\n\t\t *\n\t\t * @param {object} item The plan item.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tenable(item) {\n\t\t\treturn this.act(() => axios.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/enable`), {}))\n\t\t},\n\n\t\t/**\n\t\t * Move an item to a target state.\n\t\t *\n\t\t * @param {object} item The plan item.\n\t\t * @param {string} to The target state.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\ttransition(item, to) {\n\t\t\treturn this.act(() => axios.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/transition`), { to, reason: '' }))\n\t\t},\n\n\t\t/**\n\t\t * Run one move, then read the plan again: a move can cascade, so the\n\t\t * next read is the plan, not the write's answer.\n\t\t *\n\t\t * @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps\n\t\t * @param {() => Promise<unknown>} write The move.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync act(write) {\n\t\t\tthis.busy = true\n\t\t\ttry {\n\t\t\t\tawait write()\n\t\t\t\tawait this.load()\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t} catch (failure) {\n\t\t\t\tthis.error = this.messageOf(failure)\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-plan__tree,\n.cn-plan__children {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-plan__children {\n\tpadding-inline-start: 24px;\n}\n\n.cn-plan__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["CnPlanWidgetRow","t","axios"],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, createBlock, withCtx, createVNode, createTextVNode, toDisplayString, Fragment, renderList, createCommentVNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "cn-plan",
|
|
5
|
+
"data-testid": "cn-plan"
|
|
6
|
+
};
|
|
7
|
+
const _hoisted_2 = {
|
|
8
|
+
key: 2,
|
|
9
|
+
class: "cn-plan__tree"
|
|
10
|
+
};
|
|
11
|
+
const _hoisted_3 = {
|
|
12
|
+
key: 0,
|
|
13
|
+
class: "cn-plan__children"
|
|
14
|
+
};
|
|
15
|
+
const _hoisted_4 = {
|
|
16
|
+
key: 3,
|
|
17
|
+
class: "cn-plan__empty",
|
|
18
|
+
"data-testid": "cn-plan-empty"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
22
|
+
const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
|
|
23
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
24
|
+
const _component_NcEmptyContent = resolveComponent("NcEmptyContent");
|
|
25
|
+
const _component_CnPlanWidgetRow = resolveComponent("CnPlanWidgetRow");
|
|
26
|
+
|
|
27
|
+
return (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
28
|
+
($data.loading)
|
|
29
|
+
? (openBlock(), createBlock(_component_NcLoadingIcon, {
|
|
30
|
+
key: 0,
|
|
31
|
+
size: 24
|
|
32
|
+
}))
|
|
33
|
+
: ($data.error)
|
|
34
|
+
? (openBlock(), createBlock(_component_NcEmptyContent, {
|
|
35
|
+
key: 1,
|
|
36
|
+
name: $options.t('nextcloud-vue', 'The plan is unavailable'),
|
|
37
|
+
description: $data.error,
|
|
38
|
+
"data-testid": "cn-plan-error"
|
|
39
|
+
}, {
|
|
40
|
+
action: withCtx(() => [
|
|
41
|
+
createVNode(_component_NcButton, {
|
|
42
|
+
"data-testid": "cn-plan-retry",
|
|
43
|
+
onClick: $options.load
|
|
44
|
+
}, {
|
|
45
|
+
default: withCtx(() => [
|
|
46
|
+
createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Try again')), 1 /* TEXT */)
|
|
47
|
+
]),
|
|
48
|
+
_: 1 /* STABLE */
|
|
49
|
+
}, 8 /* PROPS */, ["onClick"])
|
|
50
|
+
]),
|
|
51
|
+
_: 1 /* STABLE */
|
|
52
|
+
}, 8 /* PROPS */, ["name", "description"]))
|
|
53
|
+
: ($data.roots.length > 0)
|
|
54
|
+
? (openBlock(), createElementBlock("ul", _hoisted_2, [
|
|
55
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($data.roots, (node) => {
|
|
56
|
+
return (openBlock(), createElementBlock("li", {
|
|
57
|
+
key: node.uuid,
|
|
58
|
+
class: "cn-plan__node"
|
|
59
|
+
}, [
|
|
60
|
+
createVNode(_component_CnPlanWidgetRow, {
|
|
61
|
+
item: node,
|
|
62
|
+
busy: $data.busy,
|
|
63
|
+
onEnable: $options.enable,
|
|
64
|
+
onTransition: $options.transition
|
|
65
|
+
}, null, 8 /* PROPS */, ["item", "busy", "onEnable", "onTransition"]),
|
|
66
|
+
(node.children.length > 0)
|
|
67
|
+
? (openBlock(), createElementBlock("ul", _hoisted_3, [
|
|
68
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(node.children, (child) => {
|
|
69
|
+
return (openBlock(), createElementBlock("li", {
|
|
70
|
+
key: child.uuid,
|
|
71
|
+
class: "cn-plan__node"
|
|
72
|
+
}, [
|
|
73
|
+
createVNode(_component_CnPlanWidgetRow, {
|
|
74
|
+
item: child,
|
|
75
|
+
busy: $data.busy,
|
|
76
|
+
onEnable: $options.enable,
|
|
77
|
+
onTransition: $options.transition
|
|
78
|
+
}, null, 8 /* PROPS */, ["item", "busy", "onEnable", "onTransition"])
|
|
79
|
+
]))
|
|
80
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
81
|
+
]))
|
|
82
|
+
: createCommentVNode("v-if", true)
|
|
83
|
+
]))
|
|
84
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
85
|
+
]))
|
|
86
|
+
: (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.text($props.content.emptyText) || $options.t('nextcloud-vue', 'This record has no plan')), 1 /* TEXT */))
|
|
87
|
+
]))
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { render };
|
|
91
|
+
//# sourceMappingURL=CnPlanWidget.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnPlanWidget.vue3.js","sources":["../../../../src/components/CnPlanWidget/CnPlanWidget.vue?vue&type=template&id=425e0d90&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-plan\" data-testid=\"cn-plan\">\n\t\t<NcLoadingIcon v-if=\"loading\" :size=\"24\" />\n\t\t<NcEmptyContent v-else-if=\"error\"\n\t\t\t:name=\"t('nextcloud-vue', 'The plan is unavailable')\"\n\t\t\t:description=\"error\"\n\t\t\tdata-testid=\"cn-plan-error\">\n\t\t\t<template #action>\n\t\t\t\t<NcButton data-testid=\"cn-plan-retry\" @click=\"load\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Try again') }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</NcEmptyContent>\n\t\t<ul v-else-if=\"roots.length > 0\" class=\"cn-plan__tree\">\n\t\t\t<li v-for=\"node in roots\" :key=\"node.uuid\" class=\"cn-plan__node\">\n\t\t\t\t<CnPlanWidgetRow :item=\"node\"\n\t\t\t\t\t:busy=\"busy\"\n\t\t\t\t\t@enable=\"enable\"\n\t\t\t\t\t@transition=\"transition\" />\n\t\t\t\t<ul v-if=\"node.children.length > 0\" class=\"cn-plan__children\">\n\t\t\t\t\t<li v-for=\"child in node.children\" :key=\"child.uuid\" class=\"cn-plan__node\">\n\t\t\t\t\t\t<CnPlanWidgetRow :item=\"child\"\n\t\t\t\t\t\t\t:busy=\"busy\"\n\t\t\t\t\t\t\t@enable=\"enable\"\n\t\t\t\t\t\t\t@transition=\"transition\" />\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\t\t<p v-else class=\"cn-plan__empty\" data-testid=\"cn-plan-empty\">\n\t\t\t{{ text(content.emptyText) || t('nextcloud-vue', 'This record has no plan') }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'\nimport CnPlanWidgetRow from './CnPlanWidgetRow.vue'\nimport { planTree } from '../../utils/planTree.js'\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/**\n * CnPlanWidget — the `plan` detail widget: a record's planned steps (stages,\n * tasks and milestones) as OpenRegister's case layer holds them, read from\n * `/api/cases/{id}`, with the moves OpenRegister allows: start a\n * discretionary item, complete or terminate one. It judges nothing:\n * OpenRegister decides every move and its refusal is shown as it says it.\n * A 404 means the record has no plan; any other failure is an error with a\n * retry, never an empty plan. Any app whose records run on OpenRegister's\n * case layer uses it; dossiq's case plan is the first.\n *\n * `content`: `emptyText`, through the host translate.\n *\n * The record's id comes from `objectId`, else the bound record.\n */\nexport default {\n\tname: 'CnPlanWidget',\n\n\tcomponents: { CnPlanWidgetRow, NcButton, NcEmptyContent, NcLoadingIcon },\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/**\n\t\t * The widget's configuration: `{ emptyText? }`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The bound record, on a detail page.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The record's id (else the bound record's). */\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\tloading: true,\n\t\t\tbusy: false,\n\t\t\terror: '',\n\t\t\troots: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The record id. */\n\t\tid() {\n\t\t\tconst bound = this.objectData || {}\n\t\t\treturn String(this.objectId || bound.id || (bound['@self'] && bound['@self'].id) || '')\n\t\t},\n\t},\n\n\tmounted() {\n\t\tsubscribe(PAGE_REFRESH, this.load)\n\t\tthis.load()\n\t},\n\n\tbeforeUnmount() {\n\t\tunsubscribe(PAGE_REFRESH, this.load)\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * The server's sentence for a failure.\n\t\t *\n\t\t * @param {unknown} failure The rejection.\n\t\t * @return {string}\n\t\t */\n\t\tmessageOf(failure) {\n\t\t\tconst response = failure && failure.response\n\t\t\tif (response && response.status === 403) {\n\t\t\t\treturn t('nextcloud-vue', 'You are not allowed to see this plan.')\n\t\t\t}\n\t\t\tconst body = response && response.data\n\t\t\tconst detail = body && (body.error || body.message)\n\t\t\treturn typeof detail === 'string' && detail !== '' ? detail : t('nextcloud-vue', 'The plan could not be loaded. Try again.')\n\t\t},\n\n\t\t/**\n\t\t * Read the plan; 404 is \"no plan\", anything else an error.\n\t\t *\n\t\t * @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tif (!this.id) {\n\t\t\t\tthis.loading = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst { data } = await axios.get(generateUrl(`/apps/openregister/api/cases/${encodeURIComponent(this.id)}`))\n\t\t\t\tthis.roots = data && Array.isArray(data.items) ? planTree(data.items) : []\n\t\t\t} catch (failure) {\n\t\t\t\tthis.roots = []\n\t\t\t\tif (!(failure && failure.response && failure.response.status === 404)) {\n\t\t\t\t\tthis.error = this.messageOf(failure)\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Start a discretionary item.\n\t\t *\n\t\t * @param {object} item The plan item.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tenable(item) {\n\t\t\treturn this.act(() => axios.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/enable`), {}))\n\t\t},\n\n\t\t/**\n\t\t * Move an item to a target state.\n\t\t *\n\t\t * @param {object} item The plan item.\n\t\t * @param {string} to The target state.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\ttransition(item, to) {\n\t\t\treturn this.act(() => axios.post(generateUrl(`/apps/openregister/api/cases/items/${encodeURIComponent(item.uuid)}/transition`), { to, reason: '' }))\n\t\t},\n\n\t\t/**\n\t\t * Run one move, then read the plan again: a move can cascade, so the\n\t\t * next read is the plan, not the write's answer.\n\t\t *\n\t\t * @spec openspec/changes/plan-widget/specs/plan-widget/spec.md#requirement-a-record-shows-its-planned-steps\n\t\t * @param {() => Promise<unknown>} write The move.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync act(write) {\n\t\t\tthis.busy = true\n\t\t\ttry {\n\t\t\t\tawait write()\n\t\t\t\tawait this.load()\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t} catch (failure) {\n\t\t\t\tthis.error = this.messageOf(failure)\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-plan__tree,\n.cn-plan__children {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-plan__children {\n\tpadding-inline-start: 24px;\n}\n\n.cn-plan__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createBlock","_createVNode","_Fragment","_renderList"],"mappings":";;;AASM,EAAA,KAAK,EAAC,SAAS;AAAC,EAAA,aAAA,EAAA,SAAA;;;;AAYF,EAAA,KAAA,EAAA,eAAA;;;;AAME,EAAA,KAAA,EAAA,mBAAA;;;;;;;;;;;;;;AAlBnB,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;KACoB,KAAO,CAAA,OAAA;iCAAA,CAAA,wBAAA,EAAA;;AAAA,UAAA,IAAA,EAAA,EAAA;;SACV,KAAA,CAAA,KAAA;wBAAjBC,WASa,CAAA,yBAAA,EAAA;;AARZ,YAAA,IAAI,EAAE,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,yBAAA,CAAA;AACN,YAAA,WAAU,EAAE,KAAK,CAAA,KAAA;yBACR,EAAA,eAAA;;AACD,YAAA,MAAA,UACT,MAEW;cAFXC,WAEW,CAAA,mBAAA,EAAA;AAFD,gBAAA,aAAI,EAAA,eAAA;AAAA,gBAAA,OAAA,EAAA,QAAA,CAAA,IAAA;;uCACwB;kDAAlC,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,WAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;AAIQ,UAAA,CAAA,KAAA,CAAA,KAAG,CAAA,MAAA,GAAA,CAAA;AAAf,aAAAH,SAAA,EAAA,EAAAC,kBAAA,CAeC,MAfD,UAeC,EAAA;kDADD,CAAAG,QAAA,EAAA,IAAA,EAAAC,UAAA,CAbiB,KAAK,CAAA,KAAA,EAAA,CAAb,IAAI,KAAA;uDAab,CAAA,IAAA,EAAA;kBAbyB,GAAC,EAAA,IAAA,CAAA,IAAA;AAAA,kBAAA,KAAA,EAAA,eAAA;;kBAC3BF,WAGc,CAAA,0BAAA,EAAA;AAHI,oBAAA,IAAI,EAAE,IAAI;AAC1B,oBAAA,IAAI,EAAE,KAAI,CAAA,IAAA;AACV,oBAAA,QAAM,EAAE,QAAM,CAAA,MAAA;gCACJ,EAAE,QAAA,CAAA,UAAA;;mBACJ,IAAI,CAAC,QAAG,CAAA,MAAA,GAAA,CAAA;AAAf,uBAAAH,SAAA,EAAA,EAAAC,kBAAA,CAOE,MAPF,UAOE,EAAA;6DADCG,QALe,EAAA,IAAA,EAAAC,UAAA,CAAA,IAAI,CAAC,QAAG,GAAjB,KAAK,KAAA;iEAKX,CAAA,IAAA,EAAA;4BALuB,GAAA,EAAA,KAAA,CAAA,IAAA;AAAA,4BAAA,KAAA,EAAA,eAAA;;4BAC3BF,WAGA,CAAA,0BAAA,EAAA;AAHG,8BAAA,IAAA,EAAA,KAAA;AACD,8BAAA,IAAA,EAAA,KAAA,CAAA,IAAA;AACD,8BAAA,QAAA,EAAA,QAAA,CAAA,MAAA;AACD,8BAAA,YAAA,EAAA,QAAA,CAAA,UAAA;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnPlanWidgetRow.vue2.js';
|
|
2
|
+
import { render } from './CnPlanWidgetRow.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-06842774";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnPlanWidgetRow.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnPlanWidgetRow.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { translate } from '@nextcloud/l10n';
|
|
2
|
+
import { NcButton } from '@nextcloud/vue';
|
|
3
|
+
import { offeredTransitions } from '../../utils/planTree.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* One plan item in CnPlanWidget: its name, its state and the moves offered.
|
|
7
|
+
*/
|
|
8
|
+
var script = {
|
|
9
|
+
name: 'CnPlanWidgetRow',
|
|
10
|
+
|
|
11
|
+
components: { NcButton },
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
/**
|
|
15
|
+
* The plan item (`uuid`, `key`, `name`, `state`, `type`, `discretionary`).
|
|
16
|
+
*
|
|
17
|
+
* @type {object}
|
|
18
|
+
*/
|
|
19
|
+
item: {
|
|
20
|
+
type: Object,
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/** A move is running. */
|
|
25
|
+
busy: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
emits: ['enable', 'transition'],
|
|
32
|
+
|
|
33
|
+
computed: {
|
|
34
|
+
/** @return {string[]} The moves offered. */
|
|
35
|
+
targets() {
|
|
36
|
+
return offeredTransitions(this.item)
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
methods: {
|
|
41
|
+
t: translate,
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The word for a state.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} state The state.
|
|
47
|
+
* @return {string}
|
|
48
|
+
*/
|
|
49
|
+
stateLabel(state) {
|
|
50
|
+
const labels = {
|
|
51
|
+
available: translate('nextcloud-vue', 'Waiting'),
|
|
52
|
+
enabled: translate('nextcloud-vue', 'Can start'),
|
|
53
|
+
active: translate('nextcloud-vue', 'In progress'),
|
|
54
|
+
completed: translate('nextcloud-vue', 'Done'),
|
|
55
|
+
terminated: translate('nextcloud-vue', 'Stopped'),
|
|
56
|
+
disabled: translate('nextcloud-vue', 'Not needed'),
|
|
57
|
+
};
|
|
58
|
+
return labels[state] || String(state || '')
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export { script as default };
|
|
64
|
+
//# sourceMappingURL=CnPlanWidgetRow.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnPlanWidgetRow.vue2.js","sources":["../../../../src/components/CnPlanWidget/CnPlanWidgetRow.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-plan-row\" :data-testid=\"`cn-plan-row-${item.key || item.uuid}`\">\n\t\t<span class=\"cn-plan-row__name\">{{ item.name }}</span>\n\t\t<span class=\"cn-plan-row__state\" :data-state=\"item.state\">{{ stateLabel(item.state) }}</span>\n\t\t<NcButton v-if=\"item.state === 'enabled' && item.discretionary\"\n\t\t\t:disabled=\"busy\"\n\t\t\t:data-testid=\"`cn-plan-enable-${item.key || item.uuid}`\"\n\t\t\t@click=\"$emit('enable', item)\">\n\t\t\t{{ t('nextcloud-vue', 'Start') }}\n\t\t</NcButton>\n\t\t<NcButton v-for=\"target in targets\"\n\t\t\t:key=\"target\"\n\t\t\t:disabled=\"busy\"\n\t\t\t:data-testid=\"`cn-plan-${target}-${item.key || item.uuid}`\"\n\t\t\t@click=\"$emit('transition', item, target)\">\n\t\t\t{{ target === 'completed' ? t('nextcloud-vue', 'Complete') : t('nextcloud-vue', 'Stop') }}\n\t\t</NcButton>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport { offeredTransitions } from '../../utils/planTree.js'\n\n/**\n * One plan item in CnPlanWidget: its name, its state and the moves offered.\n */\nexport default {\n\tname: 'CnPlanWidgetRow',\n\n\tcomponents: { NcButton },\n\n\tprops: {\n\t\t/**\n\t\t * The plan item (`uuid`, `key`, `name`, `state`, `type`, `discretionary`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\titem: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** A move is running. */\n\t\tbusy: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['enable', 'transition'],\n\n\tcomputed: {\n\t\t/** @return {string[]} The moves offered. */\n\t\ttargets() {\n\t\t\treturn offeredTransitions(this.item)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * The word for a state.\n\t\t *\n\t\t * @param {string} state The state.\n\t\t * @return {string}\n\t\t */\n\t\tstateLabel(state) {\n\t\t\tconst labels = {\n\t\t\t\tavailable: t('nextcloud-vue', 'Waiting'),\n\t\t\t\tenabled: t('nextcloud-vue', 'Can start'),\n\t\t\t\tactive: t('nextcloud-vue', 'In progress'),\n\t\t\t\tcompleted: t('nextcloud-vue', 'Done'),\n\t\t\t\tterminated: t('nextcloud-vue', 'Stopped'),\n\t\t\t\tdisabled: t('nextcloud-vue', 'Not needed'),\n\t\t\t}\n\t\t\treturn labels[state] || String(state || '')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-plan-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding-block: 6px;\n}\n\n.cn-plan-row__name {\n\tflex: 1 1 auto;\n\tfont-weight: 600;\n}\n\n.cn-plan-row__state {\n\tpadding: 2px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n}\n\n.cn-plan-row__state[data-state='active'] {\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-plan-row__state[data-state='completed'] {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n</style>\n"],"names":["t"],"mappings":";;;;AA6BA;;;AAGA,aAAe;CACd,IAAI,EAAE,iBAAiB;;AAEvB,CAAA,UAAU,EAAE,EAAE,UAAU;;AAExB,CAAA,KAAK,EAAE;AACN;AACC;AACA;;;EAGD,IAAI,EAAE;GACL,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;EACA,IAAI,EAAE;GACL,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;EACD;;CAED,KAAK,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC;;AAE/B,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAA;GACnC;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;AACC;AACA;;AAEA;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;GACjB,MAAM,MAAK,GAAI;AACd,IAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;AACxC,IAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,WAAW,CAAC;AACxC,IAAA,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,aAAa,CAAC;AACzC,IAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,MAAM,CAAC;AACrC,IAAA,UAAU,EAAEA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;AACzC,IAAA,QAAQ,EAAEA,SAAC,CAAC,eAAe,EAAE,YAAY,CAAC;AAC3C,KAAA;AACA,GAAA,OAAO,MAAM,CAAC,KAAK,CAAE,IAAG,MAAM,CAAC,KAAI,IAAK,EAAE,CAAA;GAC1C;EACD;AACF;;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, createElementVNode, toDisplayString, createBlock, withCtx, createTextVNode, createCommentVNode, Fragment, renderList } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = ["data-testid"];
|
|
4
|
+
const _hoisted_2 = { class: "cn-plan-row__name" };
|
|
5
|
+
const _hoisted_3 = ["data-state"];
|
|
6
|
+
|
|
7
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
8
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
9
|
+
|
|
10
|
+
return (openBlock(), createElementBlock("div", {
|
|
11
|
+
class: "cn-plan-row",
|
|
12
|
+
"data-testid": `cn-plan-row-${$props.item.key || $props.item.uuid}`
|
|
13
|
+
}, [
|
|
14
|
+
createElementVNode("span", _hoisted_2, toDisplayString($props.item.name), 1 /* TEXT */),
|
|
15
|
+
createElementVNode("span", {
|
|
16
|
+
class: "cn-plan-row__state",
|
|
17
|
+
"data-state": $props.item.state
|
|
18
|
+
}, toDisplayString($options.stateLabel($props.item.state)), 9 /* TEXT, PROPS */, _hoisted_3),
|
|
19
|
+
($props.item.state === 'enabled' && $props.item.discretionary)
|
|
20
|
+
? (openBlock(), createBlock(_component_NcButton, {
|
|
21
|
+
key: 0,
|
|
22
|
+
disabled: $props.busy,
|
|
23
|
+
"data-testid": `cn-plan-enable-${$props.item.key || $props.item.uuid}`,
|
|
24
|
+
onClick: _cache[0] || (_cache[0] = $event => (_ctx.$emit('enable', $props.item)))
|
|
25
|
+
}, {
|
|
26
|
+
default: withCtx(() => [
|
|
27
|
+
createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Start')), 1 /* TEXT */)
|
|
28
|
+
]),
|
|
29
|
+
_: 1 /* STABLE */
|
|
30
|
+
}, 8 /* PROPS */, ["disabled", "data-testid"]))
|
|
31
|
+
: createCommentVNode("v-if", true),
|
|
32
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.targets, (target) => {
|
|
33
|
+
return (openBlock(), createBlock(_component_NcButton, {
|
|
34
|
+
key: target,
|
|
35
|
+
disabled: $props.busy,
|
|
36
|
+
"data-testid": `cn-plan-${target}-${$props.item.key || $props.item.uuid}`,
|
|
37
|
+
onClick: $event => (_ctx.$emit('transition', $props.item, target))
|
|
38
|
+
}, {
|
|
39
|
+
default: withCtx(() => [
|
|
40
|
+
createTextVNode(toDisplayString(target === 'completed' ? $options.t('nextcloud-vue', 'Complete') : $options.t('nextcloud-vue', 'Stop')), 1 /* TEXT */)
|
|
41
|
+
]),
|
|
42
|
+
_: 2 /* DYNAMIC */
|
|
43
|
+
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"]))
|
|
44
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
45
|
+
], 8 /* PROPS */, _hoisted_1))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { render };
|
|
49
|
+
//# sourceMappingURL=CnPlanWidgetRow.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnPlanWidgetRow.vue3.js","sources":["../../../../src/components/CnPlanWidget/CnPlanWidgetRow.vue?vue&type=template&id=06842774&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-plan-row\" :data-testid=\"`cn-plan-row-${item.key || item.uuid}`\">\n\t\t<span class=\"cn-plan-row__name\">{{ item.name }}</span>\n\t\t<span class=\"cn-plan-row__state\" :data-state=\"item.state\">{{ stateLabel(item.state) }}</span>\n\t\t<NcButton v-if=\"item.state === 'enabled' && item.discretionary\"\n\t\t\t:disabled=\"busy\"\n\t\t\t:data-testid=\"`cn-plan-enable-${item.key || item.uuid}`\"\n\t\t\t@click=\"$emit('enable', item)\">\n\t\t\t{{ t('nextcloud-vue', 'Start') }}\n\t\t</NcButton>\n\t\t<NcButton v-for=\"target in targets\"\n\t\t\t:key=\"target\"\n\t\t\t:disabled=\"busy\"\n\t\t\t:data-testid=\"`cn-plan-${target}-${item.key || item.uuid}`\"\n\t\t\t@click=\"$emit('transition', item, target)\">\n\t\t\t{{ target === 'completed' ? t('nextcloud-vue', 'Complete') : t('nextcloud-vue', 'Stop') }}\n\t\t</NcButton>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton } from '@nextcloud/vue'\nimport { offeredTransitions } from '../../utils/planTree.js'\n\n/**\n * One plan item in CnPlanWidget: its name, its state and the moves offered.\n */\nexport default {\n\tname: 'CnPlanWidgetRow',\n\n\tcomponents: { NcButton },\n\n\tprops: {\n\t\t/**\n\t\t * The plan item (`uuid`, `key`, `name`, `state`, `type`, `discretionary`).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\titem: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** A move is running. */\n\t\tbusy: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\t},\n\n\temits: ['enable', 'transition'],\n\n\tcomputed: {\n\t\t/** @return {string[]} The moves offered. */\n\t\ttargets() {\n\t\t\treturn offeredTransitions(this.item)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * The word for a state.\n\t\t *\n\t\t * @param {string} state The state.\n\t\t * @return {string}\n\t\t */\n\t\tstateLabel(state) {\n\t\t\tconst labels = {\n\t\t\t\tavailable: t('nextcloud-vue', 'Waiting'),\n\t\t\t\tenabled: t('nextcloud-vue', 'Can start'),\n\t\t\t\tactive: t('nextcloud-vue', 'In progress'),\n\t\t\t\tcompleted: t('nextcloud-vue', 'Done'),\n\t\t\t\tterminated: t('nextcloud-vue', 'Stopped'),\n\t\t\t\tdisabled: t('nextcloud-vue', 'Not needed'),\n\t\t\t}\n\t\t\treturn labels[state] || String(state || '')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-plan-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tpadding-block: 6px;\n}\n\n.cn-plan-row__name {\n\tflex: 1 1 auto;\n\tfont-weight: 600;\n}\n\n.cn-plan-row__state {\n\tpadding: 2px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n}\n\n.cn-plan-row__state[data-state='active'] {\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-plan-row__state[data-state='completed'] {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createBlock"],"mappings":";;;AAUQ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,mBAAmB,GAAA;;;;;;uBAD9BA;AAAG,IAAA,KAAK,EAAC,aAAM;AAAA,IAAA,aAAA,iBAAA,MAAA,CAAA,IAAA,CAAA,GAAA,IAAA,MAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA;;uBACsC,kBAAA,EAAnBC,eAAA,CAAA,MAAA,CAAA,IAAI,CAAC,IAAK,CAAA,EAAA,CAAA,YAAA;sBACd,CAAA,MAAA,EAAA;AAAzB,MAAA,KAAK,EAAC,oBAAmB;MAAA,YAAA,EAAA,MAAA,CAAA,IAAA,CAAA,KAAA;uBAAA,QAAA,CAAA,UAAA,CAAA,MAAA,CAAA,IAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AACf,IAAA,CAAA,MAAA,CAAA,IAAI,CAAC,KAAK,KAAO,SAAA,IAAA,MAAA,CAAA,IAAA,CAAA,aAAA;iCAKtB,CAAA,mBAAA,EAAA;;AAJT,UAAA,QAAQ,EAAA,MAAA,CAAA,IAAA;AACR,UAAA,aAAW,oBAAoB,MAAC,CAAA,IAAA,CAAA,GAAA,IAAA,MAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA;UAChC,OAAK,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,IAAI,CAAA,KAAA,CAAA,QAAA,EAAA,MAAA,CAAA,IAAA,CAAA,CAAA,CAAA;;2BACZ,MAAe;4CAAZ,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,OAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;sBAEJD,8CAA0B,QAAM,CAAA,OAAA,EAAA,CAAhB,MAAM,KAAA;2BAAtBE;AACC,QAAA,GAAG,EAAE,MAAM;AACX,QAAA,QAAQ,EAAA,MAAA,CAAA,IAAA;QACR,aAAE,EAAA,CAAA,QAAA,EAAA,MAAA,CAAA,CAAA,EAAA,MAAA,CAAA,IAAA,CAAA,GAAA,IAAA,MAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnRedactionEditor.vue2.js';
|
|
2
|
+
import { render } from './CnRedactionEditor.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-5802664c";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnRedactionEditor.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnRedactionEditor.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|