@conduction/nextcloud-vue 2.63.0 → 2.65.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 +253 -10
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +139 -46
- 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/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.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 +55 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +153 -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 +125 -14
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +87 -40
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +101 -7
- 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 +74 -5
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +15 -8
- 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 +495 -81
- package/dist/esm/store/useObjectStore.js +118 -33
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +14 -0
- package/dist/esm/utils/actionsDispatcher.js.map +1 -1
- 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 +7388 -6021
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +495 -81
- package/l10n/en.json +2 -0
- package/l10n/nl.json +2 -0
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +441 -14
- 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/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +72 -4
- package/src/components/CnDataTable/CnDataTable.vue +45 -1
- package/src/components/CnDetailPage/CnDetailPage.md +8 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +169 -2
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +147 -9
- package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
- package/src/components/CnStagesWidget/CnStagesWidget.vue +189 -2
- package/src/components/CnStagesWidget/stagesModel.js +5 -2
- package/src/components/CnStatWidget/CnStatWidget.vue +89 -7
- 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 +32 -4
- package/src/css/kpi-card.css +71 -1
- package/src/css/table.css +18 -6
- package/src/schemas/app-manifest-v2.schema.json +134 -3
- package/src/store/useObjectStore.js +118 -33
- package/src/utils/actionsDispatcher.js +14 -0
- package/src/utils/schemaRefSlug.js +19 -3
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -10,10 +10,11 @@ import OpenInNew from 'vue-material-design-icons/OpenInNew.vue';
|
|
|
10
10
|
import Plus from 'vue-material-design-icons/Plus.vue';
|
|
11
11
|
import ShieldAccountOutline from 'vue-material-design-icons/ShieldAccountOutline.vue';
|
|
12
12
|
import '../CnIcon/CnIcon.vue.js';
|
|
13
|
-
import __sfc_main from '../CnMenuWidget/CnMenuItemIcon.vue.js';
|
|
13
|
+
import __sfc_main$1 from '../CnMenuWidget/CnMenuItemIcon.vue.js';
|
|
14
14
|
import { isAppInstalled } from '../../utils/appInstalled.js';
|
|
15
15
|
import { isSvgPath } from '../../utils/iconUtils.js';
|
|
16
16
|
import { passesContextPredicates } from '../../utils/visibleIfContext.js';
|
|
17
|
+
import __sfc_main from '../CnActionButtons/CnActionButtons.vue.js';
|
|
17
18
|
import { bridgedMdiForCssIcon } from '../CnIcon/cssIconBridge.js';
|
|
18
19
|
import { getSemanticIconComponent } from '../CnIcon/semanticIcons.js';
|
|
19
20
|
import { isCustomIconUrl, hasRegistryIcon } from '../CnWidgetGrid/widgetIcons.js';
|
|
@@ -95,7 +96,8 @@ var script = {
|
|
|
95
96
|
NcAppNavigationSettings,
|
|
96
97
|
NcButton,
|
|
97
98
|
NcCounterBubble,
|
|
98
|
-
|
|
99
|
+
CnActionButtons: __sfc_main,
|
|
100
|
+
CnMenuItemIcon: __sfc_main$1,
|
|
99
101
|
Cog,
|
|
100
102
|
HelpCircleOutline,
|
|
101
103
|
ShieldAccountOutline,
|
|
@@ -141,6 +143,16 @@ var script = {
|
|
|
141
143
|
* @type {{ [register: string]: { [schema: string]: number } }}
|
|
142
144
|
*/
|
|
143
145
|
cnMenuCounts: { default: () => ({}) },
|
|
146
|
+
/**
|
|
147
|
+
* Provided by CnAppRoot — reactive `{ [menuItemId]: number }` totals
|
|
148
|
+
* for every menu entry whose `count` is an object
|
|
149
|
+
* (`{ register, schema, filter? }`): the total of that filtered
|
|
150
|
+
* list, fetched under the entry's own key so an index page's
|
|
151
|
+
* whole-schema total is left alone. Empty outside a CnAppRoot.
|
|
152
|
+
*
|
|
153
|
+
* @type {{ [itemId: string]: number }}
|
|
154
|
+
*/
|
|
155
|
+
cnMenuItemCounts: { default: () => ({}) },
|
|
144
156
|
},
|
|
145
157
|
|
|
146
158
|
props: {
|
|
@@ -264,7 +276,7 @@ var script = {
|
|
|
264
276
|
},
|
|
265
277
|
},
|
|
266
278
|
|
|
267
|
-
emits: ['primary-action', 'primary-action-click'],
|
|
279
|
+
emits: ['primary-action', 'primary-action-click', 'primary-action-created', 'card-action'],
|
|
268
280
|
|
|
269
281
|
/**
|
|
270
282
|
* The navigation's own state: which groups are open, and which entry
|
|
@@ -325,11 +337,70 @@ var script = {
|
|
|
325
337
|
const text = (value) => (typeof value === 'string' && value !== '' ? this.effectiveTranslate(value) : '');
|
|
326
338
|
const brand = {
|
|
327
339
|
logo: typeof declared.logo === 'string' ? declared.logo : '',
|
|
340
|
+
// A URL, or `true` for the theme's emblem (--nldesign-emblem-url).
|
|
341
|
+
emblem: declared.emblem === true ? true : (typeof declared.emblem === 'string' ? declared.emblem : ''),
|
|
328
342
|
name: text(declared.name),
|
|
329
343
|
caption: text(declared.caption),
|
|
330
344
|
alt: text(declared.alt),
|
|
331
345
|
};
|
|
332
|
-
return (brand.logo || brand.name || brand.caption) ? brand : null
|
|
346
|
+
return (brand.logo || brand.emblem || brand.name || brand.caption) ? brand : null
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* The card above the footer entries (`nav.card`): `{ title, text?,
|
|
351
|
+
* link?: { label, route?, params?, href?, action? } }`. Title, text
|
|
352
|
+
* and link label go through the translate function. The link is a
|
|
353
|
+
* router link for a `route` (with a router), an anchor for an
|
|
354
|
+
* `href`, and a button emitting `card-action` with the `action` id
|
|
355
|
+
* otherwise. Null without a title.
|
|
356
|
+
*
|
|
357
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-navigation-carries-a-card-and-a-help-entry
|
|
358
|
+
* @return {object|null}
|
|
359
|
+
*/
|
|
360
|
+
resolvedCard() {
|
|
361
|
+
const declared = this.effectiveManifest?.nav?.card;
|
|
362
|
+
if (!declared || typeof declared !== 'object' || typeof declared.title !== 'string' || declared.title === '') {
|
|
363
|
+
return null
|
|
364
|
+
}
|
|
365
|
+
const text = (value) => (typeof value === 'string' && value !== '' ? this.effectiveTranslate(value) : '');
|
|
366
|
+
const card = { title: text(declared.title), text: text(declared.text), linkTag: '', linkAttrs: {}, linkLabel: '', action: '' };
|
|
367
|
+
const link = declared.link;
|
|
368
|
+
if (link && typeof link === 'object' && typeof link.label === 'string' && link.label !== '') {
|
|
369
|
+
card.linkLabel = text(link.label);
|
|
370
|
+
if (link.route && this.$router) {
|
|
371
|
+
card.linkTag = 'router-link';
|
|
372
|
+
card.linkAttrs = { to: { name: link.route, ...(link.params && typeof link.params === 'object' ? { params: link.params } : {}) } };
|
|
373
|
+
} else if (typeof link.href === 'string' && link.href !== '') {
|
|
374
|
+
card.linkTag = 'a';
|
|
375
|
+
card.linkAttrs = { href: link.href };
|
|
376
|
+
} else if (typeof link.action === 'string' && link.action !== '') {
|
|
377
|
+
card.linkTag = 'button';
|
|
378
|
+
card.linkAttrs = { type: 'button' };
|
|
379
|
+
card.action = link.action;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return card
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* The help entry (`nav.help`): `{ label, route?, href? }` rendered as
|
|
387
|
+
* a footer entry with a help icon. Null without a label or a target.
|
|
388
|
+
*
|
|
389
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-navigation-carries-a-card-and-a-help-entry
|
|
390
|
+
* @return {{label: string, to?: object, href?: string}|null}
|
|
391
|
+
*/
|
|
392
|
+
resolvedHelp() {
|
|
393
|
+
const declared = this.effectiveManifest?.nav?.help;
|
|
394
|
+
if (!declared || typeof declared !== 'object' || typeof declared.label !== 'string' || declared.label === '') {
|
|
395
|
+
return null
|
|
396
|
+
}
|
|
397
|
+
if (declared.route && this.$router) {
|
|
398
|
+
return { label: this.effectiveTranslate(declared.label), to: { name: declared.route }, href: undefined }
|
|
399
|
+
}
|
|
400
|
+
if (typeof declared.href === 'string' && declared.href !== '') {
|
|
401
|
+
return { label: this.effectiveTranslate(declared.label), to: undefined, href: declared.href }
|
|
402
|
+
}
|
|
403
|
+
return null
|
|
333
404
|
},
|
|
334
405
|
|
|
335
406
|
/**
|
|
@@ -350,20 +421,30 @@ var script = {
|
|
|
350
421
|
* 2. `manifest.nav.primaryAction` as app-wide default
|
|
351
422
|
* 3. `null` — no primary-action button renders
|
|
352
423
|
*
|
|
353
|
-
* Page-scoped declarations always win over the nav-root default.
|
|
424
|
+
* Page-scoped declarations always win over the nav-root default. An
|
|
425
|
+
* action declaring `permission` or `visibleIf` is gated like a menu
|
|
426
|
+
* entry.
|
|
354
427
|
*
|
|
428
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-navigation-primary-action-runs-a-page-action
|
|
355
429
|
* @return {object|null}
|
|
356
430
|
*/
|
|
357
431
|
activePrimaryAction() {
|
|
358
432
|
const pages = this.effectiveManifest?.pages ?? [];
|
|
359
433
|
const routeName = this.$route?.name;
|
|
434
|
+
// The same `permission` / `visibleIf` gate a menu entry has: an
|
|
435
|
+
// action the reader may not take, or that a condition hides, is
|
|
436
|
+
// not drawn. A gated-out page action falls back to the nav one.
|
|
437
|
+
const gated = (action) => (action && this.passesPermission(action) && this.passesVisibleIf(action) ? action : null);
|
|
360
438
|
if (routeName) {
|
|
361
439
|
const page = pages.find((p) => p.id === routeName);
|
|
362
440
|
if (page && page.primaryAction) {
|
|
363
|
-
|
|
441
|
+
const pageAction = gated(page.primaryAction);
|
|
442
|
+
if (pageAction) {
|
|
443
|
+
return pageAction
|
|
444
|
+
}
|
|
364
445
|
}
|
|
365
446
|
}
|
|
366
|
-
return this.effectiveManifest?.nav?.primaryAction ?? null
|
|
447
|
+
return gated(this.effectiveManifest?.nav?.primaryAction ?? null)
|
|
367
448
|
},
|
|
368
449
|
|
|
369
450
|
/**
|
|
@@ -377,6 +458,31 @@ var script = {
|
|
|
377
458
|
return this.mdiIconComponent(this.activePrimaryAction) ?? Plus
|
|
378
459
|
},
|
|
379
460
|
|
|
461
|
+
/**
|
|
462
|
+
* The CnActionButtons entry for a primary action that carries an
|
|
463
|
+
* `action` (`$defs/action`: open-form, navigate, api-call, ...):
|
|
464
|
+
* the action with the primary action's `id`, `label` and `icon`
|
|
465
|
+
* folded in and `variant: "primary"`. Null for a plain primary
|
|
466
|
+
* action, which keeps its link or button.
|
|
467
|
+
*
|
|
468
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-navigation-primary-action-runs-a-page-action
|
|
469
|
+
* @return {object|null}
|
|
470
|
+
*/
|
|
471
|
+
primaryDispatchEntry() {
|
|
472
|
+
const action = this.activePrimaryAction;
|
|
473
|
+
const inner = action && action.action;
|
|
474
|
+
if (!inner || typeof inner !== 'object' || typeof inner.type !== 'string') {
|
|
475
|
+
return null
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
icon: action.icon || 'Plus',
|
|
479
|
+
...inner,
|
|
480
|
+
id: inner.id || action.id || 'primary-action',
|
|
481
|
+
label: action.label,
|
|
482
|
+
variant: 'primary',
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
|
|
380
486
|
/**
|
|
381
487
|
* Link props for the primary action's button: an `href` opens in a
|
|
382
488
|
* new tab, a `route` is a router link. Null when the action is
|
|
@@ -434,17 +540,113 @@ var script = {
|
|
|
434
540
|
* Documentation, Features & Roadmap, About.
|
|
435
541
|
*/
|
|
436
542
|
footerItems() {
|
|
437
|
-
|
|
543
|
+
const footer = this.visibleItems.filter((item) => item.section === 'footer');
|
|
544
|
+
const declared = this.declaredFooter;
|
|
545
|
+
if (declared === null) {
|
|
546
|
+
return footer
|
|
547
|
+
}
|
|
548
|
+
// A declared footer (`nav.footer`) keeps only the entries it names,
|
|
549
|
+
// in the order it names them.
|
|
550
|
+
return declared
|
|
551
|
+
.map((id) => footer.find((item) => item.id === id))
|
|
552
|
+
.filter(Boolean)
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* The footer the manifest declares (`nav.footer`): an ordered list of
|
|
557
|
+
* menu entry ids plus the reserved ids `help` (the `nav.help` entry)
|
|
558
|
+
* and `settings` (the settings foldout). Null when the manifest
|
|
559
|
+
* declares none, which keeps today's footer: the help entry, then
|
|
560
|
+
* every `section: "footer"` entry, then the foldout.
|
|
561
|
+
*
|
|
562
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
563
|
+
* @return {Array<string>|null}
|
|
564
|
+
*/
|
|
565
|
+
declaredFooter() {
|
|
566
|
+
const declared = this.effectiveManifest?.nav?.footer;
|
|
567
|
+
if (!Array.isArray(declared)) {
|
|
568
|
+
return null
|
|
569
|
+
}
|
|
570
|
+
return declared.filter((id) => typeof id === 'string' && id !== '')
|
|
571
|
+
},
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Footer-section entries a declared footer leaves out. They move into
|
|
575
|
+
* the settings foldout rather than disappearing, so a page such as
|
|
576
|
+
* Store or Reports stays reachable. Empty without `nav.footer`.
|
|
577
|
+
*
|
|
578
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
579
|
+
* @return {Array<object>}
|
|
580
|
+
*/
|
|
581
|
+
undeclaredFooterItems() {
|
|
582
|
+
const declared = this.declaredFooter;
|
|
583
|
+
if (declared === null) {
|
|
584
|
+
return []
|
|
585
|
+
}
|
|
586
|
+
return this.visibleItems.filter((item) => item.section === 'footer' && !declared.includes(item.id))
|
|
587
|
+
},
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Whether the help entry renders: whenever it resolves, unless a
|
|
591
|
+
* declared footer leaves `help` out.
|
|
592
|
+
*
|
|
593
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
594
|
+
* @return {boolean}
|
|
595
|
+
*/
|
|
596
|
+
showsHelp() {
|
|
597
|
+
if (!this.resolvedHelp) {
|
|
598
|
+
return false
|
|
599
|
+
}
|
|
600
|
+
return this.declaredFooter === null || this.declaredFooter.includes('help')
|
|
601
|
+
},
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Whether the help entry goes AFTER the footer entries. Only a declared
|
|
605
|
+
* footer that names an entry before `help` puts it there; by default
|
|
606
|
+
* it leads the list.
|
|
607
|
+
*
|
|
608
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
609
|
+
* @return {boolean}
|
|
610
|
+
*/
|
|
611
|
+
helpAfterItems() {
|
|
612
|
+
const declared = this.declaredFooter;
|
|
613
|
+
if (declared === null) {
|
|
614
|
+
return false
|
|
615
|
+
}
|
|
616
|
+
const help = declared.indexOf('help');
|
|
617
|
+
return this.footerItems.some((item) => declared.indexOf(item.id) < help)
|
|
618
|
+
},
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Whether the settings foldout goes ABOVE the footer list: only when a
|
|
622
|
+
* declared footer names `settings` before every other entry
|
|
623
|
+
* (`["settings", "help"]`, the board's "Instellingen" then "Hulp en
|
|
624
|
+
* uitleg"). Done with CSS `order` on the two siblings, so the markup
|
|
625
|
+
* of both stays as it is.
|
|
626
|
+
*
|
|
627
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
628
|
+
* @return {boolean}
|
|
629
|
+
*/
|
|
630
|
+
settingsFirst() {
|
|
631
|
+
const declared = this.declaredFooter;
|
|
632
|
+
return declared !== null && declared.indexOf('settings') === 0
|
|
438
633
|
},
|
|
439
634
|
|
|
440
635
|
/**
|
|
441
636
|
* Items that render INSIDE the NcAppNavigationSettings foldout
|
|
442
637
|
* (section: "settings"). The foldout is the NC-native gear-icon
|
|
443
638
|
* button that slides a panel open; these entries are app-level
|
|
444
|
-
* configuration pages (Forms, Pipelines, Automations, …).
|
|
639
|
+
* configuration pages (Forms, Pipelines, Automations, …). A declared
|
|
640
|
+
* footer (`nav.footer`) adds the footer entries it leaves out.
|
|
641
|
+
*
|
|
642
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-the-navigation-footer-can-be-declared
|
|
643
|
+
* @return {Array<object>}
|
|
445
644
|
*/
|
|
446
645
|
settingsItems() {
|
|
447
|
-
return
|
|
646
|
+
return [
|
|
647
|
+
...this.visibleItems.filter((item) => item.section === 'settings'),
|
|
648
|
+
...this.undeclaredFooterItems,
|
|
649
|
+
]
|
|
448
650
|
},
|
|
449
651
|
|
|
450
652
|
/**
|
|
@@ -1241,6 +1443,9 @@ var script = {
|
|
|
1241
1443
|
* `NcAppNavigationItem`).
|
|
1242
1444
|
*
|
|
1243
1445
|
* - Literal positive integer in `item.count` → return as-is.
|
|
1446
|
+
* - `item.count` is an object (`{ register, schema, filter? }`) →
|
|
1447
|
+
* `cnMenuItemCounts[item.id] ?? null`, the filtered total CnAppRoot
|
|
1448
|
+
* fetched for this entry.
|
|
1244
1449
|
* - `item.count === "auto"` → look up the entry's resolved page;
|
|
1245
1450
|
* when that page is `type: "index"` with a `register`/`schema`
|
|
1246
1451
|
* in its `config`, return
|
|
@@ -1264,6 +1469,11 @@ var script = {
|
|
|
1264
1469
|
if (typeof raw === 'number') {
|
|
1265
1470
|
return raw > 0 ? raw : null
|
|
1266
1471
|
}
|
|
1472
|
+
if (raw && typeof raw === 'object') {
|
|
1473
|
+
// A filtered count: CnAppRoot fetched it per entry id.
|
|
1474
|
+
const value = this.cnMenuItemCounts?.[item.id];
|
|
1475
|
+
return (typeof value === 'number' && value > 0) ? value : null
|
|
1476
|
+
}
|
|
1267
1477
|
if (raw !== 'auto') {
|
|
1268
1478
|
return null
|
|
1269
1479
|
}
|
|
@@ -1574,6 +1784,39 @@ var script = {
|
|
|
1574
1784
|
*
|
|
1575
1785
|
* @return {void}
|
|
1576
1786
|
*/
|
|
1787
|
+
/**
|
|
1788
|
+
* Re-emit the object an `open-form` primary action created, so the
|
|
1789
|
+
* host can refresh a list or open the record.
|
|
1790
|
+
*
|
|
1791
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-navigation-primary-action-runs-a-page-action
|
|
1792
|
+
* @param {object} created The created object.
|
|
1793
|
+
* @return {void}
|
|
1794
|
+
*/
|
|
1795
|
+
onPrimaryActionCreated(created) {
|
|
1796
|
+
/**
|
|
1797
|
+
* @event primary-action-created Emitted after an `open-form` primary action saves. Payload: the created object.
|
|
1798
|
+
*/
|
|
1799
|
+
this.$emit('primary-action-created', created);
|
|
1800
|
+
},
|
|
1801
|
+
|
|
1802
|
+
/**
|
|
1803
|
+
* A card link that is a button (an `action` id) emits `card-action`
|
|
1804
|
+
* with that id for the host to run; links and anchors navigate on
|
|
1805
|
+
* their own.
|
|
1806
|
+
*
|
|
1807
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-the-navigation-carries-a-card-and-a-help-entry
|
|
1808
|
+
* @return {void}
|
|
1809
|
+
*/
|
|
1810
|
+
onCardLinkClick() {
|
|
1811
|
+
const card = this.resolvedCard;
|
|
1812
|
+
if (card && card.action) {
|
|
1813
|
+
/**
|
|
1814
|
+
* @event card-action Emitted when the nav card's link is an action button. Payload: the action id.
|
|
1815
|
+
*/
|
|
1816
|
+
this.$emit('card-action', card.action);
|
|
1817
|
+
}
|
|
1818
|
+
},
|
|
1819
|
+
|
|
1577
1820
|
onPrimaryActionClick() {
|
|
1578
1821
|
const action = this.activePrimaryAction;
|
|
1579
1822
|
if (!action) {
|