@7365admin1/layer-common 4.117.0 → 4.118.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @iservice365/layer-common
2
2
 
3
+ ## 4.118.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 42930fa: Robot screens: Add robot, Edit, Remove and the building-map editor show only for Seven365 Super Admin. Commands on a HERO Fleet Core robot show only for Seven365 Super Admin; other users see status and position (view only). Matches the server rule that Fleet Core and robot setup are Super Admin only.
8
+
3
9
  ## 4.117.0
4
10
 
5
11
  ### Minor Changes
@@ -3117,11 +3123,11 @@ Monthly report: a month that had patrols opens the list of that month's patrol r
3117
3123
  `utils/console-tier.ts` + `composables/useConsoleTier.ts` mirror the server's
3118
3124
  own rule from two endpoints the console already calls, unprojected:
3119
3125
 
3120
- GET /api/members/user/:user/app/admin the Seven365 staff membership
3121
- GET /api/roles/id/:role that membership's role document
3126
+ GET /api/members/user/:user/app/admin the Seven365 staff membership
3127
+ GET /api/roles/id/:role that membership's role document
3122
3128
 
3123
- owner = member.type === "admin" && role.type === "admin" && role.default === true
3124
- staff = member.type === "admin" && role.type === "admin"
3129
+ owner = member.type === "admin" && role.type === "admin" && role.default === true
3130
+ staff = member.type === "admin" && role.type === "admin"
3125
3131
 
3126
3132
  `role.default` is the marker because it is the only property of a platform
3127
3133
  staff role no API caller can set - `role.controller.ts` validates create and
@@ -138,7 +138,7 @@
138
138
  <div v-if="commands.length" class="hero-detail__commands">
139
139
  <RobotCommandBar
140
140
  :capabilities="caps"
141
- :can-command="canCommand"
141
+ :can-command="cmdOk"
142
142
  :online="live?.ok === true && live.online === true"
143
143
  :mode="statusMode"
144
144
  :type="robotType"
@@ -151,7 +151,7 @@
151
151
  {{ commandResult.text }}
152
152
  </div>
153
153
  </div>
154
- <RobotViewOnlyNotice v-if="!canCommand" />
154
+ <RobotViewOnlyNotice v-if="!cmdOk" />
155
155
  </section>
156
156
  </div>
157
157
 
@@ -369,11 +369,13 @@ const props = withDefaults(
369
369
  canEdit?: boolean;
370
370
  canCommand?: boolean;
371
371
  canDelete?: boolean;
372
+ /** Seven365 Super Admin: the only one who may command a HERO Fleet Core robot (owner, 12 Oct 2026). */
373
+ superAdmin?: boolean;
372
374
  /** The robot types this app presents - the edit dialog shows Type only with both. */
373
375
  types?: Array<"cleaning" | "security">;
374
376
  tickMs?: number;
375
377
  }>(),
376
- { backLabel: "", canEdit: false, canCommand: false, canDelete: false, types: () => [], tickMs: 1200 },
378
+ { backLabel: "", canEdit: false, canCommand: false, canDelete: false, superAdmin: false, types: () => [], tickMs: 1200 },
377
379
  );
378
380
  const emit = defineEmits<{
379
381
  back: [];
@@ -398,6 +400,7 @@ const {
398
400
  } = useRobots();
399
401
 
400
402
  const record = ref<Record<string, any> | null>(null);
403
+ const cmdOk = computed(() => props.canCommand && (props.superAdmin || record.value?.brand !== "fleet-core"));
401
404
  const topEl = ref<HTMLElement | null>(null);
402
405
  const brands = ref<Array<Record<string, any>>>([]);
403
406
  const error = ref("");
@@ -478,7 +481,7 @@ const makerApp = computed(() => (live.value?.ok ? live.value.profile?.makerApp :
478
481
 
479
482
  const online = computed(() => live.value?.ok === true && live.value.online === true);
480
483
  const commands = computed(() =>
481
- visibleCommands({ capabilities: caps.value, canCommand: props.canCommand, online: online.value, mode: statusMode.value, type: robotType.value, resumable: resumable.value }),
484
+ visibleCommands({ capabilities: caps.value, canCommand: cmdOk.value, online: online.value, mode: statusMode.value, type: robotType.value, resumable: resumable.value }),
482
485
  );
483
486
 
484
487
  /* ---- the plan ---- */
@@ -506,7 +509,7 @@ watch(
506
509
  const readout = computed(() => `${positionText(live.value, caps.value, now.value)} · ${speedText(prevPose.value, nextPose.value, statusMode.value)}`);
507
510
 
508
511
  const spot = ref<Array<{ x: number; y: number }>>([]);
509
- const spotOn = computed(() => showSpotClean({ canCommand: props.canCommand, capabilities: caps.value, online: online.value, type: robotType.value }));
512
+ const spotOn = computed(() => showSpotClean({ canCommand: cmdOk.value, capabilities: caps.value, online: online.value, type: robotType.value }));
510
513
 
511
514
  // The route drawn on the plan: the shown map's first route, else the first with placed checkpoints (the rest are listed by name).
512
515
  const route = computed<TPatrolRouteView | null>(() =>
@@ -839,9 +842,9 @@ function onPick(p: TSavedPoint) {
839
842
  const livePanel = ref<{ show(): void } | null>(null);
840
843
  const hasCamera = computed(() => caps.value?.liveVideo === true || canDrive.value);
841
844
  const driveOpen = ref(false);
842
- const canDrive = computed(() => props.canCommand && caps.value?.manualDrive === true && online.value);
845
+ const canDrive = computed(() => cmdOk.value && caps.value?.manualDrive === true && online.value);
843
846
  const canResolve = computed(
844
- () => props.canCommand && caps.value?.resolveAlerts === true && faultBadge(fault.value) === "ALARM" && typeof fault.value?.code === "string",
847
+ () => cmdOk.value && caps.value?.resolveAlerts === true && faultBadge(fault.value) === "ALARM" && typeof fault.value?.code === "string",
845
848
  );
846
849
  const resolving = ref(false);
847
850
  async function resolveFault() {
@@ -26,9 +26,10 @@
26
26
  :key="robotId"
27
27
  :robot-id="robotId"
28
28
  :back-label="siteName || names.siteName ? `${siteName || names.siteName} fleet` : ''"
29
- :can-edit="canEdit"
29
+ :can-edit="canEdit && superAdmin"
30
30
  :can-command="canCommand"
31
- :can-delete="canDelete"
31
+ :super-admin="superAdmin"
32
+ :can-delete="canDelete && superAdmin"
32
33
  :types="types"
33
34
  @back="emit('back')"
34
35
  @removed="onRemoved"
@@ -42,7 +43,7 @@
42
43
  :site-name="siteName"
43
44
  :client-name="clientName"
44
45
  :type="type"
45
- :can-edit-map="canSetup && canEdit"
46
+ :can-edit-map="canSetup && canEdit && superAdmin"
46
47
  :back-to-network="backToNetwork"
47
48
  @open="(id) => emit('open', id)"
48
49
  @network="emit('network')"
@@ -57,7 +58,7 @@
57
58
  :client-name="clientName"
58
59
  :type="type"
59
60
  :can-command="canCommand"
60
- :can-edit-map="canSetup && canEdit"
61
+ :can-edit-map="canSetup && canEdit && superAdmin"
61
62
  :back-to-network="backToNetwork"
62
63
  @open="(id) => emit('open', id)"
63
64
  @network="emit('network')"
@@ -90,7 +91,7 @@
90
91
  :site-name="siteName"
91
92
  :client-name="clientName"
92
93
  :type="type"
93
- :can-setup="canSetup"
94
+ :can-setup="canSetup && superAdmin"
94
95
  :back-to-network="backToNetwork"
95
96
  :reload-key="reloadKey"
96
97
  @open="(r) => emit('open', String(r._id))"
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.117.0",
5
+ "version": "4.118.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.",