Fix data exports UI and scope format
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-01-06 12:59:38 +01:00
parent e82a10cb8b
commit a3538f6470
5 changed files with 96 additions and 4 deletions

View File

@@ -23,6 +23,7 @@ import { formatRelativeTime } from './lib/relativeTime';
import { useAdminTheme } from './theme';
import i18n from '../i18n';
import { triggerDownloadFromBlob } from './invite-layout/export-utils';
import { hasInProgressExports } from './lib/dataExports';
const statusTone: Record<DataExportSummary['status'], 'success' | 'warning' | 'muted'> = {
pending: 'warning',
@@ -89,6 +90,22 @@ export default function MobileDataExportsPage() {
void load();
}, [load]);
const hasInProgress = hasInProgressExports(exports);
React.useEffect(() => {
if (!hasInProgress) {
return;
}
const interval = window.setInterval(() => {
void load();
}, 5000);
return () => {
window.clearInterval(interval);
};
}, [hasInProgress, load]);
const handleRequest = async () => {
if (requesting) {
return;
@@ -152,7 +169,7 @@ export default function MobileDataExportsPage() {
value={scope}
onChange={(event) => setScope(event.target.value as 'tenant' | 'event')}
compact
style={{ minWidth: 160 }}
style={{ minWidth: 140, maxWidth: 180 }}
>
<option value="tenant">{t('dataExports.scopes.tenant', 'Tenant')}</option>
<option value="event">{t('dataExports.scopes.event', 'Event')}</option>
@@ -167,7 +184,7 @@ export default function MobileDataExportsPage() {
value={eventId ? String(eventId) : ''}
onChange={(event) => setEventId(event.target.value ? Number(event.target.value) : null)}
compact
style={{ minWidth: 200 }}
style={{ minWidth: 180, maxWidth: 220 }}
>
<option value="">{t('dataExports.fields.eventPlaceholder', 'Choose event')}</option>
{events.map((event) => (
@@ -187,7 +204,14 @@ export default function MobileDataExportsPage() {
{t('dataExports.fields.includeMediaHint', 'Bigger ZIP; choose when needed.')}
</Text>
</YStack>
<Switch checked={includeMedia} onCheckedChange={setIncludeMedia} />
<Switch
size="$3"
checked={includeMedia}
onCheckedChange={setIncludeMedia}
aria-label={t('dataExports.fields.includeMedia', 'Include raw media')}
>
<Switch.Thumb />
</Switch>
</XStack>
</YStack>
<CTAButton

View File

@@ -0,0 +1,22 @@
import { describe, expect, it } from 'vitest';
import { hasInProgressExports } from './dataExports';
describe('dataExports helpers', () => {
it('detects in-progress exports', () => {
const result = hasInProgressExports([
{ id: 1, status: 'pending' } as any,
{ id: 2, status: 'ready' } as any,
]);
expect(result).toBe(true);
});
it('returns false when exports are terminal', () => {
const result = hasInProgressExports([
{ id: 1, status: 'ready' } as any,
{ id: 2, status: 'failed' } as any,
]);
expect(result).toBe(false);
});
});

View File

@@ -0,0 +1,5 @@
import type { DataExportSummary } from '../../api';
export function hasInProgressExports(exports: DataExportSummary[]): boolean {
return exports.some((entry) => entry.status === 'pending' || entry.status === 'processing');
}