mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 02:13:41 +00:00
Merge pull request #27 from jhbruhn/fix/error-badge-auto-popup
feature: Add error badge with auto-opening popover for machine errors
This commit is contained in:
commit
213be4670c
4 changed files with 203 additions and 72 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { useState, useEffect, useRef } from "react";
|
||||
import { useShallow } from "zustand/react/shallow";
|
||||
import { useMachineStore } from "../stores/useMachineStore";
|
||||
import { useUIStore } from "../stores/useUIStore";
|
||||
|
|
@ -7,6 +8,7 @@ import {
|
|||
getStateVisualInfo,
|
||||
getStatusIndicatorState,
|
||||
} from "../utils/machineStateHelpers";
|
||||
import { hasError, getErrorDetails } from "../utils/errorCodeHelpers";
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
BoltIcon,
|
||||
|
|
@ -58,6 +60,15 @@ export function AppHeader() {
|
|||
})),
|
||||
);
|
||||
|
||||
// State management for error popover auto-open/close
|
||||
const [errorPopoverOpen, setErrorPopoverOpen] = useState(false);
|
||||
const [dismissedErrorCode, setDismissedErrorCode] = useState<number | null>(
|
||||
null,
|
||||
);
|
||||
const prevMachineErrorRef = useRef<number | undefined>(undefined);
|
||||
const prevErrorMessageRef = useRef<string | null>(null);
|
||||
const prevPyodideErrorRef = useRef<string | null>(null);
|
||||
|
||||
// Get state visual info for header status badge
|
||||
const stateVisual = getStateVisualInfo(machineStatus);
|
||||
const stateIcons = {
|
||||
|
|
@ -75,6 +86,66 @@ export function AppHeader() {
|
|||
? getStatusIndicatorState(machineStatus)
|
||||
: "idle";
|
||||
|
||||
// Auto-open/close error popover based on error state changes
|
||||
/* eslint-disable react-hooks/set-state-in-effect */
|
||||
useEffect(() => {
|
||||
const currentError = machineError;
|
||||
const prevError = prevMachineErrorRef.current;
|
||||
const currentErrorMessage = machineErrorMessage;
|
||||
const prevErrorMessage = prevErrorMessageRef.current;
|
||||
const currentPyodideError = pyodideError;
|
||||
const prevPyodideError = prevPyodideErrorRef.current;
|
||||
|
||||
// Check if there's any error now
|
||||
const hasAnyError =
|
||||
machineErrorMessage || pyodideError || hasError(currentError);
|
||||
// Check if there was any error before
|
||||
const hadAnyError =
|
||||
prevErrorMessage || prevPyodideError || hasError(prevError);
|
||||
|
||||
// Auto-open popover when new error appears
|
||||
const isNewMachineError =
|
||||
hasError(currentError) &&
|
||||
currentError !== prevError &&
|
||||
currentError !== dismissedErrorCode;
|
||||
const isNewErrorMessage =
|
||||
currentErrorMessage && currentErrorMessage !== prevErrorMessage;
|
||||
const isNewPyodideError =
|
||||
currentPyodideError && currentPyodideError !== prevPyodideError;
|
||||
|
||||
if (isNewMachineError || isNewErrorMessage || isNewPyodideError) {
|
||||
setErrorPopoverOpen(true);
|
||||
}
|
||||
|
||||
// Auto-close popover when all errors are cleared
|
||||
if (!hasAnyError && hadAnyError) {
|
||||
setErrorPopoverOpen(false);
|
||||
setDismissedErrorCode(null); // Reset dismissed tracking
|
||||
}
|
||||
|
||||
// Update refs for next comparison
|
||||
prevMachineErrorRef.current = currentError;
|
||||
prevErrorMessageRef.current = currentErrorMessage;
|
||||
prevPyodideErrorRef.current = currentPyodideError;
|
||||
}, [machineError, machineErrorMessage, pyodideError, dismissedErrorCode]);
|
||||
/* eslint-enable react-hooks/set-state-in-effect */
|
||||
|
||||
// Handle manual popover dismiss
|
||||
const handlePopoverOpenChange = (open: boolean) => {
|
||||
setErrorPopoverOpen(open);
|
||||
|
||||
// If user manually closes it, remember the current error state to prevent reopening
|
||||
if (!open) {
|
||||
// For machine errors, track the error code
|
||||
if (hasError(machineError)) {
|
||||
setDismissedErrorCode(machineError);
|
||||
}
|
||||
// Update refs so we don't reopen for the same error message/pyodide error
|
||||
prevErrorMessageRef.current = machineErrorMessage;
|
||||
prevPyodideErrorRef.current = pyodideError;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<header className="bg-gradient-to-r from-primary-600 via-primary-700 to-primary-800 dark:from-primary-700 dark:via-primary-800 dark:to-primary-900 px-4 sm:px-6 lg:px-8 py-3 shadow-lg border-b-2 border-primary-900/20 dark:border-primary-800/30 flex-shrink-0">
|
||||
|
|
@ -166,22 +237,22 @@ export function AppHeader() {
|
|||
)}
|
||||
|
||||
{/* Error indicator - always render to prevent layout shift */}
|
||||
<Popover>
|
||||
<Popover
|
||||
open={errorPopoverOpen}
|
||||
onOpenChange={handlePopoverOpenChange}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
<button
|
||||
className={cn(
|
||||
"gap-1.5 flex-shrink-0",
|
||||
"inline-flex items-center rounded-full border border-transparent bg-destructive text-white px-2.5 py-1.5 text-xs font-semibold gap-1.5 cursor-pointer hover:bg-destructive/90 transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-destructive focus-visible:ring-offset-2",
|
||||
machineErrorMessage || pyodideError
|
||||
? "animate-pulse hover:animate-none"
|
||||
: "invisible pointer-events-none",
|
||||
)}
|
||||
aria-label="View error details"
|
||||
disabled={!(machineErrorMessage || pyodideError)}
|
||||
>
|
||||
<ExclamationTriangleIcon className="w-3.5 h-3.5 flex-shrink-0" />
|
||||
<span>
|
||||
<span className="font-semibold">
|
||||
{(() => {
|
||||
if (pyodideError) return "Python Error";
|
||||
if (isPairingError) return "Pairing Required";
|
||||
|
|
@ -202,17 +273,19 @@ export function AppHeader() {
|
|||
return "Pattern Error";
|
||||
}
|
||||
if (machineError !== undefined) {
|
||||
return `Machine Error`;
|
||||
// Get short name from error details
|
||||
const errorDetails = getErrorDetails(machineError);
|
||||
return errorDetails?.shortName || "Machine Error";
|
||||
}
|
||||
|
||||
// Default fallback
|
||||
return "Error";
|
||||
})()}
|
||||
</span>
|
||||
</Button>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
|
||||
{/* Error popover content */}
|
||||
{/* Error popover content - unchanged */}
|
||||
{(machineErrorMessage || pyodideError) && (
|
||||
<ErrorPopoverContent
|
||||
machineError={
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
ExclamationTriangleIcon,
|
||||
} from "@heroicons/react/24/solid";
|
||||
import { MachineStatus } from "../types/machine";
|
||||
import { getErrorDetails, hasError } from "../utils/errorCodeHelpers";
|
||||
|
||||
interface Step {
|
||||
id: number;
|
||||
|
|
@ -28,38 +27,7 @@ const steps: Step[] = [
|
|||
];
|
||||
|
||||
// Helper function to get guide content for a step
|
||||
function getGuideContent(
|
||||
stepId: number,
|
||||
machineStatus: MachineStatus,
|
||||
hasError: boolean,
|
||||
errorCode?: number,
|
||||
errorMessage?: string,
|
||||
) {
|
||||
// Check for errors first
|
||||
if (hasError) {
|
||||
const errorDetails = getErrorDetails(errorCode);
|
||||
|
||||
if (errorDetails?.isInformational) {
|
||||
return {
|
||||
type: "info" as const,
|
||||
title: errorDetails.title,
|
||||
description: errorDetails.description,
|
||||
items: errorDetails.solutions || [],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: "error" as const,
|
||||
title: errorDetails?.title || "Error Occurred",
|
||||
description:
|
||||
errorDetails?.description ||
|
||||
errorMessage ||
|
||||
"An error occurred. Please check the machine and try again.",
|
||||
items: errorDetails?.solutions || [],
|
||||
errorCode,
|
||||
};
|
||||
}
|
||||
|
||||
function getGuideContent(stepId: number, machineStatus: MachineStatus) {
|
||||
// Return content based on step
|
||||
switch (stepId) {
|
||||
case 1:
|
||||
|
|
@ -273,17 +241,10 @@ function getCurrentStep(
|
|||
|
||||
export function WorkflowStepper() {
|
||||
// Machine store
|
||||
const {
|
||||
machineStatus,
|
||||
isConnected,
|
||||
machineError,
|
||||
error: errorMessage,
|
||||
} = useMachineStore(
|
||||
const { machineStatus, isConnected } = useMachineStore(
|
||||
useShallow((state) => ({
|
||||
machineStatus: state.machineStatus,
|
||||
isConnected: state.isConnected,
|
||||
machineError: state.machineError,
|
||||
error: state.error,
|
||||
})),
|
||||
);
|
||||
|
||||
|
|
@ -297,7 +258,6 @@ export function WorkflowStepper() {
|
|||
// Derived state: pattern is uploaded if machine has pattern info
|
||||
const patternUploaded = usePatternUploaded();
|
||||
const hasPattern = pesData !== null;
|
||||
const hasErrorFlag = hasError(machineError);
|
||||
const currentStep = getCurrentStep(
|
||||
machineStatus,
|
||||
isConnected,
|
||||
|
|
@ -443,13 +403,7 @@ export function WorkflowStepper() {
|
|||
aria-label="Step guidance"
|
||||
>
|
||||
{(() => {
|
||||
const content = getGuideContent(
|
||||
popoverStep,
|
||||
machineStatus,
|
||||
hasErrorFlag,
|
||||
machineError,
|
||||
errorMessage || undefined,
|
||||
);
|
||||
const content = getGuideContent(popoverStep, machineStatus);
|
||||
if (!content) return null;
|
||||
|
||||
const colorClasses = {
|
||||
|
|
@ -497,7 +451,7 @@ export function WorkflowStepper() {
|
|||
};
|
||||
|
||||
const Icon =
|
||||
content.type === "error"
|
||||
content.type === "warning"
|
||||
? ExclamationTriangleIcon
|
||||
: InformationCircleIcon;
|
||||
|
||||
|
|
@ -538,18 +492,6 @@ export function WorkflowStepper() {
|
|||
))}
|
||||
</ul>
|
||||
)}
|
||||
{content.type === "error" &&
|
||||
content.errorCode !== undefined && (
|
||||
<p
|
||||
className={`text-xs ${descColorClasses[content.type]} mt-3 font-mono`}
|
||||
>
|
||||
Error Code: 0x
|
||||
{content.errorCode
|
||||
.toString(16)
|
||||
.toUpperCase()
|
||||
.padStart(2, "0")}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
84
src/utils/errorCodeHelpers.test.ts
Normal file
84
src/utils/errorCodeHelpers.test.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { describe, it, expect } from "vitest";
|
||||
import { getErrorDetails, SewingMachineError } from "./errorCodeHelpers";
|
||||
|
||||
describe("errorCodeHelpers", () => {
|
||||
describe("shortName validation", () => {
|
||||
it("should ensure all error shortNames are 15 characters or less", () => {
|
||||
// Get all error codes except None (0xDD) and Unknown (0xEE) since they might not have details
|
||||
const errorCodes = Object.values(SewingMachineError).filter(
|
||||
(code) =>
|
||||
code !== SewingMachineError.None &&
|
||||
code !== SewingMachineError.Unknown &&
|
||||
code !== SewingMachineError.OtherError,
|
||||
);
|
||||
|
||||
const violations: Array<{
|
||||
code: number;
|
||||
shortName: string;
|
||||
length: number;
|
||||
}> = [];
|
||||
|
||||
errorCodes.forEach((code) => {
|
||||
const details = getErrorDetails(code);
|
||||
if (details?.shortName) {
|
||||
const length = details.shortName.length;
|
||||
if (length > 15) {
|
||||
violations.push({
|
||||
code,
|
||||
shortName: details.shortName,
|
||||
length,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If there are violations, create a helpful error message
|
||||
if (violations.length > 0) {
|
||||
const violationMessages = violations
|
||||
.map(
|
||||
(v) =>
|
||||
`Error code 0x${v.code.toString(16).toUpperCase()}: "${v.shortName}" (${v.length} chars)`,
|
||||
)
|
||||
.join("\n ");
|
||||
|
||||
expect.fail(
|
||||
`The following error shortNames exceed 15 characters:\n ${violationMessages}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Assertion to confirm test ran
|
||||
expect(violations).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("should ensure all error details have a shortName", () => {
|
||||
// Get all error codes except None (0xDD) and Unknown (0xEE)
|
||||
const errorCodes = Object.values(SewingMachineError).filter(
|
||||
(code) =>
|
||||
code !== SewingMachineError.None &&
|
||||
code !== SewingMachineError.Unknown &&
|
||||
code !== SewingMachineError.OtherError,
|
||||
);
|
||||
|
||||
const missing: number[] = [];
|
||||
|
||||
errorCodes.forEach((code) => {
|
||||
const details = getErrorDetails(code);
|
||||
if (details && !details.shortName) {
|
||||
missing.push(code);
|
||||
}
|
||||
});
|
||||
|
||||
if (missing.length > 0) {
|
||||
const missingCodes = missing
|
||||
.map((code) => `0x${code.toString(16).toUpperCase()}`)
|
||||
.join(", ");
|
||||
|
||||
expect.fail(
|
||||
`The following error codes are missing shortName: ${missingCodes}`,
|
||||
);
|
||||
}
|
||||
|
||||
expect(missing).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -42,6 +42,8 @@ export const SewingMachineError = {
|
|||
*/
|
||||
interface ErrorInfo {
|
||||
title: string;
|
||||
/** Short name for badge display (max 15 characters) */
|
||||
shortName: string;
|
||||
description: string;
|
||||
solutions: string[];
|
||||
/** If true, this "error" is really just an informational step, not a real error */
|
||||
|
|
@ -55,12 +57,14 @@ interface ErrorInfo {
|
|||
const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
||||
[SewingMachineError.NeedlePositionError]: {
|
||||
title: "The Needle is Down",
|
||||
shortName: "Needle Down",
|
||||
description:
|
||||
"The needle is in the down position and needs to be raised before continuing.",
|
||||
solutions: ["Press the needle position switch to raise the needle"],
|
||||
},
|
||||
[SewingMachineError.SafetyError]: {
|
||||
title: "Safety Error",
|
||||
shortName: "Safety Error",
|
||||
description: "The machine is sensing an operational issue.",
|
||||
solutions: [
|
||||
"Remove the thread on the top of the fabric and then remove the needle",
|
||||
|
|
@ -72,21 +76,25 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.LowerThreadSafetyError]: {
|
||||
title: "Lower Thread Safety Error",
|
||||
shortName: "Lower Thread",
|
||||
description: "The bobbin winder safety device is activated.",
|
||||
solutions: ["Check if the thread is tangled"],
|
||||
},
|
||||
[SewingMachineError.LowerThreadFreeError]: {
|
||||
title: "Lower Thread Free Error",
|
||||
shortName: "Lower Thread",
|
||||
description: "Problem with lower thread.",
|
||||
solutions: ["Slide the bobbin winder shaft toward the front"],
|
||||
},
|
||||
[SewingMachineError.RestartError10]: {
|
||||
title: "Restart Required",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred.",
|
||||
solutions: ["Turn the machine off, then on again"],
|
||||
},
|
||||
[SewingMachineError.RestartError11]: {
|
||||
title: "Restart Required (M519411)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519411",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -95,6 +103,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError12]: {
|
||||
title: "Restart Required (M519412)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519412",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -103,6 +112,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError13]: {
|
||||
title: "Restart Required (M519413)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519413",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -111,6 +121,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError14]: {
|
||||
title: "Restart Required (M519414)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519414",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -119,6 +130,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError15]: {
|
||||
title: "Restart Required (M519415)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519415",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -127,6 +139,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError16]: {
|
||||
title: "Restart Required (M519416)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519416",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -135,6 +148,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError17]: {
|
||||
title: "Restart Required (M519417)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519417",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -143,6 +157,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError18]: {
|
||||
title: "Restart Required (M519418)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519418",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -151,6 +166,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError19]: {
|
||||
title: "Restart Required (M519419)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M519419",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -159,6 +175,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError1A]: {
|
||||
title: "Restart Required (M51941A)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M51941A",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -167,6 +184,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError1B]: {
|
||||
title: "Restart Required (M51941B)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M51941B",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -175,6 +193,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RestartError1C]: {
|
||||
title: "Restart Required (M51941C)",
|
||||
shortName: "Restart Needed",
|
||||
description: "A malfunction occurred. Error code: M51941C",
|
||||
solutions: [
|
||||
"Turn the machine off, then on again",
|
||||
|
|
@ -183,6 +202,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.NeedlePlateError]: {
|
||||
title: "Needle Plate Error",
|
||||
shortName: "Needle Plate",
|
||||
description: "Check the needle plate cover.",
|
||||
solutions: [
|
||||
"Reattach the needle plate cover",
|
||||
|
|
@ -191,11 +211,13 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.ThreadLeverError]: {
|
||||
title: "Thread Lever Error",
|
||||
shortName: "Thread Lever",
|
||||
description: "The needle threading lever is not in its original position.",
|
||||
solutions: ["Return the needle threading lever to its original position"],
|
||||
},
|
||||
[SewingMachineError.UpperThreadError]: {
|
||||
title: "Upper Thread Error",
|
||||
shortName: "Upper Thread",
|
||||
description: "Check and rethread the upper thread.",
|
||||
solutions: [
|
||||
"Check the upper thread and rethread it",
|
||||
|
|
@ -204,6 +226,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.LowerThreadError]: {
|
||||
title: "Lower Thread Error",
|
||||
shortName: "Lower Thread",
|
||||
description: "The bobbin thread is almost empty.",
|
||||
solutions: [
|
||||
"Replace the bobbin thread",
|
||||
|
|
@ -212,6 +235,7 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.UpperThreadSewingStartError]: {
|
||||
title: "Upper Thread Error at Sewing Start",
|
||||
shortName: "Upper Thread",
|
||||
description: "Check and rethread the upper thread.",
|
||||
solutions: [
|
||||
"Press the Accept button to resolve the error",
|
||||
|
|
@ -221,21 +245,25 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.PRWiperError]: {
|
||||
title: "PR Wiper Error",
|
||||
shortName: "PR Wiper",
|
||||
description: "PR Wiper Error.",
|
||||
solutions: ["Press the Accept button to resolve the error"],
|
||||
},
|
||||
[SewingMachineError.HoopError]: {
|
||||
title: "Hoop Error",
|
||||
shortName: "Hoop Error",
|
||||
description: "This embroidery frame cannot be used.",
|
||||
solutions: ["Use another frame that fits the pattern"],
|
||||
},
|
||||
[SewingMachineError.NoHoopError]: {
|
||||
title: "No Hoop Detected",
|
||||
shortName: "No Hoop",
|
||||
description: "No hoop attached.",
|
||||
solutions: ["Attach the embroidery hoop"],
|
||||
},
|
||||
[SewingMachineError.InitialHoopError]: {
|
||||
title: "Machine Initialization Required",
|
||||
shortName: "Init Required",
|
||||
description: "An initial homing procedure must be performed.",
|
||||
solutions: [
|
||||
"Remove the embroidery hoop from the machine completely",
|
||||
|
|
@ -248,12 +276,14 @@ const ERROR_DETAILS: Record<number, ErrorInfo> = {
|
|||
},
|
||||
[SewingMachineError.RegularInspectionError]: {
|
||||
title: "Regular Inspection Required",
|
||||
shortName: "Inspection Due",
|
||||
description:
|
||||
"Preventive maintenance is recommended. This message is displayed when maintenance is due.",
|
||||
solutions: ["Please contact the service center"],
|
||||
},
|
||||
[SewingMachineError.Setting]: {
|
||||
title: "Settings Error",
|
||||
shortName: "Settings Error",
|
||||
description: "Stitch count cannot be changed.",
|
||||
solutions: ["This setting cannot be modified at this time"],
|
||||
},
|
||||
|
|
@ -358,6 +388,7 @@ export function getErrorDetails(
|
|||
if (errorTitle) {
|
||||
return {
|
||||
title: errorTitle,
|
||||
shortName: errorTitle.length > 15 ? "Machine Error" : errorTitle,
|
||||
description: "Please check the machine display for more information.",
|
||||
solutions: [
|
||||
"Consult your machine manual for specific troubleshooting steps",
|
||||
|
|
@ -370,6 +401,7 @@ export function getErrorDetails(
|
|||
// Unknown error code
|
||||
return {
|
||||
title: `Machine Error 0x${errorCode.toString(16).toUpperCase().padStart(2, "0")}`,
|
||||
shortName: "Machine Error",
|
||||
description:
|
||||
"The machine has reported an error code that is not recognized.",
|
||||
solutions: [
|
||||
|
|
|
|||
Loading…
Reference in a new issue