82 lines
3.2 KiB
TypeScript
82 lines
3.2 KiB
TypeScript
import { Button, Input, Modal, Tag } from '@/components/ui';
|
|
import { formatDateTime } from '@/utils/dateTime';
|
|
import { connectionStatusLabelMap, formatLogDetail } from './channelModel';
|
|
import type { ChannelLogState } from './channelTypes';
|
|
|
|
export function ChannelLogModal({
|
|
logState,
|
|
keyword,
|
|
onKeywordChange,
|
|
onClose,
|
|
}: {
|
|
logState: ChannelLogState;
|
|
keyword: string;
|
|
onKeywordChange: (keyword: string) => void;
|
|
onClose: () => void;
|
|
}) {
|
|
const normalizedKeyword = keyword.trim().toLowerCase();
|
|
const filteredLogs = (logState.data?.logs ?? []).filter((log) =>
|
|
!normalizedKeyword
|
|
|| `${log.event} ${log.resourceId ?? ''} ${formatLogDetail(log.detail)}`.toLowerCase().includes(normalizedKeyword),
|
|
);
|
|
|
|
return (
|
|
<Modal
|
|
footer={<Button onClick={onClose} variant="ghost">关闭</Button>}
|
|
onClose={onClose}
|
|
open
|
|
size="xl"
|
|
title={<div className="template-modal-title"><h2>连接日志</h2><p>{logState.channel.name}</p></div>}
|
|
>
|
|
<div className="channel-log-modal">
|
|
{logState.data ? (
|
|
<div className="channel-connection-summary">
|
|
{logState.data.connectionStates.map((connection) => (
|
|
<article key={connection.id}>
|
|
<div>
|
|
<span>连接 ID</span>
|
|
<strong>{connection.connectionId}</strong>
|
|
</div>
|
|
<Tag tone={connection.status === 'connected' ? 'success' : connection.lastError ? 'danger' : 'info'}>
|
|
{connectionStatusLabelMap[connection.status] ?? connection.status}
|
|
</Tag>
|
|
<div>
|
|
<span>当前 / 期望</span>
|
|
<strong>{connection.currentConnections} / {connection.desiredConnections}</strong>
|
|
</div>
|
|
<div>
|
|
<span>最近心跳</span>
|
|
<strong>{formatDateTime(connection.lastHeartbeatAt)}</strong>
|
|
</div>
|
|
<div>
|
|
<span>自动重连</span>
|
|
<strong>{connection.reconnectCount} 次 / {formatDateTime(connection.nextReconnectAt)}</strong>
|
|
</div>
|
|
{connection.lastError ? <p>{connection.lastError}</p> : null}
|
|
</article>
|
|
))}
|
|
{logState.data.connectionStates.length === 0 ? <p className="muted">暂无连接状态回写</p> : null}
|
|
</div>
|
|
) : null}
|
|
<Input label="筛选日志" onChange={(event) => onKeywordChange(event.target.value)} placeholder="事件、资源或详情关键词" value={keyword} />
|
|
<div className="channel-log-list">
|
|
{filteredLogs.map((log) => (
|
|
<article className="channel-log-item" key={log.id}>
|
|
<div>
|
|
<strong>{log.event}</strong>
|
|
<span>{formatDateTime(log.time)}</span>
|
|
</div>
|
|
<div>
|
|
<span>{log.resourceId}</span>
|
|
<pre>{formatLogDetail(log.detail)}</pre>
|
|
</div>
|
|
</article>
|
|
))}
|
|
{logState.data && filteredLogs.length === 0 ? <p className="muted">未找到匹配的连接日志</p> : null}
|
|
{!logState.data ? <p className="muted">正在加载连接日志...</p> : null}
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
);
|
|
}
|