From df7bb9a5e118ce74d2fa6a6ef91053231da70bc0 Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 9 Oct 2026 17:49:44 +0200 Subject: [PATCH] fix(storage): Test on a mirrored phone storage row probes the backends on the form On the phone storage panel, Test on a mirrored backend sent the mirror itself to POST /api/admin/storage/test. The server expands a mirror by looking its primary and replicas up by name in the SAVED storage config, so the phone tested the saved settings instead of what the operator had just edited, and a replica added but not saved yet made the whole test fail with "references unknown backend". The desktop probes the primary and each replica with their draft options and merges the results. Cause: the phone called admin.test with the mirror candidate, while the desktop called admin.testMirror with mirrorProbeTargets. The choice lived in each shell's markup. Fix: useStoragePanel now offers loaded.testRow(row), which tests a plain row as it is and a mirrored row through admin.testMirror with mirrorProbeTargets from the draft. Both shells call it. Red test: FE-MOB-MSTOR-018 (new, MAdminStoragePanel.test.tsx) failed with "AssertionError: expected [ 'mirror' ] to deeply equal [ 'backups-local', 'off-box' ]". FE-ADMIN-STOR-PANEL-017 (new, useStoragePanel.test.ts) covers testRow itself. No existing assertion changed. --- .../Admin/storage/AdminStoragePanel.tsx | 15 +++--------- .../Admin/storage/useStoragePanel.test.ts | 23 ++++++++++++++++++- .../Admin/storage/useStoragePanel.ts | 13 +++++++++++ .../screens/admin/MAdminStoragePanel.tsx | 9 ++------ .../mobile/admin/MAdminStoragePanel.test.tsx | 22 ++++++++++++++++++ 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/client/src/components/Admin/storage/AdminStoragePanel.tsx b/client/src/components/Admin/storage/AdminStoragePanel.tsx index b567e1cc8..3223dedee 100644 --- a/client/src/components/Admin/storage/AdminStoragePanel.tsx +++ b/client/src/components/Admin/storage/AdminStoragePanel.tsx @@ -38,7 +38,7 @@ import { StatusPill, } from '../../Settings/settingsKit' import BackendForm from './BackendForm' -import { CACHE_CATEGORIES, mirrorProbeTargets, primaryNameOf } from './storageModel' +import { CACHE_CATEGORIES, primaryNameOf } from './storageModel' import { categoryNames, migrationPromptLine, useStoragePanel } from './useStoragePanel' /** The compact buttons of a backend row: white on a hairline, a size under the card's own. */ @@ -123,7 +123,7 @@ export default function AdminStoragePanel(): React.ReactElement { ) } const { - state, draft, migrationCandidates, backendNames, rows, degenerate, effective, usageSums, startAdd, startEdit, + state, draft, migrationCandidates, backendNames, rows, degenerate, effective, usageSums, startAdd, startEdit, testRow, commitBackend, removeMessage, confirmRemoval, setCategory, save, moveAndSave, routeOnlySave, } = loaded @@ -202,11 +202,6 @@ export default function AdminStoragePanel(): React.ReactElement { {rows.map((row) => { const resultKey = row.mirrorName ?? row.name const result = testResultFor(resultKey) - // row.mirrorName only exists when foldBackends adopted a draft mirror - // for this row, so the draft lookup below cannot miss. - const testCandidate = row.mirrorName - ? draft.backends.find((b) => b.name === row.mirrorName)! - : row.backend const rowUsage = usageSums?.[row.name] const backfill = row.mirrorName ? state.backfills.find((b) => b.backend === row.mirrorName) : undefined const TypeIcon = TYPE_ICON[row.type] ?? HardDrive @@ -234,11 +229,7 @@ export default function AdminStoragePanel(): React.ReactElement {