@conduction/nextcloud-vue 2.63.0 → 2.64.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/CnAppNav/CnAppNav.vue2.js +154 -7
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +119 -42
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +87 -0
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +26 -24
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +150 -133
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +37 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +12 -4
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +66 -14
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +23 -14
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +81 -4
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +22 -5
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +5 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
- package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +52 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -6
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +2 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +331 -81
- package/dist/esm/utils/schemaRefSlug.js +19 -3
- package/dist/esm/utils/schemaRefSlug.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +6933 -5958
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +331 -81
- package/l10n/en.json +2 -0
- package/l10n/nl.json +2 -0
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +297 -11
- package/src/components/CnAppRoot/CnAppRoot.md +4 -0
- package/src/components/CnAppRoot/CnAppRoot.vue +94 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
- package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +43 -2
- package/src/components/CnDataTable/CnDataTable.vue +45 -1
- package/src/components/CnDetailPage/CnDetailPage.md +4 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +60 -1
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +116 -6
- package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +180 -2
- package/src/components/CnStagesWidget/stagesModel.js +5 -2
- package/src/components/CnStatWidget/CnStatWidget.vue +57 -3
- package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
- package/src/css/detail-page.css +10 -4
- package/src/css/kpi-card.css +24 -1
- package/src/css/table.css +18 -6
- package/src/schemas/app-manifest-v2.schema.json +113 -3
- package/src/utils/schemaRefSlug.js +19 -3
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -69,6 +69,17 @@
|
|
|
69
69
|
It used to gate both, so a caller who switched the menu off
|
|
70
70
|
also lost the Save button for an inline edit, silently. -->
|
|
71
71
|
<div v-if="actionsAreVisible()" class="cn-widget-wrapper__actions">
|
|
72
|
+
<!-- One text link in the header (`headerLink`): "All deadlines",
|
|
73
|
+
"To the board". A route is a router link, an href a plain
|
|
74
|
+
anchor. Sits before the slot and the overflow menu. -->
|
|
75
|
+
<component
|
|
76
|
+
:is="headerLinkTag"
|
|
77
|
+
v-if="headerLinkTag"
|
|
78
|
+
class="cn-widget-wrapper__header-link"
|
|
79
|
+
data-testid="cn-widget-wrapper-header-link"
|
|
80
|
+
v-bind="headerLinkAttrs">
|
|
81
|
+
{{ headerLinkLabel }}
|
|
82
|
+
</component>
|
|
72
83
|
<!-- @slot actions Custom action buttons rendered before the
|
|
73
84
|
built-in overflow menu. -->
|
|
74
85
|
<slot name="actions" />
|
|
@@ -351,6 +362,22 @@ export default {
|
|
|
351
362
|
default: () => [],
|
|
352
363
|
},
|
|
353
364
|
|
|
365
|
+
/**
|
|
366
|
+
* One text link in the header's actions group, before the overflow
|
|
367
|
+
* menu: `{ label, route?, params?, query?, href? }`. A `route` is a
|
|
368
|
+
* named router link (needs a router), an `href` a plain anchor. The
|
|
369
|
+
* label goes through the host translate function. Null (the
|
|
370
|
+
* default) draws nothing. Manifest: `headerLink` on the widget
|
|
371
|
+
* definition or its layout entry.
|
|
372
|
+
*
|
|
373
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
|
|
374
|
+
* @type {{label: string, route?: string, params?: object, query?: object, href?: string}|null}
|
|
375
|
+
*/
|
|
376
|
+
headerLink: {
|
|
377
|
+
type: Object,
|
|
378
|
+
default: null,
|
|
379
|
+
},
|
|
380
|
+
|
|
354
381
|
/**
|
|
355
382
|
* Whether the header's overflow action menu (Refresh / Documentation /
|
|
356
383
|
* Request-a-feature + any `#action-items`) renders. Shown by default;
|
|
@@ -634,6 +661,62 @@ export default {
|
|
|
634
661
|
return this.translate ?? this.cnTranslate
|
|
635
662
|
},
|
|
636
663
|
|
|
664
|
+
/**
|
|
665
|
+
* The header link's tag: `router-link` for a route (when a router is
|
|
666
|
+
* mounted), `a` for an href, '' when there is no usable link.
|
|
667
|
+
*
|
|
668
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
|
|
669
|
+
* @return {string}
|
|
670
|
+
*/
|
|
671
|
+
headerLinkTag() {
|
|
672
|
+
const link = this.headerLink
|
|
673
|
+
if (!link || typeof link.label !== 'string' || link.label === '') {
|
|
674
|
+
return ''
|
|
675
|
+
}
|
|
676
|
+
if (link.route && this.$router) {
|
|
677
|
+
return 'router-link'
|
|
678
|
+
}
|
|
679
|
+
if (typeof link.href === 'string' && link.href !== '') {
|
|
680
|
+
return 'a'
|
|
681
|
+
}
|
|
682
|
+
return ''
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* The header link's attributes for its tag.
|
|
687
|
+
*
|
|
688
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
|
|
689
|
+
* @return {object}
|
|
690
|
+
*/
|
|
691
|
+
headerLinkAttrs() {
|
|
692
|
+
const link = this.headerLink || {}
|
|
693
|
+
if (this.headerLinkTag === 'router-link') {
|
|
694
|
+
const to = { name: link.route }
|
|
695
|
+
if (link.params && typeof link.params === 'object') {
|
|
696
|
+
to.params = link.params
|
|
697
|
+
}
|
|
698
|
+
if (link.query && typeof link.query === 'object') {
|
|
699
|
+
to.query = link.query
|
|
700
|
+
}
|
|
701
|
+
return { to }
|
|
702
|
+
}
|
|
703
|
+
if (this.headerLinkTag === 'a') {
|
|
704
|
+
return { href: link.href }
|
|
705
|
+
}
|
|
706
|
+
return {}
|
|
707
|
+
},
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* The header link's text, through the host translate function.
|
|
711
|
+
*
|
|
712
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
|
|
713
|
+
* @return {string}
|
|
714
|
+
*/
|
|
715
|
+
headerLinkLabel() {
|
|
716
|
+
const label = this.headerLink && this.headerLink.label
|
|
717
|
+
return label ? this.effectiveTranslate(label) : ''
|
|
718
|
+
},
|
|
719
|
+
|
|
637
720
|
/**
|
|
638
721
|
* The RENDERED widget title — `displayTitle` run through the host
|
|
639
722
|
* translate function. Kept separate from `displayTitle` on purpose:
|
|
@@ -877,7 +960,7 @@ export default {
|
|
|
877
960
|
* @return {boolean} True when the group would hold a visible control.
|
|
878
961
|
*/
|
|
879
962
|
actionsAreVisible() {
|
|
880
|
-
return this.showActions || this.actionsSlotRenders()
|
|
963
|
+
return this.showActions || this.actionsSlotRenders() || Boolean(this.headerLinkTag)
|
|
881
964
|
},
|
|
882
965
|
|
|
883
966
|
/**
|
|
@@ -1127,6 +1210,29 @@ export default {
|
|
|
1127
1210
|
flex-shrink: 0;
|
|
1128
1211
|
}
|
|
1129
1212
|
|
|
1213
|
+
/* The header's text link (`headerLink`). Theme hooks: --cn-widget-header-link-size
|
|
1214
|
+
and --cn-widget-header-link-weight. */
|
|
1215
|
+
.cn-widget-wrapper__header-link {
|
|
1216
|
+
align-self: center;
|
|
1217
|
+
padding: 0 calc(1 * var(--default-grid-baseline));
|
|
1218
|
+
color: var(--color-primary-element);
|
|
1219
|
+
font-size: var(--cn-widget-header-link-size, 14px);
|
|
1220
|
+
font-weight: var(--cn-widget-header-link-weight, 600);
|
|
1221
|
+
text-decoration: none;
|
|
1222
|
+
white-space: nowrap;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.cn-widget-wrapper__header-link:hover,
|
|
1226
|
+
.cn-widget-wrapper__header-link:focus-visible {
|
|
1227
|
+
text-decoration: underline;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.cn-widget-wrapper__header-link:focus-visible {
|
|
1231
|
+
outline: 2px solid var(--color-primary-element);
|
|
1232
|
+
outline-offset: 2px;
|
|
1233
|
+
border-radius: var(--border-radius-small, 4px);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1130
1236
|
/* Every widget's header icon is coloured — `--cn-widget-icon-color` is set on
|
|
1131
1237
|
the header from titleIconStyle, and defaults to the theme colour if a
|
|
1132
1238
|
wrapper is ever rendered without it. Material-design-icon components paint
|
package/src/css/detail-page.css
CHANGED
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
position: relative;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/* The breadcrumb line above the header (`config.breadcrumb`). */
|
|
12
|
+
.cn-detail-page__breadcrumbs {
|
|
13
|
+
margin-bottom: calc(2 * var(--default-grid-baseline));
|
|
14
|
+
color: var(--color-text-maxcontrast);
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
/* Header */
|
|
12
18
|
.cn-detail-page__header {
|
|
13
19
|
display: flex;
|
|
@@ -175,7 +181,7 @@
|
|
|
175
181
|
|
|
176
182
|
.cn-detail-page__stats-table thead th {
|
|
177
183
|
padding: calc(1.5 * var(--default-grid-baseline)) calc(2 * var(--default-grid-baseline));
|
|
178
|
-
text-align:
|
|
184
|
+
text-align: start;
|
|
179
185
|
font-weight: 600;
|
|
180
186
|
font-size: 0.9em;
|
|
181
187
|
color: var(--color-text-maxcontrast);
|
|
@@ -200,7 +206,7 @@
|
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
.cn-detail-page__stats-cell--indented {
|
|
203
|
-
padding-
|
|
209
|
+
padding-inline-start: calc(5 * var(--default-grid-baseline)) !important;
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
.cn-detail-page__stats-cell--center {
|
|
@@ -208,7 +214,7 @@
|
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
.cn-detail-page__stats-cell--right {
|
|
211
|
-
text-align:
|
|
217
|
+
text-align: end;
|
|
212
218
|
}
|
|
213
219
|
|
|
214
220
|
/* Body & content */
|
|
@@ -342,7 +348,7 @@
|
|
|
342
348
|
|
|
343
349
|
.cn-detail-page__sidebar-toggle {
|
|
344
350
|
position: fixed;
|
|
345
|
-
|
|
351
|
+
inset-inline-end: calc(5 * var(--default-grid-baseline));
|
|
346
352
|
top: 80px;
|
|
347
353
|
z-index: 10;
|
|
348
354
|
}
|
package/src/css/kpi-card.css
CHANGED
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
padding: var(--cn-kpi-padding-flat, 8px);
|
|
134
134
|
box-sizing: border-box;
|
|
135
135
|
overflow: hidden;
|
|
136
|
-
text-align:
|
|
136
|
+
text-align: start;
|
|
137
137
|
text-decoration: none;
|
|
138
138
|
color: inherit;
|
|
139
139
|
background: transparent;
|
|
@@ -248,6 +248,29 @@
|
|
|
248
248
|
white-space: nowrap;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
/* A caption coloured by a rule (`captionVariant` / `overrides[].captionVariant`):
|
|
252
|
+
"1 due today" in the error colour. Foreground tokens, which stay readable in
|
|
253
|
+
dark mode. */
|
|
254
|
+
.cn-kpi-card__label--primary {
|
|
255
|
+
color: var(--color-primary-element);
|
|
256
|
+
font-weight: 600;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.cn-kpi-card__label--success {
|
|
260
|
+
color: var(--color-text-success, var(--color-success-text));
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.cn-kpi-card__label--warning {
|
|
265
|
+
color: var(--color-element-warning, var(--color-warning-text));
|
|
266
|
+
font-weight: 600;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.cn-kpi-card__label--error {
|
|
270
|
+
color: var(--color-text-error, var(--color-error-text));
|
|
271
|
+
font-weight: 600;
|
|
272
|
+
}
|
|
273
|
+
|
|
251
274
|
/* Semantic variants. Each re-points the ONE accent token, so the icon tint
|
|
252
275
|
and the number move together by construction — there is no second place to
|
|
253
276
|
forget. The inline KPI below shares the same modifiers for the same reason:
|
package/src/css/table.css
CHANGED
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
.cn-data-table th,
|
|
156
156
|
.cn-data-table td {
|
|
157
157
|
padding: calc(3 * var(--default-grid-baseline));
|
|
158
|
-
text-align:
|
|
158
|
+
text-align: start;
|
|
159
159
|
border-bottom: 1px solid var(--color-border);
|
|
160
160
|
vertical-align: middle;
|
|
161
161
|
max-width: var(--cn-table-cell-max-width, 22rem);
|
|
@@ -174,6 +174,18 @@
|
|
|
174
174
|
white-space: normal;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/* The secondary line of a cell (`columns[].secondary`): muted, smaller, on its
|
|
178
|
+
own line under the value. Theme hooks: --cn-table-secondary-size and
|
|
179
|
+
--cn-table-secondary-color. */
|
|
180
|
+
.cn-data-table .cn-table-cell__secondary {
|
|
181
|
+
display: block;
|
|
182
|
+
color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
|
|
183
|
+
font-size: var(--cn-table-secondary-size, 0.9em);
|
|
184
|
+
line-height: 1.35;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
text-overflow: ellipsis;
|
|
187
|
+
}
|
|
188
|
+
|
|
177
189
|
/* Back to wrapping, for a column holding prose rather than a label:
|
|
178
190
|
`columns: [{ key: 'description', cellClass: 'cn-cell--wrap' }]`. */
|
|
179
191
|
.cn-data-table th.cn-cell--wrap,
|
|
@@ -235,7 +247,7 @@
|
|
|
235
247
|
}
|
|
236
248
|
|
|
237
249
|
.cn-data-table td.cn-cell--end {
|
|
238
|
-
text-align:
|
|
250
|
+
text-align: end;
|
|
239
251
|
white-space: nowrap;
|
|
240
252
|
}
|
|
241
253
|
|
|
@@ -273,7 +285,7 @@
|
|
|
273
285
|
}
|
|
274
286
|
|
|
275
287
|
.cn-table-sort-indicator {
|
|
276
|
-
margin-
|
|
288
|
+
margin-inline-start: var(--default-grid-baseline);
|
|
277
289
|
opacity: 0.6;
|
|
278
290
|
}
|
|
279
291
|
|
|
@@ -383,7 +395,7 @@
|
|
|
383
395
|
justify-content: center;
|
|
384
396
|
min-width: 14px;
|
|
385
397
|
height: 14px;
|
|
386
|
-
margin-
|
|
398
|
+
margin-inline-start: 2px;
|
|
387
399
|
padding: 0 3px;
|
|
388
400
|
border-radius: 7px;
|
|
389
401
|
background-color: var(--color-primary-element);
|
|
@@ -448,7 +460,7 @@
|
|
|
448
460
|
|
|
449
461
|
.cn-table-col--icon {
|
|
450
462
|
width: 40px;
|
|
451
|
-
padding-
|
|
463
|
+
padding-inline-end: 0;
|
|
452
464
|
text-align: center;
|
|
453
465
|
color: var(--color-text-maxcontrast);
|
|
454
466
|
}
|
|
@@ -511,7 +523,7 @@
|
|
|
511
523
|
|
|
512
524
|
.viewTable { width: 100%; border-collapse: collapse; background-color: var(--color-main-background); }
|
|
513
525
|
|
|
514
|
-
.viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align:
|
|
526
|
+
.viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: start; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
|
|
515
527
|
|
|
516
528
|
.viewTable th { background: var(--color-background-hover); font-weight: 500; color: var(--color-text-maxcontrast); background-color: var(--color-background-dark); }
|
|
517
529
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
|
|
4
4
|
"title": "Conduction App Manifest v2",
|
|
5
5
|
"description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.46.0",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": ["$schema", "version"],
|
|
9
9
|
"allOf": [
|
|
@@ -238,6 +238,40 @@
|
|
|
238
238
|
"type": "string",
|
|
239
239
|
"description": "Override label for the settings foldout's gear button. Defaults to 'Settings'."
|
|
240
240
|
},
|
|
241
|
+
"card": {
|
|
242
|
+
"type": "object",
|
|
243
|
+
"additionalProperties": false,
|
|
244
|
+
"required": ["title"],
|
|
245
|
+
"description": "A card above the footer entries, rendered by CnAppNav (zuiddrecht-pixel-gaps): a title, a line of text and one link. Title, text and link label are i18n keys. Omitted, nothing renders there.",
|
|
246
|
+
"properties": {
|
|
247
|
+
"title": { "type": "string", "minLength": 1 },
|
|
248
|
+
"text": { "type": "string" },
|
|
249
|
+
"link": {
|
|
250
|
+
"type": "object",
|
|
251
|
+
"additionalProperties": false,
|
|
252
|
+
"required": ["label"],
|
|
253
|
+
"description": "The card's link: a `route` (named page, optional `params`) is a router link, an `href` a plain anchor, an `action` id a button that emits `card-action`.",
|
|
254
|
+
"properties": {
|
|
255
|
+
"label": { "type": "string", "minLength": 1 },
|
|
256
|
+
"route": { "type": "string" },
|
|
257
|
+
"params": { "type": "object", "additionalProperties": true },
|
|
258
|
+
"href": { "type": "string" },
|
|
259
|
+
"action": { "type": "string" }
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"help": {
|
|
265
|
+
"type": "object",
|
|
266
|
+
"additionalProperties": false,
|
|
267
|
+
"required": ["label"],
|
|
268
|
+
"description": "A help entry with a help icon in the navigation footer, above the settings foldout (zuiddrecht-pixel-gaps): `route` (named page) or `href` (opens in a new tab).",
|
|
269
|
+
"properties": {
|
|
270
|
+
"label": { "type": "string", "minLength": 1 },
|
|
271
|
+
"route": { "type": "string" },
|
|
272
|
+
"href": { "type": "string" }
|
|
273
|
+
}
|
|
274
|
+
},
|
|
241
275
|
"primaryAction": {
|
|
242
276
|
"$ref": "#/$defs/primaryAction",
|
|
243
277
|
"description": "App-wide default primary action rendered as an NcAppNavigationNew button above the main menu list. A page-scoped pages[].primaryAction for the current route wins over this default."
|
|
@@ -251,6 +285,10 @@
|
|
|
251
285
|
"type": "string",
|
|
252
286
|
"description": "URL of the logo image. Decorative when `name` is set."
|
|
253
287
|
},
|
|
288
|
+
"emblem": {
|
|
289
|
+
"type": ["string", "boolean"],
|
|
290
|
+
"description": "An emblem drawn in place of the logo (zuiddrecht-pixel-gaps): the municipality's mark beside the app name, distinct from the wordmark in the top bar. A URL, or `true` to draw the theme's emblem from the `--nldesign-emblem-url` custom property. Decorative when `name` is set."
|
|
291
|
+
},
|
|
254
292
|
"name": {
|
|
255
293
|
"type": "string",
|
|
256
294
|
"description": "i18n key / text for the app or organisation name."
|
|
@@ -1158,6 +1196,23 @@
|
|
|
1158
1196
|
},
|
|
1159
1197
|
"payload": {
|
|
1160
1198
|
"description": "Free-form payload echoed back to the host inside the @primary-action-click event."
|
|
1199
|
+
},
|
|
1200
|
+
"action": {
|
|
1201
|
+
"$ref": "#/$defs/action",
|
|
1202
|
+
"description": "A page action to run on click (zuiddrecht-pixel-gaps): CnAppNav then renders the button through CnActionButtons, so `type: \"open-form\"` (with `register` + `schema`) opens the create dialog without a create page, `navigate` pushes a route, `api-call` calls an endpoint. Drawn as one solid full-width primary button. `route` / `href` on the primary action itself are ignored while `action` is set."
|
|
1203
|
+
},
|
|
1204
|
+
"solid": {
|
|
1205
|
+
"type": "boolean",
|
|
1206
|
+
"default": false,
|
|
1207
|
+
"description": "Draw the primary action as a solid, full-width primary button whatever its form (zuiddrecht-pixel-gaps). Default: a link action is already a primary button; a plain one is NcAppNavigationNew."
|
|
1208
|
+
},
|
|
1209
|
+
"permission": {
|
|
1210
|
+
"type": "string",
|
|
1211
|
+
"description": "Permission the reader must hold for the action to render, checked like `menuItem.permission` (zuiddrecht-pixel-gaps)."
|
|
1212
|
+
},
|
|
1213
|
+
"visibleIf": {
|
|
1214
|
+
"$ref": "#/$defs/visibleIfCondition",
|
|
1215
|
+
"description": "Display condition evaluated at render time, like `menuItem.visibleIf` (zuiddrecht-pixel-gaps). A gated-out page-scoped action falls back to `nav.primaryAction`."
|
|
1161
1216
|
}
|
|
1162
1217
|
}
|
|
1163
1218
|
},
|
|
@@ -1221,9 +1276,20 @@
|
|
|
1221
1276
|
"count": {
|
|
1222
1277
|
"oneOf": [
|
|
1223
1278
|
{ "type": "integer", "minimum": 0 },
|
|
1224
|
-
{ "type": "string", "enum": ["auto"] }
|
|
1279
|
+
{ "type": "string", "enum": ["auto"] },
|
|
1280
|
+
{
|
|
1281
|
+
"type": "object",
|
|
1282
|
+
"additionalProperties": false,
|
|
1283
|
+
"required": ["register", "schema"],
|
|
1284
|
+
"description": "A FILTERED count (zuiddrecht-pixel-gaps): the total of this register and schema with `filter` applied (filter-value tokens such as `@me` and `@today` resolve at fetch time), fetched by CnAppRoot under the entry's own key so an index page's whole-schema total is untouched. Renders \"My work 6\" beside \"All cases 48\".",
|
|
1285
|
+
"properties": {
|
|
1286
|
+
"register": { "type": "string", "minLength": 1 },
|
|
1287
|
+
"schema": { "type": "string", "minLength": 1 },
|
|
1288
|
+
"filter": { "type": "object", "additionalProperties": true }
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1225
1291
|
],
|
|
1226
|
-
"description": "Counter badge in the entry's #counter slot. Positive integer renders as-is; 'auto' resolves from cnMenuCounts (populated by CnAppRoot from useObjectStore totals) for the entry's resolved index-type page (register + schema)."
|
|
1292
|
+
"description": "Counter badge in the entry's #counter slot. Positive integer renders as-is; 'auto' resolves from cnMenuCounts (populated by CnAppRoot from useObjectStore totals) for the entry's resolved index-type page (register + schema); an object `{ register, schema, filter? }` is the total of that filtered list."
|
|
1227
1293
|
},
|
|
1228
1294
|
"pinned": {
|
|
1229
1295
|
"type": "boolean",
|
|
@@ -1485,6 +1551,19 @@
|
|
|
1485
1551
|
"minimum": 1,
|
|
1486
1552
|
"description": "Row span (>= 1)."
|
|
1487
1553
|
},
|
|
1554
|
+
"headerLink": {
|
|
1555
|
+
"type": "object",
|
|
1556
|
+
"additionalProperties": false,
|
|
1557
|
+
"required": ["label"],
|
|
1558
|
+
"description": "One text link in the widget header's actions group, before the overflow menu (zuiddrecht-pixel-gaps): \"All deadlines\", \"To the board\". A `route` (named page, optional `params` / `query`) is a router link, an `href` a plain anchor. The label is an i18n key. Rendered by CnWidgetWrapper; CnDashboardPage reads it off the layout entry or the widget definition.",
|
|
1559
|
+
"properties": {
|
|
1560
|
+
"label": { "type": "string", "minLength": 1 },
|
|
1561
|
+
"route": { "type": "string" },
|
|
1562
|
+
"params": { "type": "object", "additionalProperties": true },
|
|
1563
|
+
"query": { "type": "object", "additionalProperties": true },
|
|
1564
|
+
"href": { "type": "string" }
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1488
1567
|
"sizeToContent": {
|
|
1489
1568
|
"type": ["boolean", "integer"],
|
|
1490
1569
|
"minimum": 1,
|
|
@@ -3519,6 +3598,37 @@
|
|
|
3519
3598
|
"type": "string",
|
|
3520
3599
|
"description": "type='index': accessible name and tooltip for the split pane's close button. Defaults to \"Close\". Maps to CnIndexPage `splitCloseLabel`."
|
|
3521
3600
|
},
|
|
3601
|
+
"showHeader": {
|
|
3602
|
+
"type": "boolean",
|
|
3603
|
+
"default": true,
|
|
3604
|
+
"description": "type='dashboard': `false` drops the header row (title, description, header actions, edit toggle) for a page that opens with its own heading, such as a greeting widget; the title stays as a visually hidden heading (zuiddrecht-pixel-gaps). Maps to CnDashboardPage `showHeader`."
|
|
3605
|
+
},
|
|
3606
|
+
"showTitle": {
|
|
3607
|
+
"type": "boolean",
|
|
3608
|
+
"default": false,
|
|
3609
|
+
"description": "type='index': show the page header (icon, title, description) inline. Default false: the title renders visually hidden and the sidebar names the page. Maps to CnIndexPage `showTitle`."
|
|
3610
|
+
},
|
|
3611
|
+
"countSubtitle": {
|
|
3612
|
+
"type": "string",
|
|
3613
|
+
"description": "type='index': an i18n key for the description line with `{total}` replaced by the collection's total, e.g. \"{total} open cases\" (zuiddrecht-pixel-gaps). Shown in place of `description` once a total is known. Maps to CnIndexPage `countSubtitle`."
|
|
3614
|
+
},
|
|
3615
|
+
"showTypeEyebrow": {
|
|
3616
|
+
"type": "boolean",
|
|
3617
|
+
"default": true,
|
|
3618
|
+
"description": "type='detail': `false` drops the type eyebrow (the type label above the record name) once the record resolves, for a header that says the type in a pill instead (zuiddrecht-pixel-gaps). Maps to CnDetailPage `showTypeEyebrow`."
|
|
3619
|
+
},
|
|
3620
|
+
"breadcrumb": {
|
|
3621
|
+
"type": "object",
|
|
3622
|
+
"additionalProperties": false,
|
|
3623
|
+
"required": ["label"],
|
|
3624
|
+
"description": "type='detail': a breadcrumb line above the header (zuiddrecht-pixel-gaps): this crumb names the list the record belongs to (`route` + optional `params`, or `href`), the record's display name follows as the current crumb. Maps to CnDetailPage `breadcrumb`.",
|
|
3625
|
+
"properties": {
|
|
3626
|
+
"label": { "type": "string", "minLength": 1 },
|
|
3627
|
+
"route": { "type": "string" },
|
|
3628
|
+
"params": { "type": "object", "additionalProperties": true },
|
|
3629
|
+
"href": { "type": "string" }
|
|
3630
|
+
}
|
|
3631
|
+
},
|
|
3522
3632
|
"mapConfig": {
|
|
3523
3633
|
"type": "object",
|
|
3524
3634
|
"additionalProperties": true,
|
|
@@ -35,9 +35,14 @@
|
|
|
35
35
|
* registers author the slug by hand for multi-word titles) folds to one
|
|
36
36
|
* `-`, leading/trailing dashes trimmed.
|
|
37
37
|
*
|
|
38
|
-
* Idempotent: a value that is already a slug (`report-period`, `cohort
|
|
39
|
-
* passes through unchanged, so it is always safe to route an
|
|
40
|
-
* value through this function defensively.
|
|
38
|
+
* Idempotent: a value that is already a slug (`report-period`, `cohort`,
|
|
39
|
+
* `statusType`) passes through unchanged, so it is always safe to route an
|
|
40
|
+
* already-correct value through this function defensively. A slug is any
|
|
41
|
+
* value that starts with a lowercase letter or digit and holds only
|
|
42
|
+
* letters, digits and dashes; only a title (capital initial, or spaces and
|
|
43
|
+
* punctuation) is kebab-cased.
|
|
44
|
+
*
|
|
45
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-plain-schema-slug-is-left-as-written
|
|
41
46
|
*
|
|
42
47
|
* A numeric schema id (OpenRegister accepts either the slug or the numeric
|
|
43
48
|
* id in the objects-API path) is returned unchanged — slugifying a number
|
|
@@ -63,6 +68,17 @@ export function schemaRefSlug(ref) {
|
|
|
63
68
|
if (tail === '') {
|
|
64
69
|
return ''
|
|
65
70
|
}
|
|
71
|
+
// A plain slug is left as written. OpenRegister matches a slug
|
|
72
|
+
// case-insensitively (`statusType`, `statustype` and `StatusType` all
|
|
73
|
+
// answer 200) but `status-type` is another slug and 404s, so a
|
|
74
|
+
// camelCase slug authored as a slug must not be kebab-cased. Only a
|
|
75
|
+
// `$ref` TITLE is: it starts with a capital (`ReportPeriod`) or carries
|
|
76
|
+
// spaces or punctuation (`Praktijkovereenkomst (POK)`). 2.62.0 kebab-cased
|
|
77
|
+
// everything and broke every camelCase slug (dossiq: statusType, caseType,
|
|
78
|
+
// caseObject, bezwaarDecision, bacAdviceRequest, wmsLayer, ...).
|
|
79
|
+
if (/^[a-z0-9][A-Za-z0-9-]*$/.test(tail)) {
|
|
80
|
+
return tail
|
|
81
|
+
}
|
|
66
82
|
const kebab = tail
|
|
67
83
|
// PascalCase / camelCase word boundaries: `ReportPeriod` -> `Report-Period`,
|
|
68
84
|
// an acronym run followed by a new capitalised word: `HTTPServer` -> `HTTP-Server`.
|