-
Notifications
You must be signed in to change notification settings - Fork 527
/
PipelineRoutes.jsx
157 lines (140 loc) · 6.21 KB
/
PipelineRoutes.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { Route, Redirect, IndexRedirect } from 'react-router';
import React from 'react';
import { AppConfig } from '@jenkins-cd/blueocean-core-js';
import { analytics } from './analytics';
import Dashboard from './Dashboard';
import {
Pipelines,
MultiBranch,
Activity,
PullRequests,
PipelinePage,
PipelineTrends,
RunDetails,
RunDetailsPipeline,
RunDetailsChanges,
RunDetailsArtifacts,
RunDetailsTests,
} from './components';
import { CreatePipeline } from './creation';
/**
* gets the background element used for the modal underlay
*/
function getBackgroundElement() {
return document.getElementById('modal-snap-background');
}
/**
* Cleans up the copied HTML to remove IDs, react root attributes
* and other non-visible elements.
*/
function cleanupCopy(el) {
el.removeAttribute('data-reactroot');
el.removeAttribute('id');
if (el.childNodes && el.childNodes.length) {
for (let i = 0; i < el.childNodes.length; i++) {
const child = el.childNodes[i];
if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.ELEMENT_NODE) {
el.removeChild(child);
} else if (child.nodeType === Node.ELEMENT_NODE) {
cleanupCopy(child);
}
}
}
}
/**
* Removes a persisted background, restores prior
* scroll position
*/
function discardPersistedBackground() {
const bg = getBackgroundElement();
if (bg) {
const scrollY = bg.getAttribute('scrollY');
const scrollX = bg.getAttribute('scrollX');
window.scroll(scrollX, scrollY);
bg.parentElement.removeChild(bg);
}
}
/**
* Takes a snapshot of the react root, and overlays it
*/
function persistModalBackground() {
const root = document.getElementById('root');
const background = root.cloneNode(true);
cleanupCopy(background);
discardPersistedBackground();
const container = document.createElement('div');
container.id = 'modal-snap-background';
container.appendChild(background);
container.style.display = 'block';
container.style.top = `${-1 * window.scrollY}px`;
container.style.left = `${-1 * window.scrollX}px`;
container.setAttribute('scrollY', window.scrollY);
container.setAttribute('scrollX', window.scrollX);
root.appendChild(container);
}
function isEnteringRunDetails(prevState, nextState) {
return nextState.params.runId && (prevState == null || !prevState.params.runId);
}
function isLeavingRunDetails(prevState, nextState) {
return prevState !== null && prevState.params.runId && !nextState.params.runId;
}
function isPersistBackgroundRoute(prevState, nextState) {
return isEnteringRunDetails(prevState, nextState);
}
function isRemovePersistedBackgroundRoute(prevState, nextState) {
return isLeavingRunDetails(prevState, nextState);
}
function onTopLevelRouteEnter() {
analytics.trackPageView(); // Tracks the page view on load of window
}
/**
* Persists the application's DOM as a "background" when navigating to a route w/ a modal or dialog.
* Also removes the "background" when navigating away.
* Note this must be done early (from top-level onChange handler) and can't wait until a modal/dialog will mount
* due to the fact react router will have already changed the background context.
*/
function persistBackgroundOnNavigationChange(prevState, nextState, replace, callback, delay = 200) {
if (isPersistBackgroundRoute(prevState, nextState)) {
persistModalBackground();
} else if (isRemovePersistedBackgroundRoute(prevState, nextState)) {
// need to delay this a little to let the route re-render
setTimeout(discardPersistedBackground, delay);
}
if (callback) {
callback();
}
}
function onRouteChange(prevState, nextState, replace, callback, delay = 200) {
analytics.trackPageView(); // Tracks page view as the route changes
persistBackgroundOnNavigationChange(prevState, nextState, replace, callback, delay);
}
function onLeaveCheckBackground() {
persistBackgroundOnNavigationChange({ params: { runId: true } }, { params: {} }, null, null, 0);
}
const trends = AppConfig.isFeatureEnabled('trends');
export default (
<Route component={Dashboard} onEnter={onTopLevelRouteEnter} onChange={onRouteChange}>
<Route path="organizations/:organization/pipelines" component={Pipelines} onEnter={analytics.trackDashboardVisited} />
<Route path="organizations/:organization/create-pipeline" component={CreatePipeline} onEnter={analytics.trackPipelineCreationVisited} />
<Redirect from="organizations/:organization(/*)" to="organizations/:organization/pipelines" />
<Route path="organizations/:organization" component={PipelinePage}>
<Route path=":pipeline/branches" component={MultiBranch} onEnter={analytics.trackPipelineBranchesVisited} />
<Route path=":pipeline/activity" component={Activity} onEnter={analytics.trackPipelineActivityVisited} />
<Route path=":pipeline/pr" component={PullRequests} onEnter={analytics.trackPipelinePullRequestsVisited} />
{trends && <Route path=":pipeline/trends" component={PipelineTrends} />}
<Route path=":pipeline/detail/:branch/:runId" component={RunDetails} onLeave={onLeaveCheckBackground}>
<IndexRedirect to="pipeline" />
<Route path="pipeline" component={RunDetailsPipeline} onEnter={analytics.trackPipelineRunVisited}>
<Route path=":node" component={RunDetailsPipeline} />
</Route>
<Route path="changes" component={RunDetailsChanges} onEnter={analytics.trackPipelineRunChangesVisited} />
<Route path="tests" component={RunDetailsTests} onEnter={analytics.trackPipelineRunTestsVisited} />
<Route path="artifacts" component={RunDetailsArtifacts} onEnter={analytics.trackPipelineRunArtifactsVisited} />
</Route>
<Redirect from=":pipeline(/*)" to=":pipeline/activity" />
</Route>
<Route path="/pipelines" component={Pipelines} onEnter={analytics.trackDashboardVisited} />
<Route path="/create-pipeline" component={CreatePipeline} onEnter={analytics.trackPipelineCreationVisited} />
<IndexRedirect to="pipelines" />
</Route>
);