refactor(lookup): remove LookupSummaryKpi component and update LookupWizard
Deleted the LookupSummaryKpi component to streamline the lookup functionality. Updated the LookupWizard component to remove references to the deleted component and adjusted the layout to incorporate FrameFooter for improved user interaction. Modified API type documentation to reflect changes in the lookup membership wizard.
This commit is contained in:
@@ -1,62 +0,0 @@
|
|||||||
import { Globe, Layers, ListChecks, Radar } from 'lucide-react'
|
|
||||||
|
|
||||||
import { KpiStatGrid, type KpiStatItem } from '@/components/reui-kit'
|
|
||||||
import type { LookupResponse } from '@/types/api'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup summary KPI — stats-12 via KpiStatGrid.
|
|
||||||
* @see https://reui.io/preview/base/stats-12
|
|
||||||
*/
|
|
||||||
export function LookupSummaryKpi({ data }: { data: LookupResponse }) {
|
|
||||||
const entryCount = data.matches.filter((m) => m.layer === 'entry').length
|
|
||||||
const snapshotCount = data.matches.filter((m) => m.layer === 'snapshot').length
|
|
||||||
const resolvedCount = data.resolved_ips?.length ?? 0
|
|
||||||
|
|
||||||
const items: KpiStatItem[] = [
|
|
||||||
{
|
|
||||||
id: 'matched',
|
|
||||||
label: 'Результат',
|
|
||||||
value: data.matched ? 'Найдено' : 'Не найдено',
|
|
||||||
hint: data.normalized,
|
|
||||||
icon: <Radar aria-hidden />,
|
|
||||||
iconClassName: data.matched
|
|
||||||
? 'bg-success text-success-foreground [&_svg]:text-success-foreground'
|
|
||||||
: 'bg-muted text-muted-foreground [&_svg]:text-muted-foreground',
|
|
||||||
variant: data.matched ? 'default' : 'warning',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'entry',
|
|
||||||
label: 'Слой entry',
|
|
||||||
value: entryCount,
|
|
||||||
hint: 'сырые списки',
|
|
||||||
icon: <ListChecks aria-hidden />,
|
|
||||||
iconClassName: 'bg-info text-info-foreground [&_svg]:text-info-foreground',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'snapshot',
|
|
||||||
label: 'Слой snapshot',
|
|
||||||
value: snapshotCount,
|
|
||||||
hint: 'материализация',
|
|
||||||
icon: <Layers aria-hidden />,
|
|
||||||
iconClassName: 'bg-focus text-focus-foreground [&_svg]:text-focus-foreground',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
if (data.query_kind === 'domain') {
|
|
||||||
items.push({
|
|
||||||
id: 'resolved',
|
|
||||||
label: 'DNS IP',
|
|
||||||
value: resolvedCount,
|
|
||||||
hint: resolvedCount > 0 ? data.resolved_ips?.slice(0, 3).join(', ') : 'нет A/AAAA',
|
|
||||||
icon: <Globe aria-hidden />,
|
|
||||||
iconClassName: 'bg-primary text-primary-foreground [&_svg]:text-primary-foreground',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<KpiStatGrid
|
|
||||||
items={items}
|
|
||||||
aria-label={`Запрос: ${data.query_kind} · ${data.query}`}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -7,12 +7,10 @@ import { Button } from '@evobgp/ui/components/button'
|
|||||||
import { LookupAddStep } from '@/components/lookup/lookup-add-step'
|
import { LookupAddStep } from '@/components/lookup/lookup-add-step'
|
||||||
import { LookupMatchesGrid } from '@/components/lookup/lookup-matches-grid'
|
import { LookupMatchesGrid } from '@/components/lookup/lookup-matches-grid'
|
||||||
import { LookupSearchForm } from '@/components/lookup/lookup-search-form'
|
import { LookupSearchForm } from '@/components/lookup/lookup-search-form'
|
||||||
import { LookupSummaryKpi } from '@/components/lookup/lookup-summary-kpi'
|
|
||||||
import { EmptyState } from '@/components/empty-state'
|
import { EmptyState } from '@/components/empty-state'
|
||||||
import { QueryState } from '@/components/query-state'
|
import { QueryState } from '@/components/query-state'
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
AlertAction,
|
|
||||||
AlertDescription,
|
AlertDescription,
|
||||||
AlertTitle,
|
AlertTitle,
|
||||||
} from '@/components/reui/alert'
|
} from '@/components/reui/alert'
|
||||||
@@ -31,11 +29,12 @@ import {
|
|||||||
import {
|
import {
|
||||||
Frame,
|
Frame,
|
||||||
FrameDescription,
|
FrameDescription,
|
||||||
|
FrameFooter,
|
||||||
FrameHeader,
|
FrameHeader,
|
||||||
FramePanel,
|
FramePanel,
|
||||||
FrameTitle,
|
FrameTitle,
|
||||||
} from '@/components/reui/frame'
|
} from '@/components/reui/frame'
|
||||||
import { SectionCardsSkeleton, TableSkeleton } from '@/components/skeletons'
|
import { TableSkeleton } from '@/components/skeletons'
|
||||||
import { sessionCanWriteModules } from '@/lib/auth'
|
import { sessionCanWriteModules } from '@/lib/auth'
|
||||||
import { authSessionQueryOptions } from '@/queries/auth'
|
import { authSessionQueryOptions } from '@/queries/auth'
|
||||||
import { directoriesCommunitiesQueryOptions } from '@/queries/directories'
|
import { directoriesCommunitiesQueryOptions } from '@/queries/directories'
|
||||||
@@ -44,10 +43,10 @@ import { modulesListQueryOptions } from '@/queries/modules'
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup membership wizard — check → result → optional add.
|
* Lookup membership wizard — check → result → optional add.
|
||||||
* DNA: wizard-2 · surface frame · stepper.
|
* DNA: wizard-2 · surface frame · stepper · FrameFooter CTAs.
|
||||||
* @see https://reui.io/preview/base/wizard-2
|
* @see https://reui.io/preview/base/wizard-2
|
||||||
* @see https://reui.io/docs/components/base/stepper
|
* @see https://reui.io/docs/components/base/stepper
|
||||||
* @see https://reui.io/preview/base/stats-12
|
* @see https://reui.io/docs/components/base/frame
|
||||||
* @see https://reui.io/preview/base/data-grid-filtering-2
|
* @see https://reui.io/preview/base/data-grid-filtering-2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -216,12 +215,7 @@ export function LookupWizard({
|
|||||||
isError={lookupQ.isError}
|
isError={lookupQ.isError}
|
||||||
error={lookupQ.error}
|
error={lookupQ.error}
|
||||||
onRetry={() => void lookupQ.refetch()}
|
onRetry={() => void lookupQ.refetch()}
|
||||||
skeleton={
|
skeleton={<TableSkeleton rows={5} />}
|
||||||
<div className="flex flex-col gap-4 md:gap-6">
|
|
||||||
<SectionCardsSkeleton />
|
|
||||||
<TableSkeleton rows={5} />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{(result) => (
|
{(result) => (
|
||||||
<div className="flex flex-col gap-4 md:gap-6">
|
<div className="flex flex-col gap-4 md:gap-6">
|
||||||
@@ -231,7 +225,6 @@ export function LookupWizard({
|
|||||||
isPending={lookupQ.isFetching}
|
isPending={lookupQ.isFetching}
|
||||||
onSubmit={onSubmitQuery}
|
onSubmit={onSubmitQuery}
|
||||||
/>
|
/>
|
||||||
<LookupSummaryKpi data={result} />
|
|
||||||
|
|
||||||
{result.matched ? (
|
{result.matched ? (
|
||||||
<>
|
<>
|
||||||
@@ -242,66 +235,69 @@ export function LookupWizard({
|
|||||||
«{result.normalized}» найден в entries и/или snapshots
|
«{result.normalized}» найден в entries и/или snapshots
|
||||||
({result.match_count} совпад.).
|
({result.match_count} совпад.).
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
<AlertAction>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="xs"
|
|
||||||
onClick={resetToQuery}
|
|
||||||
>
|
|
||||||
Новая проверка
|
|
||||||
</Button>
|
|
||||||
</AlertAction>
|
|
||||||
</Alert>
|
</Alert>
|
||||||
<LookupMatchesGrid
|
<LookupMatchesGrid
|
||||||
items={result.matches}
|
items={result.matches}
|
||||||
isLoading={lookupQ.isFetching}
|
isLoading={lookupQ.isFetching}
|
||||||
/>
|
/>
|
||||||
|
<Frame spacing="sm" className="w-full">
|
||||||
|
<FrameFooter className="flex flex-wrap items-center justify-end gap-2">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={resetToQuery}
|
||||||
|
>
|
||||||
|
Новая проверка
|
||||||
|
</Button>
|
||||||
|
</FrameFooter>
|
||||||
|
</Frame>
|
||||||
</>
|
</>
|
||||||
) : canWrite ? (
|
) : canWrite ? (
|
||||||
<Alert variant="info">
|
<>
|
||||||
<Plus className="size-4" />
|
<Alert variant="info">
|
||||||
<AlertTitle>Не найдено в списках</AlertTitle>
|
<Plus className="size-4" />
|
||||||
<AlertDescription>
|
<AlertTitle>Не найдено в списках</AlertTitle>
|
||||||
«{result.normalized}» отсутствует. Добавить запись?
|
<AlertDescription>
|
||||||
</AlertDescription>
|
«{result.normalized}» отсутствует. Добавить запись?
|
||||||
<AlertAction>
|
</AlertDescription>
|
||||||
<Button
|
</Alert>
|
||||||
type="button"
|
<Frame spacing="sm" className="w-full">
|
||||||
size="xs"
|
<FrameFooter className="flex flex-wrap items-center justify-end gap-2">
|
||||||
onClick={() => void goToAdd()}
|
<Button
|
||||||
>
|
type="button"
|
||||||
Добавить
|
variant="outline"
|
||||||
</Button>
|
onClick={resetToQuery}
|
||||||
<Button
|
>
|
||||||
type="button"
|
Новая проверка
|
||||||
variant="outline"
|
</Button>
|
||||||
size="xs"
|
<Button type="button" onClick={() => goToAdd()}>
|
||||||
onClick={resetToQuery}
|
Добавить
|
||||||
>
|
</Button>
|
||||||
Новая проверка
|
</FrameFooter>
|
||||||
</Button>
|
</Frame>
|
||||||
</AlertAction>
|
</>
|
||||||
</Alert>
|
|
||||||
) : (
|
) : (
|
||||||
<Alert variant="warning">
|
<>
|
||||||
<ShieldAlert className="size-4" />
|
<Alert variant="warning">
|
||||||
<AlertTitle>Не найдено</AlertTitle>
|
<ShieldAlert className="size-4" />
|
||||||
<AlertDescription>
|
<AlertTitle>Не найдено</AlertTitle>
|
||||||
«{result.normalized}» отсутствует в списках. У вас нет
|
<AlertDescription>
|
||||||
права добавлять записи (нужно bgp:modules:write).
|
«{result.normalized}» отсутствует в списках. У вас нет
|
||||||
</AlertDescription>
|
права добавлять записи (нужно bgp:modules:write).
|
||||||
<AlertAction>
|
</AlertDescription>
|
||||||
<Button
|
</Alert>
|
||||||
type="button"
|
<Frame spacing="sm" className="w-full">
|
||||||
variant="outline"
|
<FrameFooter className="flex flex-wrap items-center justify-end gap-2">
|
||||||
size="xs"
|
<Button
|
||||||
onClick={resetToQuery}
|
type="button"
|
||||||
>
|
variant="outline"
|
||||||
Новая проверка
|
onClick={resetToQuery}
|
||||||
</Button>
|
>
|
||||||
</AlertAction>
|
Новая проверка
|
||||||
</Alert>
|
</Button>
|
||||||
|
</FrameFooter>
|
||||||
|
</Frame>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -340,35 +336,27 @@ export function LookupWizard({
|
|||||||
Повторная проверка обновлена. Можно посмотреть совпадения или
|
Повторная проверка обновлена. Можно посмотреть совпадения или
|
||||||
начать новый запрос.
|
начать новый запрос.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
<AlertAction>
|
</Alert>
|
||||||
<Button
|
{lookupQ.data?.matched ? (
|
||||||
type="button"
|
<LookupMatchesGrid
|
||||||
size="xs"
|
items={lookupQ.data.matches}
|
||||||
onClick={() => setStep(STEP_RESULT)}
|
isLoading={lookupQ.isFetching}
|
||||||
>
|
/>
|
||||||
К результату
|
) : null}
|
||||||
</Button>
|
<Frame spacing="sm" className="w-full">
|
||||||
|
<FrameFooter className="flex flex-wrap items-center justify-end gap-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="xs"
|
|
||||||
onClick={resetToQuery}
|
onClick={resetToQuery}
|
||||||
>
|
>
|
||||||
Новая проверка
|
Новая проверка
|
||||||
</Button>
|
</Button>
|
||||||
</AlertAction>
|
<Button type="button" onClick={() => setStep(STEP_RESULT)}>
|
||||||
</Alert>
|
К результату
|
||||||
{lookupQ.data ? (
|
</Button>
|
||||||
<>
|
</FrameFooter>
|
||||||
<LookupSummaryKpi data={lookupQ.data} />
|
</Frame>
|
||||||
{lookupQ.data.matched ? (
|
|
||||||
<LookupMatchesGrid
|
|
||||||
items={lookupQ.data.matches}
|
|
||||||
isLoading={lookupQ.isFetching}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</StepperContent>
|
</StepperContent>
|
||||||
</StepperPanel>
|
</StepperPanel>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export type BgpCommunityPatch = Partial<BgpCommunityCreate>
|
|||||||
export type CommunitiesResponse = Page<BgpCommunity>
|
export type CommunitiesResponse = Page<BgpCommunity>
|
||||||
|
|
||||||
// ---- Lookup (GET /v1/lookup) ----
|
// ---- Lookup (GET /v1/lookup) ----
|
||||||
/** @see https://reui.io/preview/base/stats-12 — KPI summary on /lookup */
|
/** @see https://reui.io/preview/base/wizard-2 — lookup membership wizard */
|
||||||
export type LookupQueryKind = 'ip' | 'domain' | 'cidr'
|
export type LookupQueryKind = 'ip' | 'domain' | 'cidr'
|
||||||
export type LookupLayer = 'entry' | 'snapshot'
|
export type LookupLayer = 'entry' | 'snapshot'
|
||||||
export type LookupMatchKind = 'ip_range' | 'domain' | 'prefix'
|
export type LookupMatchKind = 'ip_range' | 'domain' | 'prefix'
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user