This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | const React = require('react'); |
||
2 | const ReactRedux = require('react-redux'); |
||
3 | |||
4 | const StepMenu = require('../components/StepMenu.jsx'); |
||
5 | const TargetRelease = require('./TargetRelease.jsx'); |
||
6 | const TargetReleaseRO = require('./TargetReleaseRO.jsx'); |
||
7 | |||
8 | const Approval = require('./Approval.jsx'); |
||
9 | const ApprovalRO = require('./ApprovalRO.jsx'); |
||
10 | const Deployment = require('./Deployment.jsx'); |
||
11 | const DeployPlan = require('./DeployPlan.jsx'); |
||
12 | const DeployPlanRO = require('./DeployPlanRO.jsx'); |
||
13 | const Modal = require('../Modal.jsx'); |
||
14 | const LoadingBar = require('../components/LoadingBar.jsx'); |
||
15 | |||
16 | const actions = require('../_actions.js'); |
||
17 | const constants = require('../constants/deployment.js'); |
||
18 | |||
19 | function calculateSteps(props) { |
||
20 | return [ |
||
21 | { |
||
22 | title: "Target release", |
||
23 | show: props.show[0], |
||
24 | is_finished: props.is_finished[0] |
||
25 | }, |
||
26 | { |
||
27 | title: "Deployment plan", |
||
28 | show: props.show[1], |
||
29 | is_finished: props.is_finished[1] |
||
30 | }, |
||
31 | { |
||
32 | title: "Approval", |
||
33 | show: props.show[2], |
||
34 | is_finished: props.is_finished[2] |
||
35 | }, |
||
36 | { |
||
37 | title: "Deployment", |
||
38 | show: props.show[3], |
||
39 | is_finished: props.is_finished[3] |
||
40 | } |
||
41 | ]; |
||
42 | } |
||
43 | |||
44 | |||
45 | const DeployModal = React.createClass({ |
||
46 | |||
47 | componentDidMount: function() { |
||
48 | window.addEventListener("resize", this.resize); |
||
49 | const bodyElements = document.getElementsByClassName("modal-body"); |
||
50 | if (bodyElements.length === 0) { |
||
51 | return; |
||
52 | } |
||
53 | |||
54 | this.resize(); |
||
55 | }, |
||
56 | |||
57 | componentWillUpdate: function() { |
||
58 | // Before we update, we save the current scroll "position" for use in componentDidUpdate |
||
59 | this.saveScrollPosition(); |
||
60 | }, |
||
61 | |||
62 | componentDidUpdate: function(prevProps) { |
||
63 | this.resize(); |
||
64 | // when the layout changes from write to readonly we ensure that the modal is scrolled to the same position |
||
65 | // relative to the bottom to prevent a jarring jump. This happens when sending for approval or bypassing the |
||
66 | // approval step. |
||
67 | if (prevProps.can_edit !== this.props.can_edit) { |
||
68 | this.resumeScrollPosition(); |
||
69 | } |
||
70 | }, |
||
71 | |||
72 | componentWillUnmount: function() { |
||
73 | window.removeEventListener("resize", this.resize); |
||
74 | }, |
||
75 | |||
76 | bodyElement: null, |
||
77 | |||
78 | // calculate and set a pixel value on the modal height instead of a percentage |
||
79 | // value so that we get a scrollbar inside the body of the modal |
||
80 | resize: function() { |
||
81 | // We need to calculate the height of the ".modal .body" in the browsers window |
||
82 | let headerHeight = 0; |
||
83 | const headerElements = document.getElementsByClassName("modal-header"); |
||
84 | if (headerElements.length > 0) { |
||
85 | headerHeight = headerElements[0].offsetHeight; |
||
86 | } |
||
87 | const bodyElements = document.getElementsByClassName("modal-body"); |
||
88 | let bodyHeight = 0; |
||
89 | if (bodyElements.length > 0) { |
||
90 | // leave 16px of space to the bottom of the window |
||
91 | bodyHeight = (window.innerHeight - headerHeight) - 16; |
||
92 | } |
||
93 | |||
94 | if (bodyHeight === 0) { |
||
95 | return; |
||
96 | } |
||
97 | |||
98 | // Increase the height of the modal, this cannot be done reliable in CSS because |
||
99 | // a pixel value is required to use the "sticky" side bar |
||
100 | bodyElements[0].style.height = bodyHeight + 'px'; |
||
101 | // give some space at the bottom so user can scroll |
||
102 | bodyElements[0].style.paddingBottom = (bodyHeight / 10) + 'px'; |
||
103 | }, |
||
104 | |||
105 | scrollHeight: 0, |
||
106 | |||
107 | scrollTop: 0, |
||
108 | |||
109 | // save the current scroll position |
||
110 | saveScrollPosition() { |
||
111 | const node = document.getElementsByClassName("modal-body"); |
||
112 | if (node.length > 0) { |
||
113 | this.scrollHeight = node[0].scrollHeight; |
||
114 | this.scrollTop = node[0].scrollTop; |
||
115 | } |
||
116 | }, |
||
117 | |||
118 | // scroll the modal window body to the position previously saved in saveScrollPosition() relative |
||
119 | // to the bottom. This will prevent the content jumping if content above the current scroll position |
||
120 | // changes height. |
||
121 | resumeScrollPosition() { |
||
122 | const node = document.getElementsByClassName("modal-body"); |
||
123 | if (node.length > 0) { |
||
124 | node[0].scrollTop = this.scrollTop + (node[0].scrollHeight - this.scrollHeight); |
||
125 | } |
||
126 | }, |
||
127 | |||
128 | render: function() { |
||
129 | const steps = calculateSteps(this.props); |
||
130 | const content = []; |
||
131 | |||
132 | content[0] = ( |
||
133 | <div key={0} className="section"> |
||
134 | <LoadingBar show /> |
||
135 | </div> |
||
136 | ); |
||
137 | |||
138 | if (steps[0].show) { |
||
139 | if (this.props.can_edit) { |
||
140 | content[0] = (<TargetRelease key={0} />); |
||
141 | } else { |
||
142 | content[0] = (<TargetReleaseRO key={0} />); |
||
143 | } |
||
144 | } |
||
145 | if (steps[1].show) { |
||
146 | if (this.props.can_edit) { |
||
147 | content[1] = (<DeployPlan key={1} />); |
||
148 | } else { |
||
149 | content[1] = (<DeployPlanRO key={1} />); |
||
150 | } |
||
151 | } |
||
152 | if (steps[2].show) { |
||
153 | if (this.props.can_edit) { |
||
154 | content[2] = (<Approval key={2} />); |
||
155 | } else { |
||
156 | content[2] = (<ApprovalRO key={2} />); |
||
157 | } |
||
158 | } |
||
159 | if (steps[3].show) { |
||
160 | content[3] = (<Deployment key={3} />); |
||
161 | } |
||
162 | |||
163 | const options = []; |
||
164 | if (this.props.deployment_id && constants.canDelete(this.props.state)) { |
||
165 | options.push({ |
||
166 | title: 'Delete', |
||
167 | icon: 'fa fa-trash', |
||
168 | handler: this.props.onDelete |
||
169 | }); |
||
170 | } |
||
171 | |||
172 | let headerText = `Deployment to ${this.props.project_name} / ${this.props.environment_name}`; |
||
173 | switch (this.props.state) { |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
174 | case constants.STATE_COMPLETED: { |
||
175 | headerText += ` completed on ${this.props.deployment.date_started_nice}`; |
||
176 | break; |
||
177 | } |
||
178 | case constants.STATE_FAILED: { |
||
179 | headerText += ` failed at ${this.props.deployment.date_started_nice}`; |
||
180 | break; |
||
181 | } |
||
182 | case constants.STATE_REJECTED: { |
||
183 | headerText += ' has been rejected'; |
||
184 | break; |
||
185 | } |
||
186 | case constants.STATE_APPROVED: { |
||
187 | headerText += ' is ready'; |
||
188 | break; |
||
189 | } |
||
190 | case constants.STATE_QUEUED: |
||
191 | case constants.STATE_DEPLOYING: { |
||
192 | headerText += ' in progress...'; |
||
193 | break; |
||
194 | } |
||
195 | case constants.STATE_SUBMITTED: |
||
196 | headerText += ' is awaiting approval'; |
||
197 | break; |
||
198 | } |
||
199 | |||
200 | return ( |
||
201 | <Modal |
||
202 | show={this.props.is_open} |
||
203 | className={"deploy status-" + this.props.state} |
||
204 | closeHandler={this.props.onClose} |
||
205 | title={headerText} |
||
206 | closeTitle="Close" |
||
207 | options={options} |
||
208 | > |
||
209 | <div className="row"> |
||
210 | <div className="col-md-3 menu affix"> |
||
211 | <StepMenu |
||
212 | steps={steps} |
||
213 | onClick={this.props.onStepClick} |
||
214 | /> |
||
215 | </div> |
||
216 | <div className="col-md-9 main" > |
||
217 | <div className="deploy-form"> |
||
218 | <div> |
||
219 | {content} |
||
220 | </div> |
||
221 | </div> |
||
222 | </div> |
||
223 | </div> |
||
224 | </Modal> |
||
225 | ); |
||
226 | } |
||
227 | }); |
||
228 | |||
229 | const mapStateToProps = function(state, ownProps) { |
||
230 | function deployPlanIsOk() { |
||
231 | return state.plan.validation_code === 'success' || state.plan.validation_code === 'warning'; |
||
232 | } |
||
233 | |||
234 | const current = state.deployment.list[state.deployment.current_id] || {}; |
||
235 | |||
236 | const showPlan = state.git.selected_ref !== "" && (typeof state.plan.changes === "object"); |
||
237 | const showApproval = state.deployment.current_id !== "" && current.dirty === false; |
||
238 | |||
239 | return { |
||
240 | show: [ |
||
241 | (!state.git.is_loading && !state.deployment.is_loading), |
||
242 | showPlan, |
||
243 | showPlan && showApproval, |
||
244 | constants.isApproved(current.state) |
||
245 | ], |
||
246 | is_finished: [ |
||
247 | deployPlanIsOk() && state.git.selected_ref !== "", |
||
248 | deployPlanIsOk() && state.deployment.current_id !== "", |
||
249 | deployPlanIsOk() && constants.isApproved(current.state), |
||
250 | constants.isDeployDone(current.state) |
||
251 | ], |
||
252 | can_edit: constants.canEdit(state), |
||
253 | is_open: typeof (ownProps.params.id) !== 'undefined' && ownProps.params.id !== null, |
||
254 | state: current.state, |
||
255 | environment_name: state.environment.name, |
||
256 | project_name: state.environment.project_name, |
||
257 | deployment_id: state.deployment.current_id, |
||
258 | deployment: current |
||
259 | }; |
||
260 | }; |
||
261 | |||
262 | const mapDispatchToProps = function(dispatch) { |
||
263 | return { |
||
264 | onClose: function() { |
||
265 | actions.history.push('/'); |
||
266 | }, |
||
267 | onDelete: function() { |
||
268 | dispatch(actions.deleteDeployment()) |
||
269 | .then(() => actions.history.push('/')); |
||
270 | } |
||
271 | }; |
||
272 | }; |
||
273 | |||
274 | module.exports = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(DeployModal); |
||
275 |