@conduction/nextcloud-vue 2.139.0 → 2.141.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +9 -2
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue.js +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +10 -2
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +28 -4
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +2 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +64 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +76 -37
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +106 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +30 -7
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +1 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +5 -3
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +59 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +44 -34
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +28 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +65 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +120 -69
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +47 -9
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -3
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +3 -3
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +2 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js +20 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js +34 -26
- package/dist/esm/components/CnRecordListWidget/CnRecordNoteRows.vue3.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +12 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +1 -1
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue.js +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js +23 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js.map +1 -1
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js +43 -13
- package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +5 -2
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/composables/useTaskInboxStore.js +4 -3
- package/dist/esm/composables/useTaskInboxStore.js.map +1 -1
- package/dist/esm/l10n/en.json.js +3 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +6 -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 +961 -605
- package/dist/esm/utils/builtInFormatters.js +23 -1
- package/dist/esm/utils/builtInFormatters.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +7 -1
- package/dist/esm/utils/fillTemplate.js.map +1 -1
- package/dist/esm/utils/groupSublines.js +120 -0
- package/dist/esm/utils/groupSublines.js.map +1 -0
- package/dist/esm/utils/myTeam.js +24 -4
- package/dist/esm/utils/myTeam.js.map +1 -1
- package/dist/esm/utils/resolveFilterTokens.js +5 -4
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/transitionInputs.js +43 -2
- package/dist/esm/utils/transitionInputs.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1731 -846
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +961 -605
- package/l10n/en.json +3 -1
- package/l10n/nl.json +6 -1
- package/package.json +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +9 -2
- package/src/components/CnAssignDialog/CnAssignDialog.vue +10 -2
- package/src/components/CnCellRenderer/CnCellRenderer.vue +30 -6
- package/src/components/CnChartWidget/CnChartWidget.md +2 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +121 -5
- package/src/components/CnConversationThread/CnConversationWidget.vue +126 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +6 -3
- package/src/components/CnFactsWidget/CnFactsWidget.vue +72 -5
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +28 -1
- package/src/components/CnFilesBrowser/filesBrowser.js +7 -1
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +5 -0
- package/src/components/CnIndexPage/CnIndexPage.vue +30 -2
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +101 -3
- package/src/components/CnMapWidget/CnMapWidget.vue +47 -9
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +28 -3
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +3 -3
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +20 -1
- package/src/components/CnRecordListWidget/CnRecordNoteRows.vue +43 -9
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +68 -2
- package/src/components/CnTransitionInputFields/CnTransitionInputFields.vue +43 -1
- package/src/composables/indexSources.js +5 -2
- package/src/composables/useTaskInboxStore.js +4 -3
- package/src/css/dialog.css +13 -1
- package/src/css/look-board-detail.css +12 -9
- package/src/css/look-board-index.css +90 -7
- package/src/css/look-board.css +102 -2
- package/src/css/table.css +25 -0
- package/src/utils/builtInFormatters.js +22 -0
- package/src/utils/fillTemplate.js +7 -1
- package/src/utils/groupSublines.js +125 -0
- package/src/utils/myTeam.js +24 -4
- package/src/utils/resolveFilterTokens.js +5 -4
- package/src/utils/transitionInputs.js +42 -1
|
@@ -669,14 +669,14 @@ export default {
|
|
|
669
669
|
},
|
|
670
670
|
|
|
671
671
|
/**
|
|
672
|
-
* How the table draws its title column (`content.rowTitle`: link, plain
|
|
673
|
-
* or
|
|
672
|
+
* How the table draws its title column (`content.rowTitle`: link, plain,
|
|
673
|
+
* text or strong), link when unset or unknown.
|
|
674
674
|
*
|
|
675
675
|
* @return {string}
|
|
676
676
|
* @spec openspec/changes/board-log-table-plain-cells/specs/board-log-table-plain-cells/spec.md#requirement-a-tables-title-column-can-read-as-plain-text
|
|
677
677
|
*/
|
|
678
678
|
rowTitle() {
|
|
679
|
-
return ['plain', 'text'].includes(this.content.rowTitle) ? this.content.rowTitle : 'link'
|
|
679
|
+
return ['plain', 'text', 'strong'].includes(this.content.rowTitle) ? this.content.rowTitle : 'link'
|
|
680
680
|
},
|
|
681
681
|
|
|
682
682
|
/**
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<template>
|
|
7
7
|
<div
|
|
8
8
|
class="cn-record-list"
|
|
9
|
-
:class="[`cn-record-list--${presentation}`, { 'cn-record-list--compact': content.density === 'compact', 'cn-record-list--tiles': presentation === 'rows' && content.tiles === true, 'cn-record-list--rule-above': content.ruleAbove === true, 'cn-record-list--data-table': presentation === 'table' && content.tableLook === 'data' }]"
|
|
9
|
+
:class="[`cn-record-list--${presentation}`, { 'cn-record-list--compact': content.density === 'compact', 'cn-record-list--stacked': content.density === 'stacked', 'cn-record-list--tiles': presentation === 'rows' && content.tiles === true, 'cn-record-list--rule-above': content.ruleAbove === true, 'cn-record-list--data-table': presentation === 'table' && content.tableLook === 'data' }]"
|
|
10
10
|
data-testid="cn-record-list">
|
|
11
11
|
<p v-if="intro && !absent" class="cn-record-list__intro" data-testid="cn-record-list-intro">
|
|
12
12
|
{{ intro }}
|
|
@@ -713,6 +713,8 @@ export default {
|
|
|
713
713
|
* without a value.
|
|
714
714
|
* `density: "compact"` draws the rows 10px above and below, at least
|
|
715
715
|
* 56px tall, with the title at 500 (DqProcesanalyse).
|
|
716
|
+
* `density: "stacked"` stands the rows 10px apart with no rule and no
|
|
717
|
+
* row padding (DqDagAfsluiten "Morgen eerst").
|
|
716
718
|
* In `rows`, `text` is a line under the meta line ("12 dagen stil"),
|
|
717
719
|
* and `chevron: false` leaves the chevron off a linked row
|
|
718
720
|
* (DqDashboard).
|
|
@@ -3103,6 +3105,23 @@ export default {
|
|
|
3103
3105
|
font-weight: 500;
|
|
3104
3106
|
}
|
|
3105
3107
|
|
|
3108
|
+
/* `density: "stacked"`: the rows stand 10px apart with no rule and no row
|
|
3109
|
+
padding, a short side list (DqDagAfsluiten "Morgen eerst"). */
|
|
3110
|
+
.cn-record-list--stacked .cn-record-list__list {
|
|
3111
|
+
display: flex;
|
|
3112
|
+
flex-direction: column;
|
|
3113
|
+
gap: 10px;
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3116
|
+
.cn-record-list--stacked .cn-record-list__row {
|
|
3117
|
+
min-height: 0;
|
|
3118
|
+
padding: 0;
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
.cn-record-list--stacked .cn-record-list__item + .cn-record-list__item {
|
|
3122
|
+
border-top: 0;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3106
3125
|
.cn-record-list__meta {
|
|
3107
3126
|
color: var(--color-text-maxcontrast);
|
|
3108
3127
|
font-size: 13px;
|
|
@@ -37,15 +37,20 @@
|
|
|
37
37
|
data-testid="cn-record-list-due">{{ item.due.text }}</span>
|
|
38
38
|
</div>
|
|
39
39
|
<div class="cn-record-notes__fields">
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
<!-- The label stands above the field, as the leaf's own beside it
|
|
41
|
+
(humaniq "Uren"), so both fields share one line. -->
|
|
42
|
+
<div class="cn-record-notes__field">
|
|
43
|
+
<label :for="fieldId(item.key)" class="cn-record-notes__field-label">{{ fieldLabel }}</label>
|
|
44
|
+
<NcTextField
|
|
45
|
+
:id="fieldId(item.key)"
|
|
46
|
+
:modelValue="drafts[item.key] || ''"
|
|
47
|
+
:label="fieldLabel"
|
|
48
|
+
labelOutside
|
|
49
|
+
:placeholder="placeholder"
|
|
50
|
+
:disabled="busy"
|
|
51
|
+
:data-testid="`cn-record-list-note-${item.key}`"
|
|
52
|
+
@update:modelValue="setDraft(item.key, $event)" />
|
|
53
|
+
</div>
|
|
49
54
|
<div v-if="leaf && leafProvider" class="cn-record-notes__leaf" :data-testid="`cn-record-list-leaf-${item.key}`">
|
|
50
55
|
<CnLeafMountHost
|
|
51
56
|
v-if="leafIsMount"
|
|
@@ -117,6 +122,13 @@ import { readPath } from '../../utils/readPath.js'
|
|
|
117
122
|
/** The bus channel every endpoint-bound widget on the page refetches on. */
|
|
118
123
|
const PAGE_REFRESH_CHANNEL = 'cn:page:refresh'
|
|
119
124
|
|
|
125
|
+
/**
|
|
126
|
+
* The document event a recorded note sends, so a row's leaf (humaniq's
|
|
127
|
+
* hours) can record what it holds for the same object at the same moment.
|
|
128
|
+
* `detail` is the row's leaf props plus `note`.
|
|
129
|
+
*/
|
|
130
|
+
const NOTE_RECORDED_EVENT = 'cn-record-notes:recorded'
|
|
131
|
+
|
|
120
132
|
/**
|
|
121
133
|
* The rows of a record list drawn as notes to record (`presentation:
|
|
122
134
|
* "notes"`, DqDagAfsluiten "Nog open van vandaag"): per row its pill, title,
|
|
@@ -294,6 +306,16 @@ export default {
|
|
|
294
306
|
this.drafts = { ...this.drafts, [key]: String(value ?? '') }
|
|
295
307
|
},
|
|
296
308
|
|
|
309
|
+
/**
|
|
310
|
+
* The id of a row's note field, for its label.
|
|
311
|
+
*
|
|
312
|
+
* @param {string} key The row key.
|
|
313
|
+
* @return {string} The id.
|
|
314
|
+
*/
|
|
315
|
+
fieldId(key) {
|
|
316
|
+
return `cn-record-notes-${this.$.uid}-${String(key).replace(/[^A-Za-z0-9_-]/g, '-')}`
|
|
317
|
+
},
|
|
318
|
+
|
|
297
319
|
/**
|
|
298
320
|
* @param {string} key The row key.
|
|
299
321
|
* @return {boolean} Whether the row has a note typed.
|
|
@@ -351,6 +373,9 @@ export default {
|
|
|
351
373
|
try {
|
|
352
374
|
const { default: axios } = await import('@nextcloud/axios')
|
|
353
375
|
await axios.post(prefixUrl(url), { [this.action.bodyField || 'message']: text })
|
|
376
|
+
if (this.leaf) {
|
|
377
|
+
document.dispatchEvent(new CustomEvent(NOTE_RECORDED_EVENT, { detail: { ...this.leafProps(item.row), note: text } }))
|
|
378
|
+
}
|
|
354
379
|
const { [item.key]: done, ...rest } = this.drafts
|
|
355
380
|
this.drafts = rest
|
|
356
381
|
if (refresh) {
|
|
@@ -462,7 +487,16 @@ export default {
|
|
|
462
487
|
}
|
|
463
488
|
|
|
464
489
|
.cn-record-notes__field {
|
|
490
|
+
display: flex;
|
|
465
491
|
flex: 1 1 260px;
|
|
492
|
+
flex-direction: column;
|
|
493
|
+
gap: 6px;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.cn-record-notes__field-label {
|
|
497
|
+
color: var(--color-main-text);
|
|
498
|
+
font-size: 14px;
|
|
499
|
+
font-weight: 600;
|
|
466
500
|
}
|
|
467
501
|
|
|
468
502
|
.cn-record-notes__leaf {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
SPDX-License-Identifier: EUPL-1.2
|
|
4
4
|
-->
|
|
5
5
|
<template>
|
|
6
|
-
<div class="cn-stacked-bar" :class="{ 'cn-stacked-bar--inset': inset }" data-testid="cn-stacked-bar">
|
|
6
|
+
<div class="cn-stacked-bar" :class="{ 'cn-stacked-bar--inset': inset, 'cn-stacked-bar--compact': compact }" data-testid="cn-stacked-bar">
|
|
7
7
|
<div v-if="isLoading" class="cn-stacked-bar__state" role="status">
|
|
8
8
|
<NcLoadingIcon :size="20" />
|
|
9
9
|
<span>{{ loadingLabel }}</span>
|
|
@@ -183,7 +183,7 @@ export default {
|
|
|
183
183
|
* segments to the card (`header` event, `count`), for a chip after the
|
|
184
184
|
* title or a `{count}` in it.
|
|
185
185
|
*
|
|
186
|
-
* @type {{inset?: boolean, headerCount?: boolean, source?: {register?: string, schema?: string, groupBy?: string, filter?: object}, segments?: Array<{key?: string, label: string, value: number}>, order?: Array<string>, labels?: {[key: string]: string}, emptyText?: string}}
|
|
186
|
+
* @type {{inset?: boolean, compact?: boolean, headerCount?: boolean, source?: {register?: string, schema?: string, groupBy?: string, filter?: object}, segments?: Array<{key?: string, label: string, value: number}>, order?: Array<string>, labels?: {[key: string]: string}, emptyText?: string}}
|
|
187
187
|
*/
|
|
188
188
|
content: {
|
|
189
189
|
type: Object,
|
|
@@ -241,6 +241,17 @@ export default {
|
|
|
241
241
|
return Boolean(this.content && this.content.inset === true)
|
|
242
242
|
},
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Whether the widget is the compact summary box (`content.compact`):
|
|
246
|
+
* a 15px heading, one thin bar and the legend on one line.
|
|
247
|
+
*
|
|
248
|
+
* @spec openspec/changes/stacked-bar-compact/specs/stacked-bar-compact/spec.md#requirement-a-stacked-bar-can-be-drawn-as-the-compact-summary-box
|
|
249
|
+
* @return {boolean}
|
|
250
|
+
*/
|
|
251
|
+
compact() {
|
|
252
|
+
return Boolean(this.content && this.content.compact === true)
|
|
253
|
+
},
|
|
254
|
+
|
|
244
255
|
/**
|
|
245
256
|
* The translate function in use.
|
|
246
257
|
*
|
|
@@ -651,4 +662,59 @@ export default {
|
|
|
651
662
|
line-height: 1.2;
|
|
652
663
|
color: var(--color-main-text);
|
|
653
664
|
}
|
|
665
|
+
|
|
666
|
+
/* `content.compact: true`: the summary box (DqZaakDocumenten "4 van 7
|
|
667
|
+
beoordeeld"): the sunken ground, a 15px heading, one 8px bar of joined
|
|
668
|
+
segments and the legend on one line, each count beside its label. */
|
|
669
|
+
.cn-stacked-bar--compact {
|
|
670
|
+
box-sizing: border-box;
|
|
671
|
+
gap: 10px;
|
|
672
|
+
padding: 14px 16px;
|
|
673
|
+
border-radius: 10px;
|
|
674
|
+
background: var(--cn-board-sunken-ground, var(--color-background-hover));
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.cn-stacked-bar--compact .cn-stacked-bar__heading {
|
|
678
|
+
flex-wrap: wrap;
|
|
679
|
+
gap: 8px;
|
|
680
|
+
font-size: 15px;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
.cn-stacked-bar--compact .cn-stacked-bar__bar {
|
|
684
|
+
gap: 0;
|
|
685
|
+
height: 8px;
|
|
686
|
+
border-radius: 4px;
|
|
687
|
+
overflow: hidden;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.cn-stacked-bar--compact .cn-stacked-bar__segment {
|
|
691
|
+
border-radius: 0;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.cn-stacked-bar--compact .cn-stacked-bar__legend {
|
|
695
|
+
display: flex;
|
|
696
|
+
flex-wrap: wrap;
|
|
697
|
+
gap: 8px 18px;
|
|
698
|
+
font-size: 14px;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.cn-stacked-bar--compact .cn-stacked-bar__legend-item {
|
|
702
|
+
flex-direction: row;
|
|
703
|
+
align-items: center;
|
|
704
|
+
gap: 8px;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.cn-stacked-bar--compact .cn-stacked-bar__label {
|
|
708
|
+
color: var(--color-main-text);
|
|
709
|
+
font-size: 1em;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.cn-stacked-bar--compact .cn-stacked-bar__dot {
|
|
713
|
+
border-radius: 50%;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.cn-stacked-bar--compact .cn-stacked-bar__count {
|
|
717
|
+
font-size: 1em;
|
|
718
|
+
line-height: inherit;
|
|
719
|
+
}
|
|
654
720
|
</style>
|
|
@@ -162,6 +162,26 @@
|
|
|
162
162
|
</p>
|
|
163
163
|
</div>
|
|
164
164
|
|
|
165
|
+
<!-- A days input set as a date (`dateField`): today plus the days,
|
|
166
|
+
and a chosen date sets the days. -->
|
|
167
|
+
<div v-if="field.input.dateField"
|
|
168
|
+
:key="`${field.key}-date`"
|
|
169
|
+
class="cn-transition-input-fields__field cn-transition-input-fields__wide"
|
|
170
|
+
:data-testid="field.input.dateField.testid || `cn-transition-input-date-${field.key}`">
|
|
171
|
+
<label class="cn-transition-input-fields__label"
|
|
172
|
+
:for="`${inputId(field)}-date`">{{ dateFieldLabel(field) }}</label>
|
|
173
|
+
<NcTextField :id="`${inputId(field)}-date`"
|
|
174
|
+
:modelValue="field.dateValue"
|
|
175
|
+
type="date"
|
|
176
|
+
:label="dateFieldLabel(field)"
|
|
177
|
+
:labelOutside="true"
|
|
178
|
+
:disabled="disabled"
|
|
179
|
+
@update:modelValue="setValue(field.key, daysUntilIso($event))" />
|
|
180
|
+
<span v-if="field.input.dateField.note" class="cn-transition-input-fields__muted">
|
|
181
|
+
{{ field.input.dateField.note }}
|
|
182
|
+
</span>
|
|
183
|
+
</div>
|
|
184
|
+
|
|
165
185
|
<!-- What the input means once filled in, such as the day a paused
|
|
166
186
|
term comes back. Shown only once it can be worked out. -->
|
|
167
187
|
<div v-if="field.previewText"
|
|
@@ -209,7 +229,7 @@ import { NcCheckboxRadioSwitch, NcSelect, NcTextArea, NcTextField } from '@nextc
|
|
|
209
229
|
import CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'
|
|
210
230
|
import CnTemplateSelect from '../CnTemplateSelect/CnTemplateSelect.vue'
|
|
211
231
|
import { readPath } from '../../utils/readPath.js'
|
|
212
|
-
import { applyTemplateText, isInputFilled, resolveInputFields } from '../../utils/transitionInputs.js'
|
|
232
|
+
import { applyTemplateText, daysUntilIso, isInputFilled, resolveInputFields } from '../../utils/transitionInputs.js'
|
|
213
233
|
import { CnIcon } from '../CnIcon/index.js'
|
|
214
234
|
|
|
215
235
|
let uid = 0
|
|
@@ -505,6 +525,28 @@ export default {
|
|
|
505
525
|
return this.markOptional && !field.required ? `${field.label} (${t('nextcloud-vue', 'optional')})` : field.label
|
|
506
526
|
},
|
|
507
527
|
|
|
528
|
+
/**
|
|
529
|
+
* The label of a days input's date field (`dateField`), with the
|
|
530
|
+
* optional marker when asked for: the date is never required.
|
|
531
|
+
*
|
|
532
|
+
* @param {object} field The descriptor.
|
|
533
|
+
* @return {string}
|
|
534
|
+
*/
|
|
535
|
+
dateFieldLabel(field) {
|
|
536
|
+
const label = String(field.input.dateField.label || '')
|
|
537
|
+
return this.markOptional ? `${label} (${t('nextcloud-vue', 'optional')})` : label
|
|
538
|
+
},
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* The days a chosen date stands for.
|
|
542
|
+
*
|
|
543
|
+
* @param {string} iso The date input's value.
|
|
544
|
+
* @return {string} The days, '' without a date.
|
|
545
|
+
*/
|
|
546
|
+
daysUntilIso(iso) {
|
|
547
|
+
return daysUntilIso(iso)
|
|
548
|
+
},
|
|
549
|
+
|
|
508
550
|
/**
|
|
509
551
|
* Label of a sub-field, with the required marker.
|
|
510
552
|
*
|
|
@@ -702,12 +702,15 @@ function tasksSource() {
|
|
|
702
702
|
*
|
|
703
703
|
* @param {string} key The column key.
|
|
704
704
|
* @param {string} order `asc` or `desc`.
|
|
705
|
-
*
|
|
705
|
+
* Open tasks come before finished ones (`openFirst`), each in that order.
|
|
706
|
+
*
|
|
707
|
+
* @return {{sort: string, openFirst: boolean}|null} The parameters, or null for a column the inbox cannot sort by.
|
|
706
708
|
* @spec openspec/changes/tasks-source-sorts-on-server/specs/index-sources/spec.md#requirement-a-named-source-can-sort-on-the-server
|
|
709
|
+
* @spec openspec/changes/tasks-source-open-first/specs/index-sources/spec.md#requirement-a-sorted-task-list-puts-open-tasks-first
|
|
707
710
|
*/
|
|
708
711
|
sortParam: (key, order) => {
|
|
709
712
|
const field = TASK_SORT_FIELDS[key]
|
|
710
|
-
return field ? { sort: (order === 'desc' ? '-' : '') + field } : null
|
|
713
|
+
return field ? { sort: (order === 'desc' ? '-' : '') + field, openFirst: true } : null
|
|
711
714
|
},
|
|
712
715
|
|
|
713
716
|
// The scope tabs. Each tab's filter is merged over the page's
|
|
@@ -41,7 +41,8 @@ export const FLOW_TASKS_URL = '/apps/openregister/api/flow-tasks'
|
|
|
41
41
|
// creating app named it, so it is the one filter that lets a Tasks page say
|
|
42
42
|
// "the reminders" without the engine learning what a reminder is. It widens
|
|
43
43
|
// nothing: it narrows within the inbox the session already decides.
|
|
44
|
-
|
|
44
|
+
// `openFirst` asks open tasks before finished ones, a sort the engine applies.
|
|
45
|
+
const ALLOWED_PARAMS = ['scope', 'state', 'isTerminal', 'priority', 'kind', 'overdue', 'dueAfter', 'dueBefore', 'objectUuid', 'sort', 'openFirst', 'limit', 'offset']
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* The flat body `POST /api/flow-tasks` takes for a task on a record.
|
|
@@ -178,7 +179,7 @@ export const useTaskInboxStore = defineStore('cnTaskInbox', {
|
|
|
178
179
|
if (value === undefined || value === null || value === '') {
|
|
179
180
|
continue
|
|
180
181
|
}
|
|
181
|
-
params[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value
|
|
182
|
+
params[key] = (key === 'overdue' || key === 'isTerminal' || key === 'openFirst') ? String(value) : value
|
|
182
183
|
}
|
|
183
184
|
const response = await axios.get(generateUrl(FLOW_TASKS_URL), { params })
|
|
184
185
|
const results = response.data?.results || []
|
|
@@ -358,7 +359,7 @@ export const useTaskInboxStore = defineStore('cnTaskInbox', {
|
|
|
358
359
|
}
|
|
359
360
|
// The endpoint reads `overdue` as a boolean-ish string; a quick
|
|
360
361
|
// filter authors it as `true` for legibility.
|
|
361
|
-
params[key] = (key === 'overdue' || key === 'isTerminal') ? String(value) : value
|
|
362
|
+
params[key] = (key === 'overdue' || key === 'isTerminal' || key === 'openFirst') ? String(value) : value
|
|
362
363
|
}
|
|
363
364
|
|
|
364
365
|
this.loading = true
|
package/src/css/dialog.css
CHANGED
|
@@ -238,8 +238,11 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
238
238
|
padding-inline-end: 24px;
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
+
/* The body starts 22px under the header, as most dialog boards draw it
|
|
242
|
+
(header padding-bottom 4px + form padding-top 18px; DqBerichtVersturen,
|
|
243
|
+
DqOverdragen, DqNieuweZaak, DqBesluit): the 18px gap plus 4px. */
|
|
241
244
|
.cn-dialog-board .dialog__content > .cn-dialog-header {
|
|
242
|
-
margin-bottom:
|
|
245
|
+
margin-bottom: 4px;
|
|
243
246
|
}
|
|
244
247
|
|
|
245
248
|
/* Footer: 16px 24px, hairline on top, right aligned, 40px buttons, 10px gap. */
|
|
@@ -344,6 +347,15 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
344
347
|
margin-block-start: 26px;
|
|
345
348
|
}
|
|
346
349
|
|
|
350
|
+
/* A select in a form dialog sits under its label and over its help line
|
|
351
|
+
as a text field does (DqNieuweZaak "Zaaktype", "Intakekanaal"): the
|
|
352
|
+
form's label stands outside the select, so NcSelect's own 6px/4px margins
|
|
353
|
+
only pushed the control 6px below the text fields beside it and its help
|
|
354
|
+
line 4px further down. */
|
|
355
|
+
.cn-dialog-board .dialog__content .cn-form-dialog__select-wrapper > .v-select.select:not(:has(.input-field__label)) {
|
|
356
|
+
margin-block: 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
347
359
|
/* A multiple select is the board's 40px field too (DqFilterDelen "Delen
|
|
348
360
|
met"). The edge goes on the toggle, which holds the chips and the search,
|
|
349
361
|
so the chosen people and groups sit inside the field; the search inside it
|
|
@@ -721,6 +721,13 @@
|
|
|
721
721
|
padding-top: calc(14px - var(--cn-board-first-line-leading));
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
+
/* A table (an object list) starts 12px below the title's box: its head has
|
|
725
|
+
a fill and no leading, so the glyph-to-glyph gap above left it 2px short
|
|
726
|
+
(DqZaaktypeStatussen "Statussen", "Resultaten"). */
|
|
727
|
+
.cn-look-board .cn-detail-page .cn-widget-wrapper__content:has(> .cn-object-list-widget):not(.cn-detail-page__side *) {
|
|
728
|
+
padding-top: 12px;
|
|
729
|
+
}
|
|
730
|
+
|
|
724
731
|
/* Running text (DqZaak "Het verzoek") sits 12px below the title's box and
|
|
725
732
|
keeps its own half-leading, at 1.6 as drawn.
|
|
726
733
|
@spec openspec/changes/board-card-title-gap-variants/specs/board-card-title-gap-variants/spec.md#requirement-a-board-card-starts-its-body-as-drawn-for-its-kind-of-body */
|
|
@@ -1527,12 +1534,12 @@
|
|
|
1527
1534
|
}
|
|
1528
1535
|
|
|
1529
1536
|
/* ---- A card's Add ------------------------------------------------------ */
|
|
1530
|
-
/* The board draws a list card's Add as the neutral secondary
|
|
1531
|
-
|
|
1532
|
-
"
|
|
1537
|
+
/* The board draws a list card's Add as the neutral secondary right-aligned
|
|
1538
|
+
in the title row, at the title row's 34px (DqZaaktypeStatussen "Status
|
|
1539
|
+
toevoegen", DqZaaktype "Taak toevoegen", DqCatalogus "Objecttype
|
|
1540
|
+
toevoegen": 13 of the 15 boards that draw one). CnDetailWidgetHost renders
|
|
1533
1541
|
that button in the board look, so the list's footer Add bar, which ADR-062
|
|
1534
|
-
draws in the Nextcloud look, is hidden in the card.
|
|
1535
|
-
card title row's 34px buttons.
|
|
1542
|
+
draws in the Nextcloud look, is hidden in the card.
|
|
1536
1543
|
@spec openspec/changes/board-object-list-add-button/specs/board-object-list-add-button/spec.md#requirement-the-board-look-draws-a-cards-add-as-a-title-row-button */
|
|
1537
1544
|
.cn-look-board .cn-detail-page__catalog-card:not(.cn-look-nextcloud *) .cn-object-list-widget__add {
|
|
1538
1545
|
display: none;
|
|
@@ -1544,10 +1551,6 @@
|
|
|
1544
1551
|
display: none;
|
|
1545
1552
|
}
|
|
1546
1553
|
|
|
1547
|
-
.cn-look-board .cn-widget-wrapper__actions .button-vue.cn-detail-page__catalog-add:has(> .button-vue__wrapper > .button-vue__text:not(:empty)):where(:not(.cn-look-nextcloud *)) {
|
|
1548
|
-
--button-size: var(--cn-board-control-height);
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
1554
|
/* A map in a board card has the board's control corners (DqZaak, DqZaakMeer
|
|
1552
1555
|
"Locaties"); overflow keeps the tiles inside them. */
|
|
1553
1556
|
.cn-look-board .cn-map-widget:not(.cn-map-widget--fullscreen) {
|
|
@@ -52,13 +52,11 @@
|
|
|
52
52
|
grid-row: 2;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
/*
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.cn-look-board .cn-index-page .cn-header-trail.cn-detail-page__header-row2 .cn-detail-page__breadcrumbs .vue-crumb .button-vue.button-vue {
|
|
61
|
-
font-size: 15px;
|
|
55
|
+
/* The note after the breadcrumb ("38 contracten bij 21 leveranciers") is 14px
|
|
56
|
+
muted on every Dq list board (37 of 37).
|
|
57
|
+
@spec openspec/changes/board-index-header-meta-14/specs/index-page/spec.md */
|
|
58
|
+
.cn-look-board .cn-index-page .cn-page-header .cn-header-trail .cn-detail-page__header-meta {
|
|
59
|
+
font-size: 14px;
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
.cn-look-board .cn-index-page .cn-page-header .cn-header-trail ~ .cn-page-header__description {
|
|
@@ -982,6 +980,17 @@
|
|
|
982
980
|
text-decoration: none;
|
|
983
981
|
}
|
|
984
982
|
|
|
983
|
+
/* `rowTitle: "strong"` (DqZaaktypeStatussen "Statussen", "Resultaten"): the
|
|
984
|
+
name column of a card's list, the cell's 14px at weight 600 in the main
|
|
985
|
+
ink, no underline; the row stays a link.
|
|
986
|
+
@spec openspec/changes/table-strong-title/specs/table-strong-title/spec.md#requirement-a-tables-title-column-can-read-as-a-strong-name */
|
|
987
|
+
.cn-look-board .cn-table-container--board.cn-table-container--title-strong .cn-data-table td.cn-table-col--title {
|
|
988
|
+
color: var(--color-main-text);
|
|
989
|
+
font-size: 14px;
|
|
990
|
+
font-weight: 600;
|
|
991
|
+
text-decoration: none;
|
|
992
|
+
}
|
|
993
|
+
|
|
985
994
|
/* An avatar in the title column (PtAccounts): a 32px chip circle, 10px before
|
|
986
995
|
the name, the e-mail under the name beside it. The name keeps the title's
|
|
987
996
|
weight and size, and its underline: an inline-flex box is atomic, so the
|
|
@@ -2101,3 +2110,77 @@
|
|
|
2101
2110
|
.cn-look-board .cn-index-page--with-side-panel:not(.cn-look-nextcloud *) > .cn-index-page__quick-filter-row {
|
|
2102
2111
|
margin-bottom: calc(var(--cn-board-section-gap) + 12px);
|
|
2103
2112
|
}
|
|
2113
|
+
|
|
2114
|
+
/* ---- The side panel's filters as checkbox lists (DqZakenSorteren) ------- */
|
|
2115
|
+
/* "Filters" with "Alles wissen" beside it; per field its 14px semibold label
|
|
2116
|
+
over rows of a checkbox, the value and its count in 13px muted at the end,
|
|
2117
|
+
32px each.
|
|
2118
|
+
@spec openspec/changes/board-sidebar-filters-as-checkbox-lists/specs/index-sidebar/spec.md#requirement-the-board-look-draws-a-short-filter-as-a-checkbox-list-with-counts */
|
|
2119
|
+
.cn-look-board .cn-index-sidebar__filters-head {
|
|
2120
|
+
display: flex;
|
|
2121
|
+
align-items: center;
|
|
2122
|
+
justify-content: space-between;
|
|
2123
|
+
gap: 8px;
|
|
2124
|
+
margin-bottom: 14px;
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
.cn-look-board .cn-index-sidebar__filters-head h3 {
|
|
2128
|
+
margin: 0;
|
|
2129
|
+
font-size: 15px;
|
|
2130
|
+
font-weight: 700;
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
.cn-look-board .cn-index-sidebar__filters-clear {
|
|
2134
|
+
min-height: 0;
|
|
2135
|
+
margin: 0;
|
|
2136
|
+
padding: 0;
|
|
2137
|
+
border: 0;
|
|
2138
|
+
background: transparent;
|
|
2139
|
+
color: var(--color-primary-element);
|
|
2140
|
+
font-size: 14px;
|
|
2141
|
+
font-weight: 600;
|
|
2142
|
+
text-decoration: underline;
|
|
2143
|
+
cursor: pointer;
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
.cn-look-board .cn-index-sidebar__filter-group:has(> .cn-index-sidebar__checklist) .cn-index-sidebar__filter-label {
|
|
2147
|
+
font-size: 14px;
|
|
2148
|
+
font-weight: 600;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
.cn-look-board .cn-index-sidebar__checklist {
|
|
2152
|
+
display: flex;
|
|
2153
|
+
flex-direction: column;
|
|
2154
|
+
gap: 4px;
|
|
2155
|
+
margin: 0;
|
|
2156
|
+
padding: 0;
|
|
2157
|
+
border: 0;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
.cn-look-board .cn-index-sidebar__checklist-row {
|
|
2161
|
+
display: flex;
|
|
2162
|
+
align-items: center;
|
|
2163
|
+
gap: 10px;
|
|
2164
|
+
min-height: 32px;
|
|
2165
|
+
font-size: 14px;
|
|
2166
|
+
cursor: pointer;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
.cn-look-board .cn-index-sidebar__checklist-row > input[type='checkbox'] {
|
|
2170
|
+
width: 18px;
|
|
2171
|
+
min-width: 18px;
|
|
2172
|
+
height: 18px;
|
|
2173
|
+
min-height: 18px;
|
|
2174
|
+
margin: 0;
|
|
2175
|
+
accent-color: var(--color-primary-element);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
.cn-look-board .cn-index-sidebar__checklist-label {
|
|
2179
|
+
flex: 1;
|
|
2180
|
+
min-width: 0;
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
.cn-look-board .cn-index-sidebar__checklist-count {
|
|
2184
|
+
color: var(--color-text-maxcontrast);
|
|
2185
|
+
font-size: 13px;
|
|
2186
|
+
}
|