@conduction/nextcloud-vue 2.135.0 → 2.136.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 +2 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +65 -50
- package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +6 -0
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js +9 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +4 -11
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +12 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +11 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +3 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +18 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +38 -23
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue.js +1 -1
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +69 -3
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/l10n/en.json.js +20 -20
- package/dist/esm/l10n/nl.json.js +21 -21
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +322 -164
- package/dist/esm/utils/widgetDispatch.js +3 -1
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +739 -589
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +322 -164
- package/l10n/en.json +20 -20
- package/l10n/nl.json +21 -21
- package/package.json +1 -1
- package/src/components/CnActionDialog/CnActionDialog.vue +45 -4
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +15 -0
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +2 -10
- package/src/components/CnDataTable/CnDataTable.md +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +13 -1
- package/src/components/CnDetailPage/CnDetailPage.md +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +12 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +4 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +38 -2
- package/src/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue +7 -0
- package/src/composables/indexSources.js +69 -3
- package/src/css/look-board-detail.css +47 -1
- package/src/css/look-board-index.css +26 -1
- package/src/css/look-board.css +46 -3
- package/src/utils/widgetDispatch.js +3 -1
package/l10n/en.json
CHANGED
|
@@ -1484,18 +1484,6 @@
|
|
|
1484
1484
|
"Pages": "Pages",
|
|
1485
1485
|
"Open {module}": "Open {module}",
|
|
1486
1486
|
"{list} and {last}": "{list} and {last}",
|
|
1487
|
-
"%n page: {pages}": [
|
|
1488
|
-
"%n page: {pages}",
|
|
1489
|
-
"%n pages: {pages}"
|
|
1490
|
-
],
|
|
1491
|
-
"%n page, including {pages}": [
|
|
1492
|
-
"%n page, including {pages}",
|
|
1493
|
-
"%n pages, including {pages}"
|
|
1494
|
-
],
|
|
1495
|
-
"{on} of %n is in the menu": [
|
|
1496
|
-
"{on} of %n is in the menu",
|
|
1497
|
-
"{on} of %n are in the menu"
|
|
1498
|
-
],
|
|
1499
1487
|
"Put it in the menu:": "Put it in the menu:",
|
|
1500
1488
|
"Admin settings": "Admin settings",
|
|
1501
1489
|
"Support this app": "Support this app",
|
|
@@ -1513,10 +1501,6 @@
|
|
|
1513
1501
|
"{status}, {expected}": "{status}, {expected}",
|
|
1514
1502
|
"Build on this app": "Build on this app",
|
|
1515
1503
|
"AI skills": "AI skills",
|
|
1516
|
-
"%n feature": [
|
|
1517
|
-
"%n feature",
|
|
1518
|
-
"%n features"
|
|
1519
|
-
],
|
|
1520
1504
|
"Your account": "Your account",
|
|
1521
1505
|
"Only for you. Colleagues keep their own settings.": "Only for you. Colleagues keep their own settings.",
|
|
1522
1506
|
"Sections of the settings": "Sections of the settings",
|
|
@@ -2254,10 +2238,6 @@
|
|
|
2254
2238
|
"from {from}": "from {from}",
|
|
2255
2239
|
"up to {to}": "up to {to}",
|
|
2256
2240
|
"this week": "this week",
|
|
2257
|
-
"within %n day": [
|
|
2258
|
-
"within %n day",
|
|
2259
|
-
"within %n days"
|
|
2260
|
-
],
|
|
2261
2241
|
"Search term: {term}": "Search term: {term}",
|
|
2262
2242
|
"New contact": "New contact",
|
|
2263
2243
|
"Template": "Template",
|
|
@@ -2578,6 +2558,26 @@
|
|
|
2578
2558
|
"%n minute": [
|
|
2579
2559
|
"%n minute",
|
|
2580
2560
|
"%n minutes"
|
|
2561
|
+
],
|
|
2562
|
+
"%n page: {pages}": [
|
|
2563
|
+
"%n page: {pages}",
|
|
2564
|
+
"%n pages: {pages}"
|
|
2565
|
+
],
|
|
2566
|
+
"%n page, including {pages}": [
|
|
2567
|
+
"%n page, including {pages}",
|
|
2568
|
+
"%n pages, including {pages}"
|
|
2569
|
+
],
|
|
2570
|
+
"{on} of %n is in the menu": [
|
|
2571
|
+
"{on} of %n is in the menu",
|
|
2572
|
+
"{on} of %n are in the menu"
|
|
2573
|
+
],
|
|
2574
|
+
"%n feature": [
|
|
2575
|
+
"%n feature",
|
|
2576
|
+
"%n features"
|
|
2577
|
+
],
|
|
2578
|
+
"within %n day": [
|
|
2579
|
+
"within %n day",
|
|
2580
|
+
"within %n days"
|
|
2581
2581
|
]
|
|
2582
2582
|
}
|
|
2583
2583
|
}
|
package/l10n/nl.json
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"Save sharing": "Delen opslaan",
|
|
57
57
|
"Failed to save sharing": "Delen opslaan is mislukt",
|
|
58
58
|
"My views": "Mijn weergaven",
|
|
59
|
-
"Shared with me": "
|
|
59
|
+
"Shared with me": "Gedeeld met mij",
|
|
60
60
|
"Share \"{name}\"": "\"{name}\" delen",
|
|
61
61
|
"Save the current view to \"{name}\"": "Huidige weergave opslaan in \"{name}\"",
|
|
62
62
|
"Save \"{name}\" as my view": "\"{name}\" opslaan als mijn weergave",
|
|
@@ -1671,18 +1671,6 @@
|
|
|
1671
1671
|
"Pages": "Pagina's",
|
|
1672
1672
|
"Open {module}": "{module} openen",
|
|
1673
1673
|
"{list} and {last}": "{list} en {last}",
|
|
1674
|
-
"%n page: {pages}": [
|
|
1675
|
-
"%n pagina: {pages}",
|
|
1676
|
-
"%n pagina's: {pages}"
|
|
1677
|
-
],
|
|
1678
|
-
"%n page, including {pages}": [
|
|
1679
|
-
"%n pagina, waaronder {pages}",
|
|
1680
|
-
"%n pagina's, waaronder {pages}"
|
|
1681
|
-
],
|
|
1682
|
-
"{on} of %n is in the menu": [
|
|
1683
|
-
"{on} van %n staat in het menu",
|
|
1684
|
-
"{on} van %n staan in het menu"
|
|
1685
|
-
],
|
|
1686
1674
|
"Put it in the menu:": "In het menu zetten:",
|
|
1687
1675
|
"Support this app": "Steun deze app",
|
|
1688
1676
|
"No features with this status": "Geen functies met deze status",
|
|
@@ -1699,10 +1687,6 @@
|
|
|
1699
1687
|
"{status}, {expected}": "{status}, {expected}",
|
|
1700
1688
|
"Build on this app": "Bouw verder op deze app",
|
|
1701
1689
|
"AI skills": "AI-vaardigheden",
|
|
1702
|
-
"%n feature": [
|
|
1703
|
-
"%n functie",
|
|
1704
|
-
"%n functies"
|
|
1705
|
-
],
|
|
1706
1690
|
"Your account": "Uw account",
|
|
1707
1691
|
"Only for you. Colleagues keep their own settings.": "Alleen voor jou. Collega's houden hun eigen instellingen.",
|
|
1708
1692
|
"Sections of the settings": "Onderdelen van de instellingen",
|
|
@@ -2504,10 +2488,6 @@
|
|
|
2504
2488
|
"from {from}": "vanaf {from}",
|
|
2505
2489
|
"up to {to}": "tot en met {to}",
|
|
2506
2490
|
"this week": "deze week",
|
|
2507
|
-
"within %n day": [
|
|
2508
|
-
"binnen %n dag",
|
|
2509
|
-
"binnen %n dagen"
|
|
2510
|
-
],
|
|
2511
2491
|
"Search term: {term}": "Zoekterm: {term}",
|
|
2512
2492
|
"New contact": "Nieuw contact",
|
|
2513
2493
|
"Template": "Sjabloon",
|
|
@@ -2845,6 +2825,26 @@
|
|
|
2845
2825
|
"%n minute": [
|
|
2846
2826
|
"%n minuut",
|
|
2847
2827
|
"%n minuten"
|
|
2828
|
+
],
|
|
2829
|
+
"%n page: {pages}": [
|
|
2830
|
+
"%n pagina: {pages}",
|
|
2831
|
+
"%n pagina's: {pages}"
|
|
2832
|
+
],
|
|
2833
|
+
"%n page, including {pages}": [
|
|
2834
|
+
"%n pagina, waaronder {pages}",
|
|
2835
|
+
"%n pagina's, waaronder {pages}"
|
|
2836
|
+
],
|
|
2837
|
+
"{on} of %n is in the menu": [
|
|
2838
|
+
"{on} van %n staat in het menu",
|
|
2839
|
+
"{on} van %n staan in het menu"
|
|
2840
|
+
],
|
|
2841
|
+
"%n feature": [
|
|
2842
|
+
"%n functie",
|
|
2843
|
+
"%n functies"
|
|
2844
|
+
],
|
|
2845
|
+
"within %n day": [
|
|
2846
|
+
"binnen %n dag",
|
|
2847
|
+
"binnen %n dagen"
|
|
2848
2848
|
]
|
|
2849
2849
|
}
|
|
2850
2850
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/nextcloud-vue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.136.0",
|
|
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": {
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
<div v-if="!done" class="cn-action-dialog">
|
|
15
15
|
<!-- The record the action is about: its title, a meta line, a badge. -->
|
|
16
16
|
<div v-if="summary" class="cn-action-dialog__summary" data-testid="cn-action-dialog-summary">
|
|
17
|
-
<
|
|
17
|
+
<span class="cn-action-dialog__summary-icon">
|
|
18
|
+
<CnIcon :name="config.summary.icon || 'FolderOutline'" :size="20" />
|
|
19
|
+
</span>
|
|
18
20
|
<span class="cn-action-dialog__summary-text">
|
|
19
21
|
<strong>{{ summary.title }}</strong>
|
|
20
22
|
<span v-if="summary.meta" class="cn-action-dialog__muted">{{ summary.meta }}</span>
|
|
@@ -142,6 +144,9 @@
|
|
|
142
144
|
:type="noteType"
|
|
143
145
|
:heading="text(config.note.title)"
|
|
144
146
|
data-testid="cn-action-dialog-note">
|
|
147
|
+
<template v-if="config.note.icon" #icon>
|
|
148
|
+
<CnIcon :name="config.note.icon" :size="20" />
|
|
149
|
+
</template>
|
|
145
150
|
{{ text(config.note.text) }}
|
|
146
151
|
</NcNoteCard>
|
|
147
152
|
|
|
@@ -239,7 +244,8 @@ let reasonSeq = 0
|
|
|
239
244
|
* - `reason`: `{ label?, hint?, required?, field?, rows? }`: a text area; required by
|
|
240
245
|
* default; sent as `field` (default `reason`). `rows` is its height in lines
|
|
241
246
|
* (default 2; board DqBesluit draws 4).
|
|
242
|
-
* - `note`: `{ variant?, title?, text }`: a read-only note
|
|
247
|
+
* - `note`: `{ variant?, title?, text, icon? }`: a read-only note; `icon` an
|
|
248
|
+
* icon name in place of the variant's own ("LockOutline").
|
|
243
249
|
* - `confirm`: `{ label, icon?, request?: { method?, url, body? }, action? }`.
|
|
244
250
|
* `request` posts itself (`body` templates filled with the record and
|
|
245
251
|
* `{reason}`); `action` dispatches a manifest action through the page.
|
|
@@ -808,10 +814,32 @@ export default {
|
|
|
808
814
|
.cn-action-dialog__summary {
|
|
809
815
|
display: flex;
|
|
810
816
|
align-items: center;
|
|
811
|
-
gap:
|
|
817
|
+
gap: 12px;
|
|
812
818
|
padding: 12px 14px;
|
|
813
819
|
border: 1px solid var(--color-border);
|
|
814
|
-
border-radius: var(--border-radius-large,
|
|
820
|
+
border-radius: var(--border-radius-large, 10px);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/* The record's icon on a tinted tile (DqArchiveren). */
|
|
824
|
+
.cn-action-dialog__summary-icon {
|
|
825
|
+
display: flex;
|
|
826
|
+
flex: none;
|
|
827
|
+
align-items: center;
|
|
828
|
+
justify-content: center;
|
|
829
|
+
width: 36px;
|
|
830
|
+
height: 36px;
|
|
831
|
+
border-radius: 8px;
|
|
832
|
+
background: var(--color-primary-element-light);
|
|
833
|
+
color: var(--color-primary-element-light-text);
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.cn-action-dialog__summary-text strong {
|
|
837
|
+
font-size: 15px;
|
|
838
|
+
font-weight: 600;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.cn-action-dialog__summary-text .cn-action-dialog__muted {
|
|
842
|
+
font-size: 13px;
|
|
815
843
|
}
|
|
816
844
|
|
|
817
845
|
.cn-action-dialog__summary-text {
|
|
@@ -853,13 +881,26 @@ export default {
|
|
|
853
881
|
border-bottom: 1px solid var(--color-border);
|
|
854
882
|
}
|
|
855
883
|
|
|
884
|
+
/* The server draws every dt as a 130px right-aligned inline block and pads
|
|
885
|
+
dt and dd 12px; a fact is a label over its value. */
|
|
886
|
+
.cn-action-dialog__facts dt,
|
|
887
|
+
.cn-action-dialog__facts dd {
|
|
888
|
+
display: block;
|
|
889
|
+
width: auto;
|
|
890
|
+
white-space: normal;
|
|
891
|
+
text-align: start;
|
|
892
|
+
}
|
|
893
|
+
|
|
856
894
|
.cn-action-dialog__facts dt {
|
|
895
|
+
margin: 0;
|
|
896
|
+
padding: 0;
|
|
857
897
|
color: var(--color-text-maxcontrast);
|
|
858
898
|
font-size: 13px;
|
|
859
899
|
}
|
|
860
900
|
|
|
861
901
|
.cn-action-dialog__facts dd {
|
|
862
902
|
margin: 0;
|
|
903
|
+
padding: 0;
|
|
863
904
|
font-size: 15px;
|
|
864
905
|
font-weight: 500;
|
|
865
906
|
}
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
</p>
|
|
48
48
|
</li>
|
|
49
49
|
</ul>
|
|
50
|
+
<p v-if="footnote" class="cn-audit-card__footnote" data-testid="cn-audit-trail-widget-footnote">
|
|
51
|
+
{{ footnote }}
|
|
52
|
+
</p>
|
|
50
53
|
<template v-if="shownEntries.length > maxDisplay" #footer>
|
|
51
54
|
<button class="cn-audit-card__show-all" @click="$emit('show-all')">
|
|
52
55
|
{{ showAllLabel }} ({{ shownEntries.length }})
|
|
@@ -93,6 +96,12 @@ export default {
|
|
|
93
96
|
components: { CnDetailCard, NcLoadingIcon },
|
|
94
97
|
|
|
95
98
|
props: {
|
|
99
|
+
/**
|
|
100
|
+
* A muted line under the trail, inside the card ("Kenmerk ZT-OMV-REG").
|
|
101
|
+
*
|
|
102
|
+
* @spec openspec/changes/audit-trail-footnote/specs/audit-trail/spec.md#requirement-a-history-card-can-end-in-a-line-about-the-record
|
|
103
|
+
*/
|
|
104
|
+
footnote: { type: String, default: '' },
|
|
96
105
|
/** OpenRegister register id (slug or uuid). Optional for `scope: "app"`. */
|
|
97
106
|
register: { type: String, default: '' },
|
|
98
107
|
/** OpenRegister schema id (slug or uuid). Optional for `scope: "app"`. */
|
|
@@ -523,6 +532,12 @@ export default {
|
|
|
523
532
|
padding: 12px 0;
|
|
524
533
|
}
|
|
525
534
|
|
|
535
|
+
.cn-audit-card__footnote {
|
|
536
|
+
margin: 12px 0 0;
|
|
537
|
+
color: var(--color-text-maxcontrast);
|
|
538
|
+
font-size: 13px;
|
|
539
|
+
}
|
|
540
|
+
|
|
526
541
|
.cn-audit-card__show-all {
|
|
527
542
|
background: none;
|
|
528
543
|
border: none;
|
|
@@ -20,10 +20,8 @@
|
|
|
20
20
|
:actionLabels="actionLabels"
|
|
21
21
|
:valueLabels="valueLabels"
|
|
22
22
|
:relatedSources="relatedSources"
|
|
23
|
+
:footnote="footnote"
|
|
23
24
|
v-bind="emptyText ? { noEntriesLabel: emptyText } : {}" />
|
|
24
|
-
<p v-if="footnote" class="cn-audit-trail-widget__footnote" data-testid="cn-audit-trail-widget-footnote">
|
|
25
|
-
{{ footnote }}
|
|
26
|
-
</p>
|
|
27
25
|
</div>
|
|
28
26
|
</template>
|
|
29
27
|
|
|
@@ -283,14 +281,8 @@ export default {
|
|
|
283
281
|
</script>
|
|
284
282
|
|
|
285
283
|
<style scoped>
|
|
286
|
-
/* The card keeps its own box
|
|
284
|
+
/* The card keeps its own box, footnote included. */
|
|
287
285
|
.cn-audit-trail-widget {
|
|
288
286
|
display: contents;
|
|
289
287
|
}
|
|
290
|
-
|
|
291
|
-
.cn-audit-trail-widget__footnote {
|
|
292
|
-
margin: 0;
|
|
293
|
-
font-size: 13px;
|
|
294
|
-
color: var(--color-text-maxcontrast);
|
|
295
|
-
}
|
|
296
288
|
</style>
|
|
@@ -209,6 +209,7 @@ export default {
|
|
|
209
209
|
| `filterable` | Boolean | `false` | Show a filter button in every header whose column can filter: enum, boolean, text, number, date and reference columns backed by a schema property. A column opts out with `filterable: false`. Applying a filter emits `column-filter`; the host owns the state and passes it back as `activeFilters`. `CnIndexPage` turns it on by default. |
|
|
210
210
|
| `activeFilters` | Object | `{}` | The active filter map, `{ paramKey: values[] }`: the same map the facet sidebar writes, so a header filter and a sidebar filter on one field show the same state. |
|
|
211
211
|
| `filterSchema` | Object | `null` | The schema the header filters read instead of `schema`, for a page that filters through other fields than the rows' own (a named source's search fields). Null: the header filters read `schema`. |
|
|
212
|
+
| `filterChips` | Boolean | `true` | Draw the active header filters as removable chips above the table. A host that lists them itself (the index page's board Active line) turns this off, so a filter is not shown twice. |
|
|
212
213
|
| `filterRegister` | String | `''` | Register slug a reference column's filter searches in when the column names none. |
|
|
213
214
|
| `lensReasonTexts` | Object \| null | `null` | App wording for an unavailable personal lens in self-fetch mode, keyed `<lens>.<reason>` or `<reason>`. Without it the library's text is used (see below). |
|
|
214
215
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
<!-- Active header filters, one removable chip each. -->
|
|
26
26
|
<ul
|
|
27
|
-
v-if="!isLoading && activeColumnFilterChips.length > 0"
|
|
27
|
+
v-if="filterChips && !isLoading && activeColumnFilterChips.length > 0"
|
|
28
28
|
class="cn-data-table__filter-chips"
|
|
29
29
|
:aria-label="activeFiltersLabel"
|
|
30
30
|
data-testid="cn-table-filter-chips">
|
|
@@ -1081,6 +1081,18 @@ export default {
|
|
|
1081
1081
|
default: null,
|
|
1082
1082
|
},
|
|
1083
1083
|
|
|
1084
|
+
/**
|
|
1085
|
+
* Draw the active header filters as removable chips above the table.
|
|
1086
|
+
* A host that lists them itself (the index page's board Active line)
|
|
1087
|
+
* turns this off, so a filter is not shown twice.
|
|
1088
|
+
*
|
|
1089
|
+
* @spec openspec/changes/index-table-filter-chips-once/specs/cn-data-table/spec.md#requirement-a-host-that-lists-the-active-filters-itself-turns-the-table-chips-off
|
|
1090
|
+
*/
|
|
1091
|
+
filterChips: {
|
|
1092
|
+
type: Boolean,
|
|
1093
|
+
default: true,
|
|
1094
|
+
},
|
|
1095
|
+
|
|
1084
1096
|
/**
|
|
1085
1097
|
* The active filter map, `{ paramKey: values[] }`: the same map the
|
|
1086
1098
|
* facet sidebar writes, so a header filter and a sidebar filter on one
|
|
@@ -372,6 +372,7 @@ The header carries the shared [CnActionsMenu](./cn-actions-menu.md) overflow (Re
|
|
|
372
372
|
| `formSize` (`form-size`) | String | `'normal'` | NcDialog size for this page's create and edit form dialogs (`'small'`, `'normal'`, `'large'`). Set from the manifest as `config.formSize`. Before 2.44.0 the page passed no size, so both forms sat at `normal` however many properties the schema declared, while a manifest `open-form` header action could already ask for `large`. |
|
|
373
373
|
| `formColumns` (`form-columns`) | Number | `1` | How many columns the create and edit forms flow their fields into (`1` or `2`). Pair `2` with `formSize: 'large'`, or the two columns are merely two narrow ones. Textareas and JSON editors still span both, and the layout collapses back to one column below 700px. Set from the manifest as `config.formColumns`. |
|
|
374
374
|
| `editLabel` | String | `''` | Label for the header Edit button. Defaults to a translated "Edit". |
|
|
375
|
+
| `editTitle` | String | `''` | Title of the record edit form, run through the host translate. Empty uses the Edit button's label. |
|
|
375
376
|
| `editSubtitle` | String | `''` | One line under the edit form's title, run through the host translate. Empty shows none. |
|
|
376
377
|
| `showRequestFeature` | Boolean | `true` | Show the Request-a-feature item. Emits `@request-feature`; the default opens the forge's feature-request issue form (repo and forge injected by CnAppRoot) in a new tab, pre-filled with the page title and `surface: "detail:<id>"`. |
|
|
377
378
|
| `documentationUrl` | String | `''` | When set, adds a **Documentation** entry opening the link in a new tab. Empty hides it. |
|
|
@@ -1324,7 +1324,7 @@
|
|
|
1324
1324
|
:schema="currentSchema"
|
|
1325
1325
|
:item="currentObject"
|
|
1326
1326
|
:register="register"
|
|
1327
|
-
:dialogTitle="
|
|
1327
|
+
:dialogTitle="editFormTitle"
|
|
1328
1328
|
:subtitle="editFormSubtitle"
|
|
1329
1329
|
:excludeFields="excludeFields"
|
|
1330
1330
|
:includeFields="includeFields"
|
|
@@ -2454,6 +2454,12 @@ export default {
|
|
|
2454
2454
|
default: '',
|
|
2455
2455
|
},
|
|
2456
2456
|
|
|
2457
|
+
/** Title of the record edit form, run through the host translate. Empty uses the Edit button's label. */
|
|
2458
|
+
editTitle: {
|
|
2459
|
+
type: String,
|
|
2460
|
+
default: '',
|
|
2461
|
+
},
|
|
2462
|
+
|
|
2457
2463
|
/** One line under the edit form's title, run through the host translate. Empty shows none. */
|
|
2458
2464
|
editSubtitle: {
|
|
2459
2465
|
type: String,
|
|
@@ -4790,6 +4796,11 @@ export default {
|
|
|
4790
4796
|
return this.editLabel ? this.effectiveTranslate(this.editLabel) : t('nextcloud-vue', 'Edit')
|
|
4791
4797
|
},
|
|
4792
4798
|
|
|
4799
|
+
/** @return {string} The edit form's title, translated; the Edit button's label when none is configured. */
|
|
4800
|
+
editFormTitle() {
|
|
4801
|
+
return this.editTitle ? this.effectiveTranslate(this.editTitle) : this.editActionLabel
|
|
4802
|
+
},
|
|
4803
|
+
|
|
4793
4804
|
/** @return {string} The edit form's subtitle, translated; empty when none is configured. */
|
|
4794
4805
|
editFormSubtitle() {
|
|
4795
4806
|
return this.editSubtitle ? this.effectiveTranslate(this.editSubtitle) : ''
|
|
@@ -871,6 +871,7 @@
|
|
|
871
871
|
<CnDataTable
|
|
872
872
|
v-else-if="currentViewMode === 'table'"
|
|
873
873
|
:schema="effectiveSchema"
|
|
874
|
+
:filterChips="!isBoardLook"
|
|
874
875
|
:columns="renderedColumns"
|
|
875
876
|
:pinnedCount="pinnedColumnCount"
|
|
876
877
|
:rowIcon="rowIcon"
|
|
@@ -10863,7 +10864,8 @@ export default {
|
|
|
10863
10864
|
/**
|
|
10864
10865
|
* A view's state as the edit dialog shows it under a criteria choice:
|
|
10865
10866
|
* its filters, search term and sort in sentences, read against the
|
|
10866
|
-
* page schema's titles
|
|
10867
|
+
* page schema's titles and the page's `filterLabels` (a `hidden`
|
|
10868
|
+
* filter is left out).
|
|
10867
10869
|
*
|
|
10868
10870
|
* @param {object} state A view state (`extractViewState` or `currentViewState`).
|
|
10869
10871
|
* @return {string} The sentences.
|
|
@@ -10873,6 +10875,7 @@ export default {
|
|
|
10873
10875
|
const schema = this.effectiveSchema
|
|
10874
10876
|
return viewCriteriaSummary(state, {
|
|
10875
10877
|
properties: (schema && schema.properties) || {},
|
|
10878
|
+
filterLabels: this.filterLabels || {},
|
|
10876
10879
|
translate: (text) => this.cnTranslate(text),
|
|
10877
10880
|
})
|
|
10878
10881
|
},
|
|
@@ -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 }]"
|
|
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' }]"
|
|
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 }}
|
|
@@ -448,7 +448,21 @@
|
|
|
448
448
|
data-testid="cn-record-list-action-error">
|
|
449
449
|
{{ actionError }}
|
|
450
450
|
</p>
|
|
451
|
-
<
|
|
451
|
+
<div
|
|
452
|
+
v-if="footnoteTone && footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)"
|
|
453
|
+
class="cn-record-list__notice cn-record-list__notice--footnote"
|
|
454
|
+
:class="`cn-record-list__notice--${footnoteTone}`"
|
|
455
|
+
data-testid="cn-record-list-footnote">
|
|
456
|
+
<CnIcon
|
|
457
|
+
:name="footnoteTone === 'info' ? 'InformationOutline' : 'AlertOutline'"
|
|
458
|
+
:size="16"
|
|
459
|
+
class="cn-record-list__notice-icon"
|
|
460
|
+
aria-hidden="true" />
|
|
461
|
+
<p class="cn-record-list__notice-text">
|
|
462
|
+
{{ footnote }}
|
|
463
|
+
</p>
|
|
464
|
+
</div>
|
|
465
|
+
<p v-else-if="footnote && !error && !absent && (rows.length > 0 || footnoteFromAnswer)" class="cn-record-list__footnote" data-testid="cn-record-list-footnote">
|
|
452
466
|
{{ footnote }}
|
|
453
467
|
</p>
|
|
454
468
|
<!-- `footerLink`: a text link under the rows ("Naar Mijn werk"). -->
|
|
@@ -685,6 +699,11 @@ export default {
|
|
|
685
699
|
* `pill.cases` (`[{ when, label, variant? }]`) labels a row by the
|
|
686
700
|
* first case whose `when` holds on it, else by the pill's own `label`
|
|
687
701
|
* and `variant` (Concept, Vastgezet, Actief).
|
|
702
|
+
* `footnoteVariant` (`info`, `warning` or `error`) draws the footnote
|
|
703
|
+
* as a toned notice box with its icon (DqZaaktype opt-out note).
|
|
704
|
+
* `tableLook: "data"` marks a `table` as a data table, which the board
|
|
705
|
+
* look draws as its card table (header band, 40px rows, hairlines)
|
|
706
|
+
* instead of the compact grid (DqZaaktype "Berichten aan de aanvrager").
|
|
688
707
|
* `groupBy` (a field path) draws the rows in groups under a heading
|
|
689
708
|
* per value, headed by the field's `valueLabels` entry; `groupOrder`
|
|
690
709
|
* (values) orders the groups and `groupEmptyLabel` heads the rows
|
|
@@ -1212,6 +1231,19 @@ export default {
|
|
|
1212
1231
|
return typeof note === 'string' && note !== '' ? this.translate(note) : ''
|
|
1213
1232
|
},
|
|
1214
1233
|
|
|
1234
|
+
/**
|
|
1235
|
+
* The tone the footnote is drawn in as a notice box
|
|
1236
|
+
* (`content.footnoteVariant`: info, warning or error); '' for a plain
|
|
1237
|
+
* muted line.
|
|
1238
|
+
*
|
|
1239
|
+
* @return {string} The tone, or ''.
|
|
1240
|
+
* @spec openspec/changes/record-list-data-table-and-notice-footnote/specs/record-list/spec.md#requirement-a-record-list-footnote-can-be-a-toned-notice
|
|
1241
|
+
*/
|
|
1242
|
+
footnoteTone() {
|
|
1243
|
+
const tone = this.content?.footnoteVariant
|
|
1244
|
+
return NOTICE_VARIANTS.includes(tone) ? tone : ''
|
|
1245
|
+
},
|
|
1246
|
+
|
|
1215
1247
|
/**
|
|
1216
1248
|
* Whether the footnote reads the answer: it then shows with no rows too.
|
|
1217
1249
|
*
|
|
@@ -2938,6 +2970,10 @@ export default {
|
|
|
2938
2970
|
color: var(--color-error-text, var(--color-main-text));
|
|
2939
2971
|
}
|
|
2940
2972
|
|
|
2973
|
+
.cn-record-list__notice--footnote {
|
|
2974
|
+
margin-top: 12px;
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2941
2977
|
.cn-record-list__notice-icon {
|
|
2942
2978
|
flex: 0 0 auto;
|
|
2943
2979
|
margin-top: 1px;
|
|
@@ -701,13 +701,20 @@ export default {
|
|
|
701
701
|
width: 1px;
|
|
702
702
|
}
|
|
703
703
|
|
|
704
|
+
/* A theme's paragraph rule sets every p's size and colour with !important
|
|
705
|
+
(thematiq), so the note and the footnote also set its tokens.
|
|
706
|
+
@spec openspec/changes/calendar-footnote-paragraph-tokens/specs/working-calendar-footnote/spec.md */
|
|
704
707
|
.cn-working-calendar__note {
|
|
708
|
+
--nldesign-component-paragraph-color: var(--color-text-maxcontrast);
|
|
705
709
|
color: var(--color-text-maxcontrast);
|
|
706
710
|
margin: 0;
|
|
707
711
|
}
|
|
708
712
|
|
|
709
713
|
/* @spec openspec/changes/working-calendar-footnote/specs/working-calendar-footnote/spec.md */
|
|
710
714
|
.cn-working-calendar__footnote {
|
|
715
|
+
--nldesign-component-paragraph-font-size: 13px;
|
|
716
|
+
--nldesign-component-paragraph-line-height: 1.3;
|
|
717
|
+
--nldesign-component-paragraph-color: var(--color-text-maxcontrast);
|
|
711
718
|
margin: 0;
|
|
712
719
|
font-size: 13px;
|
|
713
720
|
line-height: 1.3;
|
|
@@ -1401,6 +1401,32 @@ function searchSource(config = {}, context = {}) {
|
|
|
1401
1401
|
}
|
|
1402
1402
|
}
|
|
1403
1403
|
|
|
1404
|
+
/**
|
|
1405
|
+
* The members that match a search, in the asked order, and the page of them
|
|
1406
|
+
* the pager asks for.
|
|
1407
|
+
*
|
|
1408
|
+
* @param {Array<object>} members The members, by name.
|
|
1409
|
+
* @param {object} config `search`, `sortKey`, `sortOrder`, `limit`, `offset`.
|
|
1410
|
+
* @return {{rows: Array<object>, total: number}} The page and how many match.
|
|
1411
|
+
*/
|
|
1412
|
+
function membersPage(members, config = {}) {
|
|
1413
|
+
const term = String(config.search || '').trim().toLowerCase()
|
|
1414
|
+
let rows = term === ''
|
|
1415
|
+
? members.slice()
|
|
1416
|
+
: members.filter((member) => ['displayname', 'function', 'roles', 'email'].some((field) => String(member[field] || '').toLowerCase().includes(term)))
|
|
1417
|
+
if (config.sortKey) {
|
|
1418
|
+
const sign = config.sortOrder === 'desc' ? -1 : 1
|
|
1419
|
+
rows = rows.sort((a, b) => sign * String(a[config.sortKey] ?? '').localeCompare(String(b[config.sortKey] ?? '')))
|
|
1420
|
+
}
|
|
1421
|
+
const total = rows.length
|
|
1422
|
+
const limit = Number(config.limit) || 0
|
|
1423
|
+
if (limit > 0) {
|
|
1424
|
+
const offset = Number(config.offset) || 0
|
|
1425
|
+
rows = rows.slice(offset, offset + limit)
|
|
1426
|
+
}
|
|
1427
|
+
return { rows, total }
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1404
1430
|
/**
|
|
1405
1431
|
* The users source: the members of a Nextcloud group, with their function,
|
|
1406
1432
|
* roles, e-mail and whether they are in today (`entitySource: "users"`,
|
|
@@ -1417,12 +1443,20 @@ function searchSource(config = {}, context = {}) {
|
|
|
1417
1443
|
* Listing a group needs an admin or the group's sub-admin; a refused request
|
|
1418
1444
|
* leaves the list empty.
|
|
1419
1445
|
*
|
|
1446
|
+
* The page gets a pager (`pages`), and the search term and the header's order
|
|
1447
|
+
* come as `search` and `sortKey` / `sortOrder`: the group's members are read
|
|
1448
|
+
* once and searched, sorted and paged here, so a new page, term or order does
|
|
1449
|
+
* not read every member's presence again.
|
|
1450
|
+
*
|
|
1420
1451
|
* @return {object} The source adapter.
|
|
1421
1452
|
* @spec openspec/changes/index-groups-users-source/specs/index-page/spec.md#requirement-an-index-page-can-list-nextcloud-groups-and-their-members
|
|
1422
1453
|
*/
|
|
1423
1454
|
function usersSource() {
|
|
1424
|
-
const state = reactive({ rows: [], loading: false })
|
|
1455
|
+
const state = reactive({ rows: [], loading: false, total: 0 })
|
|
1425
1456
|
let seq = 0
|
|
1457
|
+
// The members last read, for the group and request they were read for.
|
|
1458
|
+
let readMembers = []
|
|
1459
|
+
let membersKey = null
|
|
1426
1460
|
const presenceLabels = {
|
|
1427
1461
|
present: t('nextcloud-vue', 'Present'),
|
|
1428
1462
|
away: t('nextcloud-vue', 'Away'),
|
|
@@ -1441,6 +1475,15 @@ function usersSource() {
|
|
|
1441
1475
|
*/
|
|
1442
1476
|
load: async (config) => {
|
|
1443
1477
|
const group = String((config && (config.group || config.defaultGroup)) || '')
|
|
1478
|
+
const { search, sortKey, sortOrder, limit, offset, ...request } = config || {}
|
|
1479
|
+
const key = JSON.stringify({ ...request, group })
|
|
1480
|
+
// A new page, term or order of the members already read: no request.
|
|
1481
|
+
if (key === membersKey && (offset !== undefined || search !== undefined || sortKey !== undefined)) {
|
|
1482
|
+
const page = membersPage(readMembers, config)
|
|
1483
|
+
state.rows = page.rows
|
|
1484
|
+
state.total = page.total
|
|
1485
|
+
return
|
|
1486
|
+
}
|
|
1444
1487
|
const mine = ++seq
|
|
1445
1488
|
state.loading = true
|
|
1446
1489
|
try {
|
|
@@ -1475,11 +1518,18 @@ function usersSource() {
|
|
|
1475
1518
|
}
|
|
1476
1519
|
}))
|
|
1477
1520
|
if (mine === seq) {
|
|
1478
|
-
|
|
1521
|
+
readMembers = rows.sort((a, b) => a.displayname.localeCompare(b.displayname))
|
|
1522
|
+
membersKey = key
|
|
1523
|
+
const page = membersPage(readMembers, config)
|
|
1524
|
+
state.rows = page.rows
|
|
1525
|
+
state.total = page.total
|
|
1479
1526
|
}
|
|
1480
1527
|
} catch (error) {
|
|
1481
1528
|
if (mine === seq) {
|
|
1529
|
+
readMembers = []
|
|
1530
|
+
membersKey = null
|
|
1482
1531
|
state.rows = []
|
|
1532
|
+
state.total = 0
|
|
1483
1533
|
}
|
|
1484
1534
|
throw error
|
|
1485
1535
|
} finally {
|
|
@@ -1490,10 +1540,26 @@ function usersSource() {
|
|
|
1490
1540
|
},
|
|
1491
1541
|
|
|
1492
1542
|
/**
|
|
1493
|
-
* @return {Array<object>} The members.
|
|
1543
|
+
* @return {Array<object>} The members on this page.
|
|
1494
1544
|
*/
|
|
1495
1545
|
rows: () => state.rows,
|
|
1496
1546
|
|
|
1547
|
+
pages: true,
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* @return {number} The members that match, on every page.
|
|
1551
|
+
*/
|
|
1552
|
+
total: () => state.total,
|
|
1553
|
+
|
|
1554
|
+
searchParam: 'search',
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* @param {string} key The column.
|
|
1558
|
+
* @param {string} order `asc` or `desc`.
|
|
1559
|
+
* @return {object} The load arguments.
|
|
1560
|
+
*/
|
|
1561
|
+
sortParam: (key, order) => ({ sortKey: key, sortOrder: order }),
|
|
1562
|
+
|
|
1497
1563
|
/**
|
|
1498
1564
|
* @return {boolean} Whether a load is in flight.
|
|
1499
1565
|
*/
|