@7365admin1/layer-common 4.2.10 → 4.2.11
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/CHANGELOG.md +24 -4
- package/components/DashboardMain.vue +56 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @iservice365/layer-common
|
|
2
2
|
|
|
3
|
+
## 4.2.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6b6e083: Say why the dashboard is empty instead of drawing nothing.
|
|
8
|
+
|
|
9
|
+
Every widget on `DashboardMain` is permission-gated and the gate fails closed,
|
|
10
|
+
so a role holding none of the widget permissions renders the header, the site
|
|
11
|
+
name and the Customize / Export / range controls — and then nothing at all. On
|
|
12
|
+
2026-09-04 a security-agency member whose role carried only Vehicle Mgmt and
|
|
13
|
+
Daily Occurrence Books reported that as a broken page; the gating was correct
|
|
14
|
+
and the blankness was the whole defect.
|
|
15
|
+
|
|
16
|
+
The dashboard now says which of the two reasons it is empty for, because they
|
|
17
|
+
need different people to act: the role grants no widget (an administrator has
|
|
18
|
+
to add the permission) or every widget was hidden in Customize (the reader can
|
|
19
|
+
put them back). Nothing is granted and no gate is loosened. The message is
|
|
20
|
+
suppressed while the role is still resolving and when the role fetch failed, so
|
|
21
|
+
it never flashes on load and never blames a role for a failed request.
|
|
22
|
+
|
|
3
23
|
## 4.2.10
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
|
@@ -554,11 +574,11 @@
|
|
|
554
574
|
`utils/console-tier.ts` + `composables/useConsoleTier.ts` mirror the server's
|
|
555
575
|
own rule from two endpoints the console already calls, unprojected:
|
|
556
576
|
|
|
557
|
-
|
|
558
|
-
|
|
577
|
+
GET /api/members/user/:user/app/admin the Seven365 staff membership
|
|
578
|
+
GET /api/roles/id/:role that membership's role document
|
|
559
579
|
|
|
560
|
-
|
|
561
|
-
|
|
580
|
+
owner = member.type === "admin" && role.type === "admin" && role.default === true
|
|
581
|
+
staff = member.type === "admin" && role.type === "admin"
|
|
562
582
|
|
|
563
583
|
`role.default` is the marker because it is the only property of a platform
|
|
564
584
|
staff role no API caller can set - `role.controller.ts` validates create and
|
|
@@ -276,6 +276,39 @@
|
|
|
276
276
|
}}). The figures for it are missing, not zero — refresh to try again.
|
|
277
277
|
</v-alert>
|
|
278
278
|
|
|
279
|
+
<!--
|
|
280
|
+
A BLANK DASHBOARD MUST SAY WHY IT IS BLANK.
|
|
281
|
+
|
|
282
|
+
Every widget on this page is permission-gated (`canViewWidget`), and the
|
|
283
|
+
gate fails closed. A role holding none of the widget permissions therefore
|
|
284
|
+
renders the header, the range control and the Customize button — and then
|
|
285
|
+
nothing at all, with no way for the reader to tell an empty role from a
|
|
286
|
+
broken page. That cost a production escalation on 2026-09-04: a security
|
|
287
|
+
member whose role carried only Vehicle Mgmt and Daily Occurrence Books saw
|
|
288
|
+
an empty dashboard and reported it as a fault.
|
|
289
|
+
|
|
290
|
+
Two different sentences, because they need two different actions: the role
|
|
291
|
+
grants no widget (an administrator has to grant one), or the reader hid
|
|
292
|
+
them all in Customize (they can put them back themselves).
|
|
293
|
+
-->
|
|
294
|
+
<v-alert
|
|
295
|
+
v-if="noWidgetsGranted || noWidgetsShown"
|
|
296
|
+
type="info"
|
|
297
|
+
variant="tonal"
|
|
298
|
+
density="compact"
|
|
299
|
+
icon="mdi-view-dashboard-outline"
|
|
300
|
+
class="mb-4"
|
|
301
|
+
>
|
|
302
|
+
<template v-if="noWidgetsGranted">
|
|
303
|
+
Your role doesn't include any of the dashboard widgets, so there is
|
|
304
|
+
nothing to show here. Ask an administrator to add the permissions for
|
|
305
|
+
the areas you work in.
|
|
306
|
+
</template>
|
|
307
|
+
<template v-else>
|
|
308
|
+
Every widget is hidden. Use Customize to choose which ones to show.
|
|
309
|
+
</template>
|
|
310
|
+
</v-alert>
|
|
311
|
+
|
|
279
312
|
<!-- ── KPI Cards ───────────────────────────────────────────────────────── -->
|
|
280
313
|
<v-row dense class="mb-1 align-stretch">
|
|
281
314
|
<v-col
|
|
@@ -2485,6 +2518,29 @@ const visibleKpiCards = computed(() =>
|
|
|
2485
2518
|
kpiCards.value.filter((card) => isWidgetVisible(card.key))
|
|
2486
2519
|
);
|
|
2487
2520
|
|
|
2521
|
+
/**
|
|
2522
|
+
* Nothing to draw, and which of the two reasons it is.
|
|
2523
|
+
*
|
|
2524
|
+
* `noWidgetsGranted` asks the permission gate alone, over this mode's whole
|
|
2525
|
+
* widget set — not over the reader's Customize choice — so hiding every widget
|
|
2526
|
+
* by hand is never reported as a missing permission.
|
|
2527
|
+
*/
|
|
2528
|
+
const noWidgetsGranted = computed(
|
|
2529
|
+
() =>
|
|
2530
|
+
// Only once a role is actually loaded. `canViewWidget` fails closed while
|
|
2531
|
+
// it is still resolving and if the fetch fails outright, and "your role
|
|
2532
|
+
// grants nothing" is the wrong sentence for both of those — it would flash
|
|
2533
|
+
// on every load and would lie about a failed request.
|
|
2534
|
+
Boolean(userAppRole.value) &&
|
|
2535
|
+
!defaultVisibleWidgetKeys.value.some((key) => canViewWidget(key))
|
|
2536
|
+
);
|
|
2537
|
+
|
|
2538
|
+
const noWidgetsShown = computed(
|
|
2539
|
+
() =>
|
|
2540
|
+
Boolean(userAppRole.value) &&
|
|
2541
|
+
!visibleWidgetKeys.value.some((key) => isWidgetVisible(key))
|
|
2542
|
+
);
|
|
2543
|
+
|
|
2488
2544
|
/**
|
|
2489
2545
|
* The percentage pill's label. Same number the chip has always shown, written
|
|
2490
2546
|
* the way the handoff prints it - `+0%` / `-6.4%`, the sign carrying what the
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "4.2.
|
|
5
|
+
"version": "4.2.11",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|