refactor(frontend): ApiError interface, tempIdSuffix rename, NET_GRID constants, extract onPaletteDrop handlers

ApiError: defined once in utils/api.ts, replaces 9 ad-hoc anonymous casts
across MazeNET, Inspector, DeckyFleet, SwarmHosts, Webhooks, PersonaGeneration,
ServiceConfigFields, CanaryTokens.

hex4 renamed to tempIdSuffix — the name now matches the comment that already
explained its purpose.

NET_GRID_{W,H,GAP,COLS} extracted from inline magic numbers to module-level
constants in MazeNET.tsx.

onPaletteDrop (130-line useCallback) split into three module-level handlers
(_dropNetwork, _dropArchetype, _dropService); the callback becomes a 10-line
router.
This commit is contained in:
2026-04-30 22:14:20 -04:00
parent b754e9aa8b
commit 57fecb8071
9 changed files with 169 additions and 153 deletions

View File

@@ -4,7 +4,7 @@ import {
RefreshCw, Server, Shield, Terminal, Plus, X,
} from '../icons';
import { useEscapeKey } from '../hooks/useEscapeKey';
import api from '../utils/api';
import api, { type ApiError } from '../utils/api';
import { ARCHETYPES as FALLBACK_ARCHETYPES, DEFAULT_SERVICES } from './MazeNET/data';
import { useToast } from './Toasts/useToast';
import Modal from './Modal/Modal';
@@ -325,7 +325,7 @@ const DeckyCard: React.FC<DeckyCardProps> = ({
setTarpitMenuOpen(false);
onTarpitResult(decky.name, true, `TARPIT ON · ${decky.name.toUpperCase()} · ${ports.join(',')} / ${tarpitDelayMs}ms`);
} catch (err) {
const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail ?? 'Tarpit enable failed';
const msg = (err as ApiError)?.response?.data?.detail ?? 'Tarpit enable failed';
onTarpitResult(decky.name, false, msg);
} finally {
setTarpitBusy(false);
@@ -339,7 +339,7 @@ const DeckyCard: React.FC<DeckyCardProps> = ({
await api.delete(`/deckies/${encodeURIComponent(decky.name)}/tarpit`);
onTarpitResult(decky.name, true, `TARPIT OFF · ${decky.name.toUpperCase()}`);
} catch (err) {
const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail ?? 'Tarpit disable failed';
const msg = (err as ApiError)?.response?.data?.detail ?? 'Tarpit disable failed';
onTarpitResult(decky.name, false, msg);
} finally {
setTarpitBusy(false);
@@ -355,7 +355,7 @@ const DeckyCard: React.FC<DeckyCardProps> = ({
);
onServicesChanged(decky.name, data.services);
} catch (err) {
const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail
const msg = (err as ApiError)?.response?.data?.detail
?? 'Remove failed.';
setOpError(msg);
} finally {
@@ -383,7 +383,7 @@ const DeckyCard: React.FC<DeckyCardProps> = ({
} catch (err) {
// Re-raise so the modal can surface the error in its own status row.
// Also mirror onto opError for the inline picker case.
const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail
const msg = (err as ApiError)?.response?.data?.detail
?? 'Add failed.';
setOpError(msg);
throw err;
@@ -1466,7 +1466,7 @@ const DeckyFleet: React.FC<FleetProps> = ({ searchQuery = '' }) => {
await fetchDeckies(deployMode?.mode);
push({ text: `TORN DOWN · ${d.name.toUpperCase()}`, tone: 'matrix', icon: 'check-circle' });
} catch (err: unknown) {
const e = err as { response?: { data?: { detail?: string } } };
const e = err as ApiError;
push({
text: `TEARDOWN FAILED · ${e?.response?.data?.detail || d.name}`,
tone: 'alert',