@7365admin1/layer-common 4.81.1-staging.467 → 4.81.1-staging.468

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.
@@ -784,6 +784,9 @@
784
784
  .hero-faultbar__code { font-family: var(--hero-font); font-weight: 800; color: var(--hero-accent); font-size: 18px; }
785
785
  .hero-faultbar__msg { font-weight: 600; }
786
786
  .hero-faultbar__since { opacity: 0.65; font-size: 12px; }
787
+ .hero-faultbar__clear { margin-top: 8px; font-size: 13px; }
788
+ .hero-faultbar__clear-title { font-weight: 700; }
789
+ .hero-faultbar__clear ol { margin: 4px 0 0; padding-left: 20px; }
787
790
  .hero-faultbar__badge { font-size: 11px; padding: 2px 8px; background: var(--hero-accent); color: #fff; font-weight: 600; }
788
791
 
789
792
  .hero-facts {
@@ -36,11 +36,12 @@
36
36
  <div v-if="fault" class="hero-faultbar" role="alert">
37
37
  <span class="hero-faultbar__code">{{ fault.code }}</span>
38
38
  <div>
39
- <div class="hero-faultbar__msg">{{ fault.message || fault.code }}</div>
39
+ <div class="hero-faultbar__msg">{{ faultWordsWithoutCode(fault) }}</div>
40
40
  <div class="hero-faultbar__since">
41
41
  Since {{ faultSince }} · notified once
42
42
  <template v-for="ph in faultPhotos(fault)" :key="ph.label"> · <a :href="ph.url" target="_blank" rel="noopener noreferrer">{{ ph.label }}</a></template>
43
43
  </div>
44
+ <RobotFaultClearSteps :steps="clearSteps" />
44
45
  </div>
45
46
  <v-btn v-if="canResolve" variant="outlined" size="small" :loading="resolving" @click="resolveFault">Mark resolved</v-btn>
46
47
  <span class="hero-faultbar__badge">{{ faultBadge(fault) }}</span>
@@ -339,6 +340,8 @@ import {
339
340
  positionGapText,
340
341
  positionText,
341
342
  robotAbilities,
343
+ robotClearFaultSteps,
344
+ faultWordsWithoutCode,
342
345
  robotErrorMessage,
343
346
  robotFacts,
344
347
  cleaningReadings,
@@ -447,6 +450,8 @@ const statusLabel = computed(() => robotStatus(statusMode.value, robotType.value
447
450
 
448
451
  const fault = computed(() => (live.value?.ok ? live.value.fault ?? null : record.value?.fault ?? null));
449
452
  const faultSince = computed(() => sinceText(fault.value?.since, now.value));
453
+ // The maker's manual steps (Ounitech today), only while a fault shows.
454
+ const clearSteps = computed(() => robotClearFaultSteps({ fault: fault.value, profile: live.value?.ok ? live.value.profile : null }));
450
455
 
451
456
  // Only what THIS robot reports (hide, never grey); what its maker keeps back is said once, in the card.
452
457
  const facts = computed(() => robotFacts({ record: record.value, live: live.value as any, now: now.value, hideUnreported: true }));
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <div v-if="steps.length" class="hero-faultbar__clear">
3
+ <div class="hero-faultbar__clear-title">How to clear this fault</div>
4
+ <ol><li v-for="s in steps" :key="s">{{ s }}</li></ol>
5
+ </div>
6
+ </template>
7
+
8
+ <script setup lang="ts">
9
+ /** The maker's manual steps to clear a fault on the robot (`robotClearFaultSteps`). */
10
+ defineProps<{ steps: string[] }>();
11
+ </script>
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.81.1-staging.467",
5
+ "version": "4.81.1-staging.468",
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.",
@@ -162,6 +162,27 @@ export function robotFaultText(state: { fault?: { message?: unknown; code?: unkn
162
162
  return text ? `Fault: ${text}` : null;
163
163
  }
164
164
 
165
+ /**
166
+ * The maker's steps to clear a fault on the robot itself (core `profile.clearFault`,
167
+ * from its manual), shown only while the robot reports a fault. None = nothing shown.
168
+ */
169
+ export function robotClearFaultSteps(state: {
170
+ fault?: unknown;
171
+ profile?: { clearFault?: unknown } | null;
172
+ } | null | undefined): string[] {
173
+ const steps = state?.profile?.clearFault;
174
+ if (!state?.fault || !Array.isArray(steps)) return [];
175
+ return steps.filter((s): s is string => typeof s === "string" && !!s.trim()).map((s) => s.trim());
176
+ }
177
+
178
+ /** A fault's words without its code repeated in front ("306 · ..."), for a place that already shows the code. */
179
+ export function faultWordsWithoutCode(fault: { code?: unknown; message?: unknown } | null | undefined): string {
180
+ const code = typeof fault?.code === "string" ? fault.code.trim() : "";
181
+ const message = typeof fault?.message === "string" ? fault.message.trim() : "";
182
+ const prefix = `${code} · `;
183
+ return code && message.startsWith(prefix) ? message.slice(prefix.length) : message || code;
184
+ }
185
+
165
186
  /**
166
187
  * A small square around a clicked pixel, as the polygon a spot command takes.
167
188
  *
@@ -1838,10 +1859,12 @@ export function commandOutcome(
1838
1859
  if (elapsedMs < COMMAND_WATCH_MS) return null;
1839
1860
  const fault = typeof reading.fault?.message === "string" ? reading.fault.message : "";
1840
1861
  // The fault was already there when this command was sent: it is not this command's result.
1862
+ // Core's fault words may end in a sentence ("... then send the task again."): no doubled period.
1863
+ const faultWords = fault.replace(/\.\s*$/, "");
1841
1864
  if (fault && fault === input.faultBefore) {
1842
- return { ok: false, done: true, text: `${who} is still stopped by an earlier fault (${fault}). Clear it on the robot or in its maker's app, then try again.` };
1865
+ return { ok: false, done: true, text: `${who} is still stopped by an earlier fault (${faultWords}). Clear it on the robot or in its maker's app, then try again.` };
1843
1866
  }
1844
- const reason = reading.online === false ? "it stopped reporting" : fault || (said && !RESTING.test(said) ? said : "");
1867
+ const reason = reading.online === false ? "it stopped reporting" : faultWords || (said && !RESTING.test(said) ? said : "");
1845
1868
  return {
1846
1869
  ok: false,
1847
1870
  done: true,