Skip to content

Commit

Permalink
Add adblocker and 0/single node disclaimers (jaegertracing#502)
Browse files Browse the repository at this point in the history
* Temp: Default link visible with banner

Signed-off-by: Everett Ross <reverett@uber.com>

* WIP: Use server ops in ddg, track conv&collapse

Signed-off-by: Everett Ross <reverett@uber.com>

* Add tests

Signed-off-by: Everett Ross <reverett@uber.com>

* Add disclaimers for (near) empty graph&adblocker

Signed-off-by: Everett Ross <reverett@uber.com>

* Remove default enabled

Signed-off-by: Everett Ross <reverett@uber.com>

Signed-off-by: vvvprabhakar <vvvprabhakar@gmail.com>
  • Loading branch information
everett980 committed Jan 6, 2020
1 parent 03a5f67 commit 8b80b81
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 47 deletions.
6 changes: 6 additions & 0 deletions packages/jaeger-ui/src/components/DeepDependencies/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ limitations under the License.
right: 0;
}

.Ddg--center {
margin: auto;
text-align: center;
max-width: 60%;
}

.Ddg--graphWrapper {
flex: 1;
overflow: hidden;
Expand Down
150 changes: 129 additions & 21 deletions packages/jaeger-ui/src/components/DeepDependencies/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import Graph from './Graph';
import Header from './Header';
import ErrorMessage from '../common/ErrorMessage';
import LoadingIndicator from '../common/LoadingIndicator';
import * as getSearchUrl from '../SearchTracePage/url';
import { fetchedState } from '../../constants';
import getStateEntryKey from '../../model/ddg/getStateEntryKey';
import * as GraphModel from '../../model/ddg/GraphModel';
import * as codec from '../../model/ddg/visibility-codec';
import * as getConfig from '../../utils/config/get-config';

import { ECheckedStatus, EDirection, EDdgDensity, EViewModifier } from '../../model/ddg/types';

Expand Down Expand Up @@ -74,6 +76,7 @@ describe('DeepDependencyGraphPage', () => {
getVisWithUpdatedGeneration: jest.fn(),
},
};
const { operation: _o, ...urlStateWithoutOp } = props.urlState;
const ddgPageImpl = new DeepDependencyGraphPageImpl(props);
const ddgWithoutGraph = new DeepDependencyGraphPageImpl(propsWithoutGraph);
const setIdx = visibilityIdx => ({ visibilityIdx });
Expand Down Expand Up @@ -187,7 +190,6 @@ describe('DeepDependencyGraphPage', () => {

it('removes op from urlState', () => {
ddgPageImpl.clearOperation();
const { operation: _o, ...urlStateWithoutOp } = props.urlState;
expect(getUrlSpy).toHaveBeenLastCalledWith(urlStateWithoutOp, undefined);
expect(trackClearOperationSpy).toHaveBeenCalledTimes(1);
});
Expand Down Expand Up @@ -596,25 +598,27 @@ describe('DeepDependencyGraphPage', () => {

describe('render', () => {
const vertices = [{ key: 'key0' }, { key: 'key1' }, { key: 'key2' }];
const visibleFindCount = vertices.length - 1;
const graph = {
getVisible: () => ({
edges: [
{
from: vertices[0].key,
to: vertices[1].key,
},
{
from: vertices[1].key,
to: vertices[2].key,
},
],
vertices,
}),
getVisible: jest.fn(),
getDerivedViewModifiers: () => ({ edges: new Map(), vertices: new Map() }),
getHiddenUiFindMatches: () => new Set(vertices.slice(1)),
getVisibleUiFindMatches: () => new Set(vertices.slice(0, 1)),
getHiddenUiFindMatches: () => new Set(vertices.slice(visibleFindCount)),
getVisibleUiFindMatches: () => new Set(vertices.slice(0, visibleFindCount)),
getVisibleIndices: () => new Set(),
};
graph.getVisible.mockReturnValue({
edges: [
{
from: vertices[0].key,
to: vertices[1].key,
},
{
from: vertices[1].key,
to: vertices[2].key,
},
],
vertices,
});

it('renders message to query a ddg when no graphState is provided', () => {
const message = shallow(<DeepDependencyGraphPageImpl {...props} graphState={undefined} />)
Expand All @@ -639,9 +643,111 @@ describe('DeepDependencyGraphPage', () => {
expect(errorComponent.prop('error')).toBe(error);
});

it('renders graph when done', () => {
const wrapper = shallow(<DeepDependencyGraphPageImpl {...props} graph={graph} />);
expect(wrapper.find(Graph)).toHaveLength(1);
describe('graphState.state === fetchedState.DONE', () => {
function makeGraphState(specifiedDistance, vertexCount = 1) {
graph.getVisible.mockReturnValueOnce({
edges: [],
vertices: vertices.slice(vertices.length - vertexCount),
});
return {
graphState: {
...props.graphState,
model: {
...props.graphState.model,
distanceToPathElems: specifiedDistance
? new Map([[specifiedDistance, 'test elem']])
: new Map(),
},
},
};
}
let getConfigValueSpy;
let getSearchUrlSpy;
let wrapper;

beforeAll(() => {
getConfigValueSpy = jest.spyOn(getConfig, 'getConfigValue');
getSearchUrlSpy = jest.spyOn(getSearchUrl, 'getUrl');
});

beforeEach(() => {
getConfigValueSpy.mockClear();
getSearchUrlSpy.mockClear();
wrapper = shallow(<DeepDependencyGraphPageImpl {...props} graph={graph} />);
});

it('renders graph if there are multiple vertices visible', () => {
const graphComponent = wrapper.find(Graph);

expect(graphComponent).toHaveLength(1);
expect(graphComponent.prop('vertices')).toBe(vertices);
});

it('renders disclaimer to show more hops if one or fewer vertices are visible and more hops were in paylaod', () => {
const expectedHeader = 'There is nothing visible to show';
const expectedInstruction = 'Select at least one hop to view';
expect(wrapper.find(Graph)).toHaveLength(1);

wrapper.setProps(makeGraphState(1));
expect(wrapper.find(Graph)).toHaveLength(0);
expect(wrapper.find('h1.Ddg--center').text()).toBe(expectedHeader);
expect(wrapper.find('p.Ddg--center').text()).toBe(expectedInstruction);

wrapper.setProps(makeGraphState(-1, 0));
expect(wrapper.find(Graph)).toHaveLength(0);
expect(wrapper.find('h1.Ddg--center').text()).toBe(expectedHeader);
expect(wrapper.find('p.Ddg--center').text()).toBe(expectedInstruction);
});

it('renders disclaimer that service has no known dependencies with correct link to verify', () => {
const expectedHeader = 'There are no dependencies';
const { operation, service } = props.urlState;
const expectedInstruction = (withOp = true) =>
`No traces were found that contain ${service}${
withOp ? `:${operation}` : ''
} and any other service where span.kind is ‘server’.`;
const lookback = 'test look back';
getConfigValueSpy.mockReturnValue(lookback);
const mockUrl = 'test search url';
getSearchUrlSpy.mockReturnValue(mockUrl);

expect(wrapper.find(Graph)).toHaveLength(1);

wrapper.setProps(makeGraphState());
expect(wrapper.find(Graph)).toHaveLength(0);
expect(wrapper.find('h1.Ddg--center').text()).toBe(expectedHeader);
expect(
wrapper
.find('p.Ddg--center')
.first()
.text()
).toBe(expectedInstruction());
expect(wrapper.find('a').prop('href')).toBe(mockUrl);
expect(getSearchUrlSpy).toHaveBeenLastCalledWith({
lookback,
minDuration: '0ms',
operation,
service,
tags: '{"span.kind":"server"}',
});

wrapper.setProps({ urlState: urlStateWithoutOp, ...makeGraphState() });
expect(wrapper.find(Graph)).toHaveLength(0);
expect(wrapper.find('h1.Ddg--center').text()).toBe(expectedHeader);
expect(
wrapper
.find('p.Ddg--center')
.first()
.text()
).toBe(expectedInstruction(false));
expect(wrapper.find('a').prop('href')).toBe(mockUrl);
expect(getSearchUrlSpy).toHaveBeenLastCalledWith({
lookback,
minDuration: '0ms',
service,
tags: '{"span.kind":"server"}',
});
});
});

it('renders indication of unknown graphState', () => {
Expand Down Expand Up @@ -674,8 +780,10 @@ describe('DeepDependencyGraphPage', () => {
expect(wrapper.find(Header).prop('hiddenUiFindMatches')).toBe(undefined);

wrapper.setProps({ graph });
expect(wrapper.find(Header).prop('uiFindCount')).toBe(1);
expect(wrapper.find(Header).prop('hiddenUiFindMatches').size).toBe(vertices.length - 1);
expect(wrapper.find(Header).prop('uiFindCount')).toBe(visibleFindCount);
expect(wrapper.find(Header).prop('hiddenUiFindMatches').size).toBe(
vertices.length - visibleFindCount
);
});

it('passes correct operations to Header', () => {
Expand Down
92 changes: 66 additions & 26 deletions packages/jaeger-ui/src/components/DeepDependencies/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { getUrl, getUrlState, sanitizeUrlState, ROUTE_PATH } from './url';
import ErrorMessage from '../common/ErrorMessage';
import LoadingIndicator from '../common/LoadingIndicator';
import { extractUiFindFromState, TExtractUiFindFromStateReturn } from '../common/UiFindInput';
import { getUrl as getSearchUrl } from '../SearchTracePage/url';
import ddgActions from '../../actions/ddg';
import * as jaegerApiActions from '../../actions/jaeger-api';
import { fetchedState } from '../../constants';
Expand All @@ -39,6 +40,7 @@ import {
TDdgSparseUrlState,
} from '../../model/ddg/types';
import { encode, encodeDistance } from '../../model/ddg/visibility-codec';
import { getConfigValue } from '../../utils/config/get-config';
import { ReduxState } from '../../types';
import { TDdgStateEntry } from '../../types/TDdgState';

Expand Down Expand Up @@ -262,37 +264,75 @@ export class DeepDependencyGraphPageImpl extends React.PureComponent<TProps> {
visEncoding,
viewModifiers
);
// TODO: using `key` here is a hack, debug digraph to fix the underlying issue
content = (
<Graph
key={JSON.stringify(urlState)}
baseUrl={baseUrl}
density={density}
edges={edges}
edgesViewModifiers={edgesViewModifiers}
extraUrlArgs={extraUrlArgs}
focusPathsThroughVertex={this.focusPathsThroughVertex}
getGenerationVisibility={this.getGenerationVisibility}
getVisiblePathElems={this.getVisiblePathElems}
hideVertex={this.hideVertex}
setOperation={this.setOperation}
setViewModifier={this.setViewModifier}
uiFindMatches={uiFindMatches}
updateGenerationVisibility={this.updateGenerationVisibility}
vertices={vertices}
verticesViewModifiers={verticesViewModifiers}
/>
);
if (vertices.length > 1) {
// TODO: using `key` here is a hack, debug digraph to fix the underlying issue
content = (
<Graph
key={JSON.stringify(urlState)}
baseUrl={baseUrl}
density={density}
edges={edges}
edgesViewModifiers={edgesViewModifiers}
extraUrlArgs={extraUrlArgs}
focusPathsThroughVertex={this.focusPathsThroughVertex}
getGenerationVisibility={this.getGenerationVisibility}
getVisiblePathElems={this.getVisiblePathElems}
hideVertex={this.hideVertex}
setOperation={this.setOperation}
setViewModifier={this.setViewModifier}
uiFindMatches={uiFindMatches}
updateGenerationVisibility={this.updateGenerationVisibility}
vertices={vertices}
verticesViewModifiers={verticesViewModifiers}
/>
);
} else if (
graphState.model.distanceToPathElems.has(-1) ||
graphState.model.distanceToPathElems.has(1)
) {
content = (
<>
<h1 className="Ddg--center">There is nothing visible to show</h1>
<p className="Ddg--center">Select at least one hop to view</p>
</>
);
} else {
const lookback = getConfigValue('search.maxLookback.value');
const checkLink = getSearchUrl({
lookback,
minDuration: '0ms',
operation,
service,
tags: '{"span.kind":"server"}',
});
content = (
<>
<h1 className="Ddg--center">There are no dependencies</h1>
<p className="Ddg--center">
No traces were found that contain {service}
{operation && `:${operation}`} and any other service where span.kind is &lsquo;server&rsquo;.
</p>
<p className="Ddg--center">
<a href={checkLink}>Confirm by searching</a>
</p>
</>
);
}
} else if (graphState.state === fetchedState.LOADING) {
content = <LoadingIndicator centered className="u-mt-vast" />;
} else if (graphState.state === fetchedState.ERROR) {
content = <ErrorMessage error={graphState.error} className="ub-m4" />;
content = (
<>
<ErrorMessage error={graphState.error} className="ub-m4" />
<p className="Ddg--center">If you are using an adblocker, whitelist Jaeger and retry.</p>
</>
);
} else {
content = (
<div>
<h1>Unknown graphState:</h1>
<p>${JSON.stringify(graphState)}</p>
</div>
<>
<h1 className="Ddg--center">Unknown graphState:</h1>
<p className="Ddg--center">{JSON.stringify(graphState, null, 2)}</p>
</>
);
}

Expand Down

0 comments on commit 8b80b81

Please sign in to comment.