/
JobButton.jsx
140 lines (121 loc) · 4.31 KB
/
JobButton.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
import React from 'react';
import PropTypes from 'prop-types';
import { getBtnClass, findJobInstance } from '../../helpers/job';
import { getUrlParam } from '../../helpers/location';
export default class JobButtonComponent extends React.Component {
constructor(props) {
super(props);
const { job } = this.props;
const urlSelectedJob = getUrlParam('selectedJob');
this.state = {
isSelected: parseInt(urlSelectedJob, 10) === job.id,
isRunnableSelected: false,
};
}
componentDidMount() {
if (this.state.isSelected) {
// scroll to make this job if it's selected
findJobInstance(this.props.job.id, true);
}
}
/**
* Rather than making this a PureComponent, which does shallow compares of
* props and state, we are using shouldComponentUpdate, because the
* ``selectedJobId`` will change for all components, but only the previous
* selection and the next selection care and need to re-render. So our
* logic on shouldComponentUpdate is a little more complex than a simple
* shallow compare would allow.
*/
shouldComponentUpdate(nextProps, nextState) {
const { visible, resultStatus, failureClassificationId } = this.props;
const { isSelected, isRunnableSelected } = this.state;
return (
visible !== nextProps.visible ||
resultStatus !== nextProps.resultStatus ||
failureClassificationId !== nextProps.failureClassificationId ||
isSelected !== nextState.isSelected ||
isRunnableSelected !== nextState.isRunnableSelected
);
}
componentWillUnmount() {
this.setState({ isRunnableSelected: false, isSelected: false });
}
setSelected(isSelected) {
const { job, platform, filterPlatformCb, filterModel } = this.props;
// if a job was just classified, and we are in unclassified only mode,
// then the job no longer meets the filter criteria. However, if it
// is still selected, then it should stay visible so that next/previous
// navigation still works. Then, as soon as the selection changes, it
// it will disappear. So visible must be contingent on the filters AND
// whether it is still selected.
job.visible = filterModel.showJob(job);
this.setState({ isSelected });
// filterPlatformCb will keep a job and platform visible if it contains
// the selected job, so we must pass in if this job is selected or not.
filterPlatformCb(platform, isSelected ? job.id : null);
}
toggleRunnableSelected() {
this.setState({ isRunnableSelected: !this.state.isRunnableSelected });
}
render() {
const { job, resultStatus } = this.props;
const { isSelected, isRunnableSelected } = this.state;
const {
state,
job_type_name,
failure_classification_id,
end_timestamp,
start_timestamp,
ref_data_name,
visible,
id,
job_type_symbol,
} = job;
if (!visible) return null;
const runnable = state === 'runnable';
const btnClass = getBtnClass(resultStatus, failure_classification_id);
let title = `${resultStatus} | ${job_type_name}`;
if (state === 'completed') {
const duration = Math.round((end_timestamp - start_timestamp) / 60);
title += ` (${duration} mins)`;
}
const classes = ['btn', btnClass, 'filter-shown'];
const attributes = {
'data-job-id': id,
title,
};
if (runnable) {
classes.push('runnable-job-btn', 'runnable');
attributes['data-buildername'] = ref_data_name;
if (isRunnableSelected) {
classes.push('runnable-job-btn-selected');
}
} else {
classes.push('job-btn');
}
if (isSelected) {
classes.push('selected-job btn-lg-xform');
} else {
classes.push('btn-xs');
}
attributes.className = classes.join(' ');
return (
<button type="button" {...attributes}>
{job_type_symbol}
</button>
);
}
}
JobButtonComponent.propTypes = {
job: PropTypes.object.isRequired,
filterModel: PropTypes.object.isRequired,
repoName: PropTypes.string.isRequired,
visible: PropTypes.bool.isRequired,
resultStatus: PropTypes.string.isRequired,
platform: PropTypes.object.isRequired,
filterPlatformCb: PropTypes.func.isRequired,
failureClassificationId: PropTypes.number, // runnable jobs won't have this
};
JobButtonComponent.defaultProps = {
failureClassificationId: 1,
};