mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
Tracing: Fix links to traces in Explore (#50113)
* Tracing: Fix links to traces in Explore * Fix links in dashboard * Fix references and tracetimelineviewer tests * Remove hard-coded references to fix tests * Add noopener
This commit is contained in:
parent
f9ddb8bf86
commit
c65d62c95b
@ -59,7 +59,7 @@ exports[`no enzyme tests`] = {
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianLogs.test.js:3960703835": [
|
||||
[14, 19, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js:2429764318": [
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/AccordianReferences.test.js:2025513694": [
|
||||
[14, 19, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/SpanDetail/KeyValuesTable.test.js:3813002651": [
|
||||
@ -89,10 +89,10 @@ exports[`no enzyme tests`] = {
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView.test.js:551014442": [
|
||||
[13, 26, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/index.test.js:381298544": [
|
||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/index.test.js:276996587": [
|
||||
[14, 19, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"packages/jaeger-ui-components/src/url/ReferenceLink.test.js:3249503373": [
|
||||
"packages/jaeger-ui-components/src/url/ReferenceLink.test.js:261377050": [
|
||||
[14, 26, 13, "RegExp match", "2409514259"]
|
||||
],
|
||||
"public/app/core/components/PageActionBar/PageActionBar.test.tsx:1251504193": [
|
||||
|
@ -63,7 +63,7 @@ describe('<AccordianReferences>', () => {
|
||||
highContrast: false,
|
||||
isOpen: false,
|
||||
onToggle: jest.fn(),
|
||||
focusSpan: jest.fn(),
|
||||
createFocusSpanLink: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@ -88,7 +88,7 @@ describe('<References>', () => {
|
||||
|
||||
const props = {
|
||||
data: references,
|
||||
focusSpan: jest.fn(),
|
||||
createFocusSpanLink: jest.fn(),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -17,7 +17,7 @@ import * as React from 'react';
|
||||
import IoIosArrowDown from 'react-icons/lib/io/ios-arrow-down';
|
||||
import IoIosArrowRight from 'react-icons/lib/io/ios-arrow-right';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Field, GrafanaTheme2, LinkModel } from '@grafana/data';
|
||||
import { Icon, useStyles2 } from '@grafana/ui';
|
||||
|
||||
import { autoColor } from '../../Theme';
|
||||
@ -103,6 +103,11 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
serviceName: css`
|
||||
margin-right: 8px;
|
||||
`,
|
||||
title: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
||||
@ -114,7 +119,7 @@ type AccordianReferencesProps = {
|
||||
openedItems?: Set<TraceSpanReference>;
|
||||
onItemToggle?: (reference: TraceSpanReference) => void;
|
||||
onToggle?: null | (() => void);
|
||||
focusSpan: (uiFind: string) => void;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel<Field>;
|
||||
};
|
||||
|
||||
type ReferenceItemProps = {
|
||||
@ -122,20 +127,20 @@ type ReferenceItemProps = {
|
||||
interactive?: boolean;
|
||||
openedItems?: Set<TraceSpanReference>;
|
||||
onItemToggle?: (reference: TraceSpanReference) => void;
|
||||
focusSpan: (uiFind: string) => void;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel<Field>;
|
||||
};
|
||||
|
||||
// export for test
|
||||
export function References(props: ReferenceItemProps) {
|
||||
const { data, focusSpan, openedItems, onItemToggle, interactive } = props;
|
||||
const { data, createFocusSpanLink, openedItems, onItemToggle, interactive } = props;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<div className={styles.AccordianReferencesContent}>
|
||||
{data.map((reference, i) => (
|
||||
<div className={i < data.length - 1 ? styles.AccordianReferenceItem : undefined} key={reference.spanID}>
|
||||
<div className={i < data.length - 1 ? styles.AccordianReferenceItem : undefined} key={i}>
|
||||
<div className={styles.item} key={`${reference.spanID}`}>
|
||||
<ReferenceLink reference={reference} focusSpan={focusSpan}>
|
||||
<ReferenceLink reference={reference} createFocusSpanLink={createFocusSpanLink}>
|
||||
<span className={styles.itemContent}>
|
||||
{reference.span ? (
|
||||
<span>
|
||||
@ -145,7 +150,7 @@ export function References(props: ReferenceItemProps) {
|
||||
<small className="endpoint-name">{reference.span.operationName}</small>
|
||||
</span>
|
||||
) : (
|
||||
<span className="span-svc-name">
|
||||
<span className={cx('span-svc-name', styles.title)}>
|
||||
View Linked Span <Icon name="external-link-alt" />
|
||||
</span>
|
||||
)}
|
||||
@ -187,7 +192,7 @@ const AccordianReferences: React.FC<AccordianReferencesProps> = ({
|
||||
onToggle,
|
||||
onItemToggle,
|
||||
openedItems,
|
||||
focusSpan,
|
||||
createFocusSpanLink,
|
||||
}) => {
|
||||
const isEmpty = !Array.isArray(data) || !data.length;
|
||||
let arrow: React.ReactNode | null = null;
|
||||
@ -217,7 +222,7 @@ const AccordianReferences: React.FC<AccordianReferencesProps> = ({
|
||||
<References
|
||||
data={data}
|
||||
openedItems={openedItems}
|
||||
focusSpan={focusSpan}
|
||||
createFocusSpanLink={createFocusSpanLink}
|
||||
onItemToggle={onItemToggle}
|
||||
interactive={interactive}
|
||||
/>
|
||||
|
@ -116,7 +116,6 @@ type SpanDetailProps = {
|
||||
stackTracesToggle: (spanID: string) => void;
|
||||
referenceItemToggle: (spanID: string, reference: TraceSpanReference) => void;
|
||||
referencesToggle: (spanID: string) => void;
|
||||
focusSpan: (uiFind: string) => void;
|
||||
createSpanLink?: SpanLinkFunc;
|
||||
focusedSpanId?: string;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
|
||||
@ -137,7 +136,6 @@ export default function SpanDetail(props: SpanDetailProps) {
|
||||
stackTracesToggle,
|
||||
referencesToggle,
|
||||
referenceItemToggle,
|
||||
focusSpan,
|
||||
createSpanLink,
|
||||
createFocusSpanLink,
|
||||
topOfViewRefType,
|
||||
@ -284,7 +282,7 @@ export default function SpanDetail(props: SpanDetailProps) {
|
||||
openedItems={referencesState.openedItems}
|
||||
onToggle={() => referencesToggle(spanID)}
|
||||
onItemToggle={(reference) => referenceItemToggle(spanID, reference)}
|
||||
focusSpan={focusSpan}
|
||||
createFocusSpanLink={createFocusSpanLink}
|
||||
/>
|
||||
)}
|
||||
{topOfViewRefType === TopOfViewRefType.Explore && (
|
||||
|
@ -86,7 +86,6 @@ type SpanDetailRowProps = {
|
||||
span: TraceSpan;
|
||||
tagsToggle: (spanID: string) => void;
|
||||
traceStartTime: number;
|
||||
focusSpan: (uiFind: string) => void;
|
||||
hoverIndentGuideIds: Set<string>;
|
||||
addHoverIndentGuideId: (spanID: string) => void;
|
||||
removeHoverIndentGuideId: (spanID: string) => void;
|
||||
@ -122,7 +121,6 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
|
||||
span,
|
||||
tagsToggle,
|
||||
traceStartTime,
|
||||
focusSpan,
|
||||
hoverIndentGuideIds,
|
||||
addHoverIndentGuideId,
|
||||
removeHoverIndentGuideId,
|
||||
@ -169,7 +167,6 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
|
||||
span={span}
|
||||
tagsToggle={tagsToggle}
|
||||
traceStartTime={traceStartTime}
|
||||
focusSpan={focusSpan}
|
||||
createSpanLink={createSpanLink}
|
||||
focusedSpanId={focusedSpanId}
|
||||
createFocusSpanLink={createFocusSpanLink}
|
||||
|
@ -88,7 +88,6 @@ type TVirtualizedTraceViewOwnProps = {
|
||||
scrollToFirstVisibleSpan: () => void;
|
||||
registerAccessors: (accesors: Accessors) => void;
|
||||
trace: Trace;
|
||||
focusSpan: (uiFind: string) => void;
|
||||
linksGetter: (span: TraceSpan, items: TraceKeyValuePair[], itemIndex: number) => TraceLink[];
|
||||
childrenToggle: (spanID: string) => void;
|
||||
clearShouldScrollToFirstUiFindMatch: () => void;
|
||||
@ -479,7 +478,6 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
||||
detailToggle,
|
||||
spanNameColumnWidth,
|
||||
trace,
|
||||
focusSpan,
|
||||
hoverIndentGuideIds,
|
||||
addHoverIndentGuideId,
|
||||
removeHoverIndentGuideId,
|
||||
@ -514,7 +512,6 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
|
||||
span={span}
|
||||
tagsToggle={detailTagsToggle}
|
||||
traceStartTime={trace.startTime}
|
||||
focusSpan={focusSpan}
|
||||
hoverIndentGuideIds={hoverIndentGuideIds}
|
||||
addHoverIndentGuideId={addHoverIndentGuideId}
|
||||
removeHoverIndentGuideId={removeHoverIndentGuideId}
|
||||
|
@ -53,7 +53,6 @@ describe('<TraceTimelineViewer>', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = shallow(<TraceTimelineViewer {...props} />)
|
||||
.dive()
|
||||
.dive()
|
||||
.dive();
|
||||
});
|
||||
|
@ -24,7 +24,6 @@ import { merge as mergeShortcuts } from '../keyboard-shortcuts';
|
||||
import { SpanLinkFunc, TNil } from '../types';
|
||||
import TTraceTimeline from '../types/TTraceTimeline';
|
||||
import { TraceSpan, Trace, TraceLog, TraceKeyValuePair, TraceLink, TraceSpanReference } from '../types/trace';
|
||||
import ExternalLinkContext from '../url/externalLinkContext';
|
||||
|
||||
import TimelineHeaderRow from './TimelineHeaderRow';
|
||||
import VirtualizedTraceView, { TopOfViewRefType } from './VirtualizedTraceView';
|
||||
@ -79,8 +78,6 @@ type TProps = TExtractUiFindFromStateReturn & {
|
||||
updateNextViewRangeTime: (update: ViewRangeTimeUpdate) => void;
|
||||
updateViewRangeTime: TUpdateViewRangeTimeFunction;
|
||||
viewRange: ViewRange;
|
||||
focusSpan: (uiFind: string) => void;
|
||||
createLinkToExternalSpan: (traceID: string, spanID: string) => string;
|
||||
|
||||
setSpanNameColumnWidth: (width: number) => void;
|
||||
collapseAll: (spans: TraceSpan[]) => void;
|
||||
@ -163,7 +160,6 @@ export class UnthemedTraceTimelineViewer extends React.PureComponent<TProps, Sta
|
||||
updateNextViewRangeTime,
|
||||
updateViewRangeTime,
|
||||
viewRange,
|
||||
createLinkToExternalSpan,
|
||||
traceTimeline,
|
||||
theme,
|
||||
topOfViewRef,
|
||||
@ -174,35 +170,33 @@ export class UnthemedTraceTimelineViewer extends React.PureComponent<TProps, Sta
|
||||
const styles = getStyles(theme);
|
||||
|
||||
return (
|
||||
<ExternalLinkContext.Provider value={createLinkToExternalSpan}>
|
||||
<div
|
||||
className={styles.TraceTimelineViewer}
|
||||
ref={(ref: HTMLDivElement | null) => ref && this.setState({ height: ref.getBoundingClientRect().height })}
|
||||
>
|
||||
<TimelineHeaderRow
|
||||
duration={trace.duration}
|
||||
nameColumnWidth={traceTimeline.spanNameColumnWidth}
|
||||
numTicks={NUM_TICKS}
|
||||
onCollapseAll={this.collapseAll}
|
||||
onCollapseOne={this.collapseOne}
|
||||
onColummWidthChange={setSpanNameColumnWidth}
|
||||
onExpandAll={this.expandAll}
|
||||
onExpandOne={this.expandOne}
|
||||
viewRangeTime={viewRange.time}
|
||||
updateNextViewRangeTime={updateNextViewRangeTime}
|
||||
updateViewRangeTime={updateViewRangeTime}
|
||||
columnResizeHandleHeight={this.state.height}
|
||||
/>
|
||||
<VirtualizedTraceView
|
||||
{...rest}
|
||||
{...traceTimeline}
|
||||
setSpanNameColumnWidth={setSpanNameColumnWidth}
|
||||
currentViewRangeTime={viewRange.time.current}
|
||||
topOfViewRef={topOfViewRef}
|
||||
focusedSpanIdForSearch={focusedSpanIdForSearch}
|
||||
/>
|
||||
</div>
|
||||
</ExternalLinkContext.Provider>
|
||||
<div
|
||||
className={styles.TraceTimelineViewer}
|
||||
ref={(ref: HTMLDivElement | null) => ref && this.setState({ height: ref.getBoundingClientRect().height })}
|
||||
>
|
||||
<TimelineHeaderRow
|
||||
duration={trace.duration}
|
||||
nameColumnWidth={traceTimeline.spanNameColumnWidth}
|
||||
numTicks={NUM_TICKS}
|
||||
onCollapseAll={this.collapseAll}
|
||||
onCollapseOne={this.collapseOne}
|
||||
onColummWidthChange={setSpanNameColumnWidth}
|
||||
onExpandAll={this.expandAll}
|
||||
onExpandOne={this.expandOne}
|
||||
viewRangeTime={viewRange.time}
|
||||
updateNextViewRangeTime={updateNextViewRangeTime}
|
||||
updateViewRangeTime={updateViewRangeTime}
|
||||
columnResizeHandleHeight={this.state.height}
|
||||
/>
|
||||
<VirtualizedTraceView
|
||||
{...rest}
|
||||
{...traceTimeline}
|
||||
setSpanNameColumnWidth={setSpanNameColumnWidth}
|
||||
currentViewRangeTime={viewRange.time.current}
|
||||
topOfViewRef={topOfViewRef}
|
||||
focusedSpanIdForSearch={focusedSpanIdForSearch}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -16,62 +16,26 @@ import { shallow, mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
|
||||
import ReferenceLink from './ReferenceLink';
|
||||
import ExternalLinkContext from './externalLinkContext';
|
||||
|
||||
describe(ReferenceLink, () => {
|
||||
const focusMock = jest.fn();
|
||||
const createFocusSpanLinkMock = jest.fn((traceId, spanId) => {
|
||||
return {
|
||||
href: `${traceId}-${spanId}`,
|
||||
};
|
||||
});
|
||||
|
||||
const sameTraceRef = {
|
||||
refType: 'CHILD_OF',
|
||||
const ref = {
|
||||
refType: 'FOLLOWS_FROM',
|
||||
traceID: 'trace1',
|
||||
spanID: 'span1',
|
||||
span: {
|
||||
// not null or undefined is an indicator of an internal reference
|
||||
},
|
||||
};
|
||||
|
||||
const externalRef = {
|
||||
refType: 'CHILD_OF',
|
||||
traceID: 'trace2',
|
||||
spanID: 'span2',
|
||||
};
|
||||
|
||||
describe('rendering', () => {
|
||||
it('render for this trace', () => {
|
||||
const component = shallow(<ReferenceLink reference={sameTraceRef} focusSpan={focusMock} />);
|
||||
it('renders reference with correct href', () => {
|
||||
const component = shallow(<ReferenceLink reference={ref} createFocusSpanLink={createFocusSpanLinkMock} />);
|
||||
|
||||
const link = component.find('a');
|
||||
expect(link.length).toBe(1);
|
||||
expect(link.props().role).toBe('button');
|
||||
});
|
||||
|
||||
it('render for external trace', () => {
|
||||
const component = mount(
|
||||
<ExternalLinkContext.Provider value={(trace, span) => `${trace}/${span}`}>
|
||||
<ReferenceLink reference={externalRef} focusSpan={focusMock} />
|
||||
</ExternalLinkContext.Provider>
|
||||
);
|
||||
const link = component.find('a[href="trace2/span2"]');
|
||||
expect(link.length).toBe(1);
|
||||
});
|
||||
|
||||
it('throws if ExternalLinkContext is not set', () => {
|
||||
// Prevent writing to stderr during this render.
|
||||
const err = console.error;
|
||||
console.error = jest.fn();
|
||||
expect(() => mount(<ReferenceLink reference={externalRef} focusSpan={focusMock} />)).toThrow(
|
||||
'ExternalLinkContext'
|
||||
);
|
||||
// Restore writing to stderr.
|
||||
console.error = err;
|
||||
});
|
||||
});
|
||||
describe('focus span', () => {
|
||||
it('call focusSpan', () => {
|
||||
focusMock.mockReset();
|
||||
const component = shallow(<ReferenceLink reference={sameTraceRef} focusSpan={focusMock} />);
|
||||
const link = component.find('a');
|
||||
link.simulate('click');
|
||||
expect(focusMock).toHaveBeenLastCalledWith('span1');
|
||||
expect(link.prop('href')).toBe('trace1-span1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,48 +14,36 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { TraceSpanReference } from '../types/trace';
|
||||
import { Field, LinkModel } from '@grafana/data';
|
||||
|
||||
import ExternalLinkContext from './externalLinkContext';
|
||||
import { TraceSpanReference } from '../types/trace';
|
||||
|
||||
type ReferenceLinkProps = {
|
||||
reference: TraceSpanReference;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
focusSpan: (spanID: string) => void;
|
||||
onClick?: () => void;
|
||||
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel<Field>;
|
||||
};
|
||||
|
||||
export default function ReferenceLink(props: ReferenceLinkProps) {
|
||||
const { reference, children, className, focusSpan, ...otherProps } = props;
|
||||
delete otherProps.onClick;
|
||||
if (reference.span) {
|
||||
return (
|
||||
<a role="button" onClick={() => focusSpan(reference.spanID)} className={className} {...otherProps}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
const { reference, children, createFocusSpanLink } = props;
|
||||
|
||||
const link = createFocusSpanLink(reference.traceID, reference.spanID);
|
||||
|
||||
return (
|
||||
<ExternalLinkContext.Consumer>
|
||||
{(createLinkToExternalSpan) => {
|
||||
if (!createLinkToExternalSpan) {
|
||||
throw new Error("ExternalLinkContext does not have a value, you probably forgot to setup it's provider");
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href={createLinkToExternalSpan(reference.traceID, reference.spanID)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={className}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}}
|
||||
</ExternalLinkContext.Consumer>
|
||||
<a
|
||||
href={link.href}
|
||||
target={link.target}
|
||||
rel="noopener noreferrer"
|
||||
onClick={
|
||||
link.onClick
|
||||
? (event) => {
|
||||
event.preventDefault();
|
||||
link.onClick!(event);
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2017 Uber Technologies, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
/**
|
||||
* There are several places where external links to spans are created. The url layout though is something
|
||||
* that should be decided on the application level and not on the component level but at the same time
|
||||
* propagating the factory function everywhere could be cumbersome so we use this context for that.
|
||||
*/
|
||||
const ExternalLinkContext = React.createContext<((traceID: string, spanID: string) => string) | undefined>(undefined);
|
||||
ExternalLinkContext.displayName = 'ExternalLinkContext';
|
||||
export default ExternalLinkContext;
|
@ -23,6 +23,7 @@ import { TraceToLogsData } from 'app/core/components/TraceToLogs/TraceToLogsSett
|
||||
import { TraceToMetricsData } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { TempoQuery } from 'app/plugins/datasource/tempo/datasource';
|
||||
import { StoreState } from 'app/types';
|
||||
import { ExploreId } from 'app/types/explore';
|
||||
|
||||
@ -99,13 +100,9 @@ export function TraceView(props: Props) {
|
||||
refId: props.dataFrames[0]?.refId,
|
||||
exploreId: props.exploreId!,
|
||||
datasource,
|
||||
splitOpenFn: props.splitOpenFn!,
|
||||
});
|
||||
|
||||
const createLinkToExternalSpan = (traceId: string, spanId: string) => {
|
||||
const link = createFocusSpanLink(traceId, spanId);
|
||||
return link.href;
|
||||
};
|
||||
|
||||
const traceTimeline: TTraceTimeline = useMemo(
|
||||
() => ({
|
||||
childrenHiddenIDs,
|
||||
@ -162,8 +159,6 @@ export function TraceView(props: Props) {
|
||||
updateNextViewRangeTime={updateNextViewRangeTime}
|
||||
updateViewRangeTime={updateViewRangeTime}
|
||||
viewRange={viewRange}
|
||||
focusSpan={noop}
|
||||
createLinkToExternalSpan={createLinkToExternalSpan}
|
||||
setSpanNameColumnWidth={setSpanNameColumnWidth}
|
||||
collapseAll={collapseAll}
|
||||
collapseOne={collapseOne}
|
||||
@ -208,6 +203,7 @@ export function TraceView(props: Props) {
|
||||
*/
|
||||
function useFocusSpanLink(options: {
|
||||
exploreId: ExploreId;
|
||||
splitOpenFn: SplitOpen;
|
||||
refId?: string;
|
||||
datasource?: DataSourceApi;
|
||||
}): [string | undefined, (traceId: string, spanId: string) => LinkModel<Field>] {
|
||||
@ -234,7 +230,10 @@ function useFocusSpanLink(options: {
|
||||
internal: {
|
||||
datasourceUid: options.datasource?.uid!,
|
||||
datasourceName: options.datasource?.name!,
|
||||
query: query,
|
||||
query: {
|
||||
...query,
|
||||
query: traceId,
|
||||
},
|
||||
panelsState: {
|
||||
trace: {
|
||||
spanId,
|
||||
@ -243,13 +242,34 @@ function useFocusSpanLink(options: {
|
||||
},
|
||||
};
|
||||
|
||||
// Check if the link is to a different trace or not.
|
||||
// If it's the same trace, only update panel state with setFocusedSpanId (no navigation).
|
||||
// If it's a different trace, use splitOpenFn to open a new explore panel
|
||||
const sameTrace = query?.queryType === 'traceId' && (query as TempoQuery).query === traceId;
|
||||
|
||||
return mapInternalLinkToExplore({
|
||||
link,
|
||||
internalLink: link.internal!,
|
||||
scopedVars: {},
|
||||
range: {} as any,
|
||||
field: {} as Field,
|
||||
onClickFn: () => setFocusedSpanId(focusedSpanId === spanId ? undefined : spanId),
|
||||
onClickFn: sameTrace
|
||||
? () => setFocusedSpanId(focusedSpanId === spanId ? undefined : spanId)
|
||||
: options.splitOpenFn
|
||||
? () =>
|
||||
options.splitOpenFn({
|
||||
datasourceUid: options.datasource?.uid!,
|
||||
query: {
|
||||
...query!,
|
||||
query: traceId,
|
||||
},
|
||||
panelsState: {
|
||||
trace: {
|
||||
spanId,
|
||||
},
|
||||
},
|
||||
})
|
||||
: undefined,
|
||||
replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
|
||||
});
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user