Files
EvoBGP/apps/web/src/queries/modules.ts
T
Denozordec 821f342476
CI / changes (push) Successful in 7s
CI / commitlint (push) Skipped
CI / go (push) Skipped
CI / bird2 (push) Skipped
CI / openapi (push) Successful in 51s
CI / web (push) Successful in 1m26s
CI / release (push) Successful in 4m26s
feat(modules): enhance ModuleKpiCards and add update functionality for modules
Updated the ModuleKpiCards component to improve the display of KPI metrics by introducing a new entries count prop and simplifying the logic for displaying community and DoH information. Added a new mutation hook for updating modules, which includes success and error handling with toast notifications. Enhanced the ModuleDetailComponent to support editing modules with a new dialog and integrated the entries count into the KPI display.

Additionally, introduced a new helper function for generating short labels for DoH profiles, improving the overall user experience in module management.
2026-08-12 11:32:44 +07:00

79 lines
2.8 KiB
TypeScript

import { queryOptions, useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'
import { apiJSON, apiMutate } from '@/lib/api-client'
import { overviewKeys } from '@/queries/overview'
import type {
ModulePatch,
ModuleRow,
ModulesResponse,
Page,
} from '@/types/api'
export const modulesKeys = {
all: ['modules'] as const,
list: () => [...modulesKeys.all, 'list'] as const,
detail: (id: string) => [...modulesKeys.all, 'detail', id] as const,
domainEntries: (id: string) => [...modulesKeys.all, 'domain-entries', id] as const,
asEntries: (id: string) => [...modulesKeys.all, 'as-entries', id] as const,
cdnSources: (id: string) => [...modulesKeys.all, 'cdn-sources', id] as const,
ipRangeEntries: (id: string) => [...modulesKeys.all, 'ip-range-entries', id] as const,
}
function invalidateModules(qc: ReturnType<typeof useQueryClient>, id?: string) {
void qc.invalidateQueries({ queryKey: modulesKeys.all })
void qc.invalidateQueries({ queryKey: overviewKeys.modules() })
if (id) {
void qc.invalidateQueries({ queryKey: modulesKeys.detail(id) })
}
}
export function modulesListQueryOptions() {
return queryOptions<ModulesResponse>({
queryKey: modulesKeys.list(),
queryFn: () => apiJSON<ModulesResponse>('/v1/modules?limit=200'),
})
}
export function moduleDetailQueryOptions(id: string) {
return queryOptions<ModuleRow>({
queryKey: modulesKeys.detail(id),
queryFn: () => apiJSON<ModuleRow>(`/v1/modules/${id}`),
})
}
export type ModuleEntriesPage = Page<Record<string, unknown>>
export function moduleEntriesQueryOptions(id: string, type: ModuleRow['type']) {
const pathByType: Record<ModuleRow['type'], string> = {
DOMAINS: `/v1/modules/${id}/domain-entries?limit=500`,
AS_PREFIXES: `/v1/modules/${id}/as-entries?limit=500`,
CDN_CIDRS: `/v1/modules/${id}/cdn-sources?limit=500`,
IP_RANGES: `/v1/modules/${id}/ip-range-entries?limit=500`,
}
const path = pathByType[type]
const keyByType: Record<ModuleRow['type'], readonly string[]> = {
DOMAINS: modulesKeys.domainEntries(id),
AS_PREFIXES: modulesKeys.asEntries(id),
CDN_CIDRS: modulesKeys.cdnSources(id),
IP_RANGES: modulesKeys.ipRangeEntries(id),
}
return queryOptions<ModuleEntriesPage>({
queryKey: keyByType[type],
queryFn: () => apiJSON<ModuleEntriesPage>(path),
})
}
export function useUpdateModuleMutation() {
const qc = useQueryClient()
return useMutation({
mutationFn: ({ id, body }: { id: string; body: ModulePatch }) =>
apiMutate<ModuleRow>(`/v1/modules/${id}`, 'PATCH', body, { idempotent: false }),
onSuccess: (_data, vars) => {
toast.success('Модуль обновлён')
invalidateModules(qc, vars.id)
},
onError: (e) => toast.error(e instanceof Error ? e.message : 'Не удалось обновить модуль'),
})
}