improve flow indication in table
This commit is contained in:
@@ -152,6 +152,8 @@ type PacketTableRow = PacketRow & {
|
|||||||
key: string;
|
key: string;
|
||||||
__kind: 'packet' | 'flow';
|
__kind: 'packet' | 'flow';
|
||||||
flow_packet_count?: number;
|
flow_packet_count?: number;
|
||||||
|
flow_packet_index?: number;
|
||||||
|
flow_has_siblings?: boolean;
|
||||||
children?: PacketTableRow[];
|
children?: PacketTableRow[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1103,11 +1105,14 @@ export default function PacketViewer(): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const latestPacket = [...flowPackets].sort(sortPacketsByTimestampDesc)[0];
|
const latestPacket = [...flowPackets].sort(sortPacketsByTimestampDesc)[0];
|
||||||
const children = sortedPackets.map((packet) => ({
|
const children = sortedPackets.map((packet, index) => ({
|
||||||
...packet,
|
...packet,
|
||||||
flow_id: flowId,
|
flow_id: flowId,
|
||||||
key: packetKey(packet),
|
key: packetKey(packet),
|
||||||
__kind: 'packet' as const,
|
__kind: 'packet' as const,
|
||||||
|
flow_packet_count: sortedPackets.length,
|
||||||
|
flow_packet_index: index + 1,
|
||||||
|
flow_has_siblings: sortedPackets.length > 1,
|
||||||
}));
|
}));
|
||||||
flowRows.push({
|
flowRows.push({
|
||||||
...latestPacket,
|
...latestPacket,
|
||||||
@@ -1127,21 +1132,45 @@ export default function PacketViewer(): ReactElement {
|
|||||||
{
|
{
|
||||||
title: 'Group',
|
title: 'Group',
|
||||||
key: 'group',
|
key: 'group',
|
||||||
width: 130,
|
width: 180,
|
||||||
render: (_: any, rec: PacketTableRow) =>
|
render: (_: any, rec: PacketTableRow) =>
|
||||||
rec.__kind === 'flow' ? (
|
rec.__kind === 'flow' ? (
|
||||||
<Space direction="vertical" size={0}>
|
<div className="packet-group-cell packet-group-cell-flow">
|
||||||
<Tag color="blue" style={{ width: 'fit-content', marginInlineEnd: 0 }}>
|
<div className="packet-group-title">
|
||||||
|
<Tag color="blue" style={{ marginInlineEnd: 0 }}>
|
||||||
Flow
|
Flow
|
||||||
</Tag>
|
</Tag>
|
||||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
<span className="packet-group-count">{rec.flow_packet_count ?? 0} packets</span>
|
||||||
{rec.flow_packet_count ?? 0} packets
|
</div>
|
||||||
|
<Text type="secondary" className="packet-group-subtitle">
|
||||||
|
{rec.flow_id ?? 'Grouped flow'}
|
||||||
</Text>
|
</Text>
|
||||||
</Space>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Text type="secondary" style={{ paddingLeft: 18 }}>
|
<div className={`packet-group-cell ${rec.flow_has_siblings ? 'packet-group-cell-child' : 'packet-group-cell-single'}`}>
|
||||||
Packet
|
{rec.flow_has_siblings ? (
|
||||||
|
<>
|
||||||
|
<div className="packet-child-rail" aria-hidden="true" />
|
||||||
|
<div className="packet-child-content">
|
||||||
|
<Tag color="default" style={{ marginInlineEnd: 0 }}>
|
||||||
|
Packet {rec.flow_packet_index ?? 1}/{rec.flow_packet_count ?? 1}
|
||||||
|
</Tag>
|
||||||
|
<Text type="secondary" className="packet-group-subtitle">
|
||||||
|
In expanded flow
|
||||||
</Text>
|
</Text>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Tag color="default" style={{ marginInlineEnd: 0 }}>
|
||||||
|
Single Packet
|
||||||
|
</Tag>
|
||||||
|
<Text type="secondary" className="packet-group-subtitle">
|
||||||
|
Not grouped into a flow
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -1332,16 +1361,21 @@ export default function PacketViewer(): ReactElement {
|
|||||||
{`
|
{`
|
||||||
.packet-viewer .ant-table-tbody > tr.packet-flow-row > td {
|
.packet-viewer .ant-table-tbody > tr.packet-flow-row > td {
|
||||||
background: #eef6ff;
|
background: #eef6ff;
|
||||||
border-top: 1px solid #cfe2ff;
|
border-top: 1px solid #c8dbff;
|
||||||
border-bottom: 1px solid #cfe2ff;
|
border-bottom: 1px solid #c8dbff;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(165, 194, 255, 0.24);
|
||||||
}
|
}
|
||||||
|
|
||||||
.packet-viewer .ant-table-tbody > tr.packet-child-row > td {
|
.packet-viewer .ant-table-tbody > tr.packet-child-row > td {
|
||||||
background: #fafcff;
|
background: #fbfdff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.packet-viewer .ant-table-tbody > tr.packet-child-row > td:first-child {
|
.packet-viewer .ant-table-tbody > tr.packet-standalone-row > td {
|
||||||
border-left: 3px solid #d6e4ff;
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .ant-table-tbody > tr.packet-child-row > td {
|
||||||
|
border-top-color: #edf2fb;
|
||||||
}
|
}
|
||||||
|
|
||||||
.packet-viewer .ant-table-row-expand-icon {
|
.packet-viewer .ant-table-row-expand-icon {
|
||||||
@@ -1355,6 +1389,102 @@ export default function PacketViewer(): ReactElement {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-cell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
min-height: 40px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-cell-flow {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-count {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d4f91;
|
||||||
|
background: rgba(214, 232, 255, 0.85);
|
||||||
|
border: 1px solid rgba(148, 186, 242, 0.65);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 1px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-subtitle {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.3;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-cell-child {
|
||||||
|
position: relative;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 10px;
|
||||||
|
padding-left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-child-rail {
|
||||||
|
width: 16px;
|
||||||
|
flex: 0 0 16px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-child-rail::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
top: -12px;
|
||||||
|
bottom: -12px;
|
||||||
|
width: 2px;
|
||||||
|
background: linear-gradient(180deg, #c7d9fb 0%, #dbe8ff 100%);
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-child-rail::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
top: 50%;
|
||||||
|
width: 12px;
|
||||||
|
height: 2px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: #c7d9fb;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-child-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
min-width: 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .packet-group-cell-single {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .ant-table-tbody > tr.packet-flow-row:hover > td {
|
||||||
|
background: #e7f1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .ant-table-tbody > tr.packet-child-row:hover > td {
|
||||||
|
background: #f4f8ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.packet-viewer .ant-table-tbody > tr.packet-standalone-row:hover > td {
|
||||||
|
background: #fafcff;
|
||||||
|
}
|
||||||
|
|
||||||
.packet-viewer .packet-mode-toggle.ant-segmented {
|
.packet-viewer .packet-mode-toggle.ant-segmented {
|
||||||
background: ${token.colorFillTertiary};
|
background: ${token.colorFillTertiary};
|
||||||
}
|
}
|
||||||
@@ -1464,7 +1594,13 @@ export default function PacketViewer(): ReactElement {
|
|||||||
<span style={{ display: 'inline-block', width: 24 }} />
|
<span style={{ display: 'inline-block', width: 24 }} />
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
rowClassName={(record: PacketTableRow) => (record.__kind === 'flow' ? 'packet-flow-row' : 'packet-child-row')}
|
rowClassName={(record: PacketTableRow) =>
|
||||||
|
record.__kind === 'flow'
|
||||||
|
? 'packet-flow-row'
|
||||||
|
: record.flow_has_siblings
|
||||||
|
? 'packet-child-row'
|
||||||
|
: 'packet-standalone-row'
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user