@7365admin1/layer-common 4.59.2 → 4.60.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/CHANGELOG.md +17 -4
- package/components/DashboardMain.vue +47 -0
- package/package.json +1 -1
- package/utils/robot-control.ts +22 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @iservice365/layer-common
|
|
2
2
|
|
|
3
|
+
## 4.60.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b43f89e: Dashboard: the Property Management and Security dashboards show a **Low Stock** tile (inventory items at or below their alert level) wherever their own inventory store serves the property; it can be hidden in Customize. Sites without a store are unchanged. Five tiles share one row.
|
|
8
|
+
|
|
9
|
+
## 4.59.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- cae7fd1: Robot live view: turn on hls.js low-latency mode so the 1.2x catch-up actually runs after a hiccup (without it hls.js never changes the playback rate).
|
|
14
|
+
- 40b1293: Robot live view: sit 6 s behind the newest picture instead of hls.js's default 12 s, catch up at up to 1.2x after a hiccup, jump forward past 14 s.
|
|
15
|
+
|
|
3
16
|
## 4.59.2
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1648,11 +1661,11 @@
|
|
|
1648
1661
|
`utils/console-tier.ts` + `composables/useConsoleTier.ts` mirror the server's
|
|
1649
1662
|
own rule from two endpoints the console already calls, unprojected:
|
|
1650
1663
|
|
|
1651
|
-
|
|
1652
|
-
|
|
1664
|
+
GET /api/members/user/:user/app/admin the Seven365 staff membership
|
|
1665
|
+
GET /api/roles/id/:role that membership's role document
|
|
1653
1666
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1667
|
+
owner = member.type === "admin" && role.type === "admin" && role.default === true
|
|
1668
|
+
staff = member.type === "admin" && role.type === "admin"
|
|
1656
1669
|
|
|
1657
1670
|
`role.default` is the marker because it is the only property of a platform
|
|
1658
1671
|
staff role no API caller can set - `role.controller.ts` validates create and
|
|
@@ -1417,6 +1417,13 @@ const propertyWidgetPermissions: Record<string, string[]> = {
|
|
|
1417
1417
|
workOrderStatus: WORK_ORDER_SEE_ALL,
|
|
1418
1418
|
feedbacks: ["feedbacks:see-all-feedback"],
|
|
1419
1419
|
activePatrol: ["virtual-patrol:see-all-virtual-patrol-logs"],
|
|
1420
|
+
// Low Stock: shown only where the property's own inventory store serves the site.
|
|
1421
|
+
supplyAlert: [
|
|
1422
|
+
"inventory:view-inventory",
|
|
1423
|
+
"inventory:request-stock",
|
|
1424
|
+
"inventory:approve-requests",
|
|
1425
|
+
"inventory:manage-inventory",
|
|
1426
|
+
],
|
|
1420
1427
|
};
|
|
1421
1428
|
|
|
1422
1429
|
const moduleWidgetPermissions: Record<string, string[]> = {
|
|
@@ -2039,6 +2046,7 @@ const propertyDefaultWidgetKeys = [
|
|
|
2039
2046
|
"incidents",
|
|
2040
2047
|
"visitors",
|
|
2041
2048
|
"facilityBookings",
|
|
2049
|
+
"supplyAlert",
|
|
2042
2050
|
"activity",
|
|
2043
2051
|
"upcomingEvents",
|
|
2044
2052
|
"todayReminders",
|
|
@@ -2052,6 +2060,7 @@ const securityDefaultWidgetKeys = [
|
|
|
2052
2060
|
"incidents",
|
|
2053
2061
|
"visitors",
|
|
2054
2062
|
"patrolCompliance",
|
|
2063
|
+
"supplyAlert",
|
|
2055
2064
|
"activity",
|
|
2056
2065
|
"activePatrol",
|
|
2057
2066
|
"staffStatus",
|
|
@@ -2136,6 +2145,11 @@ const customizeWidgets = computed(() => {
|
|
|
2136
2145
|
title: "Facility Bookings",
|
|
2137
2146
|
description: "View booking volume and approvals waiting for action.",
|
|
2138
2147
|
},
|
|
2148
|
+
{
|
|
2149
|
+
key: "supplyAlert",
|
|
2150
|
+
title: "Low Stock",
|
|
2151
|
+
description: "Inventory items at or below their alert level (where your store serves this property).",
|
|
2152
|
+
},
|
|
2139
2153
|
{
|
|
2140
2154
|
key: "activity",
|
|
2141
2155
|
title: "This Week Activity (Line Chart)",
|
|
@@ -2193,6 +2207,11 @@ const customizeWidgets = computed(() => {
|
|
|
2193
2207
|
title: "Patrol Compliance",
|
|
2194
2208
|
description: "View missed checkpoints and ongoing patrols.",
|
|
2195
2209
|
},
|
|
2210
|
+
{
|
|
2211
|
+
key: "supplyAlert",
|
|
2212
|
+
title: "Low Stock",
|
|
2213
|
+
description: "Inventory items at or below their alert level (where your store serves this property).",
|
|
2214
|
+
},
|
|
2196
2215
|
{
|
|
2197
2216
|
key: "activity",
|
|
2198
2217
|
title: "This Week Activity (Line Chart)",
|
|
@@ -2405,6 +2424,31 @@ function getPropertyKpiCards() {
|
|
|
2405
2424
|
raw: facilityMetric,
|
|
2406
2425
|
filter: undefined,
|
|
2407
2426
|
},
|
|
2427
|
+
...inventoryLowStockCards(),
|
|
2428
|
+
];
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2431
|
+
/**
|
|
2432
|
+
* The Low Stock tile on the Property and Security dashboards. The server sends
|
|
2433
|
+
* `supplyAlert` (basis `below-alert-level`) only where this organisation's own
|
|
2434
|
+
* inventory store serves the site, so a site without a store shows no tile.
|
|
2435
|
+
*/
|
|
2436
|
+
function inventoryLowStockCards() {
|
|
2437
|
+
const metric = getMetric(["supplyAlert"]);
|
|
2438
|
+
if ((metric as { basis?: string })?.basis !== "below-alert-level") return [];
|
|
2439
|
+
return [
|
|
2440
|
+
{
|
|
2441
|
+
key: "supplyAlert",
|
|
2442
|
+
title: "Low Stock",
|
|
2443
|
+
icon: "mdi-package-variant",
|
|
2444
|
+
color: KPI_TONES.info.color,
|
|
2445
|
+
tint: KPI_TONES.info.tint,
|
|
2446
|
+
value: "",
|
|
2447
|
+
percentage: NaN,
|
|
2448
|
+
meta: "",
|
|
2449
|
+
raw: metric,
|
|
2450
|
+
filter: undefined,
|
|
2451
|
+
},
|
|
2408
2452
|
];
|
|
2409
2453
|
}
|
|
2410
2454
|
|
|
@@ -2485,6 +2529,7 @@ function getSecurityKpiCards() {
|
|
|
2485
2529
|
raw: patrolMetric,
|
|
2486
2530
|
filter: undefined,
|
|
2487
2531
|
},
|
|
2532
|
+
...inventoryLowStockCards(),
|
|
2488
2533
|
];
|
|
2489
2534
|
}
|
|
2490
2535
|
|
|
@@ -2539,6 +2584,8 @@ const visibleKpiCards = computed(() =>
|
|
|
2539
2584
|
// had been. Fewer tiles share the row instead.
|
|
2540
2585
|
const kpiColLg = computed(() => {
|
|
2541
2586
|
const shown = visibleKpiCards.value.length;
|
|
2587
|
+
// Five tiles (Property / Security with Low Stock): equal widths on one row.
|
|
2588
|
+
if (shown === 5) return true;
|
|
2542
2589
|
return shown >= 4 || shown === 0 ? 3 : 12 / shown;
|
|
2543
2590
|
});
|
|
2544
2591
|
|
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.
|
|
5
|
+
"version": "4.60.0",
|
|
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.",
|
package/utils/robot-control.ts
CHANGED
|
@@ -180,6 +180,27 @@ export function writeLivePref(storage: Pick<Storage, "setItem"> | undefined, on:
|
|
|
180
180
|
/** hls.js errors that mean "this browser cannot decode the codec", not "the camera is down". */
|
|
181
181
|
const CODEC_ERRORS = new Set(["manifestIncompatibleCodecsError", "bufferAddCodecError", "bufferIncompatibleCodecsError"]);
|
|
182
182
|
|
|
183
|
+
/**
|
|
184
|
+
* hls.js live settings. The robot camera (EZVIZ via PadBot) serves plain HLS
|
|
185
|
+
* v3: 4 s segments, a 3-segment window, no LL-HLS parts. hls.js's default
|
|
186
|
+
* sits 3 segments (12 s) behind the newest picture and never catches up after
|
|
187
|
+
* a hiccup - the owner's "10-15 s delay". Now: 6 s behind (1.5 segments, so
|
|
188
|
+
* one late segment does not stall), play up to 1.2x to win back time lost to
|
|
189
|
+
* a hiccup, and jump forward if it ever falls 14 s behind.
|
|
190
|
+
* `lowLatencyMode` must be on for the catch-up: hls.js only adjusts the
|
|
191
|
+
* playback rate in low-latency mode (it is harmless on a plain playlist - no
|
|
192
|
+
* parts, nothing else changes).
|
|
193
|
+
* ponytail: a lower-latency protocol (FLV / WebRTC) is not offered by PadBot's
|
|
194
|
+
* §6.5 video API; ask PadBot if 6 s is still too slow.
|
|
195
|
+
*/
|
|
196
|
+
export const LIVE_HLS_CONFIG = {
|
|
197
|
+
enableWorker: true,
|
|
198
|
+
lowLatencyMode: true,
|
|
199
|
+
liveSyncDuration: 6,
|
|
200
|
+
liveMaxLatencyDuration: 14,
|
|
201
|
+
maxLiveSyncPlaybackRate: 1.2,
|
|
202
|
+
} as const;
|
|
203
|
+
|
|
183
204
|
/**
|
|
184
205
|
* Plays one live-view URL into `video`. Returns a stop function that frees the
|
|
185
206
|
* player and the connection.
|
|
@@ -286,7 +307,7 @@ export function startLivePlayer(
|
|
|
286
307
|
video.addEventListener("error", noteDecode);
|
|
287
308
|
let recoveries = 0;
|
|
288
309
|
const Base = Hls.DefaultConfig?.loader;
|
|
289
|
-
const h = (hls = new Hls({
|
|
310
|
+
const h = (hls = new Hls({ ...LIVE_HLS_CONFIG, ...(Base ? { fLoader: strayAudLoader(Base) } : {}) }));
|
|
290
311
|
h.on("hlsError", (_e, data) => {
|
|
291
312
|
noteDecode();
|
|
292
313
|
if (!data.fatal) return;
|