аааааааа
This commit is contained in:
parent
2cc1c71cfa
commit
b3b0bd2190
1 changed files with 86 additions and 9 deletions
|
|
@ -3,6 +3,7 @@ import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
DownloadOutlined,
|
DownloadOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
|
EyeOutlined,
|
||||||
PlayCircleOutlined,
|
PlayCircleOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
SettingOutlined,
|
SettingOutlined,
|
||||||
|
|
@ -27,7 +28,7 @@ import type { ColumnsType } from 'antd/es/table'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import 'dayjs/locale/ru'
|
import 'dayjs/locale/ru'
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useCallback, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
useSnapshotDashboard,
|
useSnapshotDashboard,
|
||||||
useSnapshotPolicies,
|
useSnapshotPolicies,
|
||||||
|
|
@ -413,6 +414,15 @@ function ObjectsTable({
|
||||||
rowKey="object_id"
|
rowKey="object_id"
|
||||||
size="small"
|
size="small"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
onRow={(record) => ({
|
||||||
|
onClick: () =>
|
||||||
|
setExpandedKeys(
|
||||||
|
expandedKeys.includes(record.object_id)
|
||||||
|
? expandedKeys.filter((k) => k !== record.object_id)
|
||||||
|
: [...expandedKeys, record.object_id]
|
||||||
|
),
|
||||||
|
style: { cursor: 'pointer' },
|
||||||
|
})}
|
||||||
expandable={{
|
expandable={{
|
||||||
expandedRowKeys: expandedKeys,
|
expandedRowKeys: expandedKeys,
|
||||||
onExpand: (expanded, record) =>
|
onExpand: (expanded, record) =>
|
||||||
|
|
@ -486,6 +496,9 @@ function DevicesList({
|
||||||
policyId: number
|
policyId: number
|
||||||
}) {
|
}) {
|
||||||
const { data: devices, isLoading } = useDashboardDevices(objId, policyId, true)
|
const { data: devices, isLoading } = useDashboardDevices(objId, policyId, true)
|
||||||
|
const [viewContent, setViewContent] = useState<string | null>(null)
|
||||||
|
const [viewTitle, setViewTitle] = useState('')
|
||||||
|
const contentRef = useRef<HTMLPreElement>(null)
|
||||||
|
|
||||||
const handleCopy = async (snapshotId: number) => {
|
const handleCopy = async (snapshotId: number) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -513,6 +526,30 @@ function DevicesList({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleView = async (device: DeviceSnapshotStatus) => {
|
||||||
|
if (!device.snapshot_id) return
|
||||||
|
try {
|
||||||
|
const content = await fetchSnapshotContent(device.snapshot_id)
|
||||||
|
setViewTitle(`${device.hostname || device.ip} — ${objName}`)
|
||||||
|
setViewContent(content)
|
||||||
|
} catch {
|
||||||
|
message.error('Ошибка при загрузке')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelectAll = useCallback((e: React.KeyboardEvent) => {
|
||||||
|
if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
|
||||||
|
e.preventDefault()
|
||||||
|
if (contentRef.current) {
|
||||||
|
const range = document.createRange()
|
||||||
|
range.selectNodeContents(contentRef.current)
|
||||||
|
const sel = window.getSelection()
|
||||||
|
sel?.removeAllRanges()
|
||||||
|
sel?.addRange(range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (isLoading) return <Typography.Text type="secondary">Загрузка...</Typography.Text>
|
if (isLoading) return <Typography.Text type="secondary">Загрузка...</Typography.Text>
|
||||||
if (!devices || devices.length === 0) return <Typography.Text type="secondary">Нет устройств</Typography.Text>
|
if (!devices || devices.length === 0) return <Typography.Text type="secondary">Нет устройств</Typography.Text>
|
||||||
|
|
||||||
|
|
@ -554,10 +591,18 @@ function DevicesList({
|
||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
width: 80,
|
width: 120,
|
||||||
render: (_, row) =>
|
render: (_, row) =>
|
||||||
row.snapshot_id ? (
|
row.snapshot_id ? (
|
||||||
<Space size="small">
|
<Space size="small">
|
||||||
|
<Tooltip title="Просмотр">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
icon={<EyeOutlined />}
|
||||||
|
onClick={() => handleView(row)}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
<Tooltip title="Скопировать">
|
<Tooltip title="Скопировать">
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
|
|
@ -580,12 +625,44 @@ function DevicesList({
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table
|
<>
|
||||||
dataSource={devices}
|
<Table
|
||||||
columns={columns}
|
dataSource={devices}
|
||||||
rowKey="device_id"
|
columns={columns}
|
||||||
size="small"
|
rowKey="device_id"
|
||||||
pagination={false}
|
size="small"
|
||||||
/>
|
pagination={false}
|
||||||
|
/>
|
||||||
|
<Modal
|
||||||
|
title={viewTitle}
|
||||||
|
open={viewContent !== null}
|
||||||
|
onCancel={() => setViewContent(null)}
|
||||||
|
footer={null}
|
||||||
|
width={800}
|
||||||
|
maskClosable
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
<div onKeyDown={handleSelectAll} tabIndex={0} style={{ outline: 'none' }}>
|
||||||
|
<pre
|
||||||
|
ref={contentRef}
|
||||||
|
style={{
|
||||||
|
background: '#1e1e1e',
|
||||||
|
color: '#d4d4d4',
|
||||||
|
padding: 16,
|
||||||
|
borderRadius: 6,
|
||||||
|
fontSize: 12,
|
||||||
|
lineHeight: 1.5,
|
||||||
|
maxHeight: '70vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
wordBreak: 'break-all',
|
||||||
|
margin: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{viewContent}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue