♻️ refactor(web): consolidate design-system primitives and responsive data views

This commit is contained in:
t0ng7u
2026-07-11 05:13:16 +08:00
parent 262ab93123
commit 0918bdb49a
451 changed files with 7295 additions and 7693 deletions
@@ -29,9 +29,17 @@ import { useTranslation } from 'react-i18next'
import { toast } from 'sonner'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { Button } from '@/components/design-system/button'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/design-system/table'
import { ErrorState } from '@/components/error-state'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { StatusBadge, type StatusVariant } from '@/components/status-badge'
import {
Popover,
PopoverContent,
@@ -41,14 +49,6 @@ import {
PopoverTrigger,
} from '@/components/ui/popover'
import { Skeleton } from '@/components/ui/skeleton'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import {
Tooltip,
TooltipContent,
@@ -73,9 +73,9 @@ const INSTANCE_SKELETON_KEYS = [
'system-instance-skeleton-3',
]
const STATUS_CLASS_NAME: Record<SystemInstanceStatus, string> = {
online: 'bg-success/10 text-success',
stale: 'bg-warning/10 text-warning',
const STATUS_VARIANT: Record<SystemInstanceStatus, StatusVariant> = {
online: 'success',
stale: 'warning',
}
const STATUS_DOT_CLASS_NAME: Record<SystemInstanceStatus, string> = {
@@ -296,18 +296,19 @@ function SystemInstancesList(props: SystemInstancesTableProps) {
{shouldConfigure && (
<Popover>
<PopoverTrigger
className='inline-flex shrink-0 rounded-full focus-visible:ring-2 focus-visible:outline-none'
aria-label={t('Configure NODE_NAME')}
>
<Badge
variant='outline'
className='border-warning/30 bg-warning/10 text-warning'
>
<AlertTriangle
className='size-3'
aria-hidden='true'
render={
<StatusBadge
render={<button type='button' />}
variant='warning'
appearance='outline'
aria-label={t('Configure NODE_NAME')}
/>
</Badge>
}
>
<AlertTriangle
data-icon='inline-start'
aria-hidden='true'
/>
</PopoverTrigger>
<PopoverContent align='start' className='w-80'>
<PopoverHeader>
@@ -346,31 +347,23 @@ function SystemInstancesList(props: SystemInstancesTableProps) {
</div>
</TableCell>
<TableCell className='py-2.5 align-middle'>
<Badge
variant='secondary'
className={cn(
'gap-1.5',
STATUS_CLASS_NAME[instance.status]
)}
>
<span
className={cn(
'size-1.5 rounded-full',
STATUS_DOT_CLASS_NAME[instance.status]
)}
aria-hidden='true'
/>
<StatusBadge variant={STATUS_VARIANT[instance.status]}>
{t(instance.status)}
</Badge>
</StatusBadge>
</TableCell>
<TableCell className='py-2.5 align-middle'>
<TooltipProvider delay={100}>
<Tooltip>
<TooltipTrigger
className='inline-flex shrink-0 rounded-full focus-visible:ring-2 focus-visible:outline-none'
aria-label={t('Node role')}
render={
<StatusBadge
render={<button type='button' />}
appearance='outline'
aria-label={t('Node role')}
/>
}
>
<Badge variant='outline'>{roleLabel(instance)}</Badge>
{roleLabel(instance)}
</TooltipTrigger>
<TooltipContent>
{t(roleDescriptionKey(instance))}
@@ -650,7 +643,6 @@ export function SystemInstancesPanel() {
<Button
type='button'
variant='destructive'
size='sm'
onClick={() => setDeleteAllConfirmOpen(true)}
disabled={
staleInstances.length === 0 ||
@@ -676,7 +668,6 @@ export function SystemInstancesPanel() {
<Button
type='button'
variant='outline'
size='sm'
onClick={() => void instancesQuery.refetch()}
disabled={instancesQuery.isFetching}
aria-label={t('Refresh')}
@@ -18,13 +18,10 @@ For commercial licensing, please contact support@quantumnous.com
*/
import { useQuery } from '@tanstack/react-query'
import { ListChecks, RefreshCw } from 'lucide-react'
import type { ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import { ErrorState } from '@/components/error-state'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Progress } from '@/components/ui/progress'
import { Skeleton } from '@/components/ui/skeleton'
import { Button } from '@/components/design-system/button'
import {
Table,
TableBody,
@@ -32,7 +29,12 @@ import {
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
} from '@/components/design-system/table'
import { ErrorState } from '@/components/error-state'
import { StatusBadge, type StatusVariant } from '@/components/status-badge'
import { Badge } from '@/components/ui/badge'
import { Progress } from '@/components/ui/progress'
import { Skeleton } from '@/components/ui/skeleton'
import { listSystemTasks } from '@/features/system-settings/api'
import type {
SystemTask,
@@ -44,28 +46,20 @@ import { cn } from '@/lib/utils'
const TASK_LIMIT = 20
const ACTIVE_POLL_INTERVAL_MS = 8000
const TASK_SKELETON_KEYS = [
'system-task-skeleton-1',
'system-task-skeleton-2',
'system-task-skeleton-3',
'system-task-skeleton-4',
]
const STATUS_VARIANT: Record<SystemTaskStatus, 'secondary' | 'destructive'> = {
pending: 'secondary',
running: 'secondary',
succeeded: 'secondary',
const STATUS_VARIANT: Record<SystemTaskStatus, StatusVariant> = {
pending: 'warning',
running: 'info',
succeeded: 'success',
failed: 'destructive',
}
const STATUS_CLASS_NAME: Record<SystemTaskStatus, string> = {
pending: 'bg-warning/10 text-warning',
running: 'bg-info/10 text-info [&_span]:bg-info',
succeeded: 'bg-success/10 text-success',
failed: '',
}
const STATUS_DOT_CLASS_NAME: Record<SystemTaskStatus, string> = {
pending: 'bg-warning',
running: 'bg-info',
succeeded: 'bg-success',
failed: 'bg-destructive',
}
const PROGRESS_BAR_CLASS_NAME: Record<SystemTaskStatus, string> = {
pending: '[&_[data-slot=progress-indicator]]:bg-warning',
running: '[&_[data-slot=progress-indicator]]:bg-info',
@@ -145,19 +139,9 @@ function SystemTasksTable(props: SystemTasksTableProps) {
</div>
</TableCell>
<TableCell className='py-3 align-middle'>
<Badge
variant={STATUS_VARIANT[task.status]}
className={cn('gap-1.5', STATUS_CLASS_NAME[task.status])}
>
<span
className={cn(
'size-1.5 rounded-full',
STATUS_DOT_CLASS_NAME[task.status]
)}
aria-hidden='true'
/>
<StatusBadge variant={STATUS_VARIANT[task.status]}>
{t(task.status)}
</Badge>
</StatusBadge>
</TableCell>
<TableCell className='py-3 align-middle'>
<div className='flex items-center gap-2'>
@@ -227,6 +211,88 @@ export function SystemTasksPanel() {
const activeTasks = tasks.filter((task) => isActiveStatus(task.status))
const historyTasks = tasks.filter((task) => !isActiveStatus(task.status))
let tasksContent: ReactNode
if (loading) {
tasksContent = (
<div className='space-y-2 p-4 sm:p-5'>
{TASK_SKELETON_KEYS.map((key) => (
<Skeleton key={key} className='h-9 w-full rounded-md' />
))}
</div>
)
} else if (tasksQuery.isError) {
tasksContent = (
<ErrorState
title={t('We could not load system tasks.')}
description={
tasksQuery.error instanceof Error
? tasksQuery.error.message
: undefined
}
onRetry={() => {
void tasksQuery.refetch()
}}
className='min-h-[260px]'
/>
)
} else if (tasks.length === 0) {
tasksContent = (
<div className='px-4 py-10 text-center sm:px-5'>
<div className='bg-muted mx-auto mb-3 flex size-10 items-center justify-center rounded-lg'>
<ListChecks
className='text-muted-foreground size-5'
aria-hidden='true'
/>
</div>
<p className='text-muted-foreground text-sm'>
{t('No system tasks yet.')}
</p>
</div>
)
} else {
tasksContent = (
<div className='space-y-4 p-4 sm:p-5'>
<div>
<div className='mb-2 flex items-center justify-between gap-3'>
<div>
<h4 className='text-sm font-medium'>{t('Active Tasks')}</h4>
<p className='text-muted-foreground mt-0.5 text-xs'>
{t('Tasks currently pending or running.')}
</p>
</div>
<Badge variant='outline'>{activeTasks.length}</Badge>
</div>
{activeTasks.length > 0 ? (
<SystemTasksTable tasks={activeTasks} />
) : (
<div className='text-muted-foreground rounded-md border border-dashed px-4 py-6 text-center text-sm'>
{t('No active system tasks.')}
</div>
)}
</div>
<div>
<div className='mb-2 flex items-center justify-between gap-3'>
<div>
<h4 className='text-sm font-medium'>{t('Task History')}</h4>
<p className='text-muted-foreground mt-0.5 text-xs'>
{t('Recently completed or failed system task runs.')}
</p>
</div>
<Badge variant='outline'>{historyTasks.length}</Badge>
</div>
{historyTasks.length > 0 ? (
<SystemTasksTable tasks={historyTasks} />
) : (
<div className='text-muted-foreground rounded-md border border-dashed px-4 py-6 text-center text-sm'>
{t('No historical system tasks.')}
</div>
)}
</div>
</div>
)
}
return (
<section className='bg-card overflow-hidden rounded-lg border shadow-xs'>
<div className='flex flex-col gap-3 border-b px-4 py-3 sm:flex-row sm:items-center sm:justify-between sm:px-5'>
@@ -266,7 +332,6 @@ export function SystemTasksPanel() {
<Button
type='button'
variant='outline'
size='sm'
onClick={() => void tasksQuery.refetch()}
disabled={tasksQuery.isFetching}
aria-label={t('Refresh')}
@@ -281,80 +346,7 @@ export function SystemTasksPanel() {
</div>
</div>
<div aria-busy={tasksQuery.isFetching}>
{loading ? (
<div className='space-y-2 p-4 sm:p-5'>
{Array.from({ length: 4 }).map((_, i) => (
<Skeleton key={i} className='h-9 w-full rounded-md' />
))}
</div>
) : tasksQuery.isError ? (
<ErrorState
title={t('We could not load system tasks.')}
description={
tasksQuery.error instanceof Error
? tasksQuery.error.message
: undefined
}
onRetry={() => {
void tasksQuery.refetch()
}}
className='min-h-[260px]'
/>
) : tasks.length === 0 ? (
<div className='px-4 py-10 text-center sm:px-5'>
<div className='bg-muted mx-auto mb-3 flex size-10 items-center justify-center rounded-lg'>
<ListChecks
className='text-muted-foreground size-5'
aria-hidden='true'
/>
</div>
<p className='text-muted-foreground text-sm'>
{t('No system tasks yet.')}
</p>
</div>
) : (
<div className='space-y-4 p-4 sm:p-5'>
<div>
<div className='mb-2 flex items-center justify-between gap-3'>
<div>
<h4 className='text-sm font-medium'>{t('Active Tasks')}</h4>
<p className='text-muted-foreground mt-0.5 text-xs'>
{t('Tasks currently pending or running.')}
</p>
</div>
<Badge variant='outline'>{activeTasks.length}</Badge>
</div>
{activeTasks.length > 0 ? (
<SystemTasksTable tasks={activeTasks} />
) : (
<div className='text-muted-foreground rounded-md border border-dashed px-4 py-6 text-center text-sm'>
{t('No active system tasks.')}
</div>
)}
</div>
<div>
<div className='mb-2 flex items-center justify-between gap-3'>
<div>
<h4 className='text-sm font-medium'>{t('Task History')}</h4>
<p className='text-muted-foreground mt-0.5 text-xs'>
{t('Recently completed or failed system task runs.')}
</p>
</div>
<Badge variant='outline'>{historyTasks.length}</Badge>
</div>
{historyTasks.length > 0 ? (
<SystemTasksTable tasks={historyTasks} />
) : (
<div className='text-muted-foreground rounded-md border border-dashed px-4 py-6 text-center text-sm'>
{t('No historical system tasks.')}
</div>
)}
</div>
</div>
)}
</div>
<div aria-busy={tasksQuery.isFetching}>{tasksContent}</div>
</section>
)
}
+3 -3
View File
@@ -19,7 +19,7 @@ For commercial licensing, please contact support@quantumnous.com
import { useTranslation } from 'react-i18next'
import { SectionPageLayout } from '@/components/layout'
import { Badge } from '@/components/ui/badge'
import { StatusBadge } from '@/components/status-badge'
import { SystemInstancesPanel } from './components/system-instances-panel'
import { SystemTasksPanel } from './components/system-tasks-panel'
@@ -32,9 +32,9 @@ export function SystemInfo() {
<SectionPageLayout.Title>
<span className='inline-flex min-w-0 items-center gap-2'>
<span className='truncate'>{t('System Info')}</span>
<Badge variant='outline' className='shrink-0'>
<StatusBadge appearance='outline' className='shrink-0'>
Root
</Badge>
</StatusBadge>
</span>
</SectionPageLayout.Title>
<SectionPageLayout.Content>