Skip to content

Commit d18004f

Browse files
authored
Merge pull request #367 from everett980/issue-361-and-360-improve-uiFind-interactions
add uiFind icons, scroll to first match
2 parents fe6c244 + cdbdd9d commit d18004f

27 files changed

+650
-249
lines changed

packages/jaeger-ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"chance": "^1.0.10",
5252
"classnames": "^2.2.5",
5353
"combokeys": "^3.0.0",
54+
"copy-to-clipboard": "^3.1.0",
5455
"cytoscape": "^3.2.1",
5556
"cytoscape-dagre": "^2.0.0",
5657
"d3-scale": "^1.0.6",
@@ -71,7 +72,6 @@
7172
"query-string": "^6.3.0",
7273
"raven-js": "^3.22.1",
7374
"react": "^16.3.2",
74-
"react-copy-to-clipboard": "^5.0.1",
7575
"react-dimensions": "^1.3.0",
7676
"react-dom": "^16.3.2",
7777
"react-ga": "^2.4.1",

packages/jaeger-ui/src/components/TraceDiff/TraceDiffGraph/__snapshots__/drawNode.test.js.snap

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ exports[`drawNode diffNode renders as expected when props.a and props.b are the
2525
<CopyIcon
2626
className="DiffNode--copyIcon"
2727
copyText="serviceName operationName"
28+
icon="copy"
29+
placement="left"
2830
tooltipTitle="Copy label"
2931
/>
3032
</td>
@@ -70,6 +72,8 @@ exports[`drawNode diffNode renders as expected when props.a and props.b are the
7072
<CopyIcon
7173
className="DiffNode--copyIcon"
7274
copyText="serviceName operationName"
75+
icon="copy"
76+
placement="left"
7377
tooltipTitle="Copy label"
7478
/>
7579
</td>
@@ -116,6 +120,8 @@ exports[`drawNode diffNode renders as expected when props.a is 0 1`] = `
116120
<CopyIcon
117121
className="DiffNode--copyIcon"
118122
copyText="serviceName operationName"
123+
icon="copy"
124+
placement="left"
119125
tooltipTitle="Copy label"
120126
/>
121127
</td>
@@ -181,6 +187,8 @@ exports[`drawNode diffNode renders as expected when props.a is 0 1`] = `
181187
<CopyIcon
182188
className="DiffNode--copyIcon"
183189
copyText="serviceName operationName"
190+
icon="copy"
191+
placement="left"
184192
tooltipTitle="Copy label"
185193
/>
186194
</td>
@@ -242,6 +250,8 @@ exports[`drawNode diffNode renders as expected when props.a is less than props.b
242250
<CopyIcon
243251
className="DiffNode--copyIcon"
244252
copyText="serviceName operationName"
253+
icon="copy"
254+
placement="left"
245255
tooltipTitle="Copy label"
246256
/>
247257
</td>
@@ -307,6 +317,8 @@ exports[`drawNode diffNode renders as expected when props.a is less than props.b
307317
<CopyIcon
308318
className="DiffNode--copyIcon"
309319
copyText="serviceName operationName"
320+
icon="copy"
321+
placement="left"
310322
tooltipTitle="Copy label"
311323
/>
312324
</td>
@@ -368,6 +380,8 @@ exports[`drawNode diffNode renders as expected when props.a is more than props.b
368380
<CopyIcon
369381
className="DiffNode--copyIcon"
370382
copyText="serviceName operationName"
383+
icon="copy"
384+
placement="left"
371385
tooltipTitle="Copy label"
372386
/>
373387
</td>
@@ -433,6 +447,8 @@ exports[`drawNode diffNode renders as expected when props.a is more than props.b
433447
<CopyIcon
434448
className="DiffNode--copyIcon"
435449
copyText="serviceName operationName"
450+
icon="copy"
451+
placement="left"
436452
tooltipTitle="Copy label"
437453
/>
438454
</td>
@@ -494,6 +510,8 @@ exports[`drawNode diffNode renders as expected when props.b is 0 1`] = `
494510
<CopyIcon
495511
className="DiffNode--copyIcon"
496512
copyText="serviceName operationName"
513+
icon="copy"
514+
placement="left"
497515
tooltipTitle="Copy label"
498516
/>
499517
</td>
@@ -559,6 +577,8 @@ exports[`drawNode diffNode renders as expected when props.b is 0 1`] = `
559577
<CopyIcon
560578
className="DiffNode--copyIcon"
561579
copyText="serviceName operationName"
580+
icon="copy"
581+
placement="left"
562582
tooltipTitle="Copy label"
563583
/>
564584
</td>
@@ -615,6 +635,8 @@ exports[`drawNode diffNode renders as expected when props.isUiFindMatch is true
615635
<CopyIcon
616636
className="DiffNode--copyIcon"
617637
copyText="serviceName operationName"
638+
icon="copy"
639+
placement="left"
618640
tooltipTitle="Copy label"
619641
/>
620642
</td>
@@ -660,6 +682,8 @@ exports[`drawNode diffNode renders as expected when props.isUiFindMatch is true
660682
<CopyIcon
661683
className="DiffNode--copyIcon"
662684
copyText="serviceName operationName"
685+
icon="copy"
686+
placement="left"
663687
tooltipTitle="Copy label"
664688
/>
665689
</td>

packages/jaeger-ui/src/components/TraceDiff/TraceDiffGraph/drawNode.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ limitations under the License.
8888
.DiffNode--popover .DiffNode--copyIcon,
8989
.DiffNode:not(:hover) .DiffNode--copyIcon {
9090
color: transparent;
91+
pointer-events: none;
9192
}
9293

9394
/* Tweak the popover aesthetics - unfortunate but necessary */

packages/jaeger-ui/src/components/TracePage/ScrollManager.test.js

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ import ScrollManager from './ScrollManager';
2121
const SPAN_HEIGHT = 2;
2222

2323
function getTrace() {
24-
let nextSpanID = 0;
2524
const spans = [];
2625
const trace = {
2726
spans,
2827
duration: 2000,
2928
startTime: 1000,
3029
};
3130
for (let i = 0; i < 10; i++) {
32-
spans.push({ duration: 1, startTime: 1000, spanID: nextSpanID++ });
31+
spans.push({ duration: 1, startTime: 1000, spanID: i + 1 });
3332
}
3433
return trace;
3534
}
@@ -106,6 +105,9 @@ describe('ScrollManager', () => {
106105
});
107106

108107
describe('_scrollToVisibleSpan()', () => {
108+
function getRefs(spanID) {
109+
return [{ refType: 'CHILD_OF', spanID }];
110+
}
109111
let scrollPastMock;
110112

111113
beforeEach(() => {
@@ -142,7 +144,7 @@ describe('ScrollManager', () => {
142144

143145
it('skips spans that are out of view', () => {
144146
trace.spans[4].startTime = trace.startTime + trace.duration * 0.5;
145-
accessors.getViewRange = jest.fn(() => [0.4, 0.6]);
147+
accessors.getViewRange = () => [0.4, 0.6];
146148
accessors.getTopRowIndexVisible.mockReturnValue(trace.spans.length - 1);
147149
accessors.getBottomRowIndexVisible.mockReturnValue(0);
148150
manager._scrollToVisibleSpan(1);
@@ -154,18 +156,41 @@ describe('ScrollManager', () => {
154156
it('skips spans that do not match the text search', () => {
155157
accessors.getTopRowIndexVisible.mockReturnValue(trace.spans.length - 1);
156158
accessors.getBottomRowIndexVisible.mockReturnValue(0);
157-
accessors.getSearchedSpanIDs = jest.fn(() => new Set([trace.spans[4].spanID]));
159+
accessors.getSearchedSpanIDs = () => new Set([trace.spans[4].spanID]);
158160
manager._scrollToVisibleSpan(1);
159161
expect(scrollPastMock).lastCalledWith(4, 1);
160162
manager._scrollToVisibleSpan(-1);
161163
expect(scrollPastMock).lastCalledWith(4, -1);
162164
});
163165

164-
describe('scrollToNextVisibleSpan() and scrollToPrevVisibleSpan()', () => {
165-
function getRefs(spanID) {
166-
return [{ refType: 'CHILD_OF', spanID }];
167-
}
166+
it('scrolls to boundary when scrolling away from closest spanID in findMatches', () => {
167+
const closetFindMatchesSpanID = 4;
168+
accessors.getTopRowIndexVisible.mockReturnValue(closetFindMatchesSpanID - 1);
169+
accessors.getBottomRowIndexVisible.mockReturnValue(closetFindMatchesSpanID + 1);
170+
accessors.getSearchedSpanIDs = () => new Set([trace.spans[closetFindMatchesSpanID].spanID]);
171+
172+
manager._scrollToVisibleSpan(1);
173+
expect(scrollPastMock).lastCalledWith(trace.spans.length - 1, 1);
174+
175+
manager._scrollToVisibleSpan(-1);
176+
expect(scrollPastMock).lastCalledWith(0, -1);
177+
});
178+
179+
it('scrolls to last visible row when boundary is hidden', () => {
180+
const parentOfLastRowWithHiddenChildrenIndex = trace.spans.length - 2;
181+
accessors.getBottomRowIndexVisible.mockReturnValue(0);
182+
accessors.getCollapsedChildren = () =>
183+
new Set([trace.spans[parentOfLastRowWithHiddenChildrenIndex].spanID]);
184+
accessors.getSearchedSpanIDs = () => new Set([trace.spans[0].spanID]);
185+
trace.spans[trace.spans.length - 1].references = getRefs(
186+
trace.spans[parentOfLastRowWithHiddenChildrenIndex].spanID
187+
);
188+
189+
manager._scrollToVisibleSpan(1);
190+
expect(scrollPastMock).lastCalledWith(parentOfLastRowWithHiddenChildrenIndex, 1);
191+
});
168192

193+
describe('scrollToNextVisibleSpan() and scrollToPrevVisibleSpan()', () => {
169194
beforeEach(() => {
170195
// change spans so 0 and 4 are top-level and their children are collapsed
171196
const spans = trace.spans;
@@ -213,6 +238,17 @@ describe('ScrollManager', () => {
213238
expect(scrollPastMock).lastCalledWith(4, -1);
214239
});
215240
});
241+
242+
describe('scrollToFirstVisibleSpan', () => {
243+
beforeEach(() => {
244+
jest.spyOn(manager, '_scrollToVisibleSpan').mockImplementationOnce();
245+
});
246+
247+
it('calls _scrollToVisibleSpan searching downwards from first span', () => {
248+
manager.scrollToFirstVisibleSpan();
249+
expect(manager._scrollToVisibleSpan).toHaveBeenCalledWith(1, 0);
250+
});
251+
});
216252
});
217253

218254
describe('scrollPageDown() and scrollPageUp()', () => {

packages/jaeger-ui/src/components/TracePage/ScrollManager.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export default class ScrollManager {
120120
this._scroller.scrollTo(y);
121121
}
122122

123-
_scrollToVisibleSpan(direction: 1 | -1) {
123+
_scrollToVisibleSpan(direction: 1 | -1, startRow?: number) {
124124
const xrs = this._accessors;
125125
/* istanbul ignore next */
126126
if (!xrs) {
@@ -131,7 +131,14 @@ export default class ScrollManager {
131131
}
132132
const { duration, spans, startTime: traceStartTime } = this._trace;
133133
const isUp = direction < 0;
134-
const boundaryRow = isUp ? xrs.getTopRowIndexVisible() : xrs.getBottomRowIndexVisible();
134+
let boundaryRow: number;
135+
if (startRow != null) {
136+
boundaryRow = startRow;
137+
} else if (isUp) {
138+
boundaryRow = xrs.getTopRowIndexVisible();
139+
} else {
140+
boundaryRow = xrs.getBottomRowIndexVisible();
141+
}
135142
const spanIndex = xrs.mapRowIndexToSpanIndex(boundaryRow);
136143
if ((spanIndex === 0 && isUp) || (spanIndex === spans.length - 1 && !isUp)) {
137144
return;
@@ -184,7 +191,7 @@ export default class ScrollManager {
184191

185192
// If there are hidden children, scroll to the last visible span
186193
if (childrenAreHidden) {
187-
let isFallbackHidden: boolean | TNil;
194+
let isFallbackHidden: boolean;
188195
do {
189196
const { isHidden, parentIDs } = isSpanHidden(spans[nextSpanIndex], childrenAreHidden, spansMap);
190197
if (isHidden) {
@@ -255,6 +262,10 @@ export default class ScrollManager {
255262
this._scrollToVisibleSpan(-1);
256263
};
257264

265+
scrollToFirstVisibleSpan = () => {
266+
this._scrollToVisibleSpan(1, 0);
267+
};
268+
258269
destroy() {
259270
this._trace = undefined;
260271
this._scroller = undefined as any;

packages/jaeger-ui/src/components/TracePage/TraceGraph/OpNode.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ limitations under the License.
5757
.OpNode--popover .OpNode--copyIcon,
5858
.OpNode:not(:hover) .OpNode--copyIcon {
5959
color: transparent;
60+
pointer-events: none;
6061
}
6162

6263
.OpNode--service {

packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.test.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import React from 'react';
1616
import { shallow, mount } from 'enzyme';
17+
import { Link } from 'react-router-dom';
1718

1819
import AltViewOptions from './AltViewOptions';
1920
import KeyboardShortcutsHelp from './KeyboardShortcutsHelp';
@@ -110,6 +111,14 @@ describe('<TracePageHeader>', () => {
110111
expect(wrapper.find(AltViewOptions).length).toBe(0);
111112
});
112113

114+
it('renders the link to search', () => {
115+
expect(wrapper.find(Link).length).toBe(0);
116+
117+
const toSearch = 'some-link';
118+
wrapper.setProps({ toSearch });
119+
expect(wrapper.find({ to: toSearch }).length).toBe(1);
120+
});
121+
113122
it('toggles the standalone link', () => {
114123
const linkToStandalone = 'some-link';
115124
const props = {

packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageHeader.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import './TracePageHeader.css';
4040
type TracePageHeaderEmbedProps = {
4141
canCollapse: boolean;
4242
clearSearch: () => void;
43+
focusUiFindMatches: () => void;
4344
hideMap: boolean;
4445
hideSummary: boolean;
4546
linkToStandalone: string;
@@ -95,6 +96,7 @@ export function TracePageHeaderFn(props: TracePageHeaderEmbedProps & { forwarded
9596
const {
9697
canCollapse,
9798
clearSearch,
99+
focusUiFindMatches,
98100
forwardedRef,
99101
hideMap,
100102
hideSummary,
@@ -161,17 +163,17 @@ export function TracePageHeaderFn(props: TracePageHeaderEmbedProps & { forwarded
161163
) : (
162164
title
163165
)}
164-
{showShortcutsHelp && <KeyboardShortcutsHelp className="ub-mr2" />}
165166
<TracePageSearchBar
166167
clearSearch={clearSearch}
168+
focusUiFindMatches={focusUiFindMatches}
167169
nextResult={nextResult}
168170
prevResult={prevResult}
169171
ref={forwardedRef}
170172
resultCount={resultCount}
171173
textFilter={textFilter}
172174
navigable={!traceGraphView}
173175
/>
174-
176+
{showShortcutsHelp && <KeyboardShortcutsHelp className="ub-m2" />}
175177
{showViewOptions && (
176178
<AltViewOptions
177179
onTraceGraphViewClicked={onTraceGraphViewClicked}

packages/jaeger-ui/src/components/TracePage/TracePageHeader/TracePageSearchBar.css

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,31 @@ limitations under the License.
1515
*/
1616

1717
.TracePageSearchBar {
18-
max-width: 20rem;
18+
width: 40%;
1919
}
2020

2121
.TracePageSearchBar--bar {
22-
display: flex;
2322
max-width: 20rem;
23+
transition: max-width 0.5s;
24+
}
25+
26+
.TracePageSearchBar--bar:focus-within {
27+
max-width: 100%;
2428
}
2529

2630
.TracePageSearchBar--count {
2731
opacity: 0.6;
2832
}
2933

3034
.TracePageSearchBar--btn {
35+
border-left: none;
3136
transition: 0.2s;
3237
}
3338

3439
.TracePageSearchBar--btn.is-disabled {
3540
opacity: 0.5;
3641
}
42+
43+
.TracePageSearchBar--locateBtn {
44+
padding: 1px 8px 4px;
45+
}

0 commit comments

Comments
 (0)