Compare commits
25 Commits
main
...
fix/traces
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ce2ef92fe | ||
|
|
0ca264237e | ||
|
|
debf130a1d | ||
|
|
645d0f2f6d | ||
|
|
1e041590d5 | ||
|
|
8781600a48 | ||
|
|
879796cb52 | ||
|
|
55249d68fc | ||
|
|
d809b351b9 | ||
|
|
5b0d90fcce | ||
|
|
be82703820 | ||
|
|
456b505b60 | ||
|
|
9fe9c7a6ff | ||
|
|
2bdefc1051 | ||
|
|
c632fb5ef0 | ||
|
|
bd42995de6 | ||
|
|
d0a8cc4de3 | ||
|
|
dd62215246 | ||
|
|
11a4f6ae96 | ||
|
|
bfaa9df636 | ||
|
|
50e83be4af | ||
|
|
5609398f53 | ||
|
|
f70e71070a | ||
|
|
ff8e2ab6d0 | ||
|
|
8121e61409 |
@@ -37,7 +37,6 @@
|
||||
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
background: var(--bg-ink-300);
|
||||
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
@@ -45,6 +44,12 @@
|
||||
border-bottom-right-radius: 0px;
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
font-size: 12px !important;
|
||||
line-height: 27px;
|
||||
&::placeholder {
|
||||
color: #888 !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useCopyToClipboard } from 'react-use';
|
||||
function CopyClipboardHOC({
|
||||
entityKey,
|
||||
textToCopy,
|
||||
tooltipText = 'Copy to clipboard',
|
||||
children,
|
||||
}: CopyClipboardHOCProps): JSX.Element {
|
||||
const [value, setCopy] = useCopyToClipboard();
|
||||
@@ -31,7 +32,7 @@ function CopyClipboardHOC({
|
||||
<span onClick={onClick} role="presentation" tabIndex={-1}>
|
||||
<Popover
|
||||
placement="top"
|
||||
content={<span style={{ fontSize: '0.9rem' }}>Copy to clipboard</span>}
|
||||
content={<span style={{ fontSize: '0.9rem' }}>{tooltipText}</span>}
|
||||
>
|
||||
{children}
|
||||
</Popover>
|
||||
@@ -42,7 +43,11 @@ function CopyClipboardHOC({
|
||||
interface CopyClipboardHOCProps {
|
||||
entityKey: string | undefined;
|
||||
textToCopy: string;
|
||||
tooltipText?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default CopyClipboardHOC;
|
||||
CopyClipboardHOC.defaultProps = {
|
||||
tooltipText: 'Copy to clipboard',
|
||||
};
|
||||
|
||||
@@ -251,6 +251,10 @@
|
||||
.ant-input-group-addon {
|
||||
border-top-left-radius: 0px !important;
|
||||
border-top-right-radius: 0px !important;
|
||||
background: var(--bg-ink-300);
|
||||
color: var(--bg-vanilla-400);
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
|
||||
@@ -194,6 +194,7 @@ export const QueryBuilderV2 = memo(function QueryBuilderV2({
|
||||
showOnlyWhereClause={showOnlyWhereClause}
|
||||
isListViewPanel={isListViewPanel}
|
||||
signalSource={config?.signalSource || ''}
|
||||
queriesCount={currentQuery.builder.queryData.length}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -236,6 +236,10 @@
|
||||
background: var(--bg-ink-100) !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
.cm-activeLine > span {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,6 +275,9 @@
|
||||
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
.cm-placeholder {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
border-radius: 2px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 12px;
|
||||
color: #888 !important;
|
||||
|
||||
&.error {
|
||||
.cm-editor {
|
||||
@@ -231,6 +233,9 @@
|
||||
.query-aggregation-interval-input {
|
||||
input {
|
||||
max-width: 120px;
|
||||
&::placeholder {
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
.add-trace-operator-button, .add-new-query-button, .add-formula-button {
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
background: var(--bg-ink-300);
|
||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import './QueryFooter.styles.scss';
|
||||
|
||||
/* eslint-disable react/require-default-props */
|
||||
import { Button, Tooltip, Typography } from 'antd';
|
||||
import { DraftingCompass, Plus, Sigma } from 'lucide-react';
|
||||
@@ -22,8 +24,7 @@ export default function QueryFooter({
|
||||
<div className="qb-add-new-query">
|
||||
<Tooltip title={<div style={{ textAlign: 'center' }}>Add New Query</div>}>
|
||||
<Button
|
||||
className="add-new-query-button periscope-btn secondary"
|
||||
type="text"
|
||||
className="add-new-query-button periscope-btn "
|
||||
icon={<Plus size={16} />}
|
||||
onClick={addNewBuilderQuery}
|
||||
/>
|
||||
@@ -49,7 +50,7 @@ export default function QueryFooter({
|
||||
}
|
||||
>
|
||||
<Button
|
||||
className="add-formula-button periscope-btn secondary"
|
||||
className="add-formula-button periscope-btn "
|
||||
icon={<Sigma size={16} />}
|
||||
onClick={addNewFormula}
|
||||
>
|
||||
@@ -77,7 +78,7 @@ export default function QueryFooter({
|
||||
}
|
||||
>
|
||||
<Button
|
||||
className="add-trace-operator-button periscope-btn secondary"
|
||||
className="add-trace-operator-button periscope-btn "
|
||||
icon={<DraftingCompass size={16} />}
|
||||
onClick={(): void => addTraceOperator?.()}
|
||||
>
|
||||
|
||||
@@ -33,7 +33,12 @@ export const QueryV2 = memo(function QueryV2({
|
||||
showOnlyWhereClause = false,
|
||||
signalSource = '',
|
||||
isMultiQueryAllowed = false,
|
||||
}: QueryProps & { ref: React.RefObject<HTMLDivElement> }): JSX.Element {
|
||||
queriesCount = 1,
|
||||
}: QueryProps & {
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
// eslint-disable-next-line react/require-default-props
|
||||
queriesCount?: number;
|
||||
}): JSX.Element {
|
||||
const { cloneQuery, panelType } = useQueryBuilder();
|
||||
|
||||
const showFunctions = query?.functions?.length > 0;
|
||||
@@ -186,12 +191,16 @@ export const QueryV2 = memo(function QueryV2({
|
||||
icon: <Copy size={14} />,
|
||||
onClick: handleCloneEntity,
|
||||
},
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete-query',
|
||||
icon: <Trash size={14} />,
|
||||
onClick: handleDeleteQuery,
|
||||
},
|
||||
...(queriesCount && queriesCount > 1
|
||||
? [
|
||||
{
|
||||
label: 'Delete',
|
||||
key: 'delete-query',
|
||||
icon: <Trash size={14} />,
|
||||
onClick: handleDeleteQuery,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
}}
|
||||
placement="bottomRight"
|
||||
|
||||
@@ -92,6 +92,9 @@
|
||||
|
||||
.qb-trace-operator-editor-container {
|
||||
flex: 1;
|
||||
.cm-activeLine > span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&.arrow-left {
|
||||
@@ -113,6 +116,8 @@
|
||||
text-overflow: ellipsis;
|
||||
padding: 0px 8px;
|
||||
border-right: 1px solid var(--bg-slate-400);
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export default function TraceOperator({
|
||||
!isListViewPanel && 'qb-trace-operator-arrow',
|
||||
)}
|
||||
>
|
||||
<Typography.Text className="label">TRACE OPERATOR</Typography.Text>
|
||||
<Typography.Text className="label">Trace Operator</Typography.Text>
|
||||
<div className="qb-trace-operator-editor-container">
|
||||
<TraceOperatorEditor
|
||||
value={traceOperator?.expression || ''}
|
||||
|
||||
@@ -31,12 +31,14 @@
|
||||
}
|
||||
|
||||
.tab {
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
&:hover {
|
||||
color: var(--text-vanilla-100);
|
||||
}
|
||||
&::before {
|
||||
background: var(--bg-slate-400);
|
||||
&:not(.ant-radio-button-wrapper-disabled) {
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
&:hover {
|
||||
color: var(--text-vanilla-100);
|
||||
}
|
||||
&::before {
|
||||
background: var(--bg-slate-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,16 +58,18 @@
|
||||
// Light mode styles
|
||||
.lightMode {
|
||||
.signoz-radio-group {
|
||||
&.ant-radio-group-disabled {
|
||||
.tab,
|
||||
.selected_view {
|
||||
.tab,
|
||||
.selected_view {
|
||||
&.ant-radio-button-wrapper-disabled {
|
||||
background: var(--bg-vanilla-200) !important;
|
||||
border-color: var(--bg-vanilla-400) !important;
|
||||
color: var(--text-ink-400) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tab:hover,
|
||||
.selected_view:hover {
|
||||
.tab:hover,
|
||||
.selected_view:hover {
|
||||
&:not(.ant-radio-button-wrapper-disabled) {
|
||||
background: var(--bg-vanilla-200) !important;
|
||||
border-color: var(--bg-vanilla-400) !important;
|
||||
color: var(--text-ink-400) !important;
|
||||
@@ -73,6 +77,7 @@
|
||||
}
|
||||
|
||||
.tab {
|
||||
border-color: var(--bg-vanilla-400) !important;
|
||||
background: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ const themeColors = {
|
||||
cyan: '#00FFFF',
|
||||
},
|
||||
chartcolors: {
|
||||
robin: '#3F5ECC',
|
||||
radicalRed: '#FF1A66',
|
||||
dodgerBlue: '#2F80ED',
|
||||
mediumOrchid: '#BB6BD9',
|
||||
seaBuckthorn: '#F2994A',
|
||||
@@ -58,7 +58,7 @@ const themeColors = {
|
||||
oliveDrab: '#66991A',
|
||||
lavenderRose: '#FF99E6',
|
||||
electricLime: '#CCFF1A',
|
||||
radicalRed: '#FF1A66',
|
||||
robin: '#3F5ECC',
|
||||
harleyOrange: '#E6331A',
|
||||
turquoise: '#33FFCC',
|
||||
gladeGreen: '#66994D',
|
||||
@@ -80,7 +80,7 @@ const themeColors = {
|
||||
maroon: '#800000',
|
||||
navy: '#000080',
|
||||
aquamarine: '#7FFFD4',
|
||||
gold: '#FFD700',
|
||||
darkSeaGreen: '#8FBC8F',
|
||||
gray: '#808080',
|
||||
skyBlue: '#87CEEB',
|
||||
indigo: '#4B0082',
|
||||
@@ -105,7 +105,7 @@ const themeColors = {
|
||||
lawnGreen: '#7CFC00',
|
||||
mediumSeaGreen: '#3CB371',
|
||||
lightCoral: '#F08080',
|
||||
darkSeaGreen: '#8FBC8F',
|
||||
gold: '#FFD700',
|
||||
sandyBrown: '#F4A460',
|
||||
darkKhaki: '#BDB76B',
|
||||
cornflowerBlue: '#6495ED',
|
||||
@@ -113,7 +113,7 @@ const themeColors = {
|
||||
paleGreen: '#98FB98',
|
||||
},
|
||||
lightModeColor: {
|
||||
robin: '#3F5ECC',
|
||||
radicalRed: '#FF1A66',
|
||||
dodgerBlueDark: '#0C6EED',
|
||||
steelgrey: '#2f4b7c',
|
||||
steelpurple: '#665191',
|
||||
@@ -143,7 +143,7 @@ const themeColors = {
|
||||
oliveDrab: '#66991A',
|
||||
lavenderRoseDark: '#F024BD',
|
||||
electricLimeDark: '#84A800',
|
||||
radicalRed: '#FF1A66',
|
||||
robin: '#3F5ECC',
|
||||
harleyOrange: '#E6331A',
|
||||
gladeGreen: '#66994D',
|
||||
hemlock: '#66664D',
|
||||
@@ -181,7 +181,7 @@ const themeColors = {
|
||||
darkOrchid: '#9932CC',
|
||||
mediumSeaGreenDark: '#109E50',
|
||||
lightCoralDark: '#F85959',
|
||||
darkSeaGreenDark: '#509F50',
|
||||
gold: '#FFD700',
|
||||
sandyBrownDark: '#D97117',
|
||||
darkKhakiDark: '#99900A',
|
||||
cornflowerBlueDark: '#3371E6',
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons';
|
||||
import { Col, Typography } from 'antd';
|
||||
import { StyledCol, StyledRow } from 'components/Styled';
|
||||
import { IIntervalUnit } from 'container/TraceDetail/utils';
|
||||
import {
|
||||
IIntervalUnit,
|
||||
SPAN_DETAILS_LEFT_COL_WIDTH,
|
||||
} from 'container/TraceDetail/utils';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||
import {
|
||||
Dispatch,
|
||||
MouseEventHandler,
|
||||
|
||||
@@ -5,7 +5,6 @@ import { AxiosError } from 'axios';
|
||||
import Spinner from 'components/Spinner';
|
||||
import { themeColors } from 'constants/theme';
|
||||
import useGetTraceFlamegraph from 'hooks/trace/useGetTraceFlamegraph';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { generateColor } from 'lib/uPlotLib/utils/generateColor';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
@@ -48,7 +47,6 @@ function TraceFlamegraph(props: ITraceFlamegraphProps): JSX.Element {
|
||||
traceId,
|
||||
selectedSpanId: firstSpanAtFetchLevel,
|
||||
});
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
// get the current state of trace flamegraph based on the API lifecycle
|
||||
const traceFlamegraphState = useMemo(() => {
|
||||
@@ -132,36 +130,40 @@ function TraceFlamegraph(props: ITraceFlamegraphProps): JSX.Element {
|
||||
>
|
||||
<div className="exec-time-service">% exec time</div>
|
||||
<div className="stats">
|
||||
{Object.keys(serviceExecTime).map((service) => {
|
||||
const spread = endTime - startTime;
|
||||
const value = (serviceExecTime[service] * 100) / spread;
|
||||
const color = generateColor(
|
||||
service,
|
||||
isDarkMode ? themeColors.chartcolors : themeColors.lightModeColor,
|
||||
);
|
||||
return (
|
||||
<div key={service} className="value-row">
|
||||
<section className="service-name">
|
||||
<div className="square-box" style={{ backgroundColor: color }} />
|
||||
<Tooltip title={service}>
|
||||
<Typography.Text className="service-text" ellipsis>
|
||||
{service}
|
||||
{Object.keys(serviceExecTime)
|
||||
.sort((a, b) => {
|
||||
const spread = endTime - startTime;
|
||||
const aValue = (serviceExecTime[a] * 100) / spread;
|
||||
const bValue = (serviceExecTime[b] * 100) / spread;
|
||||
return bValue - aValue;
|
||||
})
|
||||
.map((service) => {
|
||||
const spread = endTime - startTime;
|
||||
const value = (serviceExecTime[service] * 100) / spread;
|
||||
const color = generateColor(service, themeColors.traceDetailColors);
|
||||
return (
|
||||
<div key={service} className="value-row">
|
||||
<section className="service-name">
|
||||
<div className="square-box" style={{ backgroundColor: color }} />
|
||||
<Tooltip title={service}>
|
||||
<Typography.Text className="service-text" ellipsis>
|
||||
{service}
|
||||
</Typography.Text>
|
||||
</Tooltip>
|
||||
</section>
|
||||
<section className="progress-service">
|
||||
<Progress
|
||||
percent={parseFloat(value.toFixed(2))}
|
||||
className="service-progress-indicator"
|
||||
showInfo={false}
|
||||
/>
|
||||
<Typography.Text className="percent-value">
|
||||
{parseFloat(value.toFixed(2))}%
|
||||
</Typography.Text>
|
||||
</Tooltip>
|
||||
</section>
|
||||
<section className="progress-service">
|
||||
<Progress
|
||||
percent={parseFloat(value.toFixed(2))}
|
||||
className="service-progress-indicator"
|
||||
showInfo={false}
|
||||
/>
|
||||
<Typography.Text className="percent-value">
|
||||
{parseFloat(value.toFixed(2))}%
|
||||
</Typography.Text>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -57,7 +57,7 @@ function ResourceAttributesFilter(): JSX.Element | null {
|
||||
query={query}
|
||||
onChange={handleChangeTagFilters}
|
||||
operatorConfigKey={OperatorConfigKeys.EXCEPTIONS}
|
||||
hideSpanScopeSelector={false}
|
||||
hideSpanScopeSelector
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button, Popover, Spin, Tooltip } from 'antd';
|
||||
import GroupByIcon from 'assets/CustomIcons/GroupByIcon';
|
||||
import cx from 'classnames';
|
||||
import { OPERATORS } from 'constants/antlrQueryConstants';
|
||||
import { useTraceActions } from 'hooks/trace/useTraceActions';
|
||||
import {
|
||||
@@ -124,7 +125,7 @@ export default function AttributeActions({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="action-btn">
|
||||
<div className={cx('action-btn', { 'action-btn--is-open': isOpen })}>
|
||||
<Tooltip title={isPinned ? 'Unpin attribute' : 'Pin attribute'}>
|
||||
<Button
|
||||
className={`filter-btn periscope-btn ${isPinned ? 'pinned' : ''}`}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
padding-block: 12px;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
@@ -25,8 +25,10 @@
|
||||
gap: 8px;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
padding: 2px 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--bg-slate-500);
|
||||
.action-btn {
|
||||
display: flex;
|
||||
}
|
||||
@@ -81,22 +83,23 @@
|
||||
|
||||
.action-btn {
|
||||
display: none;
|
||||
|
||||
&--is-open {
|
||||
display: flex;
|
||||
}
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
gap: 4px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 4px;
|
||||
padding: 2px;
|
||||
|
||||
.filter-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-color: var(--bg-slate-400);
|
||||
box-shadow: none;
|
||||
border-radius: 2px;
|
||||
background: var(--bg-slate-400);
|
||||
background: var(--bg-slate-500);
|
||||
padding: 4px;
|
||||
gap: 3px;
|
||||
height: 24px;
|
||||
@@ -129,7 +132,7 @@
|
||||
gap: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--bg-slate-400);
|
||||
background-color: var(--bg-slate-400) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +145,7 @@
|
||||
.ant-popover-inner {
|
||||
padding: 8px;
|
||||
min-width: 160px;
|
||||
background: var(--bg-slate-500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +153,9 @@
|
||||
.attributes-corner {
|
||||
.attributes-container {
|
||||
.item {
|
||||
&:hover {
|
||||
background-color: var(--bg-vanilla-300);
|
||||
}
|
||||
.item-key {
|
||||
color: var(--bg-ink-100);
|
||||
}
|
||||
@@ -163,8 +170,6 @@
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
|
||||
.filter-btn {
|
||||
background: var(--bg-vanilla-200);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import './Attributes.styles.scss';
|
||||
|
||||
import { Input, Tooltip, Typography } from 'antd';
|
||||
import { Input, Typography } from 'antd';
|
||||
import cx from 'classnames';
|
||||
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';
|
||||
import { flattenObject } from 'container/LogDetailedView/utils';
|
||||
@@ -82,37 +82,41 @@ function Attributes(props: IAttributesProps): JSX.Element {
|
||||
<section
|
||||
className={cx('attributes-container', isSearchVisible ? 'border-top' : '')}
|
||||
>
|
||||
{datasource.map((item) => (
|
||||
<div
|
||||
className={cx('item', { pinned: pinnedAttributes[item.field] })}
|
||||
key={`${item.field} + ${item.value}`}
|
||||
>
|
||||
<div className="item-key-wrapper">
|
||||
<Typography.Text className="item-key" ellipsis>
|
||||
{item.field}
|
||||
</Typography.Text>
|
||||
{pinnedAttributes[item.field] && (
|
||||
<Pin size={14} className="pin-icon" fill="currentColor" />
|
||||
)}
|
||||
</div>
|
||||
<div className="value-wrapper">
|
||||
<Tooltip title={item.value}>
|
||||
{datasource
|
||||
.filter((item) => !!item.value)
|
||||
.map((item) => (
|
||||
<div
|
||||
className={cx('item', { pinned: pinnedAttributes[item.field] })}
|
||||
key={`${item.field} + ${item.value}`}
|
||||
>
|
||||
<div className="item-key-wrapper">
|
||||
<Typography.Text className="item-key" ellipsis>
|
||||
{item.field}
|
||||
</Typography.Text>
|
||||
{pinnedAttributes[item.field] && (
|
||||
<Pin size={14} className="pin-icon" fill="currentColor" />
|
||||
)}
|
||||
</div>
|
||||
<div className="value-wrapper">
|
||||
<div className="copy-wrapper">
|
||||
<CopyClipboardHOC entityKey={item.value} textToCopy={item.value}>
|
||||
<CopyClipboardHOC
|
||||
entityKey={item.value}
|
||||
textToCopy={item.value}
|
||||
tooltipText={item.value}
|
||||
>
|
||||
<Typography.Text className="item-value" ellipsis>
|
||||
{item.value}
|
||||
</Typography.Text>
|
||||
</CopyClipboardHOC>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<AttributeActions
|
||||
record={item}
|
||||
isPinned={pinnedAttributes[item.field]}
|
||||
onTogglePin={togglePin}
|
||||
/>
|
||||
<AttributeActions
|
||||
record={item}
|
||||
isPinned={pinnedAttributes[item.field]}
|
||||
onTogglePin={togglePin}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
))}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -219,6 +219,12 @@
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.ant-tabs-content-holder {
|
||||
.bg-border {
|
||||
background: var(--bg-vanilla-300);
|
||||
border-color: var(--bg-vanilla-300);
|
||||
}
|
||||
}
|
||||
.span-details-drawer {
|
||||
border-left: 1px solid var(--bg-vanilla-300);
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import { spanServiceNameToColorMapping } from 'lib/getRandomColor';
|
||||
import history from 'lib/history';
|
||||
import { map } from 'lodash-es';
|
||||
import { PanelRight } from 'lucide-react';
|
||||
import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { ITraceForest, PayloadProps } from 'types/api/trace/getTraceItem';
|
||||
@@ -42,6 +41,7 @@ import {
|
||||
getTreeLevelsCount,
|
||||
IIntervalUnit,
|
||||
INTERVAL_UNITS,
|
||||
SPAN_DETAILS_LEFT_COL_WIDTH,
|
||||
} from './utils';
|
||||
|
||||
const { Sider } = Layout;
|
||||
|
||||
@@ -13,6 +13,8 @@ export const filterSpansByString = (
|
||||
return JSON.stringify(spanWithoutChildren).includes(searchString);
|
||||
});
|
||||
|
||||
export const SPAN_DETAILS_LEFT_COL_WIDTH = 350;
|
||||
|
||||
type TTimeUnitName = 'ms' | 's' | 'm' | 'hr' | 'day' | 'week';
|
||||
|
||||
export interface IIntervalUnit {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Typography } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ErrorInPlace from 'components/ErrorInPlace/ErrorInPlace';
|
||||
import ListViewOrderBy from 'components/OrderBy/ListViewOrderBy';
|
||||
import { ResizeTable } from 'components/ResizeTable';
|
||||
import { ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { QueryParams } from 'constants/query';
|
||||
@@ -13,16 +12,7 @@ import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { Pagination } from 'hooks/queryPagination';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { ArrowUp10, Minus } from 'lucide-react';
|
||||
import {
|
||||
Dispatch,
|
||||
memo,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { Dispatch, memo, SetStateAction, useEffect, useMemo } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { Warning } from 'types/api';
|
||||
@@ -30,7 +20,6 @@ import APIError from 'types/api/error';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
import DOCLINKS from 'utils/docLinks';
|
||||
import { transformBuilderQueryFields } from 'utils/queryTransformers';
|
||||
|
||||
import TraceExplorerControls from '../Controls';
|
||||
import { TracesLoading } from '../TraceLoading/TraceLoading';
|
||||
@@ -43,13 +32,13 @@ interface TracesViewProps {
|
||||
setIsLoadingQueries: Dispatch<SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
function TracesView({
|
||||
isFilterApplied,
|
||||
setWarning,
|
||||
setIsLoadingQueries,
|
||||
}: TracesViewProps): JSX.Element {
|
||||
const { stagedQuery, panelType } = useQueryBuilder();
|
||||
const [orderBy, setOrderBy] = useState<string>('timestamp:desc');
|
||||
|
||||
const { selectedTime: globalSelectedTime, maxTime, minTime } = useSelector<
|
||||
AppState,
|
||||
@@ -60,26 +49,9 @@ function TracesView({
|
||||
QueryParams.pagination,
|
||||
);
|
||||
|
||||
const transformedQuery = useMemo(
|
||||
() =>
|
||||
transformBuilderQueryFields(stagedQuery || initialQueriesMap.traces, {
|
||||
orderBy: [
|
||||
{
|
||||
columnName: orderBy.split(':')[0],
|
||||
order: orderBy.split(':')[1] as 'asc' | 'desc',
|
||||
},
|
||||
],
|
||||
}),
|
||||
[stagedQuery, orderBy],
|
||||
);
|
||||
|
||||
const handleOrderChange = useCallback((value: string) => {
|
||||
setOrderBy(value);
|
||||
}, []);
|
||||
|
||||
const { data, isLoading, isFetching, isError, error } = useGetQueryRange(
|
||||
{
|
||||
query: transformedQuery,
|
||||
query: stagedQuery || initialQueriesMap.traces,
|
||||
graphType: panelType || PANEL_TYPES.TRACE,
|
||||
selectedTime: 'GLOBAL_TIME',
|
||||
globalSelectedInterval: globalSelectedTime,
|
||||
@@ -100,7 +72,6 @@ function TracesView({
|
||||
stagedQuery,
|
||||
panelType,
|
||||
paginationQueryData,
|
||||
orderBy,
|
||||
],
|
||||
enabled: !!stagedQuery && panelType === PANEL_TYPES.TRACE,
|
||||
},
|
||||
@@ -148,18 +119,6 @@ function TracesView({
|
||||
</Typography>
|
||||
|
||||
<div className="trace-explorer-controls">
|
||||
<div className="order-by-container">
|
||||
<div className="order-by-label">
|
||||
Order by <Minus size={14} /> <ArrowUp10 size={14} />
|
||||
</div>
|
||||
|
||||
<ListViewOrderBy
|
||||
value={orderBy}
|
||||
onChange={handleOrderChange}
|
||||
dataSource={DataSource.TRACES}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TraceExplorerControls
|
||||
isLoading={isLoading}
|
||||
totalCount={responseData?.length || 0}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
.old-trace-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.top-header {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid var(--bg-slate-400);
|
||||
|
||||
.new-cta-btn {
|
||||
display: flex;
|
||||
padding: 4px 6px;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: var(--Vanilla-400, #c0c1c3);
|
||||
|
||||
/* Bifrost (Ancient)/Content/sm */
|
||||
font-family: Inter;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 20px; /* 142.857% */
|
||||
letter-spacing: -0.07px;
|
||||
box-shadow: none;
|
||||
|
||||
.ant-btn-icon {
|
||||
margin-inline-end: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.old-trace-container {
|
||||
.top-header {
|
||||
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||
|
||||
.new-cta-btn {
|
||||
color: var(--bg-ink-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
/* eslint-disable sonarjs/no-duplicate-string */
|
||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import ROUTES from 'constants/routes';
|
||||
import { MemoryRouter, Route } from 'react-router-dom';
|
||||
import { fireEvent, render, screen } from 'tests/test-utils';
|
||||
|
||||
import TraceDetail from '..';
|
||||
|
||||
window.HTMLElement.prototype.scrollIntoView = jest.fn();
|
||||
|
||||
jest.mock('@signozhq/badge', () => ({
|
||||
Badge: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@signozhq/resizable', () => ({
|
||||
ResizableHandle: jest.fn(),
|
||||
ResizablePanel: jest.fn(),
|
||||
ResizablePanelGroup: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useLocation: (): { pathname: string; search: string } => ({
|
||||
pathname: `${process.env.FRONTEND_API_ENDPOINT}${ROUTES.TRACE_DETAIL}`,
|
||||
search: '?spanId=28a8a67365d0bd8b&levelUp=0&levelDown=0',
|
||||
}),
|
||||
|
||||
useParams: jest.fn().mockReturnValue({
|
||||
id: '000000000000000071dc9b0a338729b4',
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('container/TraceFlameGraph/index.tsx', () => ({
|
||||
__esModule: true,
|
||||
default: (): JSX.Element => <div>TraceFlameGraph</div>,
|
||||
}));
|
||||
|
||||
describe('TraceDetail', () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(new Date('2023-10-20'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should render tracedetail', async () => {
|
||||
const { findByText, getByText, getAllByText, getByPlaceholderText } = render(
|
||||
<MemoryRouter initialEntries={['/trace/000000000000000071dc9b0a338729b4']}>
|
||||
<Route path={ROUTES.TRACE_DETAIL}>
|
||||
<TraceDetail />
|
||||
</Route>
|
||||
,
|
||||
</MemoryRouter>,
|
||||
);
|
||||
expect(await findByText('Trace Details')).toBeInTheDocument();
|
||||
|
||||
// as we have an active spanId, it should scroll to the selected span
|
||||
expect(window.HTMLElement.prototype.scrollIntoView).toHaveBeenCalled();
|
||||
|
||||
// assertions
|
||||
expect(getByText('TraceFlameGraph')).toBeInTheDocument();
|
||||
expect(getByText('Focus on selected span')).toBeInTheDocument();
|
||||
|
||||
// span action buttons
|
||||
expect(getByText('Reset Focus')).toBeInTheDocument();
|
||||
expect(getByText('50 Spans')).toBeInTheDocument();
|
||||
|
||||
// trace span detail - parent -> child
|
||||
expect(getAllByText('frontend')[0]).toBeInTheDocument();
|
||||
expect(getByText('776.76 ms')).toBeInTheDocument();
|
||||
[
|
||||
{ trace: 'HTTP GET /dispatch', duration: '776.76 ms', count: '50' },
|
||||
{ trace: 'HTTP GET: /customer', duration: '349.44 ms', count: '4' },
|
||||
{
|
||||
trace: '/driver.DriverService/FindNearest',
|
||||
duration: '173.10 ms',
|
||||
count: '15',
|
||||
},
|
||||
// and so on ...
|
||||
].forEach((traceDetail) => {
|
||||
expect(getByText(traceDetail.trace)).toBeInTheDocument();
|
||||
expect(getByText(traceDetail.duration)).toBeInTheDocument();
|
||||
expect(getByText(traceDetail.count)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Details for selected Span
|
||||
expect(getByText('Details for selected Span')).toBeInTheDocument();
|
||||
['Service', 'Operation', 'SpanKind', 'StatusCodeString'].forEach((detail) => {
|
||||
expect(getByText(detail)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// go to related logs button
|
||||
const goToRelatedLogsButton = getByText('Go to Related logs');
|
||||
expect(goToRelatedLogsButton).toBeInTheDocument();
|
||||
|
||||
// Tag and Event tabs
|
||||
expect(getByText('Tags')).toBeInTheDocument();
|
||||
expect(getByText('Events')).toBeInTheDocument();
|
||||
expect(getByPlaceholderText('traceDetails:search_tags')).toBeInTheDocument();
|
||||
|
||||
// Tag details
|
||||
[
|
||||
{ title: 'client-uuid', value: '64a18ffd5f8adbfb' },
|
||||
{ title: 'component', value: 'net/http' },
|
||||
{ title: 'host.name', value: '4f6ec470feea' },
|
||||
{ title: 'http.method', value: 'GET' },
|
||||
{ title: 'http.url', value: '/route?dropoff=728%2C326&pickup=165%2C543' },
|
||||
{ title: 'http.status_code', value: '200' },
|
||||
{ title: 'ip', value: '172.25.0.2' },
|
||||
{ title: 'opencensus.exporterversion', value: 'Jaeger-Go-2.30.0' },
|
||||
].forEach((tag) => {
|
||||
expect(getByText(tag.title)).toBeInTheDocument();
|
||||
expect(getByText(tag.value)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// see full value
|
||||
expect(getAllByText('View full value')[0]).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render tracedetail events tab', async () => {
|
||||
const { findByText, getByText } = render(
|
||||
<MemoryRouter initialEntries={['/trace/000000000000000071dc9b0a338729b4']}>
|
||||
<Route path={ROUTES.TRACE_DETAIL}>
|
||||
<TraceDetail />
|
||||
</Route>
|
||||
,
|
||||
</MemoryRouter>,
|
||||
);
|
||||
expect(await findByText('Trace Details')).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(getByText('Events'));
|
||||
|
||||
expect(await screen.findByText('HTTP request received')).toBeInTheDocument();
|
||||
|
||||
// event details
|
||||
[
|
||||
{ title: 'Event Start Time', value: '527.60 ms' },
|
||||
{ title: 'level', value: 'info' },
|
||||
].forEach((tag) => {
|
||||
expect(getByText(tag.title)).toBeInTheDocument();
|
||||
expect(getByText(tag.value)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(getByText('View full log event message')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should toggle slider - selected span details', async () => {
|
||||
const { findByTestId, queryByText } = render(
|
||||
<MemoryRouter initialEntries={['/trace/000000000000000071dc9b0a338729b4']}>
|
||||
<Route path={ROUTES.TRACE_DETAIL}>
|
||||
<TraceDetail />
|
||||
</Route>
|
||||
,
|
||||
</MemoryRouter>,
|
||||
);
|
||||
const slider = await findByTestId('span-details-sider');
|
||||
expect(slider).toBeInTheDocument();
|
||||
|
||||
fireEvent.click(slider.querySelector('.expand-collapse-btn') as HTMLElement);
|
||||
|
||||
expect(queryByText('Details for selected Span')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should be able to selected another span and see its detail', async () => {
|
||||
const { getByText } = render(
|
||||
<MemoryRouter initialEntries={['/trace/000000000000000071dc9b0a338729b4']}>
|
||||
<Route path={ROUTES.TRACE_DETAIL}>
|
||||
<TraceDetail />
|
||||
</Route>
|
||||
,
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
expect(await screen.findByText('Trace Details')).toBeInTheDocument();
|
||||
|
||||
const spanTitle = getByText('/driver.DriverService/FindNearest');
|
||||
expect(spanTitle).toBeInTheDocument();
|
||||
fireEvent.click(spanTitle);
|
||||
|
||||
// Tag details
|
||||
[
|
||||
{ title: 'client-uuid', value: '6fb81b8ca91b2b4d' },
|
||||
{ title: 'component', value: 'gRPC' },
|
||||
{ title: 'host.name', value: '4f6ec470feea' },
|
||||
].forEach((tag) => {
|
||||
expect(getByText(tag.title)).toBeInTheDocument();
|
||||
expect(getByText(tag.value)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('focus on selected span and reset focus action', async () => {
|
||||
const { getByText, getAllByText } = render(
|
||||
<MemoryRouter initialEntries={['/trace/000000000000000071dc9b0a338729b4']}>
|
||||
<Route path={ROUTES.TRACE_DETAIL}>
|
||||
<TraceDetail />
|
||||
</Route>
|
||||
,
|
||||
</MemoryRouter>,
|
||||
);
|
||||
|
||||
expect(await screen.findByText('Trace Details')).toBeInTheDocument();
|
||||
|
||||
const spanTitle = getByText('/driver.DriverService/FindNearest');
|
||||
expect(spanTitle).toBeInTheDocument();
|
||||
fireEvent.click(spanTitle);
|
||||
|
||||
expect(await screen.findByText('6fb81b8ca91b2b4d')).toBeInTheDocument();
|
||||
|
||||
// focus on selected span
|
||||
const focusButton = getByText('Focus on selected span');
|
||||
expect(focusButton).toBeInTheDocument();
|
||||
fireEvent.click(focusButton);
|
||||
|
||||
// assert selected span
|
||||
expect(getByText('15 Spans')).toBeInTheDocument();
|
||||
expect(getAllByText('/driver.DriverService/FindNearest')).toHaveLength(3);
|
||||
expect(getByText('173.10 ms')).toBeInTheDocument();
|
||||
|
||||
// reset focus
|
||||
expect(screen.queryByText('HTTP GET /dispatch')).not.toBeInTheDocument();
|
||||
|
||||
const resetFocusButton = getByText('Reset Focus');
|
||||
expect(resetFocusButton).toBeInTheDocument();
|
||||
fireEvent.click(resetFocusButton);
|
||||
|
||||
expect(window.HTMLElement.prototype.scrollIntoView).toHaveBeenCalled();
|
||||
expect(screen.queryByText('HTTP GET /dispatch')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
export const SPAN_DETAILS_LEFT_COL_WIDTH = 350;
|
||||
|
||||
export const noEventMessage =
|
||||
'The requested trace id was not found. Sometimes this happens because of insertion delay in trace data. Please try again after some time';
|
||||
@@ -1,76 +0,0 @@
|
||||
import './TraceDetail.styles.scss';
|
||||
|
||||
import { Button, Typography } from 'antd';
|
||||
import getTraceItem from 'api/trace/getTraceItem';
|
||||
import NotFound from 'components/NotFound';
|
||||
import Spinner from 'components/Spinner';
|
||||
import TraceDetailContainer from 'container/TraceDetail';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { Undo } from 'lucide-react';
|
||||
import TraceDetailsPage from 'pages/TraceDetailV2';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Props as TraceDetailProps } from 'types/api/trace/getTraceItem';
|
||||
|
||||
import { noEventMessage } from './constants';
|
||||
|
||||
function TraceDetail(): JSX.Element {
|
||||
const { id } = useParams<TraceDetailProps>();
|
||||
const [showNewTraceDetails, setShowNewTraceDetails] = useState<boolean>(false);
|
||||
const urlQuery = useUrlQuery();
|
||||
const { spanId, levelUp, levelDown } = useMemo(
|
||||
() => ({
|
||||
spanId: urlQuery.get('spanId'),
|
||||
levelUp: urlQuery.get('levelUp'),
|
||||
levelDown: urlQuery.get('levelDown'),
|
||||
}),
|
||||
[urlQuery],
|
||||
);
|
||||
|
||||
const { data: traceDetailResponse, error, isLoading, isError } = useQuery(
|
||||
`getTraceItem/${id}`,
|
||||
() => getTraceItem({ id, spanId, levelUp, levelDown }),
|
||||
{
|
||||
cacheTime: 3000,
|
||||
},
|
||||
);
|
||||
|
||||
if (showNewTraceDetails) {
|
||||
return <TraceDetailsPage />;
|
||||
}
|
||||
|
||||
if (traceDetailResponse?.error || error || isError) {
|
||||
return (
|
||||
<Typography>
|
||||
{traceDetailResponse?.error || 'Something went wrong'}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading || !(traceDetailResponse && traceDetailResponse.payload)) {
|
||||
return <Spinner tip="Loading.." />;
|
||||
}
|
||||
|
||||
if (traceDetailResponse.payload[0].events.length === 0) {
|
||||
return <NotFound text={noEventMessage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="old-trace-container">
|
||||
<div className="top-header">
|
||||
<Button
|
||||
onClick={(): void => setShowNewTraceDetails(true)}
|
||||
icon={<Undo size={14} />}
|
||||
type="text"
|
||||
className="new-cta-btn"
|
||||
>
|
||||
New Trace Detail
|
||||
</Button>
|
||||
</div>
|
||||
<TraceDetailContainer response={traceDetailResponse.payload} />;
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default TraceDetail;
|
||||
@@ -1,12 +1,10 @@
|
||||
import './TraceDetailV2.styles.scss';
|
||||
|
||||
import { Button, Tabs } from 'antd';
|
||||
import { Tabs } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import ROUTES from 'constants/routes';
|
||||
import history from 'lib/history';
|
||||
import { Compass, Cone, TowerControl, Undo } from 'lucide-react';
|
||||
import TraceDetail from 'pages/TraceDetail';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { Compass, Cone, TowerControl } from 'lucide-react';
|
||||
|
||||
import TraceDetailsV2 from './TraceDetailV2';
|
||||
|
||||
@@ -16,11 +14,10 @@ interface INewTraceDetailProps {
|
||||
key: string;
|
||||
children: JSX.Element;
|
||||
}[];
|
||||
handleOldTraceDetails: () => void;
|
||||
}
|
||||
|
||||
function NewTraceDetail(props: INewTraceDetailProps): JSX.Element {
|
||||
const { items, handleOldTraceDetails } = props;
|
||||
const { items } = props;
|
||||
return (
|
||||
<div className="traces-module-container">
|
||||
<Tabs
|
||||
@@ -39,24 +36,12 @@ function NewTraceDetail(props: INewTraceDetailProps): JSX.Element {
|
||||
history.push(ROUTES.TRACES_FUNNELS);
|
||||
}
|
||||
}}
|
||||
tabBarExtraContent={
|
||||
<Button
|
||||
type="text"
|
||||
onClick={handleOldTraceDetails}
|
||||
className="old-switch"
|
||||
icon={<Undo size={14} />}
|
||||
>
|
||||
Old Trace Details
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TraceDetailsPage(): JSX.Element {
|
||||
const [showOldTraceDetails, setShowOldTraceDetails] = useState<boolean>(false);
|
||||
|
||||
const items = [
|
||||
{
|
||||
label: (
|
||||
@@ -86,13 +71,6 @@ export default function TraceDetailsPage(): JSX.Element {
|
||||
children: <div />,
|
||||
},
|
||||
];
|
||||
const handleOldTraceDetails = useCallback(() => {
|
||||
setShowOldTraceDetails(true);
|
||||
}, []);
|
||||
|
||||
return showOldTraceDetails ? (
|
||||
<TraceDetail />
|
||||
) : (
|
||||
<NewTraceDetail items={items} handleOldTraceDetails={handleOldTraceDetails} />
|
||||
);
|
||||
return <NewTraceDetail items={items} />;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import { FilterSelect } from 'components/CeleryOverview/CeleryOverviewConfigOpti
|
||||
import { QueryParams } from 'constants/query';
|
||||
import { initialQueriesMap } from 'constants/queryBuilder';
|
||||
import QueryBuilderSearchV2 from 'container/QueryBuilder/filters/QueryBuilderSearchV2/QueryBuilderSearchV2';
|
||||
import { ChevronDown, HardHat, PencilLine } from 'lucide-react';
|
||||
import { ChevronDown, PencilLine } from 'lucide-react';
|
||||
import { LatencyPointers } from 'pages/TracesFunnelDetails/constants';
|
||||
import { useFunnelContext } from 'pages/TracesFunnels/FunnelContext';
|
||||
import { useAppContext } from 'providers/App/App';
|
||||
@@ -194,7 +194,6 @@ function FunnelStep({
|
||||
}
|
||||
hasPopupContainer={false}
|
||||
placeholder="Search for filters..."
|
||||
suffixIcon={<HardHat size={12} color="var(--bg-vanilla-400)" />}
|
||||
rootClassName="traces-funnel-where-filter"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
:root {
|
||||
--bg-vanilla-100-rgb: 255, 255, 255;
|
||||
}
|
||||
.funnel-table {
|
||||
|
||||
border-radius: 3px;
|
||||
border: 1px solid var(--bg-slate-500);
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgba(171, 189, 255, 0.01) 0%,
|
||||
rgba(171, 189, 255, 0.01) 100%
|
||||
),
|
||||
#0b0c0e;
|
||||
table {
|
||||
background: linear-gradient(
|
||||
0deg,
|
||||
rgba(171, 189, 255, 0.01) 0%,
|
||||
rgba(171, 189, 255, 0.01) 100%
|
||||
),
|
||||
#0b0c0e;
|
||||
}
|
||||
|
||||
&__header {
|
||||
padding: 12px 14px 12px;
|
||||
@@ -97,9 +103,10 @@
|
||||
}
|
||||
|
||||
.table-row-dark {
|
||||
background: var(--bg-ink-300);
|
||||
background: rgba(var(--bg-vanilla-100-rgb), 0.01);
|
||||
}
|
||||
|
||||
|
||||
.trace-id-cell {
|
||||
color: var(--bg-robin-400);
|
||||
cursor: pointer;
|
||||
|
||||
@@ -160,6 +160,8 @@
|
||||
min-width: 0;
|
||||
|
||||
.ant-select {
|
||||
font-family: 'Space Mono', monospace !important;
|
||||
|
||||
border: none;
|
||||
height: 36px;
|
||||
}
|
||||
@@ -167,6 +169,10 @@
|
||||
.ant-select-selector {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ant-select-selection-placeholder {
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
|
||||
Reference in New Issue
Block a user