From 8c4f61506afebc268a21323d8d52fe4e972890cd Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 23 Feb 2016 23:12:32 +0000 Subject: [PATCH] DIsplay basic repo list --- app/api/CircleCI.js | 23 +++++++- app/api/endpoints.js | 4 +- app/components/app.js | 2 +- app/components/projects/ProjectItem.js | 77 ++++++++++++++++++++++++-- app/components/projects/ProjectList.js | 31 +++++++---- app/components/routes/home.js | 17 ++++-- 6 files changed, 130 insertions(+), 24 deletions(-) diff --git a/app/api/CircleCI.js b/app/api/CircleCI.js index 9269a40..53de0a2 100644 --- a/app/api/CircleCI.js +++ b/app/api/CircleCI.js @@ -6,15 +6,34 @@ function JSONify(response) { return response.json(); } +const [GET] = ['GET']; + export function checkToken(possibleToken) { const url = endpoints.get('USER_INFO'); - return request(url, 'GET', {}, possibleToken).then(function (response) { + return request(url, GET, {}, possibleToken).then(function (response) { return response.ok; }); } +export async function getUserDetails() { + const CIToken = await token.get(); + const url = endpoints.get('USER_INFO'); + return await request(url, GET, {}, CIToken).then(JSONify); +} + export async function getProjects() { const CIToken = await token.get(); const url = endpoints.get('ALL_PROJECTS'); - return await request(url, 'GET', {}, CIToken).then(JSONify); + return await request(url, GET, {}, CIToken).then(JSONify); +} + +export async function getProjectRecentBuilds(user, repo) { + const CIToken = await token.get(); + const url = endpoints.get('PROJECT_RECENTS').param({ user, repo }); + return await request( + url, + GET, + {}, + CIToken) + .then(JSONify); } diff --git a/app/api/endpoints.js b/app/api/endpoints.js index 25f4399..088ec8d 100644 --- a/app/api/endpoints.js +++ b/app/api/endpoints.js @@ -5,5 +5,7 @@ const URL_BASE = UrlAssembler('https://circleci.com/api/v1'); export default Map({ USER_INFO: URL_BASE.segment('/me'), - ALL_PROJECTS: URL_BASE.segment('/projects') + ALL_PROJECTS: URL_BASE.segment('/projects'), + RECENT_BUILDS: URL_BASE.segment('/recent-builds'), + PROJECT_RECENTS: URL_BASE.template('/project/:user/:repo') }); diff --git a/app/components/app.js b/app/components/app.js index 396f8e7..c8d65ea 100644 --- a/app/components/app.js +++ b/app/components/app.js @@ -32,7 +32,7 @@ export default class extends React.Component { diff --git a/app/components/projects/ProjectItem.js b/app/components/projects/ProjectItem.js index f0ac41b..6cdd62f 100644 --- a/app/components/projects/ProjectItem.js +++ b/app/components/projects/ProjectItem.js @@ -1,15 +1,84 @@ import React from 'react-native'; +import GlobalStyles from '../../settings/styles'; +import { getProjectRecentBuilds } from '../../api/CircleCI'; -var { +const { View, Text, - StyleSheet, + StyleSheet } = React; +const styles = StyleSheet.create({ + container: { + flex: 1, + height: 70, + alignItems: 'stretch', + backgroundColor: GlobalStyles.get('CIRCLE_ITEM_BG'), + borderBottomColor: GlobalStyles.get('CIRCLE_ITEM_BORDER'), + borderBottomWidth: 1, + marginBottom: 5, + flexDirection: 'row' + }, + cell: { + paddingHorizontal: 4, + paddingVertical: 2 + }, + imageCell: { + width: 45, + }, + repoName: { + fontSize: 14, + fontWeight: '500' + } +}); + export default class ProjectItem extends React.Component { - render() { + constructor() { + super(); + this.state = { + recentBuild: false + }; + this._displayMoreInfo = this._displayMoreInfo.bind(this); + } + + componentDidMount() { + getProjectRecentBuilds(this.props.project.username, this.props.project.reponame).then(function (recentBuild) { + this.setState({ recentBuild: recentBuild[0] }); + }.bind(this)); + } + + _displayMoreInfo(mostRecentBuild) { + let seconds = Math.floor(mostRecentBuild.build_time_millis / 1000); + const minutes = Math.floor(seconds / 60); + seconds = seconds - (minutes * 60); + const format = minutes + ':' + seconds; return ( - {this.props.project.reponame} + { format } + ); + } + + render() { + console.log(this.props.userDetails); + const project = this.props.project; + const mostRecentBuild = this.state.recentBuild; + const statusColour = mostRecentBuild.failed ? '#ED5C5C' : '#42C88A'; + let username; + if (this.props.userDetails && this.props.userDetails.login !== project.username) { + username = project.username; + } else { + username = 'me'; + } + const buildDetails = mostRecentBuild ? this._displayMoreInfo(mostRecentBuild) : null; + + return ( + + + + + {username}/{project.reponame} + { buildDetails } + + ); } }; diff --git a/app/components/projects/ProjectList.js b/app/components/projects/ProjectList.js index bd1d60d..2acda9b 100644 --- a/app/components/projects/ProjectList.js +++ b/app/components/projects/ProjectList.js @@ -2,20 +2,19 @@ import React from 'react-native'; import ProjectItem from './ProjectItem'; -var { +const { ListView, StyleSheet, - Text, ScrollView } = React; -var styles = StyleSheet.create({ - composerListView: { +const styles = StyleSheet.create({ + listView: { flex: 1, - flexDirection: 'row', + flexDirection: 'column', + alignItems: 'stretch', justifyContent: 'center', flexWrap: 'wrap', - padding: 15 }, }); @@ -23,24 +22,32 @@ export default class ProjectList extends React.Component { constructor(props) { super(props); const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); - console.log(JSON.stringify(this.props.data)); + const sortedProjects = this._sortByDate(this.props.data); this.state = { - dataSource: ds.cloneWithRows(this.props.data) + dataSource: ds.cloneWithRows(sortedProjects), }; this.renderRow = this.renderRow.bind(this); } + _sortByDate(projects) { + return projects.sort(function (a, b) { + const keyA = a.username + '/' + a.reponame; + const keyB = b.reponame + '/' + b.username; + if (keyA < keyB) { return -1; } + if (keyA > keyB) { return 1; } + return 0; + }.bind(this)); + } + renderRow(project) { - return ( - - ); + return ; } render() { return ( diff --git a/app/components/routes/home.js b/app/components/routes/home.js index 352d4fa..9f19bcc 100644 --- a/app/components/routes/home.js +++ b/app/components/routes/home.js @@ -1,12 +1,12 @@ import React from 'react-native'; -import { getProjects } from '../../api/CircleCI'; +import { getProjects, getUserDetails } from '../../api/CircleCI'; import loaderHandler from 'react-native-busy-indicator/LoaderHandler'; import ProjectList from '../projects/ProjectList'; import GlobalStyles from '../../settings/styles'; + const { StyleSheet, - Text, View, BackAndroid, } = React; @@ -23,7 +23,8 @@ export default class Home extends React.Component { super(); this.state = { - projects: '' + projects: '', + userDetails: '' }; } @@ -37,18 +38,26 @@ export default class Home extends React.Component { } componentDidMount() { + this.props.nav.navigationContext.addListener('didfocus', function () { + this.props.nav.immediatelyResetRouteStack([this.props.currentRoute]); + }.bind(this)); + getProjects().then(function (data) { this.setState({ projects: data }); }.bind(this)); + + getUserDetails().then(function (userDetails) { + this.setState({userDetails}); + }.bind(this)); } render() { let list; if (this.state.projects) { list = ( - + ); loaderHandler.hideLoader(); } else {