Add list of recent builds

This commit is contained in:
Jake Howard 2016-03-11 20:56:26 +00:00
parent df83d61f7a
commit 8fc894559c
4 changed files with 130 additions and 10 deletions

View file

@ -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>
);
} }
}; };

View file

@ -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>
); );
} }

View file

@ -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
}; };

View file

@ -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.title}>Recent Builds</Text>
<View style={styles.statusRow}>
<Text style={styles.statusHeading}>Status: </Text> <Text style={styles.statusHeading}>Status: </Text>
<Text style={[styles.statusHeading, statusStyle]}>{master.outcome}</Text>
</View>
</View>
{ list }
</View> </View>
); );
} }