Adds frontend for cms page

This commit is contained in:
2026-06-30 23:23:50 +02:00
parent c156107cb1
commit 488ab821a7
38 changed files with 2047 additions and 39 deletions
@@ -0,0 +1,97 @@
import { useTranslation } from 'react-i18next';
import { MoreHorizontal } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Button } from '@/components/ui/button';
import type { CmsInstance, CmsInstanceStatus } from '@/api/types';
function statusBadgeVariant(status: CmsInstanceStatus) {
if (status === 'Available') return 'secondary';
if (status === 'NotAvailable') return 'destructive';
return 'outline';
}
function formatDate(iso: string | null): string {
if (!iso) return '—';
return new Date(iso).toLocaleString(undefined, { dateStyle: 'medium', timeStyle: 'short' });
}
interface CmsInstanceListProps {
instances: CmsInstance[];
onSetStatus: (instance: CmsInstance) => void;
}
export function CmsInstanceList({ instances, onSetStatus }: CmsInstanceListProps) {
const { t } = useTranslation();
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>{t('cms.table.name')}</TableHead>
<TableHead>{t('cms.table.url')}</TableHead>
<TableHead>{t('cms.table.status')}</TableHead>
<TableHead>{t('cms.table.lastContact')}</TableHead>
<TableHead>{t('cms.table.disableMessage')}</TableHead>
<TableHead>{t('cms.table.actions')}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{instances.map((instance) => (
<TableRow
key={instance.id}
data-testid="cms-instance-row"
className={instance.status === 'Inactive' ? 'opacity-50' : ''}
>
<TableCell>{instance.name}</TableCell>
<TableCell>{instance.url}</TableCell>
<TableCell>
<Badge
variant={statusBadgeVariant(instance.status)}
data-testid="cms-instance-status-badge"
>
{t(`cms.status.${instance.status}`)}
</Badge>
</TableCell>
<TableCell>{formatDate(instance.lastContactedAt)}</TableCell>
<TableCell>{instance.disableMessage ?? '—'}</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
data-testid="cms-instance-actions-trigger"
>
<MoreHorizontal className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem
data-testid="cms-instance-set-status"
onClick={() => onSetStatus(instance)}
>
{t('cms.actions.setStatus')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}