feat(blocking): определять и показывать хостер в матрице блокировок
Docker / build (push) Failing after 26s
Docker / build (push) Failing after 26s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { Filter } from '@/components/reui/filters'
|
||||
import { filterCensorcheckRuns, groupRunsByService, collectServiceColumns, collectProbeColumns, shortHostLabel } from './blocking-filters'
|
||||
import type { CensorcheckRunDto } from './types'
|
||||
import { runHosterLabel, type CensorcheckRunDto } from './types'
|
||||
|
||||
const run = (overrides: Partial<CensorcheckRunDto> = {}): CensorcheckRunDto => ({
|
||||
id: 'ccrun-1',
|
||||
@@ -88,6 +88,37 @@ describe('filterCensorcheckRuns', () => {
|
||||
]),
|
||||
).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('фильтрует по хостеру из прогона, если инвентарь пуст', () => {
|
||||
const unmatched = run({
|
||||
matchedVpsId: null,
|
||||
vps: null,
|
||||
detectedHoster: 'DigitalOcean',
|
||||
})
|
||||
expect(
|
||||
filterCensorcheckRuns([unmatched], [
|
||||
{ id: '1', field: 'hoster', operator: 'contains', values: ['digital'] },
|
||||
]),
|
||||
).toHaveLength(1)
|
||||
expect(
|
||||
filterCensorcheckRuns([unmatched], [
|
||||
{ id: '1', field: 'hoster', operator: 'contains', values: ['hetzner'] },
|
||||
]),
|
||||
).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('runHosterLabel', () => {
|
||||
it('предпочитает имя из инвентаря', () => {
|
||||
expect(runHosterLabel(run())).toBe('Hoster')
|
||||
expect(runHosterLabel(run({ detectedHoster: 'Hetzner' }))).toBe('Hoster')
|
||||
})
|
||||
|
||||
it('берёт detectedHoster если VPS не сматчен', () => {
|
||||
expect(runHosterLabel(run({ matchedVpsId: null, vps: null, detectedHoster: 'Hetzner' }))).toBe(
|
||||
'Hetzner',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('groupRunsByService', () => {
|
||||
|
||||
@@ -39,7 +39,7 @@ export function filterCensorcheckRuns(
|
||||
continue
|
||||
}
|
||||
if (filter.field === 'hoster') {
|
||||
const name = (run.vps?.providerName ?? '').toLowerCase()
|
||||
const name = `${run.vps?.providerName ?? ''} ${run.detectedHoster ?? ''}`.toLowerCase()
|
||||
const hit = values.some((value) => name.includes(value.toLowerCase()) || name === value.toLowerCase())
|
||||
if (!hit) return false
|
||||
continue
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from './blocking-filters'
|
||||
import { resolveServiceIcon, ServiceGlyph } from './service-icons'
|
||||
import { StatusMatrixCell } from './status-matrix-cell'
|
||||
import type { CensorcheckRunDto } from './types'
|
||||
import { runHosterLabel, type CensorcheckRunDto } from './types'
|
||||
|
||||
/** DNA data-grid-base-4: auto width + H-scroll + pin start. Preview: https://reui.io/preview/base/data-grid-base-4 */
|
||||
export const BLOCKING_MATRIX_GRID = {
|
||||
@@ -31,12 +31,14 @@ function vpsIdentityColumn(): DataGridColumn<CensorcheckRunDto> {
|
||||
icon: ServerIcon,
|
||||
enableHiding: false,
|
||||
enablePinning: true,
|
||||
size: 220,
|
||||
minSize: 180,
|
||||
size: 240,
|
||||
minSize: 200,
|
||||
sortValue: (row) => row.vps?.dns || row.probePublicIp,
|
||||
cell: (row) => {
|
||||
const title = row.vps?.dns || row.probePublicIp
|
||||
const ip = row.probePublicIp
|
||||
const hoster = runHosterLabel(row)
|
||||
const secondary = hoster ? `${ip} · ${hoster}` : ip
|
||||
const link = row.matchedVpsId ? (
|
||||
<Link
|
||||
to="/vps/$vpsId"
|
||||
@@ -49,7 +51,7 @@ function vpsIdentityColumn(): DataGridColumn<CensorcheckRunDto> {
|
||||
) : (
|
||||
<span className="font-medium">Unknown VPS</span>
|
||||
)
|
||||
return dataGridCellStack(link, ip)
|
||||
return dataGridCellStack(link, secondary)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { GlobeIcon, MapPinIcon, ServerIcon, ShieldAlertIcon } from 'lucide-react'
|
||||
import { Building2Icon, GlobeIcon, MapPinIcon, ServerIcon, ShieldAlertIcon } from 'lucide-react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
import {
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
CENSORCHECK_STATUS_LABELS,
|
||||
formatCheckedAt,
|
||||
formatVpsResources,
|
||||
runHosterLabel,
|
||||
type CensorcheckRunDto,
|
||||
} from './types'
|
||||
|
||||
@@ -67,6 +68,12 @@ export function CheckRunSheet({ run, open, onOpenChange }: CheckRunSheetProps) {
|
||||
</Link>
|
||||
) : undefined,
|
||||
},
|
||||
{
|
||||
id: 'hoster',
|
||||
icon: <Building2Icon />,
|
||||
label: 'Хостер',
|
||||
description: runHosterLabel(detail) || '—',
|
||||
},
|
||||
{
|
||||
id: 'geo',
|
||||
icon: <MapPinIcon />,
|
||||
|
||||
@@ -40,6 +40,7 @@ export type CensorcheckRunDto = {
|
||||
createdAt: string
|
||||
completedAt: string
|
||||
observedSourceIp: string | null
|
||||
detectedHoster?: string | null
|
||||
vps: CensorcheckVpsInfo | null
|
||||
results?: CensorcheckResultDto[]
|
||||
}
|
||||
@@ -67,12 +68,19 @@ export function formatCheckedAt(iso: string): string {
|
||||
return date.toLocaleString('ru-RU')
|
||||
}
|
||||
|
||||
export function runHosterLabel(run: CensorcheckRunDto): string {
|
||||
const inventory = run.vps?.providerName?.trim() ?? ''
|
||||
if (inventory) return inventory
|
||||
return run.detectedHoster?.trim() ?? ''
|
||||
}
|
||||
|
||||
export function runSearchText(run: CensorcheckRunDto): string {
|
||||
const parts = [
|
||||
run.probePublicIp,
|
||||
run.claimedPublicIp ?? '',
|
||||
run.vps?.dns ?? '',
|
||||
run.vps?.providerName ?? '',
|
||||
run.detectedHoster ?? '',
|
||||
run.vps?.country ?? '',
|
||||
...(run.results ?? []).map((row) => `${row.serviceKey} ${row.serviceLabel}`),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user