фикс разметки и кодировки

This commit is contained in:
dv 2026-05-05 12:27:12 +03:00
parent 3feb05ce0f
commit ecb3f6b524
3 changed files with 163 additions and 144 deletions

View file

@ -10,19 +10,19 @@ import { useDashboardMonitorSSE } from '../hooks/useDashboardMonitorSSE'
function formatAge(seconds: number | null | undefined): string {
if (seconds == null) return '-'
if (seconds < 60) return `${seconds}ñ`
if (seconds < 3600) return `${Math.floor(seconds / 60)}ì`
return `${Math.floor(seconds / 3600)}÷ ${Math.floor((seconds % 3600) / 60)}ì`
if (seconds < 60) return `${seconds}с`
if (seconds < 3600) return `${Math.floor(seconds / 60)}м`
return `${Math.floor(seconds / 3600)}ч ${Math.floor((seconds % 3600) / 60)}м`
}
function reasonLabel(reason: string): string {
const map: Record<string, string> = {
object_include_policy: 'Âêëþ÷åí ïîëèòèêîé îáúåêòà',
object_exclude_policy: 'Èñêëþ÷åí ïîëèòèêîé îáúåêòà',
inherit_default: 'Íàñëåäîâàíèå ïî óìîë÷àíèþ',
tag_policy_enabled: 'Âêëþ÷åí ïîëèòèêîé òåãîâ',
tag_policy_disabled: 'Èñêëþ÷åí ïîëèòèêîé òåãîâ',
scope_filtered: 'Âíå òåêóùåãî scope',
object_include_policy: 'Включен политикой объекта',
object_exclude_policy: 'Исключен политикой объекта',
inherit_default: 'Наследование по умолчанию',
tag_policy_enabled: 'Включен политикой тегов',
tag_policy_disabled: 'Исключен политикой тегов',
scope_filtered: 'Вне текущего scope',
}
return map[reason] ?? reason
}
@ -72,9 +72,9 @@ export function HomePage() {
const handleRunNow = async () => {
try {
await runNow.mutateAsync({ ...scope, force: true })
message.success('Ìîíèòîðèíã çàïóùåí')
message.success('Мониторинг запущен')
} catch {
message.error('Íå óäàëîñü çàïóñòèòü ìîíèòîðèíã')
message.error('Не удалось запустить мониторинг')
}
}
@ -82,7 +82,7 @@ export function HomePage() {
const columns = [
{
title: 'Îáúåêò',
title: 'Объект',
key: 'object',
render: (_: unknown, row: any) => (
<Space>
@ -99,12 +99,12 @@ export function HomePage() {
),
},
{
title: 'Ïðè÷èíà',
title: 'Причина',
key: 'reason',
render: (_: unknown, row: any) => <Typography.Text>{reasonLabel(row.inclusion_reason)}</Typography.Text>,
},
{
title: 'Óñòðîéñòâ',
title: 'Устройств',
dataIndex: 'device_count',
key: 'device_count',
},
@ -137,22 +137,26 @@ export function HomePage() {
return (
<div>
<Space style={{ width: '100%', justifyContent: 'space-between', marginBottom: 12 }} align="center">
<Row justify="space-between" align="middle" gutter={[8, 8]} style={{ marginBottom: 12 }}>
<Col>
<Typography.Title level={4} style={{ margin: 0 }}>
NOC Äåøáîðä
NOC Дешборд
</Typography.Title>
<Space>
<Button onClick={() => navigate(`/home/settings${scopeToSearch(scope)}`)}>Íàñòðîéêè ìîíèòîðèíãà</Button>
</Col>
<Col>
<Space wrap>
<Button onClick={() => navigate(`/home/settings${scopeToSearch(scope)}`)}>Настройки мониторинга</Button>
<Button type="primary" onClick={handleRunNow} loading={runNow.isPending}>
Çàïóñòèòü ñåé÷àñ
Запустить сейчас
</Button>
</Space>
</Space>
</Col>
</Row>
<Row gutter={12} style={{ marginBottom: 12 }}>
<Col span={5}>
<Row gutter={[12, 12]} style={{ marginBottom: 12 }}>
<Col xs={24} sm={12} lg={6}>
<Select
placeholder="Ãîðîä"
placeholder="Город"
allowClear
style={{ width: '100%' }}
options={(meta?.cities ?? []).map((c) => ({ value: c, label: c }))}
@ -160,9 +164,9 @@ export function HomePage() {
onChange={setCity}
/>
</Col>
<Col span={5}>
<Col xs={24} sm={12} lg={6}>
<Select
placeholder="Êëèåíò"
placeholder="Клиент"
allowClear
style={{ width: '100%' }}
options={(meta?.clients ?? []).map((c) => ({ value: c, label: c }))}
@ -170,10 +174,10 @@ export function HomePage() {
onChange={setClient}
/>
</Col>
<Col span={7}>
<Col xs={24} sm={12} lg={6}>
<Select
mode="multiple"
placeholder="Îáúåêòû"
placeholder="Объекты"
allowClear
style={{ width: '100%' }}
value={objectIds}
@ -181,10 +185,10 @@ export function HomePage() {
options={(objects ?? []).map((o) => ({ value: o.id, label: o.name }))}
/>
</Col>
<Col span={7}>
<Col xs={24} sm={12} lg={6}>
<Select
mode="multiple"
placeholder="Òåãè"
placeholder="Теги"
allowClear
style={{ width: '100%' }}
value={tagIds}
@ -197,9 +201,9 @@ export function HomePage() {
<Row gutter={12} style={{ marginBottom: 16 }}>
<Col>
<Typography.Text type="secondary">
Ñòàòóñ: {monitorStatus?.status ?? '-'}
Статус: {monitorStatus?.status ?? '-'}
{monitorStatus?.last_success_at
? ` · óñïåøíûé çàïóñê ${dayjs(monitorStatus.last_success_at).format('DD.MM HH:mm:ss')}`
? ` · успешный запуск ${dayjs(monitorStatus.last_success_at).format('DD.MM HH:mm:ss')}`
: ''}
</Typography.Text>
</Col>
@ -209,22 +213,22 @@ export function HomePage() {
<Alert type="error" showIcon style={{ marginBottom: 12 }} message={monitorStatus.last_error} />
)}
<Row gutter={12} style={{ marginBottom: 16 }}>
<Col span={6}>
<Card><Statistic title="Îáúåêòû" value={totals.objects} /></Card>
<Row gutter={[12, 12]} style={{ marginBottom: 16 }}>
<Col xs={24} sm={12} lg={6}>
<Card><Statistic title="Объекты" value={totals.objects} /></Card>
</Col>
<Col span={6}>
<Card><Statistic title="Â ìîíèòîðèíãå" value={summary?.included_count ?? totals.allowed_objects} /></Card>
<Col xs={24} sm={12} lg={6}>
<Card><Statistic title="В мониторинге" value={summary?.included_count ?? totals.allowed_objects} /></Card>
</Col>
<Col span={6}>
<Card><Statistic title="Âíå ìîíèòîðèíãà" value={summary?.excluded_count ?? totals.excluded_objects} /></Card>
<Col xs={24} sm={12} lg={6}>
<Card><Statistic title="Вне мониторинга" value={summary?.excluded_count ?? totals.excluded_objects} /></Card>
</Col>
<Col span={6}>
<Card><Statistic title="Óñòðîéñòâà" value={totals.devices} /></Card>
<Col xs={24} sm={12} lg={6}>
<Card><Statistic title="Устройства" value={totals.devices} /></Card>
</Col>
</Row>
<Card title="Ïðîáëåìíûå îáúåêòû" style={{ marginBottom: 16 }}>
<Card title="Проблемные объекты" style={{ marginBottom: 16 }}>
<Table
size="small"
dataSource={summary?.problem_objects ?? []}
@ -232,12 +236,13 @@ export function HomePage() {
columns={columns}
pagination={false}
loading={isLoading}
scroll={{ x: 900 }}
/>
</Card>
<Row gutter={12}>
<Col span={12}>
<Card title="Â ìîíèòîðèíãå" style={{ marginBottom: 16 }}>
<Row gutter={[12, 12]}>
<Col xs={24} xl={12}>
<Card title="В мониторинге" style={{ marginBottom: 16 }}>
<Table
size="small"
dataSource={summary?.included_objects ?? []}
@ -245,11 +250,12 @@ export function HomePage() {
columns={columns}
pagination={{ pageSize: 8 }}
loading={isLoading}
scroll={{ x: 900 }}
/>
</Card>
</Col>
<Col span={12}>
<Card title="Âíå ìîíèòîðèíãà" style={{ marginBottom: 16 }}>
<Col xs={24} xl={12}>
<Card title="Вне мониторинга" style={{ marginBottom: 16 }}>
<Table
size="small"
dataSource={summary?.excluded_objects ?? []}
@ -257,6 +263,7 @@ export function HomePage() {
columns={columns}
pagination={{ pageSize: 8 }}
loading={isLoading}
scroll={{ x: 900 }}
/>
</Card>
</Col>

View file

@ -2,6 +2,7 @@ import { ArrowLeftOutlined } from '@ant-design/icons'
import { Alert, Button, Card, Col, Row, Select, Space, Table, Tag, Typography } from 'antd'
import dayjs from 'dayjs'
import { useMemo, useState } from 'react'
import { useQueryClient } from '@tanstack/react-query'
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
import {
useDashboardObjectAvailability,
@ -12,16 +13,15 @@ import {
type DashboardScope,
} from '../api/dashboard'
import { useDashboardMonitorSSE } from '../hooks/useDashboardMonitorSSE'
import { useQueryClient } from '@tanstack/react-query'
function reasonLabel(reason: string): string {
const map: Record<string, string> = {
object_include_policy: 'Âêëþ÷åí ïîëèòèêîé îáúåêòà',
object_exclude_policy: 'Èñêëþ÷åí ïîëèòèêîé îáúåêòà',
inherit_default: 'Íàñëåäîâàíèå ïî óìîë÷àíèþ',
tag_policy_enabled: 'Âêëþ÷åí ïîëèòèêîé òåãîâ',
tag_policy_disabled: 'Èñêëþ÷åí ïîëèòèêîé òåãîâ',
scope_filtered: 'Âíå òåêóùåãî scope',
object_include_policy: 'Включен политикой объекта',
object_exclude_policy: 'Исключен политикой объекта',
inherit_default: 'Наследование по умолчанию',
tag_policy_enabled: 'Включен политикой тегов',
tag_policy_disabled: 'Исключен политикой тегов',
scope_filtered: 'Вне текущего scope',
}
return map[reason] ?? reason
}
@ -93,24 +93,28 @@ export function HomeObjectDetailPage() {
return (
<div>
<Space style={{ width: '100%', justifyContent: 'space-between', marginBottom: 12 }} align="center">
<Space>
<Row justify="space-between" align="middle" gutter={[8, 8]} style={{ marginBottom: 12 }}>
<Col>
<Space wrap>
<Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/home')}>
Íàçàä
Назад
</Button>
<Typography.Title level={4} style={{ margin: 0 }}>
{object?.object_name ?? `Îáúåêò #${objectId}`}
{object?.object_name ?? `Объект #${objectId}`}
</Typography.Title>
</Space>
<Space>
{object?.allowed ? <Tag color="green">Â ìîíèòîðèíãå</Tag> : <Tag color="red">Âíå ìîíèòîðèíãà</Tag>}
</Col>
<Col>
<Space wrap>
{object?.allowed ? <Tag color="green">В мониторинге</Tag> : <Tag color="red">Вне мониторинга</Tag>}
{object?.health_score != null && (
<Tag color={object.health_score >= 80 ? 'green' : object.health_score >= 60 ? 'orange' : 'red'}>
Health {object.health_score}
</Tag>
)}
</Space>
</Space>
</Col>
</Row>
{object && (
<Typography.Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
@ -123,43 +127,43 @@ export function HomeObjectDetailPage() {
type="info"
showIcon
style={{ marginBottom: 12 }}
message="Íåäîñòàòî÷íî äàííûõ äëÿ ãðàôèêà äîñòóïíîñòè â âûáðàííîì îêíå"
message="Недостаточно данных для графика доступности в выбранном окне"
/>
)}
<Row gutter={12} style={{ marginBottom: 16 }}>
<Col span={8}>
<Row gutter={[12, 12]} style={{ marginBottom: 16 }}>
<Col xs={24} sm={12} lg={8}>
<Card loading={summaryLoading}>
<Typography.Text type="secondary">Óñòðîéñòâ</Typography.Text>
<Typography.Text type="secondary">Устройств</Typography.Text>
<Typography.Title level={3} style={{ margin: 0 }}>{summary?.totals.devices ?? 0}</Typography.Title>
</Card>
</Col>
<Col span={8}>
<Col xs={24} sm={12} lg={8}>
<Card loading={summaryLoading}>
<Typography.Text type="secondary">Ïðîáëåìíûõ</Typography.Text>
<Typography.Text type="secondary">Проблемных</Typography.Text>
<Typography.Title level={3} style={{ margin: 0 }}>{summary?.totals.problem_devices ?? 0}</Typography.Title>
</Card>
</Col>
<Col span={8}>
<Col xs={24} sm={12} lg={8}>
<Card loading={availLoading}>
<Typography.Text type="secondary">Äîñòóïíîñòü ({window})</Typography.Text>
<Typography.Text type="secondary">Доступность ({window})</Typography.Text>
<Typography.Title level={3} style={{ margin: 0 }}>
{availability?.overall_availability_pct != null ? `${availability.overall_availability_pct}%` : '—'}
{availability?.overall_availability_pct != null ? `${availability.overall_availability_pct}%` : '—'}
</Typography.Title>
</Card>
</Col>
</Row>
<Card
title="Ãðàôèê äîñòóïíîñòè ïî Ping"
title="График доступности по Ping"
extra={
<Select
value={window}
onChange={(v) => setWindow(v as DashboardAvailabilityWindow)}
options={[
{ value: '24h', label: '24÷' },
{ value: '3d', label: '3ä' },
{ value: '7d', label: '7ä' },
{ value: '24h', label: '24ч' },
{ value: '3d', label: '3д' },
{ value: '7d', label: '7д' },
]}
style={{ width: 100 }}
/>
@ -169,13 +173,14 @@ export function HomeObjectDetailPage() {
<AvailabilityChart points={availability?.overall_series ?? []} />
</Card>
<Card title="Ñòàòóñ óñòðîéñòâ" style={{ marginBottom: 16 }}>
<Card title="Статус устройств" style={{ marginBottom: 16 }}>
<Table
loading={devicesLoading}
dataSource={devices?.devices ?? []}
rowKey="device_id"
size="small"
pagination={{ pageSize: 20 }}
scroll={{ x: 1000 }}
columns={[
{
title: 'IP / Hostname',
@ -183,11 +188,11 @@ export function HomeObjectDetailPage() {
render: (_: unknown, row: any) => (
<Space direction="vertical" size={0}>
<code>{row.ip}</code>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{row.hostname ?? '—'}</Typography.Text>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>{row.hostname ?? '—'}</Typography.Text>
</Space>
),
},
{ title: 'Êàòåãîðèÿ', dataIndex: 'category', key: 'category' },
{ title: 'Категория', dataIndex: 'category', key: 'category' },
{
title: 'Ping',
key: 'ping',
@ -197,8 +202,8 @@ export function HomeObjectDetailPage() {
{row.ping_status}
</Tag>
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
{row.ping_checked_at ? dayjs(row.ping_checked_at).format('DD.MM HH:mm:ss') : '—'}
{row.last_ping_ms != null ? ` · ${row.last_ping_ms}ms` : ''}
{row.ping_checked_at ? dayjs(row.ping_checked_at).format('DD.MM HH:mm:ss') : '—'}
{row.last_ping_ms != null ? ` · ${row.last_ping_ms}ms` : ''}
</Typography.Text>
</Space>
),
@ -211,37 +216,38 @@ export function HomeObjectDetailPage() {
<Tag color={row.disk_status === 'ok' ? 'green' : row.disk_status === 'warn' ? 'orange' : 'red'}>
{row.disk_status}{row.disk_max_pct != null ? ` (${row.disk_max_pct}%)` : ''}
</Tag>
) : '—',
) : '—',
},
{
title: 'Ïðîáëåìà',
title: 'Проблема',
key: 'problem',
render: (_: unknown, row: any) => row.has_problem ? <Tag color="red">Äà</Tag> : <Tag color="green">Íåò</Tag>,
render: (_: unknown, row: any) => row.has_problem ? <Tag color="red">Да</Tag> : <Tag color="green">Нет</Tag>,
},
]}
/>
</Card>
<Card title="Per-device äîñòóïíîñòü (âûáîðêà)">
<Card title="Per-device доступность (выборка)">
<Table
loading={availLoading}
dataSource={availability?.devices ?? []}
rowKey="device_id"
size="small"
pagination={{ pageSize: 10 }}
scroll={{ x: 900 }}
columns={[
{ title: 'IP', dataIndex: 'ip', key: 'ip', render: (v: string) => <code>{v}</code> },
{ title: 'Hostname', dataIndex: 'hostname', key: 'hostname', render: (v: string | null) => v ?? '—' },
{ title: 'Hostname', dataIndex: 'hostname', key: 'hostname', render: (v: string | null) => v ?? '—' },
{
title: 'Availability',
key: 'availability_pct',
render: (_: unknown, row: any) => row.availability_pct != null ? `${row.availability_pct}%` : '—',
render: (_: unknown, row: any) => row.availability_pct != null ? `${row.availability_pct}%` : '—',
},
{ title: 'Samples', dataIndex: 'samples', key: 'samples' },
{
title: 'Ïîñëåäíèé ñòàòóñ',
title: 'Последний статус',
key: 'last_status',
render: (_: unknown, row: any) => row.last_status ? <Tag>{row.last_status}</Tag> : '—',
render: (_: unknown, row: any) => row.last_status ? <Tag>{row.last_status}</Tag> : '—',
},
]}
/>

View file

@ -110,32 +110,36 @@ export function HomeSettingsPage() {
const handleRunNow = async () => {
try {
await runNow.mutateAsync({ force: true })
message.success('Ìîíèòîðèíã çàïóùåí')
message.success('Мониторинг запущен')
} catch {
message.error('Íå óäàëîñü çàïóñòèòü ìîíèòîðèíã')
message.error('Не удалось запустить мониторинг')
}
}
return (
<div>
<Space style={{ width: '100%', justifyContent: 'space-between', marginBottom: 12 }} align="center">
<Space>
<Row justify="space-between" align="middle" gutter={[8, 8]} style={{ marginBottom: 12 }}>
<Col>
<Space wrap>
<Button icon={<ArrowLeftOutlined />} onClick={() => navigate('/home')}>
Íàçàä
Назад
</Button>
<Typography.Title level={4} style={{ margin: 0 }}>
Íàñòðîéêè ìîíèòîðèíãà
Настройки мониторинга
</Typography.Title>
</Space>
</Col>
<Col>
<Button type="primary" onClick={handleRunNow} loading={runNow.isPending}>
Çàïóñòèòü ñåé÷àñ
Запустить сейчас
</Button>
</Space>
</Col>
</Row>
<Typography.Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
Ñòàòóñ: {monitorStatus?.status ?? '-'}
Статус: {monitorStatus?.status ?? '-'}
{monitorStatus?.last_success_at
? ` · óñïåøíûé çàïóñê ${dayjs(monitorStatus.last_success_at).format('DD.MM HH:mm:ss')}`
? ` · успешный запуск ${dayjs(monitorStatus.last_success_at).format('DD.MM HH:mm:ss')}`
: ''}
</Typography.Text>
@ -143,12 +147,12 @@ export function HomeSettingsPage() {
<Alert type="error" showIcon style={{ marginBottom: 12 }} message={monitorStatus.last_error} />
)}
<Card title="Ðàñïèñàíèå ïðîâåðîê" style={{ marginBottom: 16 }}>
<Card title="Расписание проверок" style={{ marginBottom: 16 }}>
<Space direction="vertical" style={{ width: '100%' }}>
{(checksData?.checks ?? []).map((check) => (
<Row key={check.check_key} gutter={12} align="middle">
<Col span={4}><Typography.Text strong>{check.check_key}</Typography.Text></Col>
<Col span={3}>
<Row key={check.check_key} gutter={[12, 12]} align="middle">
<Col xs={24} md={6}><Typography.Text strong>{check.check_key}</Typography.Text></Col>
<Col xs={24} md={4}>
<Switch
checked={check.enabled}
onChange={async (enabled) => {
@ -156,7 +160,7 @@ export function HomeSettingsPage() {
}}
/>
</Col>
<Col span={5}>
<Col xs={24} md={6}>
<InputNumber
min={30}
value={check.interval_sec_default}
@ -168,7 +172,7 @@ export function HomeSettingsPage() {
}}
/>
</Col>
<Col span={10}>
<Col xs={24} md={8}>
<Select
mode="multiple"
allowClear
@ -185,10 +189,10 @@ export function HomeSettingsPage() {
</Space>
</Card>
<Card title="Ïîëèòèêà ïî òåãàì" style={{ marginBottom: 16 }}>
<Card title="Политика по тегам" style={{ marginBottom: 16 }}>
<Row gutter={[12, 8]}>
{(tags ?? []).map((tag) => (
<Col span={8} key={tag.id}>
<Col xs={24} md={12} xl={8} key={tag.id}>
<Space>
<Tag color={tag.color}>{tag.name}</Tag>
<Switch
@ -204,16 +208,17 @@ export function HomeSettingsPage() {
</Row>
</Card>
<Card title="Ïîëèòèêà îáúåêòîâ è overrides" style={{ marginBottom: 16 }}>
<Card title="Политика объектов и overrides" style={{ marginBottom: 16 }}>
<Table
size="small"
rowKey="id"
pagination={{ pageSize: 8 }}
dataSource={objects ?? []}
scroll={{ x: 650 }}
columns={[
{ title: 'Îáúåêò', dataIndex: 'name', key: 'name' },
{ title: 'Объект', dataIndex: 'name', key: 'name' },
{
title: 'Ðåæèì',
title: 'Режим',
key: 'mode',
render: (_: unknown, row: any) => (
<Select
@ -237,14 +242,14 @@ export function HomeSettingsPage() {
<Space wrap>
<Select
placeholder="Îáúåêò"
placeholder="Объект"
style={{ width: 220 }}
value={overrideObjectId}
onChange={setOverrideObjectId}
options={(objects ?? []).map((o) => ({ value: o.id, label: o.name }))}
/>
<Select
placeholder="Ïðîâåðêà"
placeholder="Проверка"
style={{ width: 160 }}
value={overrideCheckKey}
onChange={setOverrideCheckKey}
@ -262,13 +267,13 @@ export function HomeSettingsPage() {
]}
/>
<InputNumber
placeholder="Èíòåðâàë (ñåê)"
placeholder="Интервал (сек)"
min={30}
value={overrideInterval}
onChange={(v) => setOverrideInterval(typeof v === 'number' ? v : undefined)}
/>
<Select
placeholder="Ðåæèì êàòåãîðèé"
placeholder="Режим категорий"
style={{ width: 170 }}
value={overrideCategoriesMode}
onChange={(v) => setOverrideCategoriesMode(v as OverrideCategoriesMode)}
@ -281,7 +286,7 @@ export function HomeSettingsPage() {
mode="multiple"
allowClear
disabled={overrideCategoriesMode !== 'custom'}
placeholder="Êàòåãîðèè override"
placeholder="Категории override"
style={{ width: 280 }}
value={overrideCategories}
onChange={setOverrideCategories}
@ -291,7 +296,7 @@ export function HomeSettingsPage() {
type="primary"
onClick={async () => {
if (!overrideObjectId || !overrideCheckKey) {
message.warning('Âûáåðèòå îáúåêò è ïðîâåðêó')
message.warning('Выберите объект и проверку')
return
}
await patchOverrides.mutateAsync([
@ -309,15 +314,15 @@ export function HomeSettingsPage() {
: null,
},
])
message.success('Override îáíîâëåí')
message.success('Override обновлен')
}}
>
Ñîõðàíèòü override
Сохранить override
</Button>
<Button
onClick={async () => {
if (!overrideObjectId || !overrideCheckKey) {
message.warning('Âûáåðèòå îáúåêò è ïðîâåðêó')
message.warning('Выберите объект и проверку')
return
}
await patchOverrides.mutateAsync([
@ -329,10 +334,10 @@ export function HomeSettingsPage() {
categories_override: null,
},
])
message.success('Override î÷èùåí')
message.success('Override очищен')
}}
>
Î÷èñòèòü override
Очистить override
</Button>
</Space>
@ -343,14 +348,15 @@ export function HomeSettingsPage() {
rowKey={(row) => `${row.object_id}:${row.check_key}`}
pagination={{ pageSize: 6 }}
dataSource={checksData?.object_overrides ?? []}
scroll={{ x: 900 }}
columns={[
{
title: 'Îáúåêò',
title: 'Объект',
key: 'object',
render: (_: unknown, row: DashboardObjectOverride) =>
objects?.find((o) => o.id === row.object_id)?.name ?? row.object_id,
},
{ title: 'Ïðîâåðêà', dataIndex: 'check_key', key: 'check_key' },
{ title: 'Проверка', dataIndex: 'check_key', key: 'check_key' },
{
title: 'Enabled',
key: 'enabled_override',
@ -358,13 +364,13 @@ export function HomeSettingsPage() {
row.enabled_override == null ? 'inherit' : row.enabled_override ? 'enabled' : 'disabled',
},
{
title: 'Èíòåðâàë',
title: 'Интервал',
key: 'interval_sec_override',
render: (_: unknown, row: DashboardObjectOverride) =>
row.interval_sec_override == null ? 'inherit' : `${row.interval_sec_override}s`,
},
{
title: 'Êàòåãîðèè',
title: 'Категории',
key: 'categories_override',
render: (_: unknown, row: DashboardObjectOverride) =>
row.categories_override == null