Skip to content

Commit

Permalink
Link patterns to make values in tags, processes and logs clickable
Browse files Browse the repository at this point in the history
Signed-off-by: David-Emmanuel Divernois <david-emmanuel.divernois@amadeus.com>
  • Loading branch information
divdavem committed Jul 4, 2018
1 parent fa0f161 commit 33fcae9
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type AccordianKeyValuesProps = {
highContrast?: boolean,
isOpen: boolean,
label: string,
linksGetter: ({ key: string, value: any }[], number) => { url: string, text: string }[],
onToggle: () => void,
};

Expand Down Expand Up @@ -59,7 +60,7 @@ KeyValuesSummary.defaultProps = {
};

export default function AccordianKeyValues(props: AccordianKeyValuesProps) {
const { className, data, highContrast, isOpen, label, onToggle } = props;
const { className, data, highContrast, isOpen, label, linksGetter, onToggle } = props;
const isEmpty = !Array.isArray(data) || !data.length;
const iconCls = cx('u-align-icon', { 'AccordianKeyValues--emptyIcon': isEmpty });
return (
Expand All @@ -80,7 +81,7 @@ export default function AccordianKeyValues(props: AccordianKeyValuesProps) {
</strong>
{!isOpen && <KeyValuesSummary data={data} />}
</div>
{isOpen && <KeyValuesTable data={data} />}
{isOpen && <KeyValuesTable data={data} linksGetter={linksGetter} />}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import './AccordianLogs.css';

type AccordianLogsProps = {
isOpen: boolean,
linksGetter: ({ key: string, value: any }[], number) => { url: string, text: string }[],
logs: Log[],
onItemToggle: Log => void,
onToggle: () => void,
Expand All @@ -35,7 +36,7 @@ type AccordianLogsProps = {
};

export default function AccordianLogs(props: AccordianLogsProps) {
const { isOpen, logs, openedItems, onItemToggle, onToggle, timestamp } = props;
const { isOpen, linksGetter, logs, openedItems, onItemToggle, onToggle, timestamp } = props;

return (
<div className="AccordianLogs">
Expand All @@ -59,6 +60,7 @@ export default function AccordianLogs(props: AccordianLogsProps) {
// compact
highContrast
isOpen={openedItems.has(log)}
linksGetter={linksGetter}
data={log.fields || []}
label={`${formatDuration(log.timestamp - timestamp)}`}
onToggle={() => onItemToggle(log)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ limitations under the License.
white-space: pre;
width: 125px;
}

.KeyValueTable--link {
display: block;
position: relative;
}

.KeyValueTable--linkIcon {
position: absolute;
right: 0px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import React from 'react';
import jsonMarkup from 'json-markup';
import { Dropdown, Icon, Menu } from 'antd';

import './KeyValuesTable.css';

Expand All @@ -32,10 +33,11 @@ function parseIfJson(value) {

type KeyValuesTableProps = {
data: { key: string, value: any }[],
linksGetter: ({ key: string, value: any }[], number) => { url: string, text: string }[],
};

export default function KeyValuesTable(props: KeyValuesTableProps) {
const { data } = props;
const { data, linksGetter } = props;
return (
<div className="KeyValueTable u-simple-scrollbars">
<table className="u-width-100">
Expand All @@ -45,12 +47,53 @@ export default function KeyValuesTable(props: KeyValuesTableProps) {
// eslint-disable-next-line react/no-danger
<div dangerouslySetInnerHTML={{ __html: jsonMarkup(parseIfJson(row.value)) }} />
);
let valueMarkup = jsonTable;
const links = linksGetter ? linksGetter(data, i) : null;
if (links && links.length === 1) {
valueMarkup = (
<a
className="KeyValueTable--link"
href={links[0].url}
title={links[0].text}
target="_blank"
rel="noopener noreferrer"
>
<Icon className="KeyValueTable--linkIcon" type="export" />
{jsonTable}
</a>
);
} else if (links && links.length > 1) {
const menuItems = (
<Menu>
{links.map((link, index) => {
const { text, url } = link;
return (
// `index` is necessary in the key because url can repeat
// eslint-disable-next-line react/no-array-index-key
<Menu.Item key={`${url}-${index}`}>
<a href={url} target="_blank" rel="noopener noreferrer">
{text}
</a>
</Menu.Item>
);
})}
</Menu>
);
valueMarkup = (
<Dropdown overlay={menuItems} placement="bottomRight" trigger={['click']}>
<a className="KeyValueTable--link">
<Icon className="KeyValueTable--linkIcon" type="profile" />
{jsonTable}
</a>
</Dropdown>
);
}
return (
// `i` is necessary in the key because row.key can repeat
// eslint-disable-next-line react/no-array-index-key
<tr key={`${row.key}-${i}`}>
<td className="KeyValueTable--keyColumn">{row.key}</td>
<td>{jsonTable}</td>
<td>{valueMarkup}</td>
</tr>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import './index.css';

type SpanDetailProps = {
detailState: DetailState,
linksGetter: ({ key: string, value: any }[], number) => { url: string, text: string }[],
logItemToggle: (string, Log) => void,
logsToggle: string => void,
processToggle: string => void,
Expand All @@ -37,7 +38,16 @@ type SpanDetailProps = {
};

export default function SpanDetail(props: SpanDetailProps) {
const { detailState, logItemToggle, logsToggle, processToggle, span, tagsToggle, traceStartTime } = props;
const {
detailState,
linksGetter,
logItemToggle,
logsToggle,
processToggle,
span,
tagsToggle,
traceStartTime,
} = props;
const { isTagsOpen, isProcessOpen, logs: logsState } = detailState;
const { operationName, process, duration, relativeStartTime, spanID, logs, tags } = span;
const overviewItems = [
Expand Down Expand Up @@ -73,6 +83,7 @@ export default function SpanDetail(props: SpanDetailProps) {
<AccordianKeyValues
data={tags}
label="Tags"
linksGetter={linksGetter}
isOpen={isTagsOpen}
onToggle={() => tagsToggle(spanID)}
/>
Expand All @@ -81,6 +92,7 @@ export default function SpanDetail(props: SpanDetailProps) {
className="ub-mb1"
data={process.tags}
label="Process"
linksGetter={linksGetter}
isOpen={isProcessOpen}
onToggle={() => processToggle(spanID)}
/>
Expand All @@ -89,6 +101,7 @@ export default function SpanDetail(props: SpanDetailProps) {
{logs &&
logs.length > 0 && (
<AccordianLogs
linksGetter={linksGetter}
logs={logs}
isOpen={logsState.isOpen}
openedItems={logsState.openedItems}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ type SpanDetailRowProps = {
detailState: DetailState,
onDetailToggled: string => void,
isFilteredOut: boolean,
linksGetter: (number, { key: string, value: any }[], number) => { url: string, text: string }[],
logItemToggle: (string, Log) => void,
logsToggle: string => void,
processToggle: string => void,
span: Span,
spanIndex: number,
tagsToggle: string => void,
traceStartTime: number,
};
Expand All @@ -45,6 +47,9 @@ export default class SpanDetailRow extends React.PureComponent<SpanDetailRowProp
this.props.onDetailToggled(this.props.span.spanID);
};

_linksGetter = (items: { key: string, value: any }[], itemIndex: number) =>
this.props.linksGetter(this.props.spanIndex, items, itemIndex);

render() {
const {
color,
Expand Down Expand Up @@ -76,6 +81,7 @@ export default class SpanDetailRow extends React.PureComponent<SpanDetailRowProp
<div className="detail-info-wrapper" style={{ borderTopColor: color }}>
<SpanDetail
detailState={detailState}
linksGetter={this._linksGetter}
logItemToggle={logItemToggle}
logsToggle={logsToggle}
processToggle={processToggle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
isErrorSpan,
spanContainsErredSpan,
} from './utils';
import getLinks from '../../../model/link-patterns';
import type { Accessors } from '../ScrollManager';
import type { Log, Span, Trace } from '../../../types';
import colorGenerator from '../../../utils/color-generator';
Expand Down Expand Up @@ -264,10 +265,13 @@ export class VirtualizedTraceViewImpl extends React.PureComponent<VirtualizedTra
return DEFAULT_HEIGHTS.detail;
};

linksGetter = (spanIndex: number, items: { key: string, value: any }[], itemIndex: number) =>
getLinks(this.props.trace, spanIndex, items, itemIndex);

renderRow = (key: string, style: Style, index: number, attrs: {}) => {
const { isDetail, span, spanIndex } = this.rowStates[index];
return isDetail
? this.renderSpanDetailRow(span, key, style, attrs)
? this.renderSpanDetailRow(span, spanIndex, key, style, attrs)
: this.renderSpanBarRow(span, spanIndex, key, style, attrs);
};

Expand Down Expand Up @@ -352,7 +356,7 @@ export class VirtualizedTraceViewImpl extends React.PureComponent<VirtualizedTra
);
}

renderSpanDetailRow(span: Span, key: string, style: Style, attrs: {}) {
renderSpanDetailRow(span: Span, spanIndex: number, key: string, style: Style, attrs: {}) {
const { spanID } = span;
const { serviceName } = span.process;
const {
Expand Down Expand Up @@ -380,10 +384,12 @@ export class VirtualizedTraceViewImpl extends React.PureComponent<VirtualizedTra
onDetailToggled={detailToggle}
detailState={detailState}
isFilteredOut={isFilteredOut}
linksGetter={this.linksGetter}
logItemToggle={detailLogItemToggle}
logsToggle={detailLogsToggle}
processToggle={detailProcessToggle}
span={span}
spanIndex={spanIndex}
tagsToggle={detailTagsToggle}
traceStartTime={trace.startTime}
/>
Expand Down
1 change: 1 addition & 0 deletions packages/jaeger-ui/src/constants/default-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default deepFreeze(
dagMaxNumServices: FALLBACK_DAG_MAX_NUM_SERVICES,
menuEnabled: true,
},
linkPatterns: [],
tracking: {
gaID: null,
trackErrors: true,
Expand Down
Loading

0 comments on commit 33fcae9

Please sign in to comment.