Skip to content

Commit 2ab2dbf

Browse files
authored
fix(3433): highlight the selected job when navigating from build details to event views (#1564)
1 parent dc51ce9 commit 2ab2dbf

14 files changed

Lines changed: 198 additions & 6 deletions

File tree

app/components/build-banner/component.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ export default Component.extend({
152152
}
153153
}),
154154

155+
usesLegacyUi: computed({
156+
get() {
157+
return localStorage.getItem('oldUi') === 'true';
158+
}
159+
}),
160+
161+
eventRoute: computed('usesLegacyUi', {
162+
get() {
163+
return this.usesLegacyUi
164+
? 'pipeline.events.show'
165+
: 'v2.pipeline.events.show';
166+
}
167+
}),
168+
155169
isButtonDisabledLoaded: false,
156170
isButtonDisabled: computed(
157171
'buildAction',

app/components/build-banner/template.hbs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
</LinkTo>
1111
{{else}}
1212
<LinkTo
13-
@route="v2.pipeline.events.show"
13+
@route={{this.eventRoute}}
1414
@models={{array this.pipelineId this.event.id}}
15+
@query={{hash jobId=this.jobId}}
1516
class="banner-value"
1617
>
1718
{{this.jobName}}

app/components/pipeline/event/card/component.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,15 @@ export default class PipelineEventCardComponent extends Component {
325325
}
326326

327327
get isHighlighted() {
328-
return this.router.currentURL.endsWith(this.event.id);
328+
const routeEventId = this.router.currentRoute?.attributes?.id
329+
? this.router.currentRoute.attributes.id
330+
: this.router.currentRoute?.params?.event_id;
331+
332+
if (routeEventId !== undefined) {
333+
return `${routeEventId}` === `${this.event.id}`;
334+
}
335+
336+
return this.router.currentURL.split('?')[0].endsWith(`/${this.event.id}`);
329337
}
330338

331339
get isOutlined() {

app/components/pipeline/workflow/graph/component.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export default class PipelineWorkflowGraphComponent extends Component {
4040

4141
showPRJobs;
4242

43+
lastScrolledSelectedJobKey = null;
44+
4345
constructor() {
4446
super(...arguments);
4547
this.event = this.args.event;
@@ -61,6 +63,18 @@ export default class PipelineWorkflowGraphComponent extends Component {
6163
);
6264
}
6365

66+
get selectedJobId() {
67+
return this.args.selectedJobId ? `${this.args.selectedJobId}` : '';
68+
}
69+
70+
get selectedJobKey() {
71+
if (!this.event?.id || !this.selectedJobId) {
72+
return null;
73+
}
74+
75+
return `${this.event.id}:${this.selectedJobId}`;
76+
}
77+
6478
getDecoratedGraph(
6579
workflowGraph,
6680
builds,
@@ -91,6 +105,43 @@ export default class PipelineWorkflowGraphComponent extends Component {
91105
});
92106
}
93107

108+
applySelectedJobLabel() {
109+
if (!this.graphSvg) {
110+
return;
111+
}
112+
113+
let jobFound = false;
114+
115+
this.graphSvg.selectAll('.graph-label').classed('selected-job', node => {
116+
const isSelected =
117+
!!this.selectedJobId && `${node?.id}` === this.selectedJobId;
118+
119+
if (isSelected) {
120+
jobFound = true;
121+
}
122+
123+
return isSelected;
124+
});
125+
126+
if (!jobFound) {
127+
this.lastScrolledSelectedJobKey = null;
128+
129+
return;
130+
}
131+
132+
if (
133+
this.selectedJobKey &&
134+
this.lastScrolledSelectedJobKey !== this.selectedJobKey
135+
) {
136+
const selectedLabel = this.graphSvg
137+
.select('.graph-label.selected-job')
138+
.node();
139+
140+
selectedLabel?.scrollIntoView({ block: 'center', inline: 'center' });
141+
this.lastScrolledSelectedJobKey = this.selectedJobKey;
142+
}
143+
}
144+
94145
@action
95146
draw(element) {
96147
const isSkippedEvent = isSkipped(this.event, this.builds);
@@ -188,6 +239,8 @@ export default class PipelineWorkflowGraphComponent extends Component {
188239
verticalDisplacements,
189240
horizontalDisplacements
190241
);
242+
243+
this.applySelectedJobLabel();
191244
}
192245

193246
@action
@@ -243,5 +296,6 @@ export default class PipelineWorkflowGraphComponent extends Component {
243296
nodeWidth
244297
);
245298
updateStageStatuses(this.graphSvg, this.decoratedGraph);
299+
this.applySelectedJobLabel();
246300
}
247301
}

app/components/pipeline/workflow/graph/styles.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
@mixin styles {
1414
#workflow-graph {
15+
.graph-label.selected-job {
16+
fill: colors.$sd-failure;
17+
}
18+
1519
.graph-node {
1620
font-family: 'screwdriver';
1721
fill: colors.$sd-text-light;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<div id="workflow-graph"
22
{{did-insert this.draw}}
3-
{{did-update this.redraw @workflowGraph @builds @stageBuilds @event @collapsedStages this.pipelinePageState.jobs}}
3+
{{did-update this.redraw @workflowGraph @builds @stageBuilds @event @collapsedStages @selectedJobId this.pipelinePageState.jobs}}
44
/>

app/components/pipeline/workflow/template.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
<Pipeline::Workflow::Graph
9191
@workflowGraph={{this.workflowGraphToDisplay}}
9292
@event={{this.event}}
93+
@selectedJobId={{@jobId}}
9394
@builds={{this.builds}}
9495
@stageBuilds={{this.stageBuilds}}
9596
@collapsedStages={{this.collapsedStages}}

app/components/workflow-graph-d3/component.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,53 @@ export default Component.extend({
218218
}
219219
}
220220
},
221+
getSelectedJobKey() {
222+
const eventId = this.selectedEventObj?.id;
223+
const selectedJobId = this.jobId;
224+
225+
if (!eventId || !selectedJobId || this.minified) {
226+
return null;
227+
}
228+
229+
return `${eventId}:${selectedJobId}`;
230+
},
231+
232+
applySelectedJobLabel(svg) {
233+
if (!svg) {
234+
return;
235+
}
236+
237+
const selectedJobId = this.jobId ? `${this.jobId}` : '';
238+
239+
let jobFound = false;
240+
241+
svg.selectAll('.graph-label').classed('selected-job', node => {
242+
const isSelected =
243+
!this.minified && !!selectedJobId && `${node?.id}` === selectedJobId;
244+
245+
if (isSelected) {
246+
jobFound = true;
247+
}
248+
249+
return isSelected;
250+
});
251+
252+
const selectedJobKey = this.getSelectedJobKey();
253+
254+
if (!jobFound) {
255+
this.set('lastScrolledSelectedJobKey', null);
256+
257+
return;
258+
}
259+
260+
if (selectedJobKey && this.lastScrolledSelectedJobKey !== selectedJobKey) {
261+
const selectedLabel = svg.select('.graph-label.selected-job').node();
262+
263+
selectedLabel?.scrollIntoView({ block: 'center', inline: 'center' });
264+
this.set('lastScrolledSelectedJobKey', selectedJobKey);
265+
}
266+
},
267+
221268
async redraw(data) {
222269
if (!data) return;
223270
const el = d3.select(this.element);
@@ -280,6 +327,8 @@ export default Component.extend({
280327
);
281328
}
282329
});
330+
331+
this.applySelectedJobLabel(el);
283332
},
284333
async draw(data) {
285334
if (this.isDestroying || this.isDestroyed) {
@@ -380,5 +429,7 @@ export default Component.extend({
380429
horizontalDisplacements
381430
);
382431
}
432+
433+
this.applySelectedJobLabel(svg);
383434
}
384435
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Controller from '@ember/controller';
2+
3+
export default class NewPipelineEventsShowController extends Controller {
4+
queryParams = ['jobId'];
5+
6+
jobId = '';
7+
}

app/v2/pipeline/events/show/route.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ export default class NewPipelineEventsShowRoute extends Route {
1010
async model(params, transition) {
1111
const eventId = params.event_id;
1212
const pipelineId = this.pipelinePageState.getPipelineId();
13+
const transitionLatestEvent = transition.data?.latestEvent;
1314

1415
let latestEvent;
1516

1617
let event;
1718

18-
if (transition.data.latestEvent) {
19-
event = transition.data.latestEvent;
19+
if (`${transitionLatestEvent?.id}` === `${eventId}`) {
20+
event = transitionLatestEvent;
2021
latestEvent = event;
2122
} else {
2223
event = await this.shuttle

0 commit comments

Comments
 (0)