diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx index 9b382bff768..f65d347c241 100644 --- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx +++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.test.tsx @@ -253,6 +253,7 @@ describe('', () => { it('renders deep link URL', () => { render(); expect(screen.getByTestId('share-span-button')).toBeInTheDocument(); + expect(screen.getByText('test-spanID')).toBeInTheDocument(); }); it('renders the flame graph', async () => { diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx index 4550f310064..19ddc677310 100644 --- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx +++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import { SpanStatusCode } from '@opentelemetry/api'; import { useCallback, useMemo } from 'react'; @@ -33,7 +33,7 @@ import { t } from '@grafana/i18n'; import { TraceToProfilesOptions } from '@grafana/o11y-ds-frontend'; import { usePluginLinks } from '@grafana/runtime'; import { TimeZone } from '@grafana/schema'; -import { useStyles2 } from '@grafana/ui'; +import { Icon, useStyles2 } from '@grafana/ui'; import { pyroscopeProfileIdTagKey } from '../../../createSpanLink'; import { autoColor } from '../../Theme'; @@ -174,6 +174,23 @@ const getStyles = (theme: GrafanaTheme2) => { gap: '10px', marginBottom: theme.spacing(2), }), + debugInfo: css({ + label: 'debugInfo', + display: 'block', + letterSpacing: '0.25px', + margin: '0.5em 0 -0.75em', + textAlign: 'right', + }), + debugLabel: css({ + label: 'debugLabel', + '&::before': { + color: autoColor(theme, '#bbb'), + content: 'attr(data-label)', + }, + }), + LinkIcon: css({ + fontSize: '1.5em', + }), }; }; @@ -350,7 +367,7 @@ export default function SpanDetail(props: SpanDetailProps) { app, }); - const focusSpanLink = createFocusSpanLink(traceID, spanID); + const { interpolatedParams, ...focusSpanLink } = createFocusSpanLink(traceID, spanID); const resourceLinksGetter = useResourceAttributesExtensionLinks({ process, spanTags: tags, @@ -455,6 +472,30 @@ export default function SpanDetail(props: SpanDetailProps) { traceName={traceName} /> )} + + + {/* TODO: fix keyboard a11y */} + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} + { + // click handling logic copied from react router: + // https://github.com/remix-run/react-router/blob/997b4d67e506d39ac6571cb369d6d2d6b3dda557/packages/react-router-dom/index.tsx#L392-L394s + if ( + focusSpanLink.onClick && + e.button === 0 && // Ignore everything but left clicks + (!e.currentTarget.target || e.currentTarget.target === '_self') && // Let browser handle "target=_blank" etc. + !(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) // Ignore clicks with modifier keys + ) { + e.preventDefault(); + focusSpanLink.onClick(e); + } + }} + > + + + {spanID} + ); diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx index 629e6da37c5..c4c94b9b102 100644 --- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx +++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetailRow.test.tsx @@ -40,7 +40,7 @@ const setup = (propOverrides?: SpanDetailRowProps) => { logItemToggle: jest.fn(), logsToggle: jest.fn(), processToggle: jest.fn(), - createFocusSpanLink: jest.fn(), + createFocusSpanLink: jest.fn().mockReturnValue({}), hoverIndentGuideIds: new Map(), span: testSpan, tagsToggle: jest.fn(),