diff --git a/client/src/mobile/components/MStorageTestResult.test.tsx b/client/src/mobile/components/MStorageTestResult.test.tsx
new file mode 100644
index 000000000..7f9b78260
--- /dev/null
+++ b/client/src/mobile/components/MStorageTestResult.test.tsx
@@ -0,0 +1,44 @@
+// FE-COMP-MSTORETEST-001 to FE-COMP-MSTORETEST-004
+import { describe, expect, it } from 'vitest';
+
+import { render, screen } from '../../../tests/helpers/render';
+import MStorageTestResult from './MStorageTestResult';
+
+describe('MStorageTestResult', () => {
+ it('FE-COMP-MSTORETEST-001: renders nothing before the first test', () => {
+ const { container } = render();
+
+ expect(container).toBeEmptyDOMElement();
+ });
+
+ it('FE-COMP-MSTORETEST-002: shows the running note while a test is in flight', () => {
+ render();
+
+ expect(screen.getByText('Testing…')).toHaveClass('mt-2', 'font-geist', 'text-m-muted');
+ });
+
+ it('FE-COMP-MSTORETEST-003: lists every target under a passed verdict', () => {
+ render();
+
+ expect(screen.getByText('Connection OK')).toHaveClass('font-bold', 'text-m-ink');
+ expect(screen.getByText(/off-box/).textContent).toBe('✓ off-box');
+ });
+
+ it('FE-COMP-MSTORETEST-004: marks a failed target and appends its error', () => {
+ render(
+
+ );
+
+ expect(screen.getByText('Test failed')).toBeInTheDocument();
+ expect(screen.getByText(/primary/).textContent).toBe('✓ primary');
+ expect(screen.getByText(/replica/).textContent).toBe('✗ replica — timeout');
+ });
+});
diff --git a/client/src/mobile/components/MStorageTestResult.tsx b/client/src/mobile/components/MStorageTestResult.tsx
new file mode 100644
index 000000000..fceaff056
--- /dev/null
+++ b/client/src/mobile/components/MStorageTestResult.tsx
@@ -0,0 +1,29 @@
+import type { StorageTestResponse } from '@trek/shared';
+
+import { useTranslation } from '../../i18n';
+
+/**
+ * The outcome of a storage backend test on the phone admin panel: a running
+ * note while it is in flight, then the verdict with one line per target.
+ * Renders nothing before the first test.
+ */
+export default function MStorageTestResult({ result }: { result: StorageTestResponse | 'running' | undefined }) {
+ const { t } = useTranslation();
+ if (result === 'running') {
+ return
{t('storage.test.running')}
;
+ }
+ if (!result) return null;
+ return (
+
+
+ {result.ok ? t('storage.test.ok') : t('storage.test.failed')}
+
+ {result.targets.map((target) => (
+
+ {target.ok ? '✓' : '✗'} {target.name}
+ {target.error ? ` — ${target.error}` : ''}
+
+ ))}
+
+ );
+}
diff --git a/client/src/mobile/screens/admin/MAdminStoragePanel.tsx b/client/src/mobile/screens/admin/MAdminStoragePanel.tsx
index d8d500161..d392997c9 100644
--- a/client/src/mobile/screens/admin/MAdminStoragePanel.tsx
+++ b/client/src/mobile/screens/admin/MAdminStoragePanel.tsx
@@ -14,6 +14,7 @@ import { CACHE_CATEGORIES, primaryNameOf } from '../../../components/Admin/stora
import { useBackendForm } from '../../../components/Admin/storage/useBackendForm'
import { categoryNames, migrationPromptLine, useStoragePanel } from '../../../components/Admin/storage/useStoragePanel'
import MToggle from '../../components/MToggle'
+import MStorageTestResult from '../../components/MStorageTestResult'
import MSetPickerSheet from '../settings/MSetPickerSheet'
import MConfirmSheet from '../settings/MConfirmSheet'
import { MSetSelectRow } from '../settings/MSettingsUi'
@@ -298,23 +299,7 @@ export default function MAdminStoragePanel(): React.ReactElement {
)}
- {result === 'running' ? (
- {t('storage.test.running')}
- ) : (
- result && (
-
-
- {result.ok ? t('storage.test.ok') : t('storage.test.failed')}
-
- {result.targets.map((target) => (
-
- {target.ok ? '✓' : '✗'} {target.name}
- {target.error ? ` — ${target.error}` : ''}
-
- ))}
-
- )
- )}
+
{row.mirrorTargets.length > 0 && (
{backfill?.status === 'running' ? (
@@ -401,23 +386,7 @@ export default function MAdminStoragePanel(): React.ReactElement {
{t('storage.actions.remove')}
- {result === 'running' ? (
- {t('storage.test.running')}
- ) : (
- result && (
-
-
- {result.ok ? t('storage.test.ok') : t('storage.test.failed')}
-
- {result.targets.map((target) => (
-
- {target.ok ? '✓' : '✗'} {target.name}
- {target.error ? ` — ${target.error}` : ''}
-
- ))}
-
- )
- )}
+
)
})}