@7365admin1/layer-common 3.2.2-staging.121 → 3.2.2-staging.123

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.
Files changed (34) hide show
  1. package/assets/css/primitives.css +92 -0
  2. package/assets/css/tokens.css +16 -0
  3. package/components/AppButton.vue +10 -1
  4. package/components/StatusChip.vue +63 -0
  5. package/components/VisitorManagement.vue +20 -13
  6. package/nuxt.config.ts +6 -1
  7. package/package.json +22 -1
  8. package/plugins/vuetify.ts +37 -1
  9. package/utils/materialSymbols.ts +363 -0
  10. package/.changeset/README.md +0 -8
  11. package/.changeset/camera-wall-gated-endpoint.md +0 -47
  12. package/.changeset/camera-wall-plain-english.md +0 -60
  13. package/.changeset/camera-wall-selection-and-guidance.md +0 -65
  14. package/.changeset/config.json +0 -11
  15. package/.changeset/dark-primary-contrast.md +0 -39
  16. package/.changeset/dashboard-dark-theme-contrast.md +0 -15
  17. package/.changeset/notification-preferences.md +0 -17
  18. package/.changeset/pm-sidebar-grouping-and-list-scaffold.md +0 -27
  19. package/.changeset/service-provider-invitation-actions.md +0 -28
  20. package/.editorconfig +0 -12
  21. package/.github/workflows/main.yml +0 -17
  22. package/.github/workflows/publish-staging.yml +0 -47
  23. package/.github/workflows/publish.yml +0 -39
  24. package/PUBLISHING.md +0 -269
  25. package/components/ScheduleTaskAreaFormDialog.vue +0 -141
  26. package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -104
  27. package/components/TableWithButton.vue +0 -94
  28. package/test/visitor-socket.test.mjs +0 -36
  29. package/tools/render-harness/README.md +0 -87
  30. package/tools/render-harness/baselines.json +0 -117
  31. package/tools/render-harness/harness-init.ps1 +0 -127
  32. package/tools/render-harness/probe.mjs +0 -229
  33. package/tools/render-harness/render-check.mjs +0 -306
  34. package/tools/render-harness/render-check.selftest.mjs +0 -129
@@ -0,0 +1,363 @@
1
+ /**
2
+ * mdi -> Material Symbols Outlined.
3
+ *
4
+ * The design handoff draws every icon with Google's variable
5
+ * `Material Symbols Outlined` font (`opsz,wght,FILL,GRAD@20..48,300..700,0..1,0`),
6
+ * using the icon's name as the element's text and letting the font's ligature
7
+ * table turn it into a glyph. The product ships Material Design Icons (`mdi`)
8
+ * instead - a different, heavier family - so every screen mixes two icon
9
+ * languages.
10
+ *
11
+ * Rather than rewrite ~680 call sites across this package (and again in eleven
12
+ * applications), the Vuetify icon set in `plugins/vuetify.ts` translates on the
13
+ * way out: a component still asks for `mdi-close`, this table answers `close`,
14
+ * and the span renders the Material Symbols glyph. Vuetify's own internal
15
+ * aliases (`$dropdown`, `$checkboxOn`, `$next`, ...) resolve to `mdi-*` strings
16
+ * too, so they are listed here as well and convert with everything else.
17
+ *
18
+ * Anything NOT in this table falls back to the previous Iconify rendering, so
19
+ * an unmapped name draws its old icon rather than a blank box.
20
+ *
21
+ * Every value below was checked against Google's published codepoint list for
22
+ * the variable font, so no entry is a name that does not exist.
23
+ *
24
+ * Where mdi draws something Material Symbols has no equivalent for, the entry
25
+ * is marked NEAREST with what was lost. Those are deliberate, not oversights.
26
+ */
27
+ export const MDI_TO_SYMBOL: Record<string, string> = {
28
+ // --- navigation & chevrons ---
29
+ "mdi-chevron-left": "chevron_left",
30
+ "mdi-chevron-right": "chevron_right",
31
+ "mdi-chevron-up": "expand_less",
32
+ "mdi-chevron-down": "expand_more",
33
+ "mdi-chevron-down-box-outline": "expand_more", // NEAREST: no boxed chevron
34
+ "mdi-menu": "menu",
35
+ "mdi-menu-down": "arrow_drop_down",
36
+ "mdi-menu-right": "arrow_right",
37
+ "mdi-unfold-more-horizontal": "unfold_more",
38
+ "mdi-arrow-left": "arrow_back",
39
+ "mdi-arrow-right": "arrow_forward",
40
+ "mdi-arrow-up": "arrow_upward",
41
+ "mdi-arrow-down": "arrow_downward",
42
+ "mdi-arrow-u-left-top": "undo",
43
+ "mdi-page-first": "first_page",
44
+ "mdi-page-last": "last_page",
45
+ "mdi-open-in-new": "open_in_new",
46
+ "mdi-swap-horizontal": "swap_horiz",
47
+ "mdi-drag": "drag_indicator",
48
+ "mdi-dots-vertical": "more_vert",
49
+ "mdi-dots-horizontal": "more_horiz",
50
+
51
+ // --- actions ---
52
+ "mdi-close": "close",
53
+ "mdi-close-circle": "cancel",
54
+ "mdi-close-circle-outline": "cancel",
55
+ "mdi-check": "check",
56
+ "mdi-check-circle": "check_circle",
57
+ "mdi-check-circle-outline": "check_circle",
58
+ "mdi-plus": "add",
59
+ "mdi-minus": "remove",
60
+ "mdi-minus-box": "indeterminate_check_box",
61
+ "mdi-refresh": "refresh",
62
+ "mdi-cached": "cached",
63
+ "mdi-restore": "restore",
64
+ "mdi-magnify": "search",
65
+ "mdi-magnify-close": "search_off",
66
+ "mdi-pencil": "edit",
67
+ "mdi-pencil-outline": "edit",
68
+ "mdi-square-edit-outline": "edit_square",
69
+ "mdi-delete": "delete",
70
+ "mdi-delete-outline": "delete",
71
+ "mdi-trash-outline": "delete",
72
+ "mdi-trash-can-outline": "delete",
73
+ "mdi-content-save": "save",
74
+ "mdi-content-copy": "content_copy",
75
+ "mdi-download": "download",
76
+ "mdi-download-outline": "download",
77
+ "mdi-upload": "upload",
78
+ "mdi-tray-arrow-up": "file_upload",
79
+ "mdi-export": "output",
80
+ "mdi-printer": "print",
81
+ "mdi-printer-alert": "print_error",
82
+ "mdi-printer-check": "print", // NEAREST: no printer-with-tick
83
+ "mdi-draw": "draw",
84
+ "mdi-tune-variant": "tune",
85
+ "mdi-cog": "settings",
86
+ "mdi-cog-outline": "settings",
87
+ "mdi-backspace": "backspace",
88
+ "mdi-eyedropper": "colorize",
89
+ "mdi-palette": "palette",
90
+ "mdi-sort-alphabetical-ascending": "sort_by_alpha",
91
+
92
+ // --- status & feedback ---
93
+ "mdi-alert": "warning",
94
+ "mdi-alert-outline": "warning",
95
+ "mdi-alert-circle": "error",
96
+ "mdi-alert-circle-outline": "error",
97
+ "mdi-information": "info",
98
+ "mdi-information-outline": "info",
99
+ "mdi-information-symbol": "info",
100
+ "mdi-help-circle": "help",
101
+ "mdi-loading": "progress_activity",
102
+ "mdi-progress-clock": "pending", // NEAREST: no clock-with-progress-arc
103
+ "mdi-history": "history",
104
+ "mdi-trending-up": "trending_up",
105
+ "mdi-flag": "flag",
106
+ "mdi-flash": "bolt",
107
+ "mdi-bug": "bug_report",
108
+ "mdi-bug-outline": "bug_report",
109
+ "mdi-radar": "radar",
110
+ "mdi-emoticon-happy-outline": "sentiment_satisfied",
111
+ "mdi-star": "star",
112
+ "mdi-star-outline": "star",
113
+ "mdi-star-half-full": "star_half",
114
+ "mdi-circle": "circle",
115
+ "mdi-circle-outline": "radio_button_unchecked",
116
+
117
+ // --- form controls (Vuetify's internal aliases live here) ---
118
+ "mdi-checkbox-marked": "check_box",
119
+ "mdi-checkbox-blank-outline": "check_box_outline_blank",
120
+ "mdi-checkbox-multiple-outline": "checklist", // NEAREST: no stacked checkboxes
121
+ "mdi-radiobox-marked": "radio_button_checked",
122
+ "mdi-radiobox-blank": "radio_button_unchecked",
123
+ "mdi-form-textbox": "text_fields",
124
+ "mdi-text": "subject",
125
+ "mdi-format-list-bulleted": "format_list_bulleted",
126
+ "mdi-format-list-numbered": "format_list_numbered",
127
+ "mdi-format-header-1": "format_h1",
128
+ "mdi-keyboard-return": "keyboard_return",
129
+ "mdi-keyboard-space": "space_bar",
130
+ "mdi-apple-keyboard-command": "keyboard_command_key",
131
+ "mdi-apple-keyboard-control": "keyboard_control_key",
132
+ "mdi-apple-keyboard-option": "keyboard_option_key",
133
+ "mdi-apple-keyboard-shift": "shift",
134
+
135
+ // --- time & calendar ---
136
+ "mdi-calendar": "calendar_month",
137
+ "mdi-calendar-month-outline": "calendar_month",
138
+ "mdi-calendar-range": "date_range",
139
+ "mdi-calendar-check": "event_available",
140
+ "mdi-calendar-remove": "event_busy",
141
+ "mdi-calendar-clock": "calendar_clock",
142
+ "mdi-calendar-start": "today", // NEAREST: no start/end calendar pair
143
+ "mdi-calendar-end": "event", // NEAREST: no start/end calendar pair
144
+ "mdi-clock-outline": "schedule",
145
+ "mdi-clock-check": "update",
146
+ "mdi-clock-check-outline": "update",
147
+ "mdi-clock-time-four-outline": "schedule", // NEAREST: no per-hour clock faces
148
+ "mdi-clock-time-eight-outline": "schedule", // NEAREST: no per-hour clock faces
149
+ "mdi-timer-outline": "timer",
150
+
151
+ // --- files & documents ---
152
+ "mdi-file": "draft",
153
+ "mdi-file-outline": "draft",
154
+ "mdi-file-document-outline": "description",
155
+ "mdi-file-document-remove-outline": "scan_delete",
156
+ "mdi-file-question-outline": "unknown_document",
157
+ "mdi-file-pdf": "picture_as_pdf",
158
+ "mdi-file-pdf-box": "picture_as_pdf",
159
+ "mdi-file-pdf-outline": "picture_as_pdf",
160
+ "mdi-file-word-box": "description", // NEAREST: no per-format document icons
161
+ "mdi-file-excel": "table_chart", // NEAREST: no per-format document icons
162
+ "mdi-file-excel-box": "table_chart", // NEAREST: no per-format document icons
163
+ "mdi-file-powerpoint-box": "slideshow", // NEAREST: no per-format document icons
164
+ "mdi-file-csv": "csv",
165
+ "mdi-file-delimited-outline": "csv",
166
+ "mdi-folder": "folder",
167
+ "mdi-folder-plus-outline": "create_new_folder",
168
+ "mdi-folder-zip-outline": "folder_zip",
169
+ "mdi-zip-box-outline": "folder_zip",
170
+ "mdi-paperclip": "attach_file",
171
+ "mdi-clipboard-list": "assignment",
172
+ "mdi-clipboard-text-outline": "assignment",
173
+ "mdi-clipboard-check-outline": "assignment_turned_in",
174
+ "mdi-cloud-upload": "cloud_upload",
175
+ "mdi-cloud-upload-outline": "cloud_upload",
176
+ "mdi-database-sync-outline": "sync", // NEAREST: no database-with-sync
177
+ "mdi-database-search-outline": "manage_search", // NEAREST: no database-with-search
178
+
179
+ // --- media & camera ---
180
+ "mdi-camera": "photo_camera",
181
+ "mdi-camera-outline": "photo_camera",
182
+ "mdi-camera-off": "no_photography",
183
+ "mdi-camera-off-outline": "no_photography",
184
+ "mdi-camera-plus-outline": "add_a_photo",
185
+ "mdi-camera-retake": "flip_camera_android", // NEAREST: retake reads as flip
186
+ "mdi-camera-switch": "cameraswitch",
187
+ "mdi-cctv": "videocam", // NEAREST: no dome/CCTV camera
188
+ "mdi-video": "videocam",
189
+ "mdi-image": "image",
190
+ "mdi-image-broken": "broken_image",
191
+ "mdi-play": "play_arrow",
192
+ "mdi-play-circle-outline": "play_circle",
193
+ "mdi-pause": "pause",
194
+ "mdi-fullscreen": "fullscreen",
195
+ "mdi-fullscreen-exit": "fullscreen_exit",
196
+ "mdi-microphone": "mic",
197
+ "mdi-microphone-off": "mic_off",
198
+ "mdi-volume-high": "volume_up",
199
+ "mdi-volume-medium": "volume_down",
200
+ "mdi-volume-low": "volume_mute",
201
+ "mdi-volume-variant-off": "volume_off",
202
+ "mdi-eye": "visibility",
203
+ "mdi-eye-outline": "visibility",
204
+ "mdi-eye-off": "visibility_off",
205
+ "mdi-eye-off-outline": "visibility_off",
206
+ "mdi-view-grid": "grid_view",
207
+
208
+ // --- people & accounts ---
209
+ "mdi-account": "person",
210
+ "mdi-user": "person",
211
+ "mdi-account-circle": "account_circle",
212
+ "mdi-account-plus": "person_add",
213
+ "mdi-account-off": "person_off",
214
+ "mdi-account-search-outline": "person_search",
215
+ "mdi-account-cog-outline": "manage_accounts",
216
+ "mdi-account-arrow-right": "how_to_reg", // NEAREST: person-with-arrow reads as check-in
217
+ "mdi-account-multiple": "group",
218
+ "mdi-account-group": "groups",
219
+ "mdi-account-badge": "badge",
220
+ "mdi-card-account-details": "badge",
221
+ "mdi-card-account-details-outline": "badge",
222
+ "mdi-card-account-details-star": "badge", // NEAREST: no starred ID card
223
+ "mdi-card-bulleted-outline": "badge", // NEAREST: access card reads as badge
224
+ "mdi-credit-card-outline": "credit_card",
225
+ "mdi-face-recognition": "face", // NEAREST: no face-recognition frame
226
+ "mdi-briefcase": "work",
227
+ "mdi-login": "login",
228
+ "mdi-logout": "logout",
229
+
230
+ // --- communication ---
231
+ "mdi-phone": "call",
232
+ "mdi-phone-outline": "call",
233
+ "mdi-phone-hangup": "call_end",
234
+ "mdi-phone-incoming": "call_received",
235
+ "mdi-phone-outgoing": "call_made",
236
+ "mdi-phone-in-talk": "phone_in_talk",
237
+ "mdi-phone-in-talk-outline": "phone_in_talk",
238
+ "mdi-email": "mail",
239
+ "mdi-message": "chat_bubble",
240
+ "mdi-message-outline": "chat_bubble",
241
+ "mdi-comment-multiple": "forum",
242
+ "mdi-link-variant": "link",
243
+ "mdi-lan-connect": "lan",
244
+ "mdi-lan-disconnect": "link_off", // NEAREST: no disconnected-LAN glyph
245
+ "mdi-bluetooth": "bluetooth",
246
+ "mdi-nfc": "nfc",
247
+
248
+ // --- places, security & operations ---
249
+ "mdi-office-building": "apartment",
250
+ "mdi-office-building-marker-outline": "location_city",
251
+ "mdi-building": "apartment",
252
+ "mdi-domain": "domain",
253
+ "mdi-home-city-outline": "home_work",
254
+ "mdi-warehouse": "warehouse",
255
+ "mdi-storefront-outline": "storefront",
256
+ "mdi-map-marker": "location_on",
257
+ "mdi-map-search": "travel_explore", // NEAREST: no map-with-magnifier
258
+ "mdi-door-open": "door_open",
259
+ "mdi-key": "key",
260
+ "mdi-lock": "lock",
261
+ "mdi-lock-outline": "lock",
262
+ "mdi-shield-outline": "shield",
263
+ "mdi-shield-check": "verified_user",
264
+ "mdi-shield-crown": "admin_panel_settings", // NEAREST: no crowned shield
265
+ "mdi-qrcode": "qr_code",
266
+ "mdi-qrcode-scan": "qr_code_scanner",
267
+ "mdi-barcode-scan": "barcode_scanner",
268
+ "mdi-car": "directions_car",
269
+ "mdi-car-back": "directions_car", // NEAREST: no rear-view car
270
+ "mdi-truck": "local_shipping",
271
+ "mdi-cart-plus": "add_shopping_cart",
272
+ "mdi-pool": "pool",
273
+ "mdi-broom": "cleaning_services",
274
+ "mdi-spray-bottle": "sanitizer",
275
+ "mdi-tools": "handyman",
276
+ "mdi-tree-outline": "park",
277
+ "mdi-flower": "local_florist",
278
+ "mdi-weather-sunny": "light_mode",
279
+ "mdi-weather-night": "dark_mode",
280
+
281
+ // mdi's deliberate spacer. No glyph, but `.v-icon` still holds the 1em box.
282
+ "mdi-blank": "",
283
+
284
+ // ------------------------------------------------------------------
285
+ // Names this package never uses, but the eleven applications do.
286
+ // ------------------------------------------------------------------
287
+ // The applications draw their icons through this same set, so a name
288
+ // missing here is an mdi glyph sitting next to a Material Symbols one on
289
+ // the same screen - the exact split the sweep exists to remove. Adding
290
+ // them here means no application repository needs a change of its own.
291
+ "mdi-view-dashboard": "dashboard",
292
+ "mdi-chart-bar": "bar_chart",
293
+ "mdi-update": "update",
294
+ "mdi-calendar-clock-outline": "calendar_clock",
295
+ "mdi-calendar-check-outline": "event_available",
296
+ "mdi-timer-check-outline": "timer", // NEAREST: no timer-with-tick
297
+ "mdi-timer-remove-outline": "timer_off",
298
+ "mdi-progress-check": "task_alt", // NEAREST: no progress-arc family
299
+ "mdi-progress-alert": "error", // NEAREST: no progress-arc family
300
+ "mdi-progress-question": "help", // NEAREST: no progress-arc family
301
+ "mdi-comment-outline": "chat_bubble",
302
+ "mdi-message-text": "chat",
303
+ "mdi-email-outline": "mail",
304
+ "mdi-email-fast-outline": "forward_to_inbox",
305
+ "mdi-bullhorn-outline": "campaign",
306
+ "mdi-web": "language",
307
+ "mdi-cellphone": "smartphone",
308
+ "mdi-cellphone-cog": "phonelink_setup",
309
+ "mdi-nfc-variant": "nfc",
310
+ "mdi-nfc-tap": "contactless",
311
+ "mdi-handshake": "handshake",
312
+ "mdi-hand-coin-outline": "payments", // NEAREST: no hand-holding-coin
313
+ "mdi-wallet-outline": "account_balance_wallet",
314
+ "mdi-credit-card": "credit_card",
315
+ "mdi-account-credit-card-outline": "credit_card", // NEAREST: no person-with-card
316
+ "mdi-sale-outline": "sell",
317
+ "mdi-rocket-launch": "rocket_launch",
318
+ "mdi-rocket-launch-outline": "rocket_launch",
319
+ "mdi-robot-happy-outline": "smart_toy",
320
+ "mdi-account-hard-hat": "engineering",
321
+ "mdi-account-wrench": "engineering", // NEAREST: no person-with-spanner
322
+ "mdi-wrench-clock": "build", // NEAREST: no spanner-with-clock
323
+ "mdi-account-clock": "pending_actions", // NEAREST: no person-with-clock
324
+ "mdi-account-clock-outline": "pending_actions", // NEAREST: no person-with-clock
325
+ "mdi-account-remove": "person_remove",
326
+ "mdi-account-cog": "manage_accounts",
327
+ "mdi-account-multiple-outline": "group",
328
+ "mdi-account-group-outline": "groups",
329
+ "mdi-account-multiple-check-outline": "how_to_reg", // NEAREST: no group-with-tick
330
+ "mdi-badge-account-outline": "badge",
331
+ "mdi-shield": "shield",
332
+ "mdi-shield-account": "admin_panel_settings",
333
+ "mdi-shield-account-outline": "admin_panel_settings",
334
+ "mdi-shield-search": "policy",
335
+ "mdi-office-building-outline": "apartment",
336
+ "mdi-office-building-marker": "location_city",
337
+ "mdi-office-building-cog-outline": "apartment", // NEAREST: no building-with-cog
338
+ "mdi-home-modern": "house",
339
+ "mdi-sign-text": "signpost",
340
+ "mdi-car-side": "directions_car", // NEAREST: one car glyph for all views
341
+ "mdi-car-clock": "directions_car", // NEAREST: no car-with-clock
342
+ "mdi-car-emergency": "emergency",
343
+ "mdi-key-variant": "key",
344
+ "mdi-pencil-box": "edit_square",
345
+ "mdi-trash": "delete",
346
+ "mdi-delete-forever-outline": "delete_forever",
347
+ "mdi-close-box": "disabled_by_default",
348
+ "mdi-circle-slice-8": "circle",
349
+ "mdi-help-circle-outline": "help",
350
+ "mdi-folder-alert": "folder", // NEAREST: no folder-with-alert
351
+ "mdi-note-text-outline": "description",
352
+ "mdi-card-text-outline": "article",
353
+ "mdi-list-box-outline": "list_alt",
354
+ "mdi-form-select": "dynamic_form", // NEAREST: no form-with-select
355
+ "mdi-microsoft-excel": "table_chart", // NEAREST: no per-format document icons
356
+ "mdi-tray-arrow-down": "file_download",
357
+ "mdi-image-off-outline": "hide_image",
358
+ "mdi-eye-arrow-right-outline": "visibility", // NEAREST: no eye-with-arrow
359
+
360
+ // Landed on staging while this branch was open (the HID screens).
361
+ "mdi-account-off-outline": "person_off",
362
+ "mdi-deskphone": "deskphone",
363
+ };
@@ -1,8 +0,0 @@
1
- # Changesets
2
-
3
- Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
4
- with multi-package repos, or single-package repos to help you version and publish your code. You can
5
- find the full documentation for it [in our repository](https://github.com/changesets/changesets)
6
-
7
- We have a quick list of common questions to get you started engaging with this project in
8
- [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
@@ -1,47 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Draw the camera wall from the gated wall endpoint, and show the server's own
6
- reason on a tile.
7
-
8
- `CameraWall` fetched its cameras from `GET /api/site-cameras` - the Settings
9
- panel's paginated CRUD list, which took its site from an optional query
10
- parameter and checked nothing about the caller. Any signed-in user from any
11
- organisation could read every camera in the estate through it, `host` and
12
- `username` included.
13
-
14
- It now calls `GET /api/site-cameras/site/:siteId/wall`, which already exists,
15
- which the React Native monitoring app was built against, and which is
16
- authorised server-side: the caller must be a member of the site, of its owning
17
- organisation, or work for an organisation actively engaged to serve it. That
18
- endpoint also returns `type: "ip"` cameras only and each camera's capability
19
- descriptor, so a wall cannot be handed an ANPR unit and a tile can explain
20
- itself.
21
-
22
- Two consequences worth stating:
23
-
24
- - **The pager is gone.** The wall endpoint returns the site's cameras in one
25
- answer. Paging a video wall was an artefact of borrowing the CRUD list.
26
- - **A tile now prefers the server's `unavailableReason`** over the reason it
27
- used to work out itself. The server knows things the browser cannot - chiefly
28
- "No recorder is configured for this camera's relay", which is the true answer
29
- for every camera in the estate until the API host is configured, and which the
30
- wall used to replace with its own guess. Offline still beats everything, since
31
- it explains every tile at once.
32
-
33
- No permission gate was invented here. Each application still gates its own menu
34
- entry; this component draws what it is given, and the server decides.
35
-
36
- Two smaller things in the same area:
37
-
38
- - **A refused wall now says so.** The catch-all message told every failure to
39
- "check your connection", which sends somebody who simply may not see that
40
- site off to debug their wifi. A 401/403/404 now reads "You do not have access
41
- to this site's cameras." The server answers "not yours" and "does not exist"
42
- identically, so this wording does not distinguish them either.
43
- - **`middleware/member.ts` is removed.** It read a cookie into an unused
44
- variable and did nothing else - a file named like a membership gate that was
45
- not one. No page in any of the eleven web apps referenced it. The real check
46
- is `plugins/secure-member.client.ts`, driven by `memberOnly` page meta, which
47
- is untouched.
@@ -1,60 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Rewrite the camera wall's detail panel for the people who read it, and stop
6
- repeating the same sentence four times.
7
-
8
- The panel under the tiles was written for a developer. On the live wall it
9
- read:
10
-
11
- > BBQ AREA
12
- > The video page loaded, but this browser cannot confirm a picture is arriving.
13
- > The player belongs to the video service and a browser cannot look inside it.
14
- > Judge the tile by what you can see, and report a blank or frozen picture.
15
- > ● Recorder responding Last picture this server received: none yet
16
- > Firmware and device clock are not available: this recorder is reachable over
17
- > video only.
18
-
19
- Every one of those statements is true, and the screen was still wrong: it
20
- explained cross-origin isolation to a guard, repeated the camera's name the
21
- tile already showed, put a green light beside the words "none yet", and printed
22
- the same reason on four capability cards in a row.
23
-
24
- Changes, all copy and layout — **no behaviour, no capability gating and no
25
- permission check is touched**:
26
-
27
- - **The badge reads "Not confirmed"**, not "Not verified". "Not verified"
28
- describes a check we failed to make; "Not confirmed" describes the picture,
29
- which is the thing the reader cares about. Same claim, and the wall still
30
- refuses to say "Live" until the video service reports a decoded frame.
31
- - **The sentence behind it is now an instruction**: "This page cannot confirm
32
- the picture is arriving, so check the tile yourself. If it is blank or frozen,
33
- report the camera." Why the software cannot confirm it is our problem, and it
34
- has been removed from the product.
35
- - **The camera's name is no longer a heading of its own.** It is the subject of
36
- the status line — "BBQ AREA · Recorder responding" — so a reader on a 3x3 wall
37
- still knows which tile the panel describes, without a second caption under the
38
- first one.
39
- - **"Last picture" is drawn only when there has been one.** A green "Recorder
40
- responding" beside "none yet" read as a contradiction. They were never in
41
- conflict, but a screen that has to be explained is wrong. The tile's own
42
- health line has always behaved this way; the panel now matches it.
43
- - **The firmware-and-device-clock sentence is gone**, from the panel and from
44
- the tile's tooltip. This screen never showed either value, so explaining their
45
- absence gave the reader nothing to do. The server still sends
46
- `detailUnavailableReason`; nothing draws it.
47
- - **One reason for the group instead of four copies.** When every switched-off
48
- control is off for the same reason, that reason and its next step are stated
49
- once above the row and each card keeps only its title and its state. When the
50
- reasons differ — "the recorder is unreachable" and "this camera cannot move"
51
- are two problems with two different people to ask — the group note is refused
52
- and each card carries its own again. New rule 7, in `camera-wall.ts`, with
53
- four tests.
54
- - Shorter next-step and no-signal wording, and a subject on the recorder's
55
- status labels ("Recorder not checked yet" rather than "Health not checked
56
- yet").
57
-
58
- Rules 3 and 6 are intact: the server's own sentence is still shown verbatim and
59
- never rewritten, and the recorder's state is still a separate fact from the
60
- tile's badge.
@@ -1,65 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Mark the selected camera on the wall, and stop telling the reader to raise a
6
- ticket without saying what for.
7
-
8
- Two things the owner found on the live wall after the last copy pass. Both are
9
- copy and presentation only — **no behaviour, no capability gating, no permission
10
- check and no request is changed.**
11
-
12
- **1. The camera's name was still printed twice.**
13
-
14
- The tile said `BBQ AREA` and the panel underneath said it again. The last pass
15
- merged the panel's heading into its status line, which changed the layout and
16
- left the repetition exactly where it was.
17
-
18
- The name was there to answer "which of these nine tiles is this panel about?".
19
- That is a real question and a name is the wrong answer to it — it makes the
20
- reader scan the wall for a matching caption. So:
21
-
22
- - **the selected tile is now visibly selected**: a 3 px accent ring with a scrim
23
- hairline inside it, so the ring holds against a bright picture as well as a
24
- dark one, plus the accent underline on the name chip that the toolbar already
25
- uses to mark a selected tool. Both read at 1x1, 2x2 and 3x3;
26
- - **the camera's name is removed from the panel entirely**. The panel opens on
27
- the recorder's state — "● Recorder responding";
28
- - `aria-current` marks the same tile for anyone not looking at the ring.
29
-
30
- The highlight had never worked in the most common case, which is why the name
31
- was load-bearing: it was bound to the raw clicked id, and before anyone clicks —
32
- or after paging — nothing on the wall was marked while the panel was already
33
- describing the first tile. It is now bound to the tile the panel actually
34
- resolves to, so the two can never disagree.
35
-
36
- **The panel can never be about a tile that is off screen**, so it never needs to
37
- name one: the focused camera is resolved out of the current PAGE, so paging away
38
- from a selection re-resolves to the first tile of the page in front of you and
39
- the ring follows. Paging back restores the original selection. Extracted as
40
- `focusedCamera()` in `camera-wall.ts` with four tests, including the 5-cameras
41
- -across-2-pages case.
42
-
43
- **2. "Ask your Seven365 administrator" was a dead end.**
44
-
45
- It was the whole of the advice under every switched-off control, and it tells
46
- the administrator nothing and a property manager only to go and wait. The screen
47
- never said what the request should ask for.
48
-
49
- The advice now names the two changes that are actually missing, because they are
50
- two different jobs for two different people: **the site's network has to let our
51
- server reach the camera recorder**, and **that recorder then has to be added to
52
- the server's configuration**. Both are stated in plain words, with who arranges
53
- them, and with the fact that neither is switchable from this page.
54
-
55
- No environment variable name appears in any of it — those belong in
56
- `iservice365-core/docs/camera-integration-config.md`, not on a property
57
- manager's screen — and there is a test that keeps it that way. The other reason
58
- codes (`device-http-disabled`, `device-http-unreachable`, `device-http-locked-out`,
59
- `control-not-enabled`, `no-recorder-configured`, and the unknown-code fallback)
60
- get the same treatment; the Site Settings ones already said what to do and are
61
- unchanged.
62
-
63
- The truthful-status rules are untouched: the wall still refuses to say "Live"
64
- until the video service reports a decoded frame, and the recorder's state is
65
- still a separate fact from the tile's badge.
@@ -1,11 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json",
3
- "changelog": "@changesets/cli/changelog",
4
- "commit": false,
5
- "fixed": [],
6
- "linked": [],
7
- "access": "public",
8
- "baseBranch": "main",
9
- "updateInternalDependencies": "patch",
10
- "ignore": []
11
- }
@@ -1,39 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Split the dark theme's `primary` into a foreground colour and a fill, so text
6
- using it is readable again.
7
-
8
- Dark `primary` was set to the brand navy `#17506F` so the navigation drawer
9
- would read as a surface. That is the right value for a fill — a white label on
10
- it measures 8.70:1 — but Vuetify emits `.text-primary` from the same token, so
11
- every `class="text-primary"` sentence and every `color="primary"` icon, spinner
12
- and text button rendered navy on a dark background:
13
-
14
- | | before | now |
15
- |---|---|---|
16
- | `primary` as text on the dark page `#0E1319` | 2.14:1 | **6.40:1** |
17
- | `primary` as text on a dark card `#1B242F` | 1.80:1 | **5.38:1** |
18
- | `primary` as text on `surface-bright` `#26313E`| 1.52:1 | **4.53:1** |
19
-
20
- Dark `primary` is now `#5B9BE0`. That is not a new colour: it is the blue the
21
- camera wall already draws its accents in (`--vms-accent`), so the two dark
22
- surfaces in this product agree on one blue.
23
-
24
- The navigation drawer no longer depends on `primary`. Both themes gain a
25
- `brand-surface` colour — `#042134` light (identical to light `primary`, so
26
- light mode renders exactly as before) and `#17506F` dark — and
27
- `Layout/NavigationDrawer.vue` is painted with it. Its white label still reads
28
- 16.51:1 light and 8.70:1 dark. `floating` was dropped from the drawer so it
29
- draws its own edge: the fill is 2.14:1 against the dark page, under the 3:1 a
30
- boundary wants, and the border at `border-opacity` 0.35 is 3.22:1.
31
-
32
- Where `primary` is still used as a fill, Vuetify derives `on-primary` from it
33
- and picks black, which reads at 7.21:1. What a light `primary` cannot carry is
34
- a hardcoded white label, and a handful of app-side sites still set one — see
35
- the pull request for the list.
36
-
37
- The light theme is unchanged. The colours moved to `utils/theme.ts` and
38
- `utils/theme.test.ts` now measures them, so a token cannot be moved for one use
39
- and quietly broken for the other again.
@@ -1,15 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Dashboard and filled-primary surfaces now follow the theme in dark mode.
6
-
7
- - `DashboardMain` painted its panels, list rows and text with fixed hex values,
8
- so the ACTIVE PATROL / STAFF STATUS / Feedbacks cards rendered white on the
9
- dark page and the heading and KPI figures were dark grey on near-black
10
- (1.19:1). They now use the theme's surface and foreground tokens.
11
- - `DARK_THEME` had no `on-primary`, so Vuetify derived white for every filled
12
- `primary` button, chip, alert, tab bar and snackbar - 2.91:1. It is now set
13
- explicitly and measures 6.40:1.
14
-
15
- The print / PDF / Word export styles are unchanged and stay ink-on-white.
@@ -1,17 +0,0 @@
1
- ---
2
- "@7365admin1/layer-common": patch
3
- ---
4
-
5
- Add a Notification Settings screen, shared by every web app.
6
-
7
- A person can now choose, per module and per delivery route, what they hear
8
- about: in the app, on their phone, or by email. The screen only lists modules
9
- their role actually gives them, and a route a module cannot use is shown dimmed
10
- with the reason in plain words rather than hidden.
11
-
12
- Modules are collapsed by default with a one-line summary of what is on, so
13
- somebody with many modules gets a short list instead of thirty switches. There
14
- is a master control for everything and one per module.
15
-
16
- The choices are enforced where notifications are sent, in `@7365admin1/core` and
17
- in the API, so a switch here actually stops the message.