Skip to content

Commit

Permalink
Derive DDG from search results
Browse files Browse the repository at this point in the history
Signed-off-by: Ruben Vargas <ruben.vp8510@gmail.com>
  • Loading branch information
rubenvp8510 committed Oct 3, 2019
1 parent a0b4b11 commit e4ed5fa
Show file tree
Hide file tree
Showing 17 changed files with 460 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type TProps = {
vertexKey: string;
};

// While browsers suport URLs of unlimited length, many server clients do not handle more than this max
// While browsers support URLs of unlimited length, many server clients do not handle more than this max
const MAX_LENGTH = 2083;
const MAX_LINKED_TRACES = 35;
const MIN_LENGTH = getSearchUrl().length;
Expand All @@ -55,13 +55,17 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
getVisiblePathElems: (vertexKey: string) => PathElem[] | undefined,
setViewModifier: (vertexKey: string, viewModifier: EViewModifier, enable: boolean) => void,
density: EDdgDensity,
showOp: boolean
showOp: boolean,
baseUrl: string,
extraUrlArgs: { [key: string]: unknown } | undefined
) {
return function renderNode(vertex: TDdgVertex, utils: TRendererUtils, lv: TLayoutVertex<any> | null) {
const { isFocalNode, key, operation, service } = vertex;
return (
<DdgNodeContent
focalNodeUrl={isFocalNode ? null : getUrl({ density, operation, service, showOp })}
focalNodeUrl={
isFocalNode ? null : getUrl({ density, operation, service, showOp, ...extraUrlArgs }, baseUrl)
}
getVisiblePathElems={getVisiblePathElems}
isFocalNode={isFocalNode}
isPositioned={Boolean(lv)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type TProps = {
uiFindMatches: Set<TDdgVertex> | undefined;
vertices: TDdgVertex[];
verticesViewModifiers: Map<string, number>;
baseUrl: string;
extraUrlArgs?: { [key: string]: unknown };
};

// The dichotomy between w/ & w/o VMs assumes that any edge VM neccesitates unmodified edges are de-emphasized
Expand Down Expand Up @@ -82,6 +84,8 @@ export default class Graph extends PureComponent<TProps> {
uiFindMatches,
vertices,
verticesViewModifiers,
baseUrl,
extraUrlArgs,
} = this.props;
const nodeRenderers = this.getNodeRenderers(uiFindMatches || this.emptyFindSet, verticesViewModifiers);

Expand Down Expand Up @@ -134,7 +138,14 @@ export default class Graph extends PureComponent<TProps> {
layerType: 'html',
measurable: true,
measureNode: DdgNodeContent.measureNode,
renderNode: this.getNodeContentRenderer(getVisiblePathElems, setViewModifier, density, showOp),
renderNode: this.getNodeContentRenderer(
getVisiblePathElems,
setViewModifier,
density,
showOp,
baseUrl,
extraUrlArgs
),
},
]}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type TProps = {
distanceToPathElems?: TDdgDistanceToPathElems;
handleClick: (distance: number, direction: EDirection) => void;
visEncoding?: string;
extraUrlArgs?: { [key: string]: unknown };
};

export default memo(function HopsSelector({ distanceToPathElems, handleClick, visEncoding }: TProps) {
Expand Down
45 changes: 28 additions & 17 deletions packages/jaeger-ui/src/components/DeepDependencies/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,16 @@ type TProps = {
toggleShowOperations: (enable: boolean) => void;
uiFindCount: number | undefined;
visEncoding?: string;
showParameters?: boolean;
extraUrlArgs?: { [key: string]: unknown };
};
export default class Header extends React.PureComponent<TProps> {
private _uiFindInput: React.RefObject<Input> = React.createRef();

static defaultProps = {
showParameters: true,
};

focusUiFindInput = () => {
if (this._uiFindInput.current) {
this._uiFindInput.current.focus();
Expand Down Expand Up @@ -101,30 +107,34 @@ export default class Header extends React.PureComponent<TProps> {
showOperations,
toggleShowOperations,
visEncoding,
showParameters,
extraUrlArgs,
} = this.props;

return (
<header className="DdgHeader">
<div className="DdgHeader--paramsHeader">
<NameSelector
label="Service:"
placeholder="Select a service…"
value={service || null}
setValue={setService}
required
options={services || []}
/>
{service && (
{showParameters && (
<div className="DdgHeader--paramsHeader">
<NameSelector
label="Operation:"
placeholder="Select an operation…"
value={operation || null}
setValue={setOperation}
label="Service:"
placeholder="Select a service…"
value={service || null}
setValue={setService}
required
options={operations || []}
options={services || []}
/>
)}
</div>
{service && (
<NameSelector
label="Operation:"
placeholder="Select an operation…"
value={operation || null}
setValue={setOperation}
required
options={operations || []}
/>
)}
</div>
)}
<div className="DdgHeader--controlHeader">
<LayoutSettings
density={density}
Expand All @@ -136,6 +146,7 @@ export default class Header extends React.PureComponent<TProps> {
distanceToPathElems={distanceToPathElems}
handleClick={setDistance}
visEncoding={visEncoding}
extraUrlArgs={extraUrlArgs}
/>
<div className="DdgHeader--findWrapper">
<div className="DdgHeader--uiFind" role="button" onClick={this.focusUiFindInput}>
Expand Down
15 changes: 9 additions & 6 deletions packages/jaeger-ui/src/components/DeepDependencies/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ describe('DeepDependencyGraphPage', () => {
const value = `new ${propName}`;
const kwarg = { [propName]: value };
ddgPageImpl.updateUrlState(kwarg);
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, props.urlState, kwarg));
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, props.urlState, kwarg), undefined);
expect(props.history.push).toHaveBeenCalledTimes(i + 1);
});
});
Expand All @@ -115,7 +115,7 @@ describe('DeepDependencyGraphPage', () => {
start: 'new start',
};
ddgPageImpl.updateUrlState(kwarg);
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, props.urlState, kwarg));
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, props.urlState, kwarg), undefined);
expect(props.history.push).toHaveBeenCalledTimes(1);
});

Expand All @@ -130,7 +130,7 @@ describe('DeepDependencyGraphPage', () => {
};
const ddgPageWithFewerProps = new DeepDependencyGraphPageImpl(otherProps);
ddgPageWithFewerProps.updateUrlState(kwarg);
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, otherUrlState, kwarg));
expect(getUrlSpy).toHaveBeenLastCalledWith(Object.assign({}, otherUrlState, kwarg), undefined);
expect(getUrlSpy).not.toHaveBeenLastCalledWith(expect.objectContaining({ start: expect.anything() }));
expect(props.history.push).toHaveBeenCalledTimes(1);
});
Expand Down Expand Up @@ -172,7 +172,8 @@ describe('DeepDependencyGraphPage', () => {
prevVisEncoding: visEncoding,
});
expect(getUrlSpy).toHaveBeenLastCalledWith(
Object.assign({}, props.urlState, { visEncoding: mockNewEncoding })
Object.assign({}, props.urlState, { visEncoding: mockNewEncoding }),
undefined
);
expect(props.history.push).toHaveBeenCalledTimes(1);
});
Expand All @@ -183,7 +184,8 @@ describe('DeepDependencyGraphPage', () => {
const operation = 'newOperation';
ddgPageImpl.setOperation(operation);
expect(getUrlSpy).toHaveBeenLastCalledWith(
Object.assign({}, props.urlState, { operation, visEncoding: undefined })
Object.assign({}, props.urlState, { operation, visEncoding: undefined }),
undefined
);
expect(props.history.push).toHaveBeenCalledTimes(1);
});
Expand All @@ -199,7 +201,8 @@ describe('DeepDependencyGraphPage', () => {
it('updates service and clears operation and visEncoding', () => {
ddgPageImpl.setService(service);
expect(getUrlSpy).toHaveBeenLastCalledWith(
Object.assign({}, props.urlState, { operation: undefined, service, visEncoding: undefined })
Object.assign({}, props.urlState, { operation: undefined, service, visEncoding: undefined }),
undefined
);
expect(props.history.push).toHaveBeenCalledTimes(1);
});
Expand Down
37 changes: 29 additions & 8 deletions packages/jaeger-ui/src/components/DeepDependencies/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { connect } from 'react-redux';

import Header from './Header';
import Graph from './Graph';
import { getUrl, getUrlState } from './url';
import { getUrl, getUrlState, ROUTE_PATH } from './url';
import ErrorMessage from '../common/ErrorMessage';
import LoadingIndicator from '../common/LoadingIndicator';
import { extractUiFindFromState, TExtractUiFindFromStateReturn } from '../common/UiFindInput';
Expand All @@ -43,7 +43,7 @@ import { TDdgStateEntry } from '../../types/TDdgState';

import './index.css';

type TDispatchProps = {
export type TDispatchProps = {
addViewModifier: (kwarg: TDdgModelParams & { viewModifier: number; visibilityIndices: number[] }) => void;
fetchDeepDependencyGraph: (query: TDdgModelParams) => void;
fetchServices: () => void;
Expand All @@ -53,23 +53,31 @@ type TDispatchProps = {
) => void;
};

type TReduxProps = TExtractUiFindFromStateReturn & {
export type TReduxProps = TExtractUiFindFromStateReturn & {
graph: GraphModel | undefined;
graphState?: TDdgStateEntry;
operationsForService: Record<string, string[]>;
services?: string[] | null;
urlState: TDdgSparseUrlState;
};

type TOwnProps = {
export type TOwnProps = {
history: RouterHistory;
location: Location;
showServicesOpsHeader: boolean;
baseUrl: string;
extraFocusLInkArgs?: { [key: string]: unknown };
};

type TProps = TDispatchProps & TReduxProps & TOwnProps;
export type TProps = TDispatchProps & TReduxProps & TOwnProps;

// export for tests
export class DeepDependencyGraphPageImpl extends React.PureComponent<TProps> {
static defaultProps = {
showServicesOpsHeader: true,
baseUrl: ROUTE_PATH,
};

static fetchModelIfStale(props: TProps) {
const { fetchDeepDependencyGraph, graphState = null, urlState } = props;
const { service, operation } = urlState;
Expand Down Expand Up @@ -173,12 +181,22 @@ export class DeepDependencyGraphPageImpl extends React.PureComponent<TProps> {
toggleShowOperations = (enable: boolean) => this.updateUrlState({ showOp: enable });

updateUrlState = (newValues: Partial<TDdgSparseUrlState>) => {
const { uiFind, urlState, history } = this.props;
history.push(getUrl({ uiFind, ...urlState, ...newValues }));
const { uiFind, urlState, history, baseUrl, extraFocusLInkArgs } = this.props;
history.push(getUrl({ uiFind, ...urlState, ...newValues, ...extraFocusLInkArgs }, baseUrl));
};

render() {
const { graph, graphState, operationsForService, services, uiFind, urlState } = this.props;
const {
graph,
graphState,
operationsForService,
services,
uiFind,
urlState,
showServicesOpsHeader,
baseUrl,
extraFocusLInkArgs,
} = this.props;
const { density, operation, service, showOp, visEncoding } = urlState;
const distanceToPathElems =
graphState && graphState.state === fetchedState.DONE ? graphState.model.distanceToPathElems : undefined;
Expand Down Expand Up @@ -208,6 +226,8 @@ export class DeepDependencyGraphPageImpl extends React.PureComponent<TProps> {
uiFindMatches={uiFindMatches}
vertices={vertices}
verticesViewModifiers={verticesViewModifiers}
baseUrl={baseUrl}
extraUrlArgs={extraFocusLInkArgs}
/>
);
} else if (graphState.state === fetchedState.LOADING) {
Expand All @@ -227,6 +247,7 @@ export class DeepDependencyGraphPageImpl extends React.PureComponent<TProps> {
<div className="Ddg">
<div ref={this.headerWrapper}>
<Header
showParameters={showServicesOpsHeader}
density={density}
distanceToPathElems={distanceToPathElems}
hiddenUiFindMatches={hiddenUiFindMatches}
Expand Down
98 changes: 98 additions & 0 deletions packages/jaeger-ui/src/components/DeepDependencies/traces.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) 2019 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 queryString from 'query-string';
import { bindActionCreators, Dispatch } from 'redux';
import * as React from 'react';
import { connect } from 'react-redux';
import { ReduxState } from '../../types';
import * as jaegerApiActions from '../../actions/jaeger-api';
import ddgActions from '../../actions/ddg';
import { getUrlState } from './url';
import { TDdgStateEntry } from '../../types/TDdgState';
import GraphModel, { makeGraph } from '../../model/ddg/GraphModel';
import { fetchedState } from '../../constants';
import { extractUiFindFromState } from '../common/UiFindInput';
import transformDdgData from '../../model/ddg/transformDdgData';
import transformTracesToPaths from '../../model/ddg/transformTracesToPaths';
import { TDdgPayload } from '../../model/ddg/types';
import { ROUTE_PATH } from '../SearchTracePage/url';
import { DeepDependencyGraphPageImpl, TDispatchProps, TOwnProps, TProps, TReduxProps } from '.';

// export for tests
export function mapDispatchToProps(dispatch: Dispatch<ReduxState>): TDispatchProps {
const { fetchDeepDependencyGraph, fetchServiceOperations, fetchServices } = bindActionCreators(
jaegerApiActions,
dispatch
);
const { addViewModifier, removeViewModifierFromIndices } = bindActionCreators(ddgActions, dispatch);

return {
addViewModifier,
fetchDeepDependencyGraph,
fetchServiceOperations,
fetchServices,
removeViewModifierFromIndices,
};
}

export function mapStateToProps(state: ReduxState, ownProps: TOwnProps): TReduxProps {
const { trace } = state;
const urlState = getUrlState(ownProps.location.search);
const { density, operation, service, showOp } = urlState;
let graphState: TDdgStateEntry | undefined;
let graph: GraphModel | undefined;
let payload: TDdgPayload;
if (service) {
payload = transformTracesToPaths(trace.traces, service, operation);
graphState = {
model: transformDdgData(payload, { service, operation }),
state: fetchedState.DONE,
viewModifiers: new Map(),
};
graph = makeGraph(graphState.model, showOp, density);
}

return {
graph,
graphState,
services: undefined,
operationsForService: {},
urlState,
...extractUiFindFromState(state),
};
}

function tracesDDG() {
return class extends React.PureComponent<TProps & { showServicesOpsHeader: never; baseUrl: never }> {
render(): React.ReactNode {
const { location } = this.props;
const urlArgs = queryString.parse(location.search);
const { end, start, limit, lookback, maxDuration, minDuration, view } = urlArgs;
const extraArgs = { end, start, limit, lookback, maxDuration, minDuration, view };
return (
<DeepDependencyGraphPageImpl
showServicesOpsHeader={false}
baseUrl={ROUTE_PATH}
extraFocusLInkArgs={extraArgs}
{...this.props}
/>
);
}
};
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(tracesDDG());
Loading

0 comments on commit e4ed5fa

Please sign in to comment.