Add list of recent builds
This commit is contained in:
parent
df83d61f7a
commit
8fc894559c
4 changed files with 130 additions and 10 deletions
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react-native';
|
import React from 'react-native';
|
||||||
import GlobalStyles from '../../settings/styles';
|
import GlobalStyles from '../../settings/styles';
|
||||||
import Icon from 'react-native-vector-icons/Octicons';
|
import Icon from 'react-native-vector-icons/Octicons';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { timeSince } from '../../helpers/time-utils';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
View,
|
View,
|
||||||
|
@ -18,11 +20,82 @@ const styles = StyleSheet.create({
|
||||||
borderBottomColor: GlobalStyles.get('CIRCLE_ITEM_BORDER'),
|
borderBottomColor: GlobalStyles.get('CIRCLE_ITEM_BORDER'),
|
||||||
borderBottomWidth: 2,
|
borderBottomWidth: 2,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
marginVertical: 2.5,
|
||||||
|
},
|
||||||
|
repoCell: {
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
paddingVertical: 3,
|
||||||
|
flex: 0.84
|
||||||
|
},
|
||||||
|
buildCell: {
|
||||||
|
flex: 0.25,
|
||||||
|
padding: 4,
|
||||||
|
borderLeftColor: GlobalStyles.get('CIRCLE_ITEM_BORDER'),
|
||||||
|
borderLeftWidth: 1
|
||||||
|
},
|
||||||
|
colourPanel: {
|
||||||
|
flex: 0.02
|
||||||
|
},
|
||||||
|
repoName: {
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: '500'
|
||||||
|
},
|
||||||
|
details: {
|
||||||
|
fontSize: 12.5,
|
||||||
|
fontWeight: '300',
|
||||||
|
},
|
||||||
|
detailsRow: {
|
||||||
|
flex: 1,
|
||||||
|
flexDirection: 'row'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default class BuildItem extends React.Component {
|
export default class BuildItem extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this._displayMoreInfo = this._displayMoreInfo.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_displayMoreInfo(build) {
|
||||||
|
const mask = build.build_time_millis <= 60000 ? 'ss[s]' : 'm:ss';
|
||||||
|
const buildTime = moment.duration(build.build_time_millis, 'ms').format(mask);
|
||||||
|
const commit = build.all_commit_details[0];
|
||||||
|
return (
|
||||||
|
<View style={styles.buildCell}>
|
||||||
|
<Text style={styles.details}>
|
||||||
|
<Icon name="info" /> { this.props.statusColour }
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.details}><Icon name="clock" /> { buildTime }</Text>
|
||||||
|
<Text style={styles.details}><Icon name="git-commit" /> { commit.commit.substring(0, 6) }</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return null;
|
const build = this.props.build;
|
||||||
|
const buildDetails = this._displayMoreInfo(build);
|
||||||
|
return (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.button}
|
||||||
|
underlayColor={GlobalStyles.get('CIRCLE_BG')}>
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={styles.repoCell}>
|
||||||
|
<Text style={styles.repoName}>{build.branch} - #{build.build_num}</Text>
|
||||||
|
<View style={styles.detailsRow}>
|
||||||
|
<Text style={styles.details}>
|
||||||
|
<Icon name="clock" /> {timeSince(moment(build.stop_time).toDate())} ago
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.detailsRow}>
|
||||||
|
<Text style={styles.details}><Icon name="comment-discussion" /> { build.subject }</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{ buildDetails }
|
||||||
|
<View style={[styles.colourPanel, {backgroundColor: this.props.statusColour}]} />
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react-native';
|
import React from 'react-native';
|
||||||
|
import GlobalStyles from '../../settings/styles';
|
||||||
import BuildItem from './BuildItem';
|
import BuildItem from './BuildItem';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -21,10 +22,17 @@ const styles = StyleSheet.create({
|
||||||
export default class BuildList extends React.Component {
|
export default class BuildList extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
|
||||||
|
this.state = {
|
||||||
|
dataSource: ds.cloneWithRows(this.props.builds),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRow(build) {
|
renderRow(build) {
|
||||||
return <BuildItem build={build} />;
|
const statusColour = build.status === 'failed' ?
|
||||||
|
GlobalStyles.get('CIRCLE_TEST_FAIL') :
|
||||||
|
GlobalStyles.get('CIRCLE_TEST_PASS');
|
||||||
|
return <BuildItem build={build} project={this.props.project} statusColour={statusColour} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -33,7 +41,7 @@ export default class BuildList extends React.Component {
|
||||||
<ListView
|
<ListView
|
||||||
contentContainerStyle={styles.listView}
|
contentContainerStyle={styles.listView}
|
||||||
dataSource={this.state.dataSource}
|
dataSource={this.state.dataSource}
|
||||||
renderRow={this.renderRow} />
|
renderRow={this.renderRow.bind(this)} />
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ const styles = StyleSheet.create({
|
||||||
details: {
|
details: {
|
||||||
fontSize: 12.5,
|
fontSize: 12.5,
|
||||||
fontWeight: '300',
|
fontWeight: '300',
|
||||||
marginLeft: 3
|
|
||||||
},
|
},
|
||||||
detailsRow: {
|
detailsRow: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
@ -75,6 +74,7 @@ export default class ProjectItem extends React.Component {
|
||||||
|
|
||||||
_viewBuildDetails() {
|
_viewBuildDetails() {
|
||||||
const destination = RouteMaster.get('PROJECT_DETAILS');
|
const destination = RouteMaster.get('PROJECT_DETAILS');
|
||||||
|
destination.title = this.props.project.reponame;
|
||||||
destination.props = {
|
destination.props = {
|
||||||
project: this.props.project
|
project: this.props.project
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import React from 'react-native';
|
import React from 'react-native';
|
||||||
import { getProjectRecentBuilds } from '../../api/CircleCI';
|
import { getProjectRecentBuilds } from '../../api/CircleCI';
|
||||||
import loaderHandler from 'react-native-busy-indicator/LoaderHandler';
|
import loaderHandler from 'react-native-busy-indicator/LoaderHandler';
|
||||||
// import BuildList from '../builds/BuildList';
|
import BuildList from '../builds/BuildList';
|
||||||
import GlobalStyles from '../../settings/styles';
|
import GlobalStyles from '../../settings/styles';
|
||||||
|
import _ from 'underscore';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
BackAndroid,
|
BackAndroid,
|
||||||
Text
|
Text,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
@ -24,6 +24,17 @@ const styles = StyleSheet.create({
|
||||||
statusHeading: {
|
statusHeading: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
textAlign: 'center'
|
textAlign: 'center'
|
||||||
|
},
|
||||||
|
statusRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
alignSelf: 'center',
|
||||||
|
},
|
||||||
|
panel: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderBottomColor: GlobalStyles.get('CIRCLE_NAVBAR_TEXT'),
|
||||||
|
borderBottomWidth: 2,
|
||||||
|
paddingVertical: 10
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -31,14 +42,42 @@ export default class ProjectDetails extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
project: props.currentRoute.props.project
|
project: props.currentRoute.props.project,
|
||||||
|
recentBuilds: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
loaderHandler.showLoader('Fetching Data');
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
getProjectRecentBuilds(this.state.project.username, this.state.project.reponame, 30).then(function (recentBuilds) {
|
||||||
|
recentBuilds = _.sortBy(recentBuilds, (b) => b.stop_time).reverse();
|
||||||
|
this.setState({ recentBuilds });
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const master = this.state.project.branches[this.state.project.default_branch].recent_builds[0];
|
||||||
|
const statusStyle = master.outcome === 'failed' ?
|
||||||
|
{ color: GlobalStyles.get('CIRCLE_TEST_FAIL')} :
|
||||||
|
{ color: GlobalStyles.get('CIRCLE_TEST_PASS')};
|
||||||
|
let list = null;
|
||||||
|
if (this.state.recentBuilds) {
|
||||||
|
loaderHandler.hideLoader();
|
||||||
|
list = ( <BuildList builds={this.state.recentBuilds} project={this.state.project}/> );
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.title}>{this.state.project.reponame}</Text>
|
<View style={styles.panel}>
|
||||||
<Text style={styles.statusHeading}>Status: </Text>
|
<Text style={styles.title}>Recent Builds</Text>
|
||||||
|
<View style={styles.statusRow}>
|
||||||
|
<Text style={styles.statusHeading}>Status: </Text>
|
||||||
|
<Text style={[styles.statusHeading, statusStyle]}>{master.outcome}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{ list }
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue