refactor: Replace legacy UI components with new App components across various files for improved consistency and maintainability
Build, Test, and Push CFDM Docker Image / test (push) Successful in 3m55s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Successful in 2m14s
Build, Test, and Push CFDM Docker Image / update-wiki (push) Successful in 7s
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped

This commit is contained in:
Denozordec
2026-06-25 16:54:21 +07:00
parent 9569c22e4d
commit 2147782ba6
46 changed files with 901 additions and 534 deletions
+17 -17
View File
@@ -14,14 +14,14 @@ import { EmptyState } from '@/components/empty-state'
import { StatusBadge } from '@/components/status-badge'
import { DataTableCard } from '@/components/data-table-card'
import { TableToolbar } from '@/components/table-toolbar'
import { Button } from '@cfdm/ui/components/button'
import { AppButton } from '@/components/app-button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@cfdm/ui/components/card'
AppCard,
AppCardContent,
AppCardDescription,
AppCardHeader,
AppCardTitle,
} from '@/components/app-card'
import {
ChartContainer,
ChartTooltip,
@@ -116,12 +116,12 @@ function CertificatesPage() {
onRetry={refetch}
skeleton={<TableSkeleton rows={5} columns={4} />}
>
<Card>
<CardHeader>
<CardTitle>Обзор статусов</CardTitle>
<CardDescription>Распределение сертификатов по статусам</CardDescription>
</CardHeader>
<CardContent>
<AppCard>
<AppCardHeader>
<AppCardTitle>Обзор статусов</AppCardTitle>
<AppCardDescription>Распределение сертификатов по статусам</AppCardDescription>
</AppCardHeader>
<AppCardContent>
{chartData.length > 0 ? (
<ChartContainer config={chartConfig} className="aspect-auto h-64 w-full">
<BarChart data={chartData}>
@@ -143,8 +143,8 @@ function CertificatesPage() {
description="Запустите проверку сертификатов"
/>
)}
</CardContent>
</Card>
</AppCardContent>
</AppCard>
<DataTableCard
title="Сертификаты"
description="Хосты с активными сервисами или ручным мониторингом"
@@ -159,9 +159,9 @@ function CertificatesPage() {
}
emptyAction={
isFilteredEmpty ? (
<Button variant="outline" onClick={() => setSearchQuery('')}>
<AppButton variant="outline" onClick={() => setSearchQuery('')}>
Сбросить фильтр
</Button>
</AppButton>
) : (
<LoadingButton
onClick={() => checkMutation.mutate()}
@@ -18,9 +18,9 @@ import { LoadingButton } from '@/components/loading-button'
import { TableSkeleton } from '@/components/table-skeleton'
import { TableToolbar } from '@/components/table-toolbar'
import { DnsRecordsTable } from '@/components/dns-records-table'
import { Button } from '@cfdm/ui/components/button'
import { Input } from '@cfdm/ui/components/input'
import { Field, FieldGroup, FieldLabel } from '@cfdm/ui/components/field'
import { AppButton } from '@/components/app-button'
import { AppInput } from '@/components/app-input'
import { AppField, AppFieldGroup, AppFieldLabel } from '@/components/app-field'
import {
Select,
SelectContent,
@@ -28,7 +28,7 @@ import {
SelectTrigger,
SelectValue,
} from '@cfdm/ui/components/select'
import { Switch } from '@cfdm/ui/components/switch'
import { AppSwitch } from '@/components/app-switch'
const DNS_TYPES = ['A', 'AAAA', 'CNAME', 'TXT', 'MX'] as const
@@ -158,9 +158,9 @@ function DnsPage() {
}
actions={
<>
<Button variant="outline" onClick={() => setSheetOpen(true)}>
<AppButton variant="outline" onClick={() => setSheetOpen(true)}>
Новая запись
</Button>
</AppButton>
<LoadingButton
onClick={() => syncMutation.mutate()}
isLoading={syncMutation.isPending}
@@ -197,11 +197,11 @@ function DnsPage() {
isEmpty={!hasRecords}
emptyAction={
isFilteredEmpty ? (
<Button variant="outline" onClick={() => setSearchQuery('')}>
<AppButton variant="outline" onClick={() => setSearchQuery('')}>
Сбросить фильтр
</Button>
</AppButton>
) : (
<Button onClick={() => setSheetOpen(true)}>Новая запись</Button>
<AppButton onClick={() => setSheetOpen(true)}>Новая запись</AppButton>
)
}
toolbar={
@@ -244,7 +244,7 @@ function DnsPage() {
</LoadingButton>
}
>
<FieldGroup>
<AppFieldGroup>
<FormFieldSimple label="Тип" htmlFor="record_type">
<Controller
control={form.control}
@@ -274,7 +274,7 @@ function DnsPage() {
htmlFor="name"
error={form.formState.errors.name}
>
<Input
<AppInput
id="name"
placeholder="@"
{...form.register('name')}
@@ -286,7 +286,7 @@ function DnsPage() {
htmlFor="content"
error={form.formState.errors.content}
>
<Input
<AppInput
id="content"
placeholder="192.168.1.1"
{...form.register('content')}
@@ -298,28 +298,28 @@ function DnsPage() {
htmlFor="ttl"
error={form.formState.errors.ttl}
>
<Input
<AppInput
id="ttl"
type="number"
{...form.register('ttl', { valueAsNumber: true })}
aria-invalid={!!form.formState.errors.ttl}
/>
</FormFieldSimple>
<Field className="flex flex-row items-center justify-between gap-4">
<FieldLabel htmlFor="proxied">Прокси Cloudflare</FieldLabel>
<AppField className="flex flex-row items-center justify-between gap-4">
<AppFieldLabel htmlFor="proxied">Прокси Cloudflare</AppFieldLabel>
<Controller
control={form.control}
name="proxied"
render={({ field }) => (
<Switch
<AppSwitch
id="proxied"
checked={field.value}
onCheckedChange={field.onChange}
/>
)}
/>
</Field>
</FieldGroup>
</AppField>
</AppFieldGroup>
</FormSheet>
</PageShell>
)
@@ -24,15 +24,15 @@ import {
} from '@/components/subdomain-edit-sheet'
import { StatusBadge } from '@/components/status-badge'
import { formatDate } from '@/lib/format'
import { Badge } from '@cfdm/ui/components/badge'
import { Button } from '@cfdm/ui/components/button'
import { AppBadge } from '@/components/app-badge'
import { AppButton } from '@/components/app-button'
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from '@cfdm/ui/components/card'
AppCard,
AppCardContent,
AppCardDescription,
AppCardHeader,
AppCardTitle,
} from '@/components/app-card'
import { LoadingButton } from '@/components/loading-button'
import { TableSkeleton } from '@/components/table-skeleton'
@@ -174,7 +174,7 @@ function DomainOverviewPage() {
>
Синхронизировать
</LoadingButton>
<Button
<AppButton
variant="outline"
nativeButton={false}
render={
@@ -186,7 +186,7 @@ function DomainOverviewPage() {
}
>
DNS-записи
</Button>
</AppButton>
</>
}
/>
@@ -209,12 +209,12 @@ function DomainOverviewPage() {
/>
<div className="grid gap-4 md:grid-cols-2">
<Card>
<CardHeader>
<CardTitle>Сводка</CardTitle>
<CardDescription>Основные параметры зоны</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-3 text-sm">
<AppCard>
<AppCardHeader>
<AppCardTitle>Сводка</AppCardTitle>
<AppCardDescription>Основные параметры зоны</AppCardDescription>
</AppCardHeader>
<AppCardContent className="flex flex-col gap-3 text-sm">
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">Статус</span>
<StatusBadge status={domain.status} />
@@ -222,7 +222,7 @@ function DomainOverviewPage() {
<div className="flex items-center justify-between gap-2">
<span className="text-muted-foreground">Группа</span>
{domain.group_id ? (
<Button
<AppButton
variant="link"
className="h-auto p-0"
nativeButton={false}
@@ -234,9 +234,9 @@ function DomainOverviewPage() {
}
>
Открыть группу
</Button>
</AppButton>
) : (
<Badge variant="outline">Без группы</Badge>
<AppBadge variant="outline">Без группы</AppBadge>
)}
</div>
<div className="flex items-center justify-between gap-2">
@@ -247,8 +247,8 @@ function DomainOverviewPage() {
{formatDate(domain.last_synced_at)}
</span>
</div>
</CardContent>
</Card>
</AppCardContent>
</AppCard>
<DomainBindingsCard bindings={bindings} />
</div>
@@ -261,14 +261,14 @@ function DomainOverviewPage() {
emptyIcon={GlobeIcon}
emptyAction={
<div className="flex flex-wrap justify-center gap-2">
<Button onClick={openCreateSheet}>Создать поддомен</Button>
<Button
<AppButton onClick={openCreateSheet}>Создать поддомен</AppButton>
<AppButton
variant="outline"
onClick={() => syncMutation.mutate()}
disabled={syncMutation.isPending}
>
Синхронизировать
</Button>
</AppButton>
</div>
}
toolbar={<DomainActionsBar onCreateSubdomain={openCreateSheet} />}
+12 -12
View File
@@ -22,9 +22,9 @@ import { FormSheet } from '@/components/form-sheet'
import { FormFieldSimple } from '@/components/form-field'
import { LoadingButton } from '@/components/loading-button'
import { TableSkeleton } from '@/components/table-skeleton'
import { Button } from '@cfdm/ui/components/button'
import { Input } from '@cfdm/ui/components/input'
import { FieldGroup } from '@cfdm/ui/components/field'
import { AppButton } from '@/components/app-button'
import { AppInput } from '@/components/app-input'
import { AppFieldGroup } from '@/components/app-field'
import {
Select,
SelectContent,
@@ -145,10 +145,10 @@ function DomainsPage() {
description={`${tableData.length} зон · ${tableData.reduce((sum, d) => sum + d.service_count, 0)} привязок сервисов`}
actions={
<>
<Button variant="outline" nativeButton={false} render={<Link to="/groups" />}>
<AppButton variant="outline" nativeButton={false} render={<Link to="/groups" />}>
Канбан групп
</Button>
<Button onClick={() => setSheetOpen(true)}>Импортировать домен</Button>
</AppButton>
<AppButton onClick={() => setSheetOpen(true)}>Импортировать домен</AppButton>
</>
}
/>
@@ -175,11 +175,11 @@ function DomainsPage() {
emptyIcon={GlobeIcon}
emptyAction={
isZeroResults ? (
<Button variant="outline" onClick={() => setFilterGroupId('')}>
<AppButton variant="outline" onClick={() => setFilterGroupId('')}>
Сбросить фильтр
</Button>
</AppButton>
) : (
<Button onClick={() => setSheetOpen(true)}>Импортировать домен</Button>
<AppButton onClick={() => setSheetOpen(true)}>Импортировать домен</AppButton>
)
}
>
@@ -214,13 +214,13 @@ function DomainsPage() {
</LoadingButton>
}
>
<FieldGroup>
<AppFieldGroup>
<FormFieldSimple
label="Имя зоны"
htmlFor="zone_name"
error={form.formState.errors.zone_name}
>
<Input
<AppInput
id="zone_name"
placeholder="example.com"
{...form.register('zone_name')}
@@ -245,7 +245,7 @@ function DomainsPage() {
</SelectContent>
</Select>
</FormFieldSimple>
</FieldGroup>
</AppFieldGroup>
</FormSheet>
</PageShell>
)
+5 -5
View File
@@ -22,7 +22,7 @@ import { DomainGroupEditSheet } from '@/components/domain-group-edit-sheet'
import { GroupsBoard } from '@/components/groups-board/groups-board'
import { GroupsBoardSkeleton } from '@/components/groups-board/groups-board-skeleton'
import { useGroupsBoard } from '@/hooks/use-groups-board'
import { Button } from '@cfdm/ui/components/button'
import { AppButton } from '@/components/app-button'
export const Route = createFileRoute('/_auth/groups')({
loader: ({ context: { queryClient } }) =>
@@ -128,9 +128,9 @@ function GroupsPage() {
title="Группы доменов"
description="Перетащите домен в группу или создайте новую группу для организации зон"
actions={
<Button onClick={() => setCreateSheetOpen(true)}>
<AppButton onClick={() => setCreateSheetOpen(true)}>
Добавить группу
</Button>
</AppButton>
}
/>
@@ -147,9 +147,9 @@ function GroupsPage() {
title="Группы не найдены"
description="Создайте группу и назначьте домены при импорте или перетаскиванием на доске."
action={
<Button onClick={() => setCreateSheetOpen(true)}>
<AppButton onClick={() => setCreateSheetOpen(true)}>
Добавить группу
</Button>
</AppButton>
}
/>
) : (
+11 -11
View File
@@ -13,7 +13,7 @@ import { StatusBadge } from '@/components/status-badge'
import { DataTableCard } from '@/components/data-table-card'
import { TableSkeleton } from '@/components/table-skeleton'
import { TableToolbar } from '@/components/table-toolbar'
import { Button } from '@cfdm/ui/components/button'
import { AppButton } from '@/components/app-button'
import {
Table,
TableBody,
@@ -76,13 +76,13 @@ function GroupDetailPage() {
: 'Домены в группе'
}
actions={
<Button
<AppButton
variant="outline"
nativeButton={false}
render={<Link to="/groups" />}
>
К группам
</Button>
</AppButton>
}
/>
<QueryState
@@ -110,17 +110,17 @@ function GroupDetailPage() {
isEmpty={!hasRecords}
emptyAction={
isFilteredEmpty ? (
<Button variant="outline" onClick={() => setSearchQuery('')}>
<AppButton variant="outline" onClick={() => setSearchQuery('')}>
Сбросить фильтр
</Button>
</AppButton>
) : (
<Button
<AppButton
variant="outline"
nativeButton={false}
render={<Link to="/groups" />}
>
Открыть канбан групп
</Button>
</AppButton>
)
}
toolbar={
@@ -149,7 +149,7 @@ function GroupDetailPage() {
<StatusBadge status={domain.status} />
</TableCell>
<TableCell>
<Button
<AppButton
variant="link"
className="h-auto p-0 tabular-nums"
nativeButton={false}
@@ -161,10 +161,10 @@ function GroupDetailPage() {
}
>
{domain.service_count}
</Button>
</AppButton>
</TableCell>
<TableCell className="text-right">
<Button
<AppButton
variant="outline"
size="sm"
nativeButton={false}
@@ -176,7 +176,7 @@ function GroupDetailPage() {
}
>
Обзор
</Button>
</AppButton>
</TableCell>
</TableRow>
))}
+7 -7
View File
@@ -32,7 +32,7 @@ import { ServicesBoardSkeleton } from '@/components/services-board/services-boar
import { ServicesBulkToolbar } from '@/components/services-board/services-bulk-toolbar'
import { useServicesBoard } from '@/hooks/use-services-board'
import { useServicesSelection } from '@/hooks/use-services-selection'
import { Button } from '@cfdm/ui/components/button'
import { AppButton } from '@/components/app-button'
export const Route = createFileRoute('/_auth/services')({
validateSearch: (search: Record<string, unknown>) => ({
@@ -416,10 +416,10 @@ function ServicesPage() {
}
actions={
<div className="flex flex-wrap gap-2">
<Button variant="outline" onClick={() => setCreateGroupSheetOpen(true)}>
<AppButton variant="outline" onClick={() => setCreateGroupSheetOpen(true)}>
Добавить группу
</Button>
<Button onClick={() => handleOpenCreateService()}>Добавить сервис</Button>
</AppButton>
<AppButton onClick={() => handleOpenCreateService()}>Добавить сервис</AppButton>
</div>
}
/>
@@ -450,10 +450,10 @@ function ServicesPage() {
}
action={
<div className="flex flex-wrap justify-center gap-2">
<Button variant="outline" onClick={() => setCreateGroupSheetOpen(true)}>
<AppButton variant="outline" onClick={() => setCreateGroupSheetOpen(true)}>
Добавить группу
</Button>
<Button onClick={() => handleOpenCreateService()}>Добавить сервис</Button>
</AppButton>
<AppButton onClick={() => handleOpenCreateService()}>Добавить сервис</AppButton>
</div>
}
/>