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 && (
- +