Skip to content

Commit

Permalink
WIP - Make op optional, TODO: css/test/track/DRY
Browse files Browse the repository at this point in the history
Signed-off-by: Everett Ross <reverett@uber.com>
  • Loading branch information
everett980 committed Nov 15, 2019
1 parent 6b9e8d6 commit 01a392d
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ type TRect = { height: number; width: number };

let svcSpan: HTMLSpanElement | undefined;

// TODO remove
let log: (...args: any) => void = () => {};

/*
* Mesaurements for the words comprising a service are measured by a span that is mounted out of a view.
* Using a canvas would remove the requirement that the measuring container is part of the DOM, however canvas
Expand Down Expand Up @@ -149,11 +152,13 @@ function calcWidth(lengths: number[], lines: number, longestThusFar: number = 0)
* @returns {TRect[]} - Possible bounding rectangles.
*/
const calcRects = _memoize(
function calcRects(str: string, span: HTMLSpanElement): TRect[] {
const lengths = (str.match(WORD_RX) || [str]).map(s => {
function calcRects(str: string | string[], span: HTMLSpanElement): TRect[] {
log(str, Array.isArray(str));
const lengths = (Array.isArray(str) ? [`${str.length} Operations}`] : (str.match(WORD_RX) || [str])).map(s => {
span.innerHTML = s; // eslint-disable-line no-param-reassign
return span.getClientRects()[0].width;
});
log(lengths);

const rects: TRect[] = [];
for (let lines = 1; lines <= lengths.length; lines++) {
Expand All @@ -162,6 +167,7 @@ const calcRects = _memoize(
if (!rects.length || width < rects[rects.length - 1].width) rects.push({ height, width });
if (height > width) break;
}
log(rects);
return rects;
},
(str: string, span: HTMLSpanElement) => `${str}\t${span.style.fontWeight}`
Expand Down Expand Up @@ -240,9 +246,10 @@ function smallestRadius(svcRects: TRect[], opRects?: TRect[]): TSmallestRadiusRV
return rv;
}

const calcPositioning: (service: string, operation?: string | null) => TSmallestRadiusRV = _memoize(
function calcPositioningImpl(service: string, operation?: string | null) {
const calcPositioning: (service: string, operation?: string | string[] | null) => TSmallestRadiusRV = _memoize(
function calcPositioningImpl(service: string, operation?: string | string[] | null) {
const svcRects = calcRects(service, _initSvcSpan());
log = Array.isArray(operation) ? console.log : () => {};
const opRects = operation ? calcRects(operation, _initOpSpan()) : undefined;

return smallestRadius(svcRects, opRects);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ limitations under the License.
*/
.plexus-Digraph--MeasurableHtmlNode:hover {
z-index: 1;
/* TODO ease-out 150ms */
/* if ease-out also works for display none the hovered.state can be used only as a guard for calculating the
* parent/children vis */
}

.DdgNodeContent--core {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import * as React from 'react';
import { Checkbox } from 'antd';
import { Checkbox, Popover } from 'antd';
import cx from 'classnames';
import { TLayoutVertex } from '@jaegertracing/plexus/lib/types';
import IoAndroidLocate from 'react-icons/lib/io/android-locate';
Expand All @@ -33,6 +33,7 @@ import { setFocusIcon } from './node-icons';
import { trackSetFocus, trackViewTraces } from '../../index.track';
import { getUrl } from '../../url';
import BreakableText from '../../../common/BreakableText';
import FilteredList from '../../../common/FilteredList';
import NewWindowIcon from '../../../common/NewWindowIcon';
import { getUrl as getSearchUrl } from '../../../SearchTracePage/url';
import {
Expand All @@ -54,8 +55,9 @@ type TProps = {
hideVertex: (vertexKey: string) => void;
isFocalNode: boolean;
isPositioned: boolean;
operation: string | null;
operation: string | string[] | null;
service: string;
setOperation: (operation: string) => void;
setViewModifier: (vertexKey: string, viewModifier: EViewModifier, isEnabled: boolean) => void;
updateGenerationVisibility: (vertexKey: string, direction: EDirection) => void;
vertexKey: string;
Expand Down Expand Up @@ -85,8 +87,8 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
getGenerationVisibility,
getVisiblePathElems,
hideVertex,
setOperation,
setViewModifier,
showOp,
updateGenerationVisibility,
}: {
baseUrl: string;
Expand All @@ -96,16 +98,16 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
getGenerationVisibility: (vertexKey: string, direction: EDirection) => ECheckedStatus | null;
getVisiblePathElems: (vertexKey: string) => PathElem[] | undefined;
hideVertex: (vertexKey: string) => void;
setOperation: (operation: string) => void;
setViewModifier: (vertexKey: string, viewModifier: EViewModifier, enable: boolean) => void;
showOp: boolean;
updateGenerationVisibility: (vertexKey: string, direction: EDirection) => void;
}) {
return function renderNode(vertex: TDdgVertex, _: unknown, lv: TLayoutVertex<any> | null) {
const { isFocalNode, key, operation, service } = vertex;
return (
<DdgNodeContent
focalNodeUrl={
isFocalNode ? null : getUrl({ density, operation, service, showOp, ...extraUrlArgs }, baseUrl)
isFocalNode ? null : getUrl({ density, operation, service, ...extraUrlArgs }, baseUrl)
}
focusPathsThroughVertex={focusPathsThroughVertex}
getGenerationVisibility={getGenerationVisibility}
Expand All @@ -114,6 +116,7 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
isFocalNode={isFocalNode}
isPositioned={Boolean(lv)}
operation={operation}
setOperation={setOperation}
setViewModifier={setViewModifier}
service={service}
updateGenerationVisibility={updateGenerationVisibility}
Expand Down Expand Up @@ -209,6 +212,7 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
isPositioned,
operation,
service,
setOperation,
vertexKey,
} = this.props;

Expand Down Expand Up @@ -240,7 +244,24 @@ export default class DdgNodeContent extends React.PureComponent<TProps> {
className="DdgNodeContent--label"
style={{ paddingTop: `${OP_PADDING_TOP}px`, width: `${opWidth}px` }}
>
<BreakableText text={operation} wordRegexp={WORD_RX} />
{
Array.isArray(operation)
? <Popover
content={
<FilteredList
cancel={() => {}}
options={operation}
value={null}
setValue={setOperation}
/>
}
placement="bottom"
title="Select Operation to Filter Graph"
>
<span>{`${operation.length} Operations`}</span>
</Popover>
: <BreakableText text={operation} wordRegexp={WORD_RX} />
}
</div>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ limitations under the License.
border: 1px dashed #eb2f96;
}

.DdgNode--HtmlEmphasis.is-focalNode.is-findMatch {
background-image: repeating-linear-gradient(30deg, #fffb8f, #eb2f96 3px, #fffb8f 5px);
}

.DdgNode--VectorFindEmphasis--colorBand {
stroke: #fef876;
stroke-width: 10;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import { TDdgVertex, EViewModifier } from '../../../model/ddg/types';

import './getNodeRenderers.css';

export default function getNodeRenderers(findMatches: Set<TDdgVertex>, viewModifiers: Map<string, number>) {
export default function getNodeRenderers(findMatches: Set<string>, viewModifiers: Map<string, number>) {
function vectorBorder(lv: TLayoutVertex<TDdgVertex>) {
// eslint-disable-next-line no-bitwise
const isHovered = (viewModifiers.get(lv.vertex.key) || 0) & EViewModifier.Hovered;
// eslint-disable-next-line no-bitwise
const isPathHovered = (viewModifiers.get(lv.vertex.key) || 0) & EViewModifier.PathHovered;
const className = cx('DdgNode--VectorBorder', {
'is-findMatch': findMatches.has(lv.vertex),
'is-findMatch': findMatches.has(lv.vertex.key),
'is-hovered': isHovered,
'is-pathHovered': isPathHovered,
'is-focalNode': lv.vertex.isFocalNode,
Expand All @@ -45,7 +45,7 @@ export default function getNodeRenderers(findMatches: Set<TDdgVertex>, viewModif

function htmlEmphasis(lv: TLayoutVertex<any>) {
const matchClasses = cx({
'is-findMatch': findMatches.has(lv.vertex),
'is-findMatch': findMatches.has(lv.vertex.key),
'is-focalNode': lv.vertex.isFocalNode,
});
if (!matchClasses) {
Expand All @@ -63,7 +63,7 @@ export default function getNodeRenderers(findMatches: Set<TDdgVertex>, viewModif
}

function vectorFindColorBand(lv: TLayoutVertex<any>) {
if (!findMatches.has(lv.vertex)) {
if (!findMatches.has(lv.vertex.key)) {
return null;
}
return (
Expand Down
20 changes: 10 additions & 10 deletions packages/jaeger-ui/src/components/DeepDependencies/Graph/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ type TProps = {
getGenerationVisibility: (vertexKey: string, direction: EDirection) => ECheckedStatus | null;
getVisiblePathElems: (vertexKey: string) => PathElem[] | undefined;
hideVertex: (vertexKey: string) => void;
setOperation: (operation: string) => void;
setViewModifier: (vertexKey: string, viewModifier: EViewModifier, enable: boolean) => void;
showOp: boolean;
uiFindMatches: Set<TDdgVertex> | undefined;
uiFindMatches: Set<string> | undefined;
updateGenerationVisibility: (vertexKey: string, direction: EDirection) => void;
vertices: TDdgVertex[];
verticesViewModifiers: Map<string, number>;
Expand Down Expand Up @@ -85,7 +85,7 @@ export default class Graph extends PureComponent<TProps> {
useDotEdges: true,
});

private emptyFindSet: Set<TDdgVertex> = new Set();
private emptyFindSet: Set<string> = new Set();

componentWillUnmount() {
this.layoutManager.stopAndRelease();
Expand All @@ -102,8 +102,8 @@ export default class Graph extends PureComponent<TProps> {
getGenerationVisibility,
getVisiblePathElems,
hideVertex,
setOperation,
setViewModifier,
showOp,
uiFindMatches,
updateGenerationVisibility,
vertices,
Expand All @@ -121,16 +121,16 @@ export default class Graph extends PureComponent<TProps> {
vertices={vertices}
measurableNodesKey="nodes/content"
layers={[
{
key: 'nodes/find-emphasis/html',
layerType: 'html',
renderNode: nodeRenderers.htmlEmphasis,
},
{
key: 'nodes/find-emphasis/vector-color-band',
layerType: 'svg',
renderNode: nodeRenderers.vectorFindColorBand,
},
{
key: 'nodes/find-emphasis/html',
layerType: 'html',
renderNode: nodeRenderers.htmlEmphasis,
},
{
key: 'nodes/vector-border',
layerType: 'svg',
Expand Down Expand Up @@ -163,8 +163,8 @@ export default class Graph extends PureComponent<TProps> {
getGenerationVisibility,
getVisiblePathElems,
hideVertex,
setOperation,
setViewModifier,
showOp,
updateGenerationVisibility,
}),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ limitations under the License.
position: relative;
}

.NameSelector--chevron:not(:last-child) {
margin-right: 0.8em;
}

.NameSelector--clearIcon:not(:hover) {
color: var(--tx-color-muted);
}

.NameSelector--overlay .ant-popover-arrow {
border: 1px solid #999;
z-index: -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import * as React from 'react';
import { Popover } from 'antd';
import { Icon, Popover } from 'antd';
import cx from 'classnames';
import IoChevronDown from 'react-icons/lib/io/chevron-down';

Expand All @@ -22,14 +22,24 @@ import FilteredList from '../../common/FilteredList';

import './NameSelector.css';


type TOptional = {
clearValue: () => void;
required?: false;
}

type TRequired = {
clearValue?: never;
required: true;
}

type TProps = {
label: string;
placeholder?: boolean | string;
options: string[];
value: string | null;
required?: boolean;
setValue: (value: string) => void;
};
} & (TOptional | TRequired);

type TState = {
popoverVisible: boolean;
Expand All @@ -56,6 +66,13 @@ export default class NameSelector extends React.PureComponent<TProps, TState> {
this.setState({ popoverVisible });
}

private clearValue = (evt: React.MouseEvent<React.ReactSVGElement>) => {
if (this.props.required) throw new Error('Cannot clear value of required NameSelector');

evt.stopPropagation();
this.props.clearValue();
}

setValue = (value: string) => {
this.props.setValue(value);
this.changeVisible(false);
Expand All @@ -76,7 +93,7 @@ export default class NameSelector extends React.PureComponent<TProps, TState> {
};

render() {
const { label, placeholder = false, options, required = false, value } = this.props;
const { label, options, placeholder = false, required = false, value } = this.props;
const { popoverVisible } = this.state;

const rootCls = cx('NameSelector', {
Expand Down Expand Up @@ -107,9 +124,10 @@ export default class NameSelector extends React.PureComponent<TProps, TState> {
visible={popoverVisible}
>
<h2 className={rootCls}>
{useLabel && <span className="NameSelector--label">{label}</span>}
{useLabel && <span className="NameSelector--label">{label}:</span>}
<BreakableText className="NameSelector--value" text={text} />
<IoChevronDown className="NameSelector--chevron" />
{!required && value && <Icon className="NameSelector--clearIcon" type="close" onClick={this.clearValue} />}
</h2>
</Popover>
);
Expand Down
Loading

0 comments on commit 01a392d

Please sign in to comment.