diff --git a/.eslintrc.js b/.eslintrc.js
index 7067da32f8..ce1327bdc9 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -21,7 +21,7 @@ module.exports = {
settings: {
'import/resolver': {
node: {
- extensions: ['.js', '.jsx', 'json', '.tsx'],
+ extensions: ['.js', '.jsx', 'json', '.tsx', ".ts"],
},
},
},
diff --git a/packages/jaeger-ui/index.html b/packages/jaeger-ui/index.html
index afb2efbe36..1f0be049bb 100644
--- a/packages/jaeger-ui/index.html
+++ b/packages/jaeger-ui/index.html
@@ -39,26 +39,10 @@
window.global = {};
diff --git a/packages/jaeger-ui/src/api/digma/ActionDispatcher.ts b/packages/jaeger-ui/src/api/digma/ActionDispatcher.ts
new file mode 100644
index 0000000000..b791699aef
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/ActionDispatcher.ts
@@ -0,0 +1,35 @@
+import { ActionListener } from "./types";
+
+export class ActionDispatcher {
+ private actions: {
+ [key: string]: ActionListener[];
+ };
+
+ constructor() {
+ this.actions = {};
+ }
+
+ public addActionListener(type: string, listener: ActionListener) {
+ if (!this.actions[type]) {
+ this.actions[type] = [listener];
+ } else {
+ this.actions[type].push(listener);
+ }
+ }
+
+ public removeActionListener(type: string, listener: ActionListener) {
+ if (this.actions[type]) {
+ this.actions[type] = this.actions[type].filter((x) => x !== listener);
+ }
+
+ if (this.actions[type].length === 0) {
+ delete this.actions[type];
+ }
+ }
+
+ public dispatch(type: string, data?: unknown): void {
+ if (this.actions[type]) {
+ this.actions[type].forEach(fn => fn(data));
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/jaeger-ui/src/api/digma/actions.ts b/packages/jaeger-ui/src/api/digma/actions.ts
new file mode 100644
index 0000000000..46d5f45833
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/actions.ts
@@ -0,0 +1,5 @@
+export const actions = {
+ GO_TO_SPAN: "GO_TO_SPAN",
+ GET_SPANS_WITH_RESOLVED_LOCATION: "GET_SPANS_WITH_RESOLVED_LOCATION",
+ SET_SPANS_WITH_RESOLVED_LOCATION:"SET_SPANS_WITH_RESOLVED_LOCATION"
+}
\ No newline at end of file
diff --git a/packages/jaeger-ui/src/api/digma/dispatcher.ts b/packages/jaeger-ui/src/api/digma/dispatcher.ts
new file mode 100644
index 0000000000..2941e86bcc
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/dispatcher.ts
@@ -0,0 +1,3 @@
+import { ActionDispatcher } from "./ActionDispatcher";
+
+export const dispatcher = new ActionDispatcher();
\ No newline at end of file
diff --git a/packages/jaeger-ui/src/api/digma/index.ts b/packages/jaeger-ui/src/api/digma/index.ts
new file mode 100644
index 0000000000..e392c711e4
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/index.ts
@@ -0,0 +1,58 @@
+import { isObject } from "../../utils/ts/typeGuards/isObject";
+import { ActionDispatcher } from "./ActionDispatcher";
+import { updateState } from "./state";
+import { DigmaMessageEvent, IDigmaOutgoingMessageData } from "./types";
+
+const isDigmaMessageEvent = (e: MessageEvent): e is DigmaMessageEvent =>
+ isObject(e.data) && e.data.type === "digma";
+
+export const initializeDigmaMessageListener = (
+ dispatcher: ActionDispatcher
+) => {
+ window.addEventListener("message", e => {
+ if (isDigmaMessageEvent(e)) {
+ console.info("Digma message received: ", e);
+
+ updateState(e.data.action, e.data.payload);
+
+ dispatcher.dispatch(e.data.action, e.data.payload);
+ }
+ });
+};
+
+export const sendMessage = (
+ message: IDigmaOutgoingMessageData
+): string | undefined => {
+ console.info("Message to send:", message);
+
+ updateState(message.action, message.payload);
+
+ if (window.sendMessageToVSCode) {
+ window.sendMessageToVSCode(message);
+ console.info("Message has been sent to VS Code: ", message);
+ }
+
+ if (window.cefQuery) {
+ return window.cefQuery({
+ request: JSON.stringify(message),
+ onSuccess (response) {
+ console.info("cefQuery has been successfully sent: %s", response);
+ },
+ onFailure (errorCode, errorMessage) {
+ console.error(
+ "Failed to send cefQuery: %d, %s",
+ errorCode,
+ errorMessage
+ );
+ }
+ });
+ }
+
+ return undefined;
+};
+
+export const cancelMessage = (messageId: string) => {
+ if (window.cefQueryCancel) {
+ window.cefQueryCancel(messageId);
+ }
+};
diff --git a/packages/jaeger-ui/src/api/digma/state.ts b/packages/jaeger-ui/src/api/digma/state.ts
new file mode 100644
index 0000000000..8f94e5b03d
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/state.ts
@@ -0,0 +1,24 @@
+import { actions } from "./actions";
+import { SetSpansWithResolvedLocationsData } from "./types";
+
+export const state: {
+ pendingOperationsCount: number,
+ spansWithResolvedLocation: SetSpansWithResolvedLocationsData
+} = {
+ pendingOperationsCount: 0,
+ spansWithResolvedLocation: {}
+};
+
+export const updateState = (action: string, payload: any) => {
+ switch(action) {
+ case (actions.GET_SPANS_WITH_RESOLVED_LOCATION):
+ state.pendingOperationsCount++;
+ break;
+ case (actions.SET_SPANS_WITH_RESOLVED_LOCATION):
+ state.spansWithResolvedLocation = payload;
+ state.pendingOperationsCount--;
+ break;
+ default:
+ }
+}
+
diff --git a/packages/jaeger-ui/src/api/digma/types.ts b/packages/jaeger-ui/src/api/digma/types.ts
new file mode 100644
index 0000000000..4f411b8a7b
--- /dev/null
+++ b/packages/jaeger-ui/src/api/digma/types.ts
@@ -0,0 +1,20 @@
+export type ActionListener = (data: unknown) => void;
+
+export interface IDigmaIncomingMessageData {
+ type: "digma";
+ action: string;
+ payload?: unknown;
+}
+
+export interface IDigmaOutgoingMessageData {
+ action: string;
+ payload?: Record;
+}
+
+export type DigmaMessageEvent = MessageEvent;
+
+interface ISpanInfo {
+ importance?: number
+}
+
+export type SetSpansWithResolvedLocationsData = Record
\ No newline at end of file
diff --git a/packages/jaeger-ui/src/api/jaeger.js b/packages/jaeger-ui/src/api/jaeger.js
index eb42982308..254f3fee9f 100644
--- a/packages/jaeger-ui/src/api/jaeger.js
+++ b/packages/jaeger-ui/src/api/jaeger.js
@@ -17,6 +17,7 @@ import moment from 'moment';
import queryString from 'query-string';
import prefixUrl from '../utils/prefix-url';
+import { isString } from '../utils/ts/typeGuards/isString';
// export for tests
export function getMessageFromError(errData, status) {
@@ -76,7 +77,7 @@ function getJSON(url, options = {}) {
});
}
-export const DEFAULT_API_ROOT = window.VS_CODE_SETTINGS.apiBaseUrl ? `${window.VS_CODE_SETTINGS.apiBaseUrl}/api/` : prefixUrl('/api/');
+export const DEFAULT_API_ROOT = isString(window.apiBaseUrl) ? `${window.apiBaseUrl}/api/` : prefixUrl('/api/');
export const ANALYTICS_ROOT = prefixUrl('/analytics/');
export const DEFAULT_DEPENDENCY_LOOKBACK = moment.duration(1, 'weeks').asMilliseconds();
diff --git a/packages/jaeger-ui/src/components/App/index.jsx b/packages/jaeger-ui/src/components/App/index.jsx
index 9fecf249c3..a0731862a7 100644
--- a/packages/jaeger-ui/src/components/App/index.jsx
+++ b/packages/jaeger-ui/src/components/App/index.jsx
@@ -38,6 +38,7 @@ import JaegerAPI, { DEFAULT_API_ROOT } from '../../api/jaeger';
import configureStore from '../../utils/configure-store';
import processScripts from '../../utils/config/process-scripts';
import prefixUrl from '../../utils/prefix-url';
+import { isString } from '../../utils/ts/typeGuards/isString';
import '../common/vars.css';
import '../common/utils.css';
@@ -54,10 +55,10 @@ export default class JaegerUIApp extends Component {
}
render() {
- // Navigate to URL provided by VS Code
- if (window.VS_CODE_SETTINGS.startPath) {
- const urlToNavigate = window.VS_CODE_SETTINGS.startPath;
- window.VS_CODE_SETTINGS.startPath = "";
+ // Navigate to URL provided on app start
+ if (isString(window.initialRoutePath) && window.initialRoutePath) {
+ const urlToNavigate = window.initialRoutePath;
+ window.initialRoutePath = "";
history.push(urlToNavigate);
}
diff --git a/packages/jaeger-ui/src/components/Monitor/EmptyState/index.tsx b/packages/jaeger-ui/src/components/Monitor/EmptyState/index.tsx
index adc6af1087..781a5c1b8a 100644
--- a/packages/jaeger-ui/src/components/Monitor/EmptyState/index.tsx
+++ b/packages/jaeger-ui/src/components/Monitor/EmptyState/index.tsx
@@ -17,8 +17,11 @@ import { Row, Col, Button, Alert } from 'antd';
import './index.css';
import { MonitorEmptyStateConfig } from '../../../types/config';
import { getConfigValue } from '../../../utils/config/get-config';
+import { getStaticAssetPath } from '../../../utils/getStaticAssetPath';
import monitorImg from './media/monitor.png';
+const monitorImgUrl = getStaticAssetPath(monitorImg);
+
export default class MonitorATMEmptyState extends React.PureComponent {
config: MonitorEmptyStateConfig;
@@ -29,8 +32,6 @@ export default class MonitorATMEmptyState extends React.PureComponent {
}
render() {
- const monitorImgUrl = window.VS_CODE_SETTINGS.staticPath ? new URL(monitorImg, window.VS_CODE_SETTINGS.staticPath).href : monitorImg;
-
return (
diff --git a/packages/jaeger-ui/src/components/SearchTracePage/index.jsx b/packages/jaeger-ui/src/components/SearchTracePage/index.jsx
index e5cad4838d..9b8ab0f0c0 100644
--- a/packages/jaeger-ui/src/components/SearchTracePage/index.jsx
+++ b/packages/jaeger-ui/src/components/SearchTracePage/index.jsx
@@ -34,6 +34,7 @@ import { actions as traceDiffActions } from '../TraceDiff/duck';
import { fetchedState } from '../../constants';
import { sortTraces } from '../../model/search';
import { stripEmbeddedState } from '../../utils/embedded-url';
+import { getStaticAssetPath } from '../../utils/getStaticAssetPath';
import FileLoader from './FileLoader';
import './index.css';
@@ -41,8 +42,10 @@ import JaegerLogo from '../../img/jaeger-logo.svg';
const TabPane = Tabs.TabPane;
+const logoUrl = getStaticAssetPath(JaegerLogo);
+
// Sanitize query params to filter out ones provided by VS Code
-const sanitizeQueryParams = (params) => {
+const sanitizeQueryParams = params => {
const VS_CODE_PARAMS = [
"id",
"origin",
@@ -55,7 +58,7 @@ const sanitizeQueryParams = (params) => {
const filteredParams = {};
- Object.keys(params).forEach((key) => {
+ Object.keys(params).forEach(key => {
if (!VS_CODE_PARAMS.includes(key)) {
filteredParams[key] = params[key]
}
@@ -121,7 +124,6 @@ export class SearchTracePageImpl extends Component {
const hasTraceResults = traceResults && traceResults.length > 0;
const showErrors = errors && !loadingTraces;
const showLogo = isHomepage && !hasTraceResults && !loadingTraces && !errors;
- const logoUrl = window.VS_CODE_SETTINGS.staticPath ? new URL(JaegerLogo, window.VS_CODE_SETTINGS.staticPath).href : JaegerLogo;
return (
{!embedded && (
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx
index da4f93d23a..a9a4bc569c 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBarRow.tsx
@@ -23,17 +23,17 @@ import { formatDuration, ViewedBoundsFunctionType } from './utils';
import SpanTreeOffset from './SpanTreeOffset';
import SpanBar from './SpanBar';
import Ticks from './Ticks';
-
+import { dispatcher } from '../../../api/digma/dispatcher';
+import { actions } from '../../../api/digma/actions';
+import { state as globalState } from '../../../api/digma/state';
+import { getStaticAssetPath } from '../../../utils/getStaticAssetPath';
import { TNil } from '../../../types';
import { Span } from '../../../types/trace';
import codeIcon from '../../../img/code.svg';
import './SpanBarRow.css';
-
-type SpanInfo = {
- importance?: number
-}
+import { SetSpansWithResolvedLocationsData } from '../../../api/digma/types';
type SpanBarRowProps = {
className?: string;
@@ -72,6 +72,8 @@ type SpanBarRowState = {
importance?: number;
}
+const codeIconUrl = getStaticAssetPath(codeIcon);
+
/**
* This was originally a stateless function, but changing to a PureComponent
* reduced the render time of expanding a span row detail by ~50%. This is
@@ -83,7 +85,7 @@ type SpanBarRowState = {
export default class SpanBarRow extends React.PureComponent {
constructor(props: SpanBarRowProps) {
super(props);
- const span = window.spansWithResolvedLocation[props.span.spanID];
+ const span = globalState.spansWithResolvedLocation[props.span.spanID];
this.state = {
hasResolvedLocation: Boolean(span),
importance: span && span.importance,
@@ -103,23 +105,20 @@ export default class SpanBarRow extends React.PureComponent }}) => {
- const message = e.data;
- if (message.command === "setSpansWithResolvedLocation") {
- const span = message.data[this.props.span.spanID];
+ updateSpanInfo = (data: unknown) => {
+ const span = (data as SetSpansWithResolvedLocationsData)[this.props.span.spanID];
this.setState({
hasResolvedLocation: Boolean(span),
importance: span && span.importance
});
- }
}
componentDidMount(): void {
- window.addEventListener('message', this.updateSpanInfo);
+ dispatcher.addActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateSpanInfo);
}
componentWillUnmount(): void {
- window.removeEventListener('message', this.updateSpanInfo);
+ dispatcher.removeActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateSpanInfo);
}
getImportanceAltText(importance?: number): string {
@@ -172,7 +171,6 @@ export default class SpanBarRow extends React.PureComponent❗️
}
- {this.state.hasResolvedLocation &&
}
+ {this.state.hasResolvedLocation &&
}
{span.references && span.references.length > 1 && (
', () => {
props.logsToggle.mockReset();
props.logItemToggle.mockReset();
wrapper = shallow();
+ jest.spyOn(window, 'sendMessageToDigma').mockImplementation(jest.fn());
});
it('renders without exploding', () => {
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx
index 0bb2b5746e..10bf37c8a1 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanDetail/index.tsx
@@ -14,6 +14,7 @@
import React from 'react';
import { Divider, Tooltip } from 'antd';
+import { Link as RouterLink } from 'react-router-dom';
import AccordianKeyValues from './AccordianKeyValues';
import AccordianLogs from './AccordianLogs';
@@ -23,12 +24,15 @@ import DetailState from './DetailState';
import { formatDuration } from '../utils';
import CopyIcon from '../../../common/CopyIcon';
import LabeledList from '../../../common/LabeledList';
-import { Link as RouterLink } from 'react-router-dom';
import { TNil } from '../../../../types';
import { KeyValuePair, Link, Log, Span } from '../../../../types/trace';
import './index.css';
+import { actions } from '../../../../api/digma/actions';
+import { dispatcher } from '../../../../api/digma/dispatcher';
+import { state as globalState } from '../../../../api/digma/state';
+import { SetSpansWithResolvedLocationsData } from '../../../../api/digma/types';
type SpanDetailProps = {
detailState: DetailState;
@@ -44,11 +48,6 @@ type SpanDetailProps = {
focusSpan: (uiFind: string) => void;
};
-type SpanInfo = {
- hasResolvedLocation: boolean,
- importance?: number
-}
-
type SpanDetailState = {
hasResolvedLocation: boolean;
importance?: number
@@ -57,30 +56,27 @@ type SpanDetailState = {
export default class SpanDetail extends React.Component {
constructor(props: SpanDetailProps) {
super(props);
- const span = window.spansWithResolvedLocation[props.span.spanID];
+ const span = globalState.spansWithResolvedLocation[props.span.spanID];
this.state = {
hasResolvedLocation: Boolean(span),
importance: span && span.importance,
}
}
- updateSpanInfo = (e:{ data: { command: string, data: Record }}) => {
- const message = e.data;
- if (message.command === "setSpansWithResolvedLocation") {
- const span = message.data[this.props.span.spanID];
- this.setState({
- hasResolvedLocation: Boolean(span),
- importance: span && span.importance
- });
- }
- }
-
componentDidMount(): void {
- window.addEventListener('message', this.updateSpanInfo);
+ dispatcher.addActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateSpanInfo);
}
componentWillUnmount(): void {
- window.removeEventListener('message', this.updateSpanInfo);
+ dispatcher.removeActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateSpanInfo);
+ }
+
+ updateSpanInfo = (data: unknown) => {
+ const span = (data as SetSpansWithResolvedLocationsData)[this.props.span.spanID];
+ this.setState({
+ hasResolvedLocation: Boolean(span),
+ importance: span && span.importance
+ });
}
getImportanceAltText(importance?: number): string {
@@ -96,13 +92,19 @@ export default class SpanDetail extends React.Component) => {
e.preventDefault();
- const tag = this.props.span.tags.find((tag: any) => tag.key === "otel.library.name");
- if (tag && window.sendMessageToVSCode) {
- window.sendMessageToVSCode({
- command: "goToSpanLocation",
- data: {
+ const otelLibraryNameTag = this.props.span.tags.find((tag: any) => tag.key === "otel.library.name");
+ const functionTag = this.props.span.tags.find((tag: any) => tag.key === "code.function");
+ const namespaceTag = this.props.span.tags.find((tag: any) => tag.key === "code.namespace");
+
+ if (otelLibraryNameTag) {
+ window.sendMessageToDigma({
+ action: actions.GO_TO_SPAN,
+ payload: {
+ id: this.props.span.spanID,
name: this.props.span.operationName,
- instrumentationLibrary: tag && tag.value
+ instrumentationLibrary: otelLibraryNameTag.value,
+ ...(functionTag ? {function: functionTag.value} : {}),
+ ...(namespaceTag ? {namespace: namespaceTag.value} : {}),
}
});
}
@@ -149,7 +151,7 @@ export default class SpanDetail extends React.Component
{this.state.hasResolvedLocation ?
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
index 5d99585d23..36d5d87f89 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/TimelineHeaderRow/TimelineHeaderRow.tsx
@@ -23,6 +23,9 @@ import { TUpdateViewRangeTimeFunction, IViewRangeTime, ViewRangeTimeUpdate } fro
import './TimelineHeaderRow.css';
import LoadingIndicator from '../../../common/LoadingIndicator';
+import { dispatcher } from '../../../../api/digma/dispatcher';
+import { actions } from '../../../../api/digma/actions';
+import { state as globalState } from '../../../../api/digma/state';
type TimelineHeaderRowProps = {
duration: number;
@@ -46,26 +49,22 @@ export default class SpanDetailRow extends React.PureComponent }}) => {
- const message = e.data;
- if (message.command === "setSpansWithResolvedLocation") {
- this.setState({
- isLoading: false
- });
- }
- }
-
componentDidMount(): void {
- window.addEventListener('message', this.updateIsLoading);
+ dispatcher.addActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateIsLoading);
}
componentWillUnmount(): void {
- window.removeEventListener('message', this.updateIsLoading);
+ dispatcher.removeActionListener(actions.SET_SPANS_WITH_RESOLVED_LOCATION, this.updateIsLoading);
+ }
+
+ updateIsLoading = () => {
+ this.setState({
+ isLoading: false
+ });
}
render() {
@@ -89,7 +88,7 @@ export default class SpanDetailRow extends React.PureComponent
Service & Operation
{this.state.isLoading &&
-
+
Loading data...
}
', () => {
beforeAll(() => {
filterSpansSpy.mockReturnValue(new Set());
+ jest.spyOn(window, 'sendMessageToDigma').mockImplementation(jest.fn());
});
beforeEach(() => {
diff --git a/packages/jaeger-ui/src/components/TracePage/index.tsx b/packages/jaeger-ui/src/components/TracePage/index.tsx
index cb07d989a3..bcfe9b2feb 100644
--- a/packages/jaeger-ui/src/components/TracePage/index.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/index.tsx
@@ -59,6 +59,7 @@ import TraceStatistics from './TraceStatistics/index';
import TraceSpanView from './TraceSpanView/index';
import TraceFlamegraph from './TraceFlamegraph/index';
import { TraceGraphConfig } from '../../types/config';
+import { actions } from '../../api/digma/actions';
import './index.css';
@@ -163,6 +164,11 @@ export class TracePageImpl extends React.PureComponent {
}
componentDidMount() {
+ const trace = this.props.trace;
+ if (trace && trace.data) {
+ this.getSpansWithResolvedLocations(trace.data);
+ }
+
this.ensureTraceFetched();
this.updateViewRangeTime(0, 1);
/* istanbul ignore if */
@@ -185,29 +191,14 @@ export class TracePageImpl extends React.PureComponent {
componentDidUpdate({ id: prevID, trace: prevTrace }: TProps) {
const { id, trace } = this.props;
- // Get all the trace spans and send it to VS Code extension
- // to verify if they have resolved location
if (
- window.sendMessageToVSCode &&
trace &&
- trace != prevTrace &&
+ trace !== prevTrace &&
trace.data &&
trace.state &&
trace.state === fetchedState.DONE
) {
- window.sendMessageToVSCode({
- command: "getTraceSpansLocations",
- data: trace.data.spans.map(span => {
- const tag = span.tags.find(tag => tag.key === "otel.library.name");
-
- return {
- id: span.spanID,
- name: span.operationName,
- instrumentationLibrary: tag && tag.value
- }}).filter(span => span.instrumentationLibrary)
- });
-
- window.pendingOperationsCount++;
+ this.getSpansWithResolvedLocations(trace.data)
}
this._scrollManager.setTrace(trace && trace.data);
@@ -233,6 +224,28 @@ export class TracePageImpl extends React.PureComponent {
});
}
+ getSpansWithResolvedLocations(trace: Trace) {
+ // Get all the trace spans and send it Digma IDE plugin
+ // to verify if they have resolved location
+ window.sendMessageToDigma({
+ action: actions.GET_SPANS_WITH_RESOLVED_LOCATION,
+ payload: {
+ spans: trace.spans.map(span => {
+ const otelLibraryNameTag = span.tags.find(tag => tag.key === "otel.library.name");
+ const functionTag = span.tags.find(tag => tag.key === "code.function");
+ const namespaceTag = span.tags.find(tag => tag.key === "code.namespace");
+
+ return {
+ id: span.spanID,
+ name: span.operationName,
+ instrumentationLibrary: otelLibraryNameTag && otelLibraryNameTag.value,
+ ...(functionTag ? {function: functionTag.value} : {}),
+ ...(namespaceTag ? {namespace: namespaceTag.value} : {}),
+ }}).filter(span => span.instrumentationLibrary)
+ }
+ });
+ }
+
_adjustViewRange(startChange: number, endChange: number, trackSrc: string) {
const [viewStart, viewEnd] = this.state.viewRange.time.current;
let start = _clamp(viewStart + startChange, 0, 0.99);
diff --git a/packages/jaeger-ui/src/index.jsx b/packages/jaeger-ui/src/index.jsx
index 7d2e94fd24..af11e6b8ec 100644
--- a/packages/jaeger-ui/src/index.jsx
+++ b/packages/jaeger-ui/src/index.jsx
@@ -24,6 +24,9 @@ import { createRoot } from 'react-dom/client';
import JaegerUIApp from './components/App';
import { context as trackingContext } from './utils/tracking';
+import { cancelMessage, initializeDigmaMessageListener, sendMessage } from './api/digma';
+import { dispatcher } from './api/digma/dispatcher';
+
// these need to go after the App import
/* eslint-disable import/first */
import 'u-basscss/css/flexbox.css';
@@ -37,6 +40,11 @@ const UI_ROOT_ID = 'jaeger-ui-root';
const root = createRoot(document.getElementById(UI_ROOT_ID));
+initializeDigmaMessageListener(dispatcher);
+
+window.sendMessageToDigma = sendMessage;
+window.cancelMessageToDigma = cancelMessage;
+
if (typeof trackingContext === 'object' && trackingContext !== null) {
trackingContext.context(() => {
root.render(
diff --git a/packages/jaeger-ui/src/reducers/embedded.tsx b/packages/jaeger-ui/src/reducers/embedded.tsx
index 45054eb30b..82955df942 100644
--- a/packages/jaeger-ui/src/reducers/embedded.tsx
+++ b/packages/jaeger-ui/src/reducers/embedded.tsx
@@ -21,8 +21,8 @@ export default function embeddedConfig(state: EmbeddedState | undefined) {
if (state === undefined) {
let search = _get(window, 'location.search');
- let params = new URLSearchParams(search);
- if (window.VS_CODE_SETTINGS.embeddedMode && !params.get("uiEmbed")) {
+ const params = new URLSearchParams(search);
+ if (typeof window.embeddedMode === "boolean" && window.embeddedMode && !params.get("uiEmbed")) {
params.set("uiEmbed", VERSION_0);
search = params.toString();
}
diff --git a/packages/jaeger-ui/src/utils/getStaticAssetPath.ts b/packages/jaeger-ui/src/utils/getStaticAssetPath.ts
new file mode 100644
index 0000000000..d16c48344b
--- /dev/null
+++ b/packages/jaeger-ui/src/utils/getStaticAssetPath.ts
@@ -0,0 +1,4 @@
+import { isString } from "./ts/typeGuards/isString";
+
+export const getStaticAssetPath = (path: string) =>
+ isString(window.staticPath) ? new URL(path, window.staticPath).href : path
diff --git a/packages/jaeger-ui/src/utils/ts/typeGuards/isNull.ts b/packages/jaeger-ui/src/utils/ts/typeGuards/isNull.ts
new file mode 100644
index 0000000000..b20e3a4d29
--- /dev/null
+++ b/packages/jaeger-ui/src/utils/ts/typeGuards/isNull.ts
@@ -0,0 +1 @@
+export const isNull = (x: unknown): x is null => x === null;
diff --git a/packages/jaeger-ui/src/utils/ts/typeGuards/isObject.ts b/packages/jaeger-ui/src/utils/ts/typeGuards/isObject.ts
new file mode 100644
index 0000000000..acdab276c6
--- /dev/null
+++ b/packages/jaeger-ui/src/utils/ts/typeGuards/isObject.ts
@@ -0,0 +1,4 @@
+import { isNull } from "./isNull";
+
+export const isObject = (x: unknown): x is Record =>
+ typeof x === "object" && !isNull(x);
diff --git a/packages/jaeger-ui/src/utils/ts/typeGuards/isString.ts b/packages/jaeger-ui/src/utils/ts/typeGuards/isString.ts
new file mode 100644
index 0000000000..e032004f9c
--- /dev/null
+++ b/packages/jaeger-ui/src/utils/ts/typeGuards/isString.ts
@@ -0,0 +1 @@
+export const isString = (x: unknown): x is string => typeof x === "string";
diff --git a/packages/jaeger-ui/test/jest-per-test-setup.js b/packages/jaeger-ui/test/jest-per-test-setup.js
index d6c587d48d..4895275897 100644
--- a/packages/jaeger-ui/test/jest-per-test-setup.js
+++ b/packages/jaeger-ui/test/jest-per-test-setup.js
@@ -38,6 +38,8 @@ window.getJaegerVersion = () => ({
buildDate: '',
});
+window.sendMessageToDigma = () => {};
+
global.__APP_ENVIRONMENT__ = 'test';
global.__REACT_APP_GA_DEBUG__ = '';
global.__REACT_APP_VSN_STATE__ = '';
diff --git a/packages/jaeger-ui/tsconfig.json b/packages/jaeger-ui/tsconfig.json
index b1dd3c67ac..f7870445fa 100644
--- a/packages/jaeger-ui/tsconfig.json
+++ b/packages/jaeger-ui/tsconfig.json
@@ -13,5 +13,6 @@
// limitations under the License.
{
"extends": "../../tsconfig",
- "include": ["src/**/*.tsx", "typings"]
+ "include": ["src", "typings"],
+ "exclude": ["src/**/*.d.ts"],
}
diff --git a/packages/jaeger-ui/typings/custom.d.ts b/packages/jaeger-ui/typings/custom.d.ts
index 4586b3c5f5..292a3ff98b 100644
--- a/packages/jaeger-ui/typings/custom.d.ts
+++ b/packages/jaeger-ui/typings/custom.d.ts
@@ -23,15 +23,21 @@ declare interface Window {
// For getting ui config
getJaegerUiConfig?: () => Record;
getJaegerVersion?: () => Record;
- sendMessageToVSCode?: (message: { command: string, data: any }) => void;
- spansWithResolvedLocation: Record;
- pendingOperationsCount: number;
- VS_CODE_SETTINGS: {
- apiBaseUrl: string;
- startPath: string;
- staticPath: string;
- embeddedMode: boolean;
- }
+ sendMessageToVSCode?: (message) => void;
+ cefQuery?: (query: {
+ request: string;
+ persistent?: boolean;
+ onSuccess: (response) => void;
+ onFailure: (error_code, error_message) => void;
+ }) => string;
+ cefQueryCancel?: (request_id: string) => void;
+ sendMessageToDigma: (message) => string | undefined;
+ cancelMessageToDigma: (request_id: string) => void;
+ platform?: unknown;
+ apiBaseUrl?: unknown;
+ initialRoutePath?: unknown;
+ embeddedMode?: unknown;
+ staticPath?: unknown;
}
declare const __REACT_APP_GA_DEBUG__: string | undefined;