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.
79 lines
2.8 KiB
TypeScript
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 : 'Не удалось обновить модуль'),
|
|
})
|
|
}
|