Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
632adaa63f | ||
|
|
cc80858952 |
@@ -12,14 +12,6 @@ import {
|
|||||||
AlertDescription,
|
AlertDescription,
|
||||||
AlertTitle,
|
AlertTitle,
|
||||||
} from '@/components/reui/alert'
|
} from '@/components/reui/alert'
|
||||||
import {
|
|
||||||
Frame,
|
|
||||||
FrameDescription,
|
|
||||||
FrameFooter,
|
|
||||||
FrameHeader,
|
|
||||||
FramePanel,
|
|
||||||
FrameTitle,
|
|
||||||
} from '@/components/reui/frame'
|
|
||||||
import { SelectMenu } from '@/components/select-field'
|
import { SelectMenu } from '@/components/select-field'
|
||||||
import { ApiError, apiMutate } from '@/lib/api-client'
|
import { ApiError, apiMutate } from '@/lib/api-client'
|
||||||
import type {
|
import type {
|
||||||
@@ -30,9 +22,8 @@ import type {
|
|||||||
} from '@/types/api'
|
} from '@/types/api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup wizard step 3 — choose module + community and create entry.
|
* Lookup wizard step 3 — module + community (bare content for single Frame).
|
||||||
* @see https://reui.io/preview/base/wizard-2
|
* @see https://reui.io/preview/base/wizard-2
|
||||||
* @see https://reui.io/docs/components/base/frame
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function hostPrefixFromIp(ip: string): string {
|
function hostPrefixFromIp(ip: string): string {
|
||||||
@@ -153,14 +144,14 @@ export function LookupAddStep({
|
|||||||
: hostPrefixFromIp(data.normalized)
|
: hostPrefixFromIp(data.normalized)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Frame spacing="sm" className="w-full">
|
<div className="flex flex-col gap-6">
|
||||||
<FrameHeader>
|
<div className="flex flex-col gap-1">
|
||||||
<FrameTitle>Добавить в списки</FrameTitle>
|
<h3 className="text-sm font-semibold">Добавить в списки</h3>
|
||||||
<FrameDescription>
|
<p className="text-muted-foreground text-sm">
|
||||||
«{valueLabel}» отсутствует в списках. Выберите модуль и community.
|
«{valueLabel}» отсутствует в списках. Выберите модуль и community.
|
||||||
</FrameDescription>
|
</p>
|
||||||
</FrameHeader>
|
</div>
|
||||||
<FramePanel className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel htmlFor="lookup-add-module">Модуль ({wantedType})</FieldLabel>
|
<FieldLabel htmlFor="lookup-add-module">Модуль ({wantedType})</FieldLabel>
|
||||||
<SelectMenu
|
<SelectMenu
|
||||||
@@ -181,8 +172,8 @@ export function LookupAddStep({
|
|||||||
communities={communities}
|
communities={communities}
|
||||||
nullable={data.query_kind === 'domain'}
|
nullable={data.query_kind === 'domain'}
|
||||||
/>
|
/>
|
||||||
</FramePanel>
|
</div>
|
||||||
<FrameFooter className="flex flex-wrap items-center justify-end gap-2">
|
<div className="flex flex-wrap items-center justify-end gap-2 border-t pt-4">
|
||||||
<Button type="button" variant="outline" onClick={onCancel}>
|
<Button type="button" variant="outline" onClick={onCancel}>
|
||||||
Назад
|
Назад
|
||||||
</Button>
|
</Button>
|
||||||
@@ -193,7 +184,7 @@ export function LookupAddStep({
|
|||||||
>
|
>
|
||||||
Добавить
|
Добавить
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
</FrameFooter>
|
</div>
|
||||||
</Frame>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { useNavigate } from '@tanstack/react-router'
|
|||||||
|
|
||||||
import { CategoryBadge } from '@/components/category-badge'
|
import { CategoryBadge } from '@/components/category-badge'
|
||||||
import { DataGridPrimaryCell } from '@/components/data-grid-cell'
|
import { DataGridPrimaryCell } from '@/components/data-grid-cell'
|
||||||
import { FrameDataGrid } from '@/components/reui-kit'
|
|
||||||
import { DataGridSection } from '@/components/data-grid-shell'
|
import { DataGridSection } from '@/components/data-grid-shell'
|
||||||
import { Badge } from '@/components/reui/badge'
|
import { Badge } from '@/components/reui/badge'
|
||||||
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
|
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
|
||||||
@@ -12,7 +11,8 @@ import { useClientDataGrid } from '@/hooks/use-client-data-grid'
|
|||||||
import type { LookupMatch } from '@/types/api'
|
import type { LookupMatch } from '@/types/api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup matches grid — data-grid-filtering-2 pattern.
|
* Lookup matches grid — bare section for wizard-2 single Frame.
|
||||||
|
* @see https://reui.io/preview/base/wizard-2
|
||||||
* @see https://reui.io/preview/base/data-grid-filtering-2
|
* @see https://reui.io/preview/base/data-grid-filtering-2
|
||||||
* @see https://reui.io/docs/components/base/badge
|
* @see https://reui.io/docs/components/base/badge
|
||||||
*/
|
*/
|
||||||
@@ -113,10 +113,13 @@ export function LookupMatchesGrid({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FrameDataGrid
|
<div className="flex flex-col gap-3">
|
||||||
title="Совпадения"
|
<div className="flex flex-col gap-px">
|
||||||
description="Entries и snapshots · клик по строке открывает модуль"
|
<h3 className="text-sm font-semibold">Совпадения</h3>
|
||||||
>
|
<p className="text-muted-foreground text-sm">
|
||||||
|
Entries и snapshots · клик по строке открывает модуль
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<DataGridSection
|
<DataGridSection
|
||||||
table={table}
|
table={table}
|
||||||
recordCount={filteredCount}
|
recordCount={filteredCount}
|
||||||
@@ -129,6 +132,6 @@ export function LookupMatchesGrid({
|
|||||||
void navigate({ to: '/modules/$moduleId', params: { moduleId: row.module_id } })
|
void navigate({ to: '/modules/$moduleId', params: { moduleId: row.module_id } })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</FrameDataGrid>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,10 @@ import {
|
|||||||
InputGroupAddon,
|
InputGroupAddon,
|
||||||
InputGroupInput,
|
InputGroupInput,
|
||||||
} from '@evobgp/ui/components/input-group'
|
} from '@evobgp/ui/components/input-group'
|
||||||
import {
|
|
||||||
Frame,
|
|
||||||
FrameDescription,
|
|
||||||
FrameHeader,
|
|
||||||
FramePanel,
|
|
||||||
FrameTitle,
|
|
||||||
} from '@/components/reui/frame'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup search form — Frame + InputGroup (form-7 pattern).
|
* Lookup search fields — bare form for wizard-2 single-Frame surface.
|
||||||
* @see https://reui.io/preview/base/form-7
|
* @see https://reui.io/preview/base/wizard-2
|
||||||
* @see https://reui.io/docs/components/base/frame
|
* @see https://reui.io/docs/components/base/frame
|
||||||
*/
|
*/
|
||||||
export function LookupSearchForm({
|
export function LookupSearchForm({
|
||||||
@@ -40,37 +33,27 @@ export function LookupSearchForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Frame spacing="sm" className="w-full">
|
<form onSubmit={handleSubmit} className="flex flex-col gap-4 sm:flex-row sm:items-end">
|
||||||
<FrameHeader>
|
<Field className="min-w-0 flex-1">
|
||||||
<FrameTitle>Проверка списка</FrameTitle>
|
<FieldLabel htmlFor="lookup-q">IP, CIDR или домен</FieldLabel>
|
||||||
<FrameDescription>
|
<InputGroup>
|
||||||
IP, CIDR или FQDN — поиск в entries и материализованных snapshots с community.
|
<InputGroupAddon align="inline-start">
|
||||||
</FrameDescription>
|
<Search aria-hidden />
|
||||||
</FrameHeader>
|
</InputGroupAddon>
|
||||||
<FramePanel>
|
<InputGroupInput
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4 sm:flex-row sm:items-end">
|
id="lookup-q"
|
||||||
<Field className="min-w-0 flex-1">
|
name="q"
|
||||||
<FieldLabel htmlFor="lookup-q">IP, CIDR или домен</FieldLabel>
|
value={value}
|
||||||
<InputGroup>
|
onChange={(e) => setValue(e.target.value)}
|
||||||
<InputGroupAddon align="inline-start">
|
placeholder="8.8.8.8, 203.0.113.0/24 или example.com"
|
||||||
<Search aria-hidden />
|
autoComplete="off"
|
||||||
</InputGroupAddon>
|
autoFocus
|
||||||
<InputGroupInput
|
/>
|
||||||
id="lookup-q"
|
</InputGroup>
|
||||||
name="q"
|
</Field>
|
||||||
value={value}
|
<Button type="submit" disabled={isPending || !value.trim()}>
|
||||||
onChange={(e) => setValue(e.target.value)}
|
Проверить
|
||||||
placeholder="8.8.8.8, 203.0.113.0/24 или example.com"
|
</Button>
|
||||||
autoComplete="off"
|
</form>
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
</InputGroup>
|
|
||||||
</Field>
|
|
||||||
<Button type="submit" disabled={isPending || !value.trim()}>
|
|
||||||
Проверить
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</FramePanel>
|
|
||||||
</Frame>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}`}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState, type ReactNode } from 'react'
|
||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
import { Check, Plus, Search, ShieldAlert } from 'lucide-react'
|
import { Check, Plus, Search, ShieldAlert } from 'lucide-react'
|
||||||
|
|
||||||
@@ -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'
|
||||||
@@ -35,7 +33,7 @@ import {
|
|||||||
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'
|
||||||
@@ -43,11 +41,10 @@ import { lookupKeys, lookupQueryOptions } from '@/queries/lookup'
|
|||||||
import { modulesListQueryOptions } from '@/queries/modules'
|
import { modulesListQueryOptions } from '@/queries/modules'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup membership wizard — check → result → optional add.
|
* Lookup membership wizard — one Frame (wizard-2), all content inside.
|
||||||
* DNA: wizard-2 · surface frame · stepper.
|
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -56,6 +53,14 @@ const STEP_RESULT = 2
|
|||||||
const STEP_ADD = 3
|
const STEP_ADD = 3
|
||||||
const STEP_DONE = 4
|
const STEP_DONE = 4
|
||||||
|
|
||||||
|
function WizardActions({ children }: { children: ReactNode }) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-wrap items-center justify-end gap-2 border-t pt-4">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function LookupWizard({
|
export function LookupWizard({
|
||||||
q,
|
q,
|
||||||
onSubmitQuery,
|
onSubmitQuery,
|
||||||
@@ -110,13 +115,14 @@ export function LookupWizard({
|
|||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4 md:gap-6">
|
<div className="flex flex-col gap-4 md:gap-6">
|
||||||
<Frame spacing="sm" className="w-full">
|
<Frame spacing="sm" className="w-full">
|
||||||
<FrameHeader>
|
<FramePanel className="flex flex-col gap-6">
|
||||||
<FrameTitle>Мастер проверки</FrameTitle>
|
<FrameHeader className="px-0 py-0">
|
||||||
<FrameDescription>
|
<FrameTitle>Мастер проверки</FrameTitle>
|
||||||
Проверка IP / CIDR / домена в списках, затем при необходимости — добавление.
|
<FrameDescription>
|
||||||
</FrameDescription>
|
Проверка IP / CIDR / домена в списках, затем при необходимости — добавление.
|
||||||
</FrameHeader>
|
</FrameDescription>
|
||||||
<FramePanel>
|
</FrameHeader>
|
||||||
|
|
||||||
<Stepper
|
<Stepper
|
||||||
value={step}
|
value={step}
|
||||||
onValueChange={setStep}
|
onValueChange={setStep}
|
||||||
@@ -185,21 +191,21 @@ export function LookupWizard({
|
|||||||
|
|
||||||
<StepperPanel>
|
<StepperPanel>
|
||||||
<StepperContent value={STEP_QUERY}>
|
<StepperContent value={STEP_QUERY}>
|
||||||
<LookupSearchForm
|
<div className="flex flex-col gap-6">
|
||||||
key={`form-${trimmed}`}
|
<LookupSearchForm
|
||||||
initialQuery={trimmed}
|
key={`form-${trimmed}`}
|
||||||
isPending={lookupQ.isFetching}
|
initialQuery={trimmed}
|
||||||
onSubmit={onSubmitQuery}
|
isPending={lookupQ.isFetching}
|
||||||
/>
|
onSubmit={onSubmitQuery}
|
||||||
{!trimmed ? (
|
/>
|
||||||
<div className="mt-4">
|
{!trimmed ? (
|
||||||
<EmptyState
|
<EmptyState
|
||||||
icon={<Search className="size-8" />}
|
icon={<Search className="size-8" />}
|
||||||
title="Введите IP, CIDR или домен"
|
title="Введите IP, CIDR или домен"
|
||||||
description="Например 8.8.8.8, 203.0.113.0/24 или example.com — проверка по entries и snapshots."
|
description="Например 8.8.8.8, 203.0.113.0/24 или example.com — проверка по entries и snapshots."
|
||||||
/>
|
/>
|
||||||
</div>
|
) : null}
|
||||||
) : null}
|
</div>
|
||||||
</StepperContent>
|
</StepperContent>
|
||||||
|
|
||||||
<StepperContent value={STEP_RESULT}>
|
<StepperContent value={STEP_RESULT}>
|
||||||
@@ -216,12 +222,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 +232,6 @@ export function LookupWizard({
|
|||||||
isPending={lookupQ.isFetching}
|
isPending={lookupQ.isFetching}
|
||||||
onSubmit={onSubmitQuery}
|
onSubmit={onSubmitQuery}
|
||||||
/>
|
/>
|
||||||
<LookupSummaryKpi data={result} />
|
|
||||||
|
|
||||||
{result.matched ? (
|
{result.matched ? (
|
||||||
<>
|
<>
|
||||||
@@ -242,66 +242,63 @@ 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}
|
||||||
/>
|
/>
|
||||||
|
<WizardActions>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
onClick={resetToQuery}
|
||||||
|
>
|
||||||
|
Новая проверка
|
||||||
|
</Button>
|
||||||
|
</WizardActions>
|
||||||
</>
|
</>
|
||||||
) : 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>
|
||||||
|
</Alert>
|
||||||
|
<WizardActions>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="xs"
|
variant="outline"
|
||||||
onClick={() => void goToAdd()}
|
onClick={resetToQuery}
|
||||||
>
|
>
|
||||||
|
Новая проверка
|
||||||
|
</Button>
|
||||||
|
<Button type="button" onClick={() => goToAdd()}>
|
||||||
Добавить
|
Добавить
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
</WizardActions>
|
||||||
type="button"
|
</>
|
||||||
variant="outline"
|
|
||||||
size="xs"
|
|
||||||
onClick={resetToQuery}
|
|
||||||
>
|
|
||||||
Новая проверка
|
|
||||||
</Button>
|
|
||||||
</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>
|
||||||
|
</Alert>
|
||||||
|
<WizardActions>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="xs"
|
|
||||||
onClick={resetToQuery}
|
onClick={resetToQuery}
|
||||||
>
|
>
|
||||||
Новая проверка
|
Новая проверка
|
||||||
</Button>
|
</Button>
|
||||||
</AlertAction>
|
</WizardActions>
|
||||||
</Alert>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -340,35 +337,21 @@ export function LookupWizard({
|
|||||||
Повторная проверка обновлена. Можно посмотреть совпадения или
|
Повторная проверка обновлена. Можно посмотреть совпадения или
|
||||||
начать новый запрос.
|
начать новый запрос.
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
<AlertAction>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
size="xs"
|
|
||||||
onClick={() => setStep(STEP_RESULT)}
|
|
||||||
>
|
|
||||||
К результату
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
variant="outline"
|
|
||||||
size="xs"
|
|
||||||
onClick={resetToQuery}
|
|
||||||
>
|
|
||||||
Новая проверка
|
|
||||||
</Button>
|
|
||||||
</AlertAction>
|
|
||||||
</Alert>
|
</Alert>
|
||||||
{lookupQ.data ? (
|
{lookupQ.data?.matched ? (
|
||||||
<>
|
<LookupMatchesGrid
|
||||||
<LookupSummaryKpi data={lookupQ.data} />
|
items={lookupQ.data.matches}
|
||||||
{lookupQ.data.matched ? (
|
isLoading={lookupQ.isFetching}
|
||||||
<LookupMatchesGrid
|
/>
|
||||||
items={lookupQ.data.matches}
|
|
||||||
isLoading={lookupQ.isFetching}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
<WizardActions>
|
||||||
|
<Button type="button" variant="outline" onClick={resetToQuery}>
|
||||||
|
Новая проверка
|
||||||
|
</Button>
|
||||||
|
<Button type="button" onClick={() => setStep(STEP_RESULT)}>
|
||||||
|
К результату
|
||||||
|
</Button>
|
||||||
|
</WizardActions>
|
||||||
</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