chore: Update package.json and pnpm-lock.yaml to add husky for Git hooks; enhance Docker workflow with pnpm setup and linting steps; refactor various components to utilize new form components and improve UI consistency.
Build, Test, and Push CFDM Docker Image / test (push) Successful in 4m5s
Build, Test, and Push CFDM Docker Image / build-and-push (push) Successful in 2m26s
Build, Test, and Push CFDM Docker Image / update-wiki (push) Successful in 8s
Build, Test, and Push CFDM Docker Image / create-release (push) Has been skipped

This commit is contained in:
Denozordec
2026-06-25 15:47:29 +07:00
parent 3632bd25e4
commit 9569c22e4d
31 changed files with 1125 additions and 547 deletions
+112 -77
View File
@@ -3,6 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useMemo, useState } from 'react'
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { GlobeIcon } from 'lucide-react'
import { toast } from 'sonner'
import { api } from '@/lib/api-client'
import { createDomainSchema, type CreateDomainInput } from '@/lib/schemas'
@@ -14,15 +15,16 @@ import {
} from '@/queries'
import { PageHeader } from '@/components/page-header'
import { PageShell } from '@/components/page-shell'
import { QueryState } from '@/components/query-state'
import { DataTableCard } from '@/components/data-table-card'
import { DomainsDataTable, type DomainTableRow } from '@/components/domains-data-table'
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 {
Field,
FieldGroup,
FieldLabel,
} from '@cfdm/ui/components/field'
import { FieldGroup } from '@cfdm/ui/components/field'
import {
Select,
SelectContent,
@@ -30,15 +32,6 @@ import {
SelectTrigger,
SelectValue,
} from '@cfdm/ui/components/select'
import {
Sheet,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
} from '@cfdm/ui/components/sheet'
import { Spinner } from '@cfdm/ui/components/spinner'
export const Route = createFileRoute('/_auth/domains/')({
loader: ({ context: { queryClient } }) =>
@@ -56,7 +49,13 @@ function DomainsPage() {
const listGroupId =
filterGroupId && filterGroupId !== 'none' ? Number(filterGroupId) : undefined
const queryClient = useQueryClient()
const { data: domains } = useQuery(domainsListQueryOptions(listGroupId))
const {
data: domains,
isLoading,
isError,
error,
refetch,
} = useQuery(domainsListQueryOptions(listGroupId))
const { data: groups } = useQuery(groupsQueryOptions())
const groupItems = useMemo(
@@ -102,12 +101,12 @@ function DomainsPage() {
deleteMutation.mutate(domain.id)
}
const handleCreate = form.handleSubmit((values) => {
const handleCreate = (values: CreateDomainInput) => {
createMutation.mutate({
zone_name: values.zone_name.trim(),
group_id: importGroupId ? Number(importGroupId) : undefined,
})
})
}
const handleImportGroupChange = (value: string | null) => {
const next = value === 'none' || !value ? '' : value
@@ -135,6 +134,10 @@ function DomainsPage() {
[filteredDomains],
)
const hasActiveFilter = filterGroupId !== ''
const isZeroResults = hasActiveFilter && tableData.length === 0 && (domains?.length ?? 0) > 0
const isTrulyEmpty = tableData.length === 0 && !hasActiveFilter
return (
<PageShell>
<PageHeader
@@ -150,68 +153,100 @@ function DomainsPage() {
}
/>
<DataTableCard
title="Список доменов"
description="Импортированные зоны Cloudflare"
<QueryState
isLoading={isLoading}
isError={isError}
error={error}
onRetry={refetch}
skeleton={<TableSkeleton />}
>
<DomainsDataTable
data={tableData}
groupFilterItems={groupItems}
groupFilterValue={filterGroupId || 'all'}
onGroupFilterChange={handleFilterGroupChange}
onDelete={handleDeleteDomain}
isDeleting={deleteMutation.isPending}
/>
</DataTableCard>
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
<SheetContent>
<SheetHeader>
<SheetTitle>Импорт домена</SheetTitle>
<SheetDescription>
Добавить зону из аккаунта Cloudflare в менеджер
</SheetDescription>
</SheetHeader>
<form onSubmit={handleCreate} className="flex flex-col gap-4 px-4">
<FieldGroup>
<Field>
<FieldLabel htmlFor="zone_name">Имя зоны</FieldLabel>
<Input
id="zone_name"
placeholder="example.com"
{...form.register('zone_name')}
aria-invalid={!!form.formState.errors.zone_name}
/>
</Field>
<Field>
<FieldLabel htmlFor="import_group_id">Группа</FieldLabel>
<Select
items={groupItems}
value={importGroupId || 'none'}
onValueChange={handleImportGroupChange}
>
<SelectTrigger id="import_group_id" className="w-full">
<SelectValue placeholder="Без группы" />
</SelectTrigger>
<SelectContent>
{groupItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</Field>
</FieldGroup>
<SheetFooter>
<Button type="submit" disabled={createMutation.isPending} className="w-full">
{createMutation.isPending && <Spinner data-icon="inline-start" />}
{createMutation.isPending ? 'Импорт…' : 'Импортировать'}
<DataTableCard
title="Список доменов"
description="Импортированные зоны Cloudflare"
isEmpty={isTrulyEmpty || isZeroResults}
emptyTitle={
isZeroResults ? 'Ничего не найдено' : 'Домены не импортированы'
}
emptyDescription={
isZeroResults
? 'По выбранному фильтру группы нет подходящих зон'
: 'Импортируйте зону из аккаунта Cloudflare'
}
emptyIcon={GlobeIcon}
emptyAction={
isZeroResults ? (
<Button variant="outline" onClick={() => setFilterGroupId('')}>
Сбросить фильтр
</Button>
</SheetFooter>
</form>
</SheetContent>
</Sheet>
) : (
<Button onClick={() => setSheetOpen(true)}>Импортировать домен</Button>
)
}
>
{!isTrulyEmpty && !isZeroResults && (
<DomainsDataTable
data={tableData}
groupFilterItems={groupItems}
groupFilterValue={filterGroupId || 'all'}
onGroupFilterChange={handleFilterGroupChange}
onDelete={handleDeleteDomain}
isDeleting={deleteMutation.isPending}
/>
)}
</DataTableCard>
</QueryState>
<FormSheet
open={sheetOpen}
onOpenChange={setSheetOpen}
title="Импорт домена"
description="Добавить зону из аккаунта Cloudflare в менеджер"
form={form}
onSubmit={handleCreate}
footer={
<LoadingButton
type="submit"
className="w-full"
isLoading={createMutation.isPending}
loadingLabel="Импорт…"
>
Импортировать
</LoadingButton>
}
>
<FieldGroup>
<FormFieldSimple
label="Имя зоны"
htmlFor="zone_name"
error={form.formState.errors.zone_name}
>
<Input
id="zone_name"
placeholder="example.com"
{...form.register('zone_name')}
aria-invalid={!!form.formState.errors.zone_name}
/>
</FormFieldSimple>
<FormFieldSimple label="Группа" htmlFor="import_group_id">
<Select
items={groupItems}
value={importGroupId || 'none'}
onValueChange={handleImportGroupChange}
>
<SelectTrigger id="import_group_id" className="w-full">
<SelectValue placeholder="Без группы" />
</SelectTrigger>
<SelectContent>
{groupItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</FormFieldSimple>
</FieldGroup>
</FormSheet>
</PageShell>
)
}