From 201de0bd5b6ad20b8a8bae054b76517e79ec0df2 Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 9 Oct 2026 15:44:13 +0200 Subject: [PATCH] refactor(storage): draw the phone backend test result with one component The phone storage panel rendered the same test result markup for regular and degenerate mirror backends. Both rows now render MStorageTestResult, with the same elements, classes and text as before. --- .../components/MStorageTestResult.test.tsx | 44 +++++++++++++++++++ .../mobile/components/MStorageTestResult.tsx | 29 ++++++++++++ .../screens/admin/MAdminStoragePanel.tsx | 37 ++-------------- 3 files changed, 76 insertions(+), 34 deletions(-) create mode 100644 client/src/mobile/components/MStorageTestResult.test.tsx create mode 100644 client/src/mobile/components/MStorageTestResult.tsx 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}` : ''} -

- ))} -
- ) - )} + ) })}