diff --git a/server/routes/device/removeAll.ts b/server/routes/device/removeAll.ts
index c017b61..899dcc1 100644
--- a/server/routes/device/removeAll.ts
+++ b/server/routes/device/removeAll.ts
@@ -163,7 +163,10 @@ export default function deviceRemoveAllRoutes(app: FastifyInstance, config: Serv
)
if (allUuids.length === 0) {
- stream.error('No deploy history found. Cannot determine which templates are custom.')
+ stream.error(
+ 'No deploy history found. Cannot determine which templates are custom.',
+ 'Deploy templates first, or pull methods templates from the device to establish tracking.',
+ )
return
}
@@ -197,7 +200,10 @@ export default function deviceRemoveAllRoutes(app: FastifyInstance, config: Serv
steps.push(`Saved backup: ${backupFilename} (${Object.keys(fileMap).length} files)`)
if (!existsSync(backupPath)) {
- stream.error('Backup verification failed — ZIP was not saved')
+ stream.error(
+ 'Backup verification failed — ZIP was not saved',
+ 'Check available disk space on the server. The backup must be saved before templates can be removed.',
+ )
return
}
diff --git a/src/components/device/DeviceBackupsCard.tsx b/src/components/device/DeviceBackupsCard.tsx
index f4d9ce6..258ef68 100644
--- a/src/components/device/DeviceBackupsCard.tsx
+++ b/src/components/device/DeviceBackupsCard.tsx
@@ -1,4 +1,5 @@
import { useState, useEffect, useRef, useCallback } from 'react'
+import { ErrorDetails } from './ErrorDetails'
interface Props {
deviceId: string | null
@@ -364,10 +365,14 @@ export function DeviceBackupsCard({ deviceId, deviceName, configured, onStatus:
)}
{restoreResult && restoreResult.type === 'error' && (
-
- {restoreResult.message}
+
-
+
)}
{/* Restore preview panel */}
diff --git a/src/components/device/DeviceConnectionCard.tsx b/src/components/device/DeviceConnectionCard.tsx
index 1040eda..d402fa3 100644
--- a/src/components/device/DeviceConnectionCard.tsx
+++ b/src/components/device/DeviceConnectionCard.tsx
@@ -235,6 +235,7 @@ export function DeviceConnectionCard({ devicesState }: Props) {
error={testResult.error!}
hint={testResult.hint}
rawError={testResult.rawError}
+ operationName="test-connection"
deviceModel={activeDevice?.deviceModel}
firmwareVersion={activeDevice?.firmwareVersion}
className="device-error"
@@ -327,6 +328,7 @@ export function DeviceConnectionCard({ devicesState }: Props) {
error={keyResult.error!}
hint={keyResult.hint}
rawError={keyResult.rawError}
+ operationName="setup-ssh-keys"
deviceModel={activeDevice?.deviceModel}
firmwareVersion={activeDevice?.firmwareVersion}
className="device-error"
@@ -465,6 +467,7 @@ export function DeviceConnectionCard({ devicesState }: Props) {
error={testResult.error!}
hint={testResult.hint}
rawError={testResult.rawError}
+ operationName="test-connection"
deviceModel={activeDevice?.deviceModel}
firmwareVersion={activeDevice?.firmwareVersion}
className="device-error"
diff --git a/src/components/device/DeviceOpComponents.tsx b/src/components/device/DeviceOpComponents.tsx
index 8943ad9..d7bfe6c 100644
--- a/src/components/device/DeviceOpComponents.tsx
+++ b/src/components/device/DeviceOpComponents.tsx
@@ -40,6 +40,7 @@ export function OpButton({
variant = 'primary',
disabled = false,
title,
+ operationName,
deviceModel,
firmwareVersion,
}: {
@@ -49,6 +50,7 @@ export function OpButton({
variant?: 'primary' | 'secondary' | 'danger'
disabled?: boolean
title?: string
+ operationName?: string
deviceModel?: string
firmwareVersion?: string
}) {
@@ -67,11 +69,16 @@ export function OpButton({
)}
{op.result && !op.result.ok && (
-
+
)}
{op.result?.ok && (
{op.result.message}
+ {op.result.warnings && op.result.warnings.length > 0 && (
+
+ {op.result.warnings.map((w, i) => - {w}
)}
+
+ )}
)}
diff --git a/src/components/device/DeviceSyncCard.tsx b/src/components/device/DeviceSyncCard.tsx
index 71bf5cb..548fa44 100644
--- a/src/components/device/DeviceSyncCard.tsx
+++ b/src/components/device/DeviceSyncCard.tsx
@@ -315,7 +315,7 @@ function SyncStatusSection({ syncStatus, autoRefreshed, deviceModel, firmwareVer
{error && (
-
+
)}
@@ -607,6 +607,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
op={pullMethods}
disabled={anyOpRunning}
title={`Download methods templates (official + custom) from ${deviceName}`}
+ operationName="pull-methods"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -617,6 +618,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
variant="secondary"
disabled={anyOpRunning}
title={`Download classic templates from ${deviceName}`}
+ operationName="pull-classic"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -640,6 +642,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
title={selective.showSelector && selective.selectedIds.size === 0
? 'Select at least one template to deploy'
: `Build and push templates to ${deviceName} in methods format — syncs across paired devices`}
+ operationName="deploy-methods"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -650,6 +653,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
variant="secondary"
disabled={anyOpRunning}
title={`Push classic templates to ${deviceName} — single device only, wiped on firmware updates`}
+ operationName="deploy-classic"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -673,6 +677,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
variant="danger"
disabled={anyOpRunning}
title={`Revert ${deviceName} to the state before your last deploy`}
+ operationName="rollback-methods"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -683,6 +688,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
variant="danger"
disabled={anyOpRunning}
title={`Restore ${deviceName} to its pre-app state`}
+ operationName="rollback-original"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -693,6 +699,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
variant="danger"
disabled={anyOpRunning}
title={`Restore ${deviceName} from the most recent classic template backup`}
+ operationName="rollback-classic"
deviceModel={deviceModel}
firmwareVersion={firmwareVersion}
/>
@@ -785,7 +792,7 @@ export function DeviceSyncCard({ deviceId, deviceName, configured, deviceModel,
{removeAll.phase === 'error' && removeAll.errorInfo && (
-
+