@conduction/nextcloud-vue 2.56.0-beta.63 → 2.56.0-beta.64
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/CnWorkQueue/CnWorkQueue.vue.js +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js +8 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue2.js.map +1 -1
- package/dist/esm/components/CnWorkQueue/CnWorkQueue.vue3.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +33 -33
- package/dist/esm/utils/actionsDispatcher.js +5 -2
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +281 -142
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +33 -33
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +134 -13
- package/src/components/CnWorkQueue/CnWorkQueue.vue +8 -1
- package/src/utils/actionsDispatcher.js +4 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/dist/nextcloud-vue.cjs.js.map
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 44704290 bytes
|
|
4
|
+
sha256: e14648ce27bae8fed4271ddde5d95e10a1a5616bf123c75c6ae73769d697d1e6
|
package/dist/nextcloud-vue.css
CHANGED
|
@@ -28366,35 +28366,35 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
28366
28366
|
}
|
|
28367
28367
|
|
|
28368
28368
|
|
|
28369
|
-
.cn-work-queue[data-v-
|
|
28369
|
+
.cn-work-queue[data-v-d5bc0a42] {
|
|
28370
28370
|
display: flex;
|
|
28371
28371
|
flex-direction: column;
|
|
28372
28372
|
gap: 24px;
|
|
28373
28373
|
}
|
|
28374
|
-
.cn-work-queue__head[data-v-
|
|
28375
|
-
.cn-work-queue__group-head[data-v-
|
|
28374
|
+
.cn-work-queue__head[data-v-d5bc0a42],
|
|
28375
|
+
.cn-work-queue__group-head[data-v-d5bc0a42] {
|
|
28376
28376
|
display: flex;
|
|
28377
28377
|
flex-wrap: wrap;
|
|
28378
28378
|
align-items: center;
|
|
28379
28379
|
justify-content: space-between;
|
|
28380
28380
|
gap: 12px;
|
|
28381
28381
|
}
|
|
28382
|
-
.cn-work-queue__title[data-v-
|
|
28382
|
+
.cn-work-queue__title[data-v-d5bc0a42] {
|
|
28383
28383
|
margin: 0;
|
|
28384
28384
|
font-size: 28px;
|
|
28385
28385
|
font-weight: 700;
|
|
28386
28386
|
}
|
|
28387
|
-
.cn-work-queue__actions[data-v-
|
|
28387
|
+
.cn-work-queue__actions[data-v-d5bc0a42] {
|
|
28388
28388
|
display: flex;
|
|
28389
28389
|
gap: 8px;
|
|
28390
28390
|
}
|
|
28391
|
-
.cn-work-queue__group[data-v-
|
|
28391
|
+
.cn-work-queue__group[data-v-d5bc0a42] {
|
|
28392
28392
|
padding: 20px 24px;
|
|
28393
28393
|
border: 1px solid var(--color-border);
|
|
28394
28394
|
border-radius: var(--border-radius-large);
|
|
28395
28395
|
background: var(--color-main-background);
|
|
28396
28396
|
}
|
|
28397
|
-
.cn-work-queue__group-title[data-v-
|
|
28397
|
+
.cn-work-queue__group-title[data-v-d5bc0a42] {
|
|
28398
28398
|
display: flex;
|
|
28399
28399
|
align-items: center;
|
|
28400
28400
|
gap: 8px;
|
|
@@ -28402,33 +28402,33 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
28402
28402
|
font-size: 18px;
|
|
28403
28403
|
font-weight: 700;
|
|
28404
28404
|
}
|
|
28405
|
-
.cn-work-queue__count[data-v-
|
|
28405
|
+
.cn-work-queue__count[data-v-d5bc0a42] {
|
|
28406
28406
|
padding: 0 8px;
|
|
28407
28407
|
border-radius: 10px;
|
|
28408
28408
|
background: var(--color-background-dark);
|
|
28409
28409
|
font-size: 12px;
|
|
28410
28410
|
font-weight: 600;
|
|
28411
28411
|
}
|
|
28412
|
-
.cn-work-queue__muted[data-v-
|
|
28412
|
+
.cn-work-queue__muted[data-v-d5bc0a42] {
|
|
28413
28413
|
margin: 4px 0 8px;
|
|
28414
28414
|
color: var(--color-text-maxcontrast);
|
|
28415
28415
|
}
|
|
28416
|
-
.cn-work-queue__items[data-v-
|
|
28416
|
+
.cn-work-queue__items[data-v-d5bc0a42] {
|
|
28417
28417
|
margin: 0;
|
|
28418
28418
|
padding: 0;
|
|
28419
28419
|
list-style: none;
|
|
28420
28420
|
}
|
|
28421
|
-
.cn-work-queue__item[data-v-
|
|
28421
|
+
.cn-work-queue__item[data-v-d5bc0a42] {
|
|
28422
28422
|
display: flex;
|
|
28423
28423
|
align-items: center;
|
|
28424
28424
|
gap: 16px;
|
|
28425
28425
|
padding: 12px 0;
|
|
28426
28426
|
border-block-end: 1px solid var(--color-border);
|
|
28427
28427
|
}
|
|
28428
|
-
.cn-work-queue__item[data-v-
|
|
28428
|
+
.cn-work-queue__item[data-v-d5bc0a42]:last-child {
|
|
28429
28429
|
border-block-end: none;
|
|
28430
28430
|
}
|
|
28431
|
-
.cn-work-queue__avatar[data-v-
|
|
28431
|
+
.cn-work-queue__avatar[data-v-d5bc0a42] {
|
|
28432
28432
|
display: inline-flex;
|
|
28433
28433
|
flex: none;
|
|
28434
28434
|
align-items: center;
|
|
@@ -28441,24 +28441,24 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
28441
28441
|
font-size: 12px;
|
|
28442
28442
|
font-weight: 700;
|
|
28443
28443
|
}
|
|
28444
|
-
.cn-work-queue__body[data-v-
|
|
28444
|
+
.cn-work-queue__body[data-v-d5bc0a42] {
|
|
28445
28445
|
display: flex;
|
|
28446
28446
|
flex: 1 1 auto;
|
|
28447
28447
|
flex-direction: column;
|
|
28448
28448
|
min-width: 0;
|
|
28449
28449
|
}
|
|
28450
|
-
.cn-work-queue__link[data-v-
|
|
28450
|
+
.cn-work-queue__link[data-v-d5bc0a42] {
|
|
28451
28451
|
color: var(--color-main-text);
|
|
28452
28452
|
font-weight: 700;
|
|
28453
28453
|
text-decoration: none;
|
|
28454
28454
|
}
|
|
28455
|
-
.cn-work-queue__link[data-v-
|
|
28455
|
+
.cn-work-queue__link[data-v-d5bc0a42]:hover {
|
|
28456
28456
|
text-decoration: underline;
|
|
28457
28457
|
}
|
|
28458
|
-
.cn-work-queue__item--late .cn-work-queue__link[data-v-
|
|
28458
|
+
.cn-work-queue__item--late .cn-work-queue__link[data-v-d5bc0a42] {
|
|
28459
28459
|
color: var(--color-error);
|
|
28460
28460
|
}
|
|
28461
|
-
.cn-work-queue__sub[data-v-
|
|
28461
|
+
.cn-work-queue__sub[data-v-d5bc0a42] {
|
|
28462
28462
|
display: flex;
|
|
28463
28463
|
flex-wrap: wrap;
|
|
28464
28464
|
gap: 12px;
|
|
@@ -41817,12 +41817,12 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
41817
41817
|
}
|
|
41818
41818
|
|
|
41819
41819
|
|
|
41820
|
-
.cn-action-dialog[data-v-
|
|
41820
|
+
.cn-action-dialog[data-v-0bb28fd1] {
|
|
41821
41821
|
display: flex;
|
|
41822
41822
|
flex-direction: column;
|
|
41823
41823
|
gap: 16px;
|
|
41824
41824
|
}
|
|
41825
|
-
.cn-action-dialog__summary[data-v-
|
|
41825
|
+
.cn-action-dialog__summary[data-v-0bb28fd1] {
|
|
41826
41826
|
display: flex;
|
|
41827
41827
|
align-items: center;
|
|
41828
41828
|
gap: 10px;
|
|
@@ -41830,13 +41830,13 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
41830
41830
|
border: 1px solid var(--color-border);
|
|
41831
41831
|
border-radius: var(--border-radius-large, 8px);
|
|
41832
41832
|
}
|
|
41833
|
-
.cn-action-dialog__summary-text[data-v-
|
|
41833
|
+
.cn-action-dialog__summary-text[data-v-0bb28fd1] {
|
|
41834
41834
|
display: flex;
|
|
41835
41835
|
flex: 1 1 auto;
|
|
41836
41836
|
flex-direction: column;
|
|
41837
41837
|
min-width: 0;
|
|
41838
41838
|
}
|
|
41839
|
-
.cn-action-dialog__badge[data-v-
|
|
41839
|
+
.cn-action-dialog__badge[data-v-0bb28fd1] {
|
|
41840
41840
|
padding: 3px 10px;
|
|
41841
41841
|
border-radius: 12px;
|
|
41842
41842
|
background: var(--color-background-dark);
|
|
@@ -41844,25 +41844,25 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
41844
41844
|
font-weight: 600;
|
|
41845
41845
|
white-space: nowrap;
|
|
41846
41846
|
}
|
|
41847
|
-
.cn-action-dialog__title[data-v-
|
|
41847
|
+
.cn-action-dialog__title[data-v-0bb28fd1] {
|
|
41848
41848
|
margin: 0 0 8px;
|
|
41849
41849
|
font-size: 15px;
|
|
41850
41850
|
font-weight: 700;
|
|
41851
41851
|
}
|
|
41852
|
-
.cn-action-dialog__facts[data-v-
|
|
41852
|
+
.cn-action-dialog__facts[data-v-0bb28fd1] {
|
|
41853
41853
|
display: grid;
|
|
41854
41854
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
41855
41855
|
gap: 8px 16px;
|
|
41856
41856
|
margin: 0;
|
|
41857
41857
|
}
|
|
41858
|
-
.cn-action-dialog__facts dt[data-v-
|
|
41858
|
+
.cn-action-dialog__facts dt[data-v-0bb28fd1] {
|
|
41859
41859
|
color: var(--color-text-maxcontrast);
|
|
41860
41860
|
font-size: 13px;
|
|
41861
41861
|
}
|
|
41862
|
-
.cn-action-dialog__facts dd[data-v-
|
|
41862
|
+
.cn-action-dialog__facts dd[data-v-0bb28fd1] {
|
|
41863
41863
|
margin: 0;
|
|
41864
41864
|
}
|
|
41865
|
-
.cn-action-dialog__checks[data-v-
|
|
41865
|
+
.cn-action-dialog__checks[data-v-0bb28fd1] {
|
|
41866
41866
|
display: flex;
|
|
41867
41867
|
flex-direction: column;
|
|
41868
41868
|
gap: 8px;
|
|
@@ -41870,28 +41870,28 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
|
|
|
41870
41870
|
padding: 0;
|
|
41871
41871
|
list-style: none;
|
|
41872
41872
|
}
|
|
41873
|
-
.cn-action-dialog__check[data-v-
|
|
41873
|
+
.cn-action-dialog__check[data-v-0bb28fd1] {
|
|
41874
41874
|
display: flex;
|
|
41875
41875
|
flex-wrap: wrap;
|
|
41876
41876
|
align-items: center;
|
|
41877
41877
|
gap: 8px;
|
|
41878
41878
|
}
|
|
41879
|
-
.cn-action-dialog__check-icon[data-v-
|
|
41879
|
+
.cn-action-dialog__check-icon[data-v-0bb28fd1] {
|
|
41880
41880
|
color: var(--color-text-maxcontrast);
|
|
41881
41881
|
}
|
|
41882
|
-
.cn-action-dialog__check-icon--met[data-v-
|
|
41882
|
+
.cn-action-dialog__check-icon--met[data-v-0bb28fd1] {
|
|
41883
41883
|
color: var(--color-success-text, var(--color-success));
|
|
41884
41884
|
}
|
|
41885
|
-
.cn-action-dialog__muted[data-v-
|
|
41885
|
+
.cn-action-dialog__muted[data-v-0bb28fd1] {
|
|
41886
41886
|
color: var(--color-text-maxcontrast);
|
|
41887
41887
|
font-size: 14px;
|
|
41888
41888
|
}
|
|
41889
|
-
.cn-action-dialog__field[data-v-
|
|
41889
|
+
.cn-action-dialog__field[data-v-0bb28fd1] {
|
|
41890
41890
|
display: flex;
|
|
41891
41891
|
flex-direction: column;
|
|
41892
41892
|
gap: 4px;
|
|
41893
41893
|
}
|
|
41894
|
-
.cn-action-dialog__error[data-v-
|
|
41894
|
+
.cn-action-dialog__error[data-v-0bb28fd1] {
|
|
41895
41895
|
margin: 0;
|
|
41896
41896
|
color: var(--color-error-text, var(--color-error));
|
|
41897
41897
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/nextcloud-vue",
|
|
3
|
-
"version": "2.56.0-beta.
|
|
3
|
+
"version": "2.56.0-beta.64",
|
|
4
4
|
"description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
|
|
5
5
|
"homepage": "https://github.com/ConductionNL/nextcloud-vue#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<template>
|
|
6
6
|
<CnDialog
|
|
7
7
|
:name="text(config.title) || t('nextcloud-vue', 'Confirm')"
|
|
8
|
-
:eyebrow="
|
|
8
|
+
:eyebrow="eyebrowText"
|
|
9
9
|
:subtitle="text(config.subtitle)"
|
|
10
10
|
width="form"
|
|
11
11
|
:noClose="busy"
|
|
@@ -63,6 +63,24 @@
|
|
|
63
63
|
</ul>
|
|
64
64
|
</section>
|
|
65
65
|
|
|
66
|
+
<!-- Fields the action asks for, sent beside the reason. -->
|
|
67
|
+
<div v-for="field in fields"
|
|
68
|
+
:key="field.field"
|
|
69
|
+
class="cn-action-dialog__field"
|
|
70
|
+
:data-testid="`cn-action-dialog-field-${field.field}`">
|
|
71
|
+
<NcSelect v-if="field.type === 'select'"
|
|
72
|
+
:modelValue="selectedOption(field)"
|
|
73
|
+
:options="optionsOf(field)"
|
|
74
|
+
:inputLabel="text(field.label) || field.field"
|
|
75
|
+
:clearable="field.required === false"
|
|
76
|
+
@update:modelValue="(option) => pick(field, option)" />
|
|
77
|
+
<NcTextField v-else
|
|
78
|
+
:modelValue="values[field.field] || ''"
|
|
79
|
+
:type="field.type === 'datetime' ? 'datetime-local' : (field.type === 'date' ? 'date' : 'text')"
|
|
80
|
+
:label="text(field.label) || field.field"
|
|
81
|
+
@update:modelValue="(value) => setValue(field.field, value)" />
|
|
82
|
+
</div>
|
|
83
|
+
|
|
66
84
|
<div v-if="config.reason" class="cn-action-dialog__field">
|
|
67
85
|
<NcTextArea
|
|
68
86
|
:id="reasonId"
|
|
@@ -116,7 +134,7 @@ import axios from '@nextcloud/axios'
|
|
|
116
134
|
import { emit } from '@nextcloud/event-bus'
|
|
117
135
|
import { translate as t } from '@nextcloud/l10n'
|
|
118
136
|
import { generateUrl } from '@nextcloud/router'
|
|
119
|
-
import { NcButton, NcNoteCard, NcTextArea } from '@nextcloud/vue'
|
|
137
|
+
import { NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'
|
|
120
138
|
import CheckCircle from 'vue-material-design-icons/CheckCircle.vue'
|
|
121
139
|
import CircleOutline from 'vue-material-design-icons/CircleOutline.vue'
|
|
122
140
|
import HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'
|
|
@@ -141,7 +159,8 @@ let reasonSeq = 0
|
|
|
141
159
|
* note and Archive it.
|
|
142
160
|
*
|
|
143
161
|
* `config`:
|
|
144
|
-
* - `title`, `
|
|
162
|
+
* - `title`, `subtitle`, `doneText`: texts, through the host translate;
|
|
163
|
+
* `eyebrow` a template filled from the record ("Close off · {identifier}").
|
|
145
164
|
* - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from
|
|
146
165
|
* the record (`source` an endpointSource to read it from, else `object`).
|
|
147
166
|
* - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template.
|
|
@@ -149,8 +168,14 @@ let reasonSeq = 0
|
|
|
149
168
|
* `{ id, met, label?, detail? }` read from `source`; `labels[id]` gives an
|
|
150
169
|
* item's `{ label, detail?, unmetDetail? }`; the ids in `required` must be
|
|
151
170
|
* met before the action can run. `met: null` reads as unknown.
|
|
152
|
-
* - `permission`: `{ source, allowedPath, reasonPath? }`:
|
|
153
|
-
* while `allowedPath` reads true; `reasonPath` says
|
|
171
|
+
* - `permission`: `{ source, listPath?, match?, allowedPath, reasonPath? }`:
|
|
172
|
+
* the action runs only while `allowedPath` reads true; `reasonPath` says
|
|
173
|
+
* why not. With `listPath` the paths read the entry of that list whose
|
|
174
|
+
* fields equal `match` (`{ act: "archive" }`).
|
|
175
|
+
* - `fields`: `[{ field, type?: "text"|"date"|"datetime"|"select", label?,
|
|
176
|
+
* required?, options?: [{ value, label, fills? }] }]`: inputs sent beside
|
|
177
|
+
* the reason, required by default; a select option's `fills` sets other
|
|
178
|
+
* fields that are still empty.
|
|
154
179
|
* - `reason`: `{ label?, hint?, required?, field? }`: a text area; required by
|
|
155
180
|
* default; sent as `field` (default `reason`).
|
|
156
181
|
* - `note`: `{ variant?, title?, text }`: a read-only note.
|
|
@@ -163,7 +188,7 @@ let reasonSeq = 0
|
|
|
163
188
|
export default {
|
|
164
189
|
name: 'CnActionDialog',
|
|
165
190
|
|
|
166
|
-
components: { CheckCircle, CircleOutline, CnDialog, CnIcon, HelpCircleOutline, NcButton, NcNoteCard, NcTextArea },
|
|
191
|
+
components: { CheckCircle, CircleOutline, CnDialog, CnIcon, HelpCircleOutline, NcButton, NcNoteCard, NcSelect, NcTextArea, NcTextField },
|
|
167
192
|
|
|
168
193
|
inject: {
|
|
169
194
|
/** The host app's translate (CnAppRoot `cnTranslate`). */
|
|
@@ -209,6 +234,7 @@ export default {
|
|
|
209
234
|
checklistError: '',
|
|
210
235
|
allowed: true,
|
|
211
236
|
reason: '',
|
|
237
|
+
values: {},
|
|
212
238
|
busy: false,
|
|
213
239
|
refusal: '',
|
|
214
240
|
done: false,
|
|
@@ -219,7 +245,21 @@ export default {
|
|
|
219
245
|
computed: {
|
|
220
246
|
/** @return {object} The token context. */
|
|
221
247
|
tokenCtx() {
|
|
222
|
-
return { objectId: this.
|
|
248
|
+
return { objectId: this.recordId, object: this.record || {} }
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* The record's id: `objectId`, or the route's `id` when the prop is
|
|
253
|
+
* empty or a token the opener could not resolve.
|
|
254
|
+
*
|
|
255
|
+
* @return {string|number}
|
|
256
|
+
*/
|
|
257
|
+
recordId() {
|
|
258
|
+
const given = this.objectId
|
|
259
|
+
if (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {
|
|
260
|
+
return given
|
|
261
|
+
}
|
|
262
|
+
return (this.$route && this.$route.params && this.$route.params.id) || ''
|
|
223
263
|
},
|
|
224
264
|
|
|
225
265
|
/** @return {object} The confirm config. */
|
|
@@ -305,7 +345,27 @@ export default {
|
|
|
305
345
|
* @return {boolean}
|
|
306
346
|
*/
|
|
307
347
|
canConfirm() {
|
|
308
|
-
return !this.busy && this.allowed && this.requiredMet && (!this.reasonNeeded || this.reason.trim() !== '')
|
|
348
|
+
return !this.busy && this.allowed && this.requiredMet && this.fieldsFilled && (!this.reasonNeeded || this.reason.trim() !== '')
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
/** @return {string} The eyebrow, filled from the record once it is known. */
|
|
352
|
+
eyebrowText() {
|
|
353
|
+
return this.record ? this.fill(this.config.eyebrow) || this.text(this.config.eyebrow) : this.text(this.config.eyebrow)
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/** @return {Array<object>} The fields with a name. */
|
|
357
|
+
fields() {
|
|
358
|
+
return (Array.isArray(this.config.fields) ? this.config.fields : []).filter((f) => f && f.field)
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Whether every required field has a value.
|
|
363
|
+
*
|
|
364
|
+
* @spec openspec/changes/action-dialog-fields-and-acts/specs/action-dialog/spec.md#requirement-an-action-dialog-asks-for-fields-and-reads-a-permission-from-a-list
|
|
365
|
+
* @return {boolean}
|
|
366
|
+
*/
|
|
367
|
+
fieldsFilled() {
|
|
368
|
+
return this.fields.every((f) => f.required === false || String(this.values[f.field] ?? '').trim() !== '')
|
|
309
369
|
},
|
|
310
370
|
},
|
|
311
371
|
|
|
@@ -380,6 +440,63 @@ export default {
|
|
|
380
440
|
}
|
|
381
441
|
},
|
|
382
442
|
|
|
443
|
+
/**
|
|
444
|
+
* The entry of a list whose fields equal `match`, or null.
|
|
445
|
+
*
|
|
446
|
+
* @param {unknown} list The list.
|
|
447
|
+
* @param {object} [match] The fields to match.
|
|
448
|
+
* @return {object|null}
|
|
449
|
+
*/
|
|
450
|
+
matchIn(list, match) {
|
|
451
|
+
const wanted = Object.entries(match || {})
|
|
452
|
+
return (Array.isArray(list) ? list : []).find((entry) => entry && wanted.every(([key, value]) => String(entry[key]) === String(value))) || null
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* A select field's options, labels translated.
|
|
457
|
+
*
|
|
458
|
+
* @param {object} field The field.
|
|
459
|
+
* @return {Array<{id: string, label: string, fills?: object}>}
|
|
460
|
+
*/
|
|
461
|
+
optionsOf(field) {
|
|
462
|
+
return (Array.isArray(field.options) ? field.options : []).map((o) => ({ id: String(o.value), label: this.text(o.label) || String(o.value), fills: o.fills }))
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* A select field's chosen option.
|
|
467
|
+
*
|
|
468
|
+
* @param {object} field The field.
|
|
469
|
+
* @return {object|null}
|
|
470
|
+
*/
|
|
471
|
+
selectedOption(field) {
|
|
472
|
+
return this.optionsOf(field).find((o) => o.id === String(this.values[field.field] ?? '')) || null
|
|
473
|
+
},
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Set a field's value.
|
|
477
|
+
*
|
|
478
|
+
* @param {string} name The field.
|
|
479
|
+
* @param {unknown} value The value.
|
|
480
|
+
*/
|
|
481
|
+
setValue(name, value) {
|
|
482
|
+
this.values = { ...this.values, [name]: value === null || value === undefined ? '' : String(value) }
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Choose a select option; its `fills` set the fields still empty.
|
|
487
|
+
*
|
|
488
|
+
* @param {object} field The select field.
|
|
489
|
+
* @param {{id: string, fills?: object}|null} option The option.
|
|
490
|
+
*/
|
|
491
|
+
pick(field, option) {
|
|
492
|
+
this.setValue(field.field, option ? option.id : '')
|
|
493
|
+
for (const [name, value] of Object.entries((option && option.fills) || {})) {
|
|
494
|
+
if (String(this.values[name] ?? '').trim() === '') {
|
|
495
|
+
this.setValue(name, this.text(value) || value)
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
|
|
383
500
|
/** @return {Promise<void>} */
|
|
384
501
|
async loadPermission() {
|
|
385
502
|
const def = this.config.permission
|
|
@@ -388,8 +505,9 @@ export default {
|
|
|
388
505
|
}
|
|
389
506
|
try {
|
|
390
507
|
const data = await this.read(def.source)
|
|
391
|
-
|
|
392
|
-
this.
|
|
508
|
+
const entry = def.listPath ? this.matchIn(readPath(data, def.listPath), def.match) : data
|
|
509
|
+
this.allowed = readPath(entry, def.allowedPath || 'allowed') === true
|
|
510
|
+
this.refusal = this.allowed || !def.reasonPath ? '' : String(readPath(entry, def.reasonPath) || '')
|
|
393
511
|
} catch {
|
|
394
512
|
this.allowed = false
|
|
395
513
|
}
|
|
@@ -420,15 +538,18 @@ export default {
|
|
|
420
538
|
if (this.config.reason) {
|
|
421
539
|
body[this.config.reason.field || 'reason'] = reason
|
|
422
540
|
}
|
|
541
|
+
for (const field of this.fields) {
|
|
542
|
+
body[field.field] = this.values[field.field] ?? ''
|
|
543
|
+
}
|
|
423
544
|
const method = String(request.method || 'POST').toLowerCase()
|
|
424
545
|
await axios[['post', 'put', 'patch', 'delete'].includes(method) ? method : 'post'](/^https?:\/\//i.test(url) ? url : generateUrl(url), body)
|
|
425
546
|
} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {
|
|
426
|
-
await this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { reason }] })
|
|
547
|
+
await this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { ...this.values, reason }] })
|
|
427
548
|
}
|
|
428
549
|
this.done = true
|
|
429
550
|
emit(PAGE_REFRESH, {})
|
|
430
|
-
/** @event done The action ran. Payload: `
|
|
431
|
-
this.$emit('done', { reason })
|
|
551
|
+
/** @event done The action ran. Payload: the field values and `reason`. */
|
|
552
|
+
this.$emit('done', { ...this.values, reason })
|
|
432
553
|
} catch (failure) {
|
|
433
554
|
const data = failure && failure.response && failure.response.data
|
|
434
555
|
this.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'The action could not be completed.'))
|
|
@@ -93,6 +93,7 @@
|
|
|
93
93
|
|
|
94
94
|
<script>
|
|
95
95
|
import axios from '@nextcloud/axios'
|
|
96
|
+
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
|
|
96
97
|
import { translate as t } from '@nextcloud/l10n'
|
|
97
98
|
import { generateUrl } from '@nextcloud/router'
|
|
98
99
|
import { NcButton, NcEmptyContent, NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'
|
|
@@ -109,7 +110,8 @@ import { openRowTarget } from '../../utils/linkNavigation.js'
|
|
|
109
110
|
* not be read is named at the top rather than folded into "nothing is
|
|
110
111
|
* waiting". A group can be hidden until tomorrow, through the server, so the
|
|
111
112
|
* choice follows the reader to another device. dossiq's personal queue is
|
|
112
|
-
* the first; pipelinq's queue has the same shape.
|
|
113
|
+
* the first; pipelinq's queue has the same shape. It reads again on
|
|
114
|
+
* `cn:page:refresh`, so work planned or closed in a dialog shows at once.
|
|
113
115
|
*
|
|
114
116
|
* `content`:
|
|
115
117
|
* - `source`: an endpointSource answering `{ groups, hiddenGroups?, unavailable? }`.
|
|
@@ -176,9 +178,14 @@ export default {
|
|
|
176
178
|
},
|
|
177
179
|
|
|
178
180
|
mounted() {
|
|
181
|
+
subscribe('cn:page:refresh', this.load)
|
|
179
182
|
this.load()
|
|
180
183
|
},
|
|
181
184
|
|
|
185
|
+
beforeUnmount() {
|
|
186
|
+
unsubscribe('cn:page:refresh', this.load)
|
|
187
|
+
},
|
|
188
|
+
|
|
182
189
|
methods: {
|
|
183
190
|
t,
|
|
184
191
|
|
|
@@ -857,7 +857,10 @@ export function dispatchAction(action, context = {}) {
|
|
|
857
857
|
return
|
|
858
858
|
}
|
|
859
859
|
|
|
860
|
-
|
|
860
|
+
// A prop that is exactly a token (`"objectId": "@objectId"`) resolves
|
|
861
|
+
// against the page's object; one the page cannot answer stays as written.
|
|
862
|
+
const props = context.tokenCtx ? resolveDeepTokens(action.props ?? {}, context.tokenCtx) : (action.props ?? {})
|
|
863
|
+
context.openModal(target, props)
|
|
861
864
|
break
|
|
862
865
|
}
|
|
863
866
|
|