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}` : ''} -

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