Compare commits
8 Commits
fix/multi-
...
fix/add-sp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3708e5fc75 | ||
|
|
1cf4504e75 | ||
|
|
bb0e37281e | ||
|
|
91c8b0fa12 | ||
|
|
4d95fd7ed7 | ||
|
|
1509c16fdb | ||
|
|
f7bdd3d677 | ||
|
|
57abf495c0 |
@@ -0,0 +1,71 @@
|
|||||||
|
.no-linked-spans {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linked-spans-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.item-key {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-wrapper {
|
||||||
|
display: flex;
|
||||||
|
padding: 2px 8px;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
max-width: 100%;
|
||||||
|
gap: 8px;
|
||||||
|
border-radius: 50px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-slate-500);
|
||||||
|
|
||||||
|
.item-value {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
letter-spacing: 0.56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.linked-spans-container {
|
||||||
|
.item {
|
||||||
|
.item-key {
|
||||||
|
color: var(--bg-ink-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-wrapper {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.item-value {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import './LinkedSpans.styles.scss';
|
||||||
|
|
||||||
|
import { Button, Tooltip, Typography } from 'antd';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
|
import { formUrlParams } from 'container/TraceDetail/utils';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { Span } from 'types/api/trace/getTraceV2';
|
||||||
|
|
||||||
|
import NoData from '../NoData/NoData';
|
||||||
|
|
||||||
|
interface LinkedSpansProps {
|
||||||
|
span: Span;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SpanReference {
|
||||||
|
traceId: string;
|
||||||
|
spanId: string;
|
||||||
|
refType: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function LinkedSpans(props: LinkedSpansProps): JSX.Element {
|
||||||
|
const { span } = props;
|
||||||
|
|
||||||
|
const getLink = useCallback((item: SpanReference): string | null => {
|
||||||
|
if (!item.traceId || !item.spanId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return `${ROUTES.TRACE}/${item.traceId}${formUrlParams({
|
||||||
|
spanId: item.spanId,
|
||||||
|
levelUp: 0,
|
||||||
|
levelDown: 0,
|
||||||
|
})}`;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Filter out CHILD_OF references as they are parent-child relationships
|
||||||
|
const linkedSpans =
|
||||||
|
span.references?.filter((ref: SpanReference) => ref.refType !== 'CHILD_OF') ||
|
||||||
|
[];
|
||||||
|
|
||||||
|
if (linkedSpans.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className="no-linked-spans">
|
||||||
|
<NoData name="linked spans" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="linked-spans-container">
|
||||||
|
{linkedSpans.map((item: SpanReference) => {
|
||||||
|
const link = getLink(item);
|
||||||
|
return (
|
||||||
|
<div className="item" key={item.spanId}>
|
||||||
|
<Typography.Text className="item-key" ellipsis>
|
||||||
|
Linked Span ID
|
||||||
|
</Typography.Text>
|
||||||
|
<div className="value-wrapper">
|
||||||
|
<Tooltip title={item.spanId}>
|
||||||
|
{link ? (
|
||||||
|
<Typography.Link href={link} className="item-value" ellipsis>
|
||||||
|
{item.spanId}
|
||||||
|
</Typography.Link>
|
||||||
|
) : (
|
||||||
|
<Button type="link" className="item-value" disabled>
|
||||||
|
{item.spanId}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LinkedSpans;
|
||||||
@@ -158,20 +158,29 @@
|
|||||||
border-bottom: 1px solid var(--bg-slate-400) !important;
|
border-bottom: 1px solid var(--bg-slate-400) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attributes-tab-btn {
|
.ant-tabs-tab {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 2px !important;
|
||||||
|
min-width: 36px;
|
||||||
|
height: 36px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
.attributes-tab-btn:hover {
|
|
||||||
background: unset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.events-tab-btn {
|
.attributes-tab-btn,
|
||||||
|
.events-tab-btn,
|
||||||
|
.linked-spans-tab-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 4px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.events-tab-btn:hover {
|
.attributes-tab-btn:hover,
|
||||||
|
.events-tab-btn:hover,
|
||||||
|
.linked-spans-tab-btn:hover {
|
||||||
background: unset;
|
background: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,3 +270,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.linked-spans-tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import { getTraceToLogsQuery } from 'container/TraceDetail/SelectedSpanDetails/c
|
|||||||
import createQueryParams from 'lib/createQueryParams';
|
import createQueryParams from 'lib/createQueryParams';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
|
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
|
||||||
import { Anvil, Bookmark, PanelRight, Search } from 'lucide-react';
|
import { Anvil, Bookmark, Link2, PanelRight, Search } from 'lucide-react';
|
||||||
import { Dispatch, SetStateAction, useState } from 'react';
|
import { Dispatch, SetStateAction, useState } from 'react';
|
||||||
import { Span } from 'types/api/trace/getTraceV2';
|
import { Span } from 'types/api/trace/getTraceV2';
|
||||||
import { formatEpochTimestamp } from 'utils/timeUtils';
|
import { formatEpochTimestamp } from 'utils/timeUtils';
|
||||||
|
|
||||||
import Attributes from './Attributes/Attributes';
|
import Attributes from './Attributes/Attributes';
|
||||||
import Events from './Events/Events';
|
import Events from './Events/Events';
|
||||||
|
import LinkedSpans from './LinkedSpans/LinkedSpans';
|
||||||
|
|
||||||
const FIVE_MINUTES_IN_MS = 5 * 60 * 1000;
|
const FIVE_MINUTES_IN_MS = 5 * 60 * 1000;
|
||||||
interface ISpanDetailsDrawerProps {
|
interface ISpanDetailsDrawerProps {
|
||||||
@@ -74,6 +75,19 @@ function SpanDetailsDrawer(props: ISpanDetailsDrawerProps): JSX.Element {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<Link2 size="14" />}
|
||||||
|
className="linked-spans-tab-btn"
|
||||||
|
>
|
||||||
|
Links
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
key: 'linked-spans',
|
||||||
|
children: <LinkedSpans span={span} />,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
const onLogsHandler = (): void => {
|
const onLogsHandler = (): void => {
|
||||||
|
|||||||
Reference in New Issue
Block a user