You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Ran npx prettier --write "**/*.js" "*.js"
This commit is contained in:
		| @@ -1,38 +1,34 @@ | ||||
| module.exports = { | ||||
| 	"extends": [ | ||||
| 		"standard", | ||||
| 		"plugin:jest/recommended", | ||||
| 		"plugin:react/recommended", | ||||
| 		"prettier", | ||||
| 		"prettier/react" | ||||
| 	], | ||||
| 	"plugins": [ | ||||
| 		"react", | ||||
| 		"jest", | ||||
| 		"prettier" | ||||
| 	], | ||||
| 	"parser": "babel-eslint", | ||||
| 	"parserOptions": { | ||||
| 		"ecmaVersion": 2016, | ||||
| 		"sourceType": "module", | ||||
| 		"ecmaFeatures": { | ||||
| 			"jsx": true | ||||
| 		} | ||||
| 	}, | ||||
| 	"env": { | ||||
| 		"es6": true, | ||||
| 		"browser": true, | ||||
| 		"node": true, | ||||
| 		"jest/globals": true | ||||
| 	}, | ||||
| 	"rules": { | ||||
| 		"react/prop-types": 1, | ||||
| 		"prettier/prettier": [ | ||||
| 			"error", | ||||
| 			{ | ||||
| 				"trailingComma": "all", | ||||
| 				"useTabs": true | ||||
| 			} | ||||
| 		] | ||||
| 	} | ||||
|   extends: [ | ||||
|     "standard", | ||||
|     "plugin:jest/recommended", | ||||
|     "plugin:react/recommended", | ||||
|     "prettier", | ||||
|     "prettier/react" | ||||
|   ], | ||||
|   plugins: ["react", "jest", "prettier"], | ||||
|   parser: "babel-eslint", | ||||
|   parserOptions: { | ||||
|     ecmaVersion: 2016, | ||||
|     sourceType: "module", | ||||
|     ecmaFeatures: { | ||||
|       jsx: true | ||||
|     } | ||||
|   }, | ||||
|   env: { | ||||
|     es6: true, | ||||
|     browser: true, | ||||
|     node: true, | ||||
|     "jest/globals": true | ||||
|   }, | ||||
|   rules: { | ||||
|     "react/prop-types": 1, | ||||
|     "prettier/prettier": [ | ||||
|       "error", | ||||
|       { | ||||
|         trailingComma: "all", | ||||
|         useTabs: true | ||||
|       } | ||||
|     ] | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -1,36 +1,36 @@ | ||||
| import React from "react"; | ||||
|  | ||||
| export const drone = (client, Component) => { | ||||
| 	// @see https://github.com/yannickcr/eslint-plugin-react/issues/512 | ||||
| 	// eslint-disable-next-line react/display-name | ||||
| 	const component = class extends React.Component { | ||||
| 		getChildContext() { | ||||
| 			return { | ||||
| 				drone: client, | ||||
| 			}; | ||||
| 		} | ||||
|   // @see https://github.com/yannickcr/eslint-plugin-react/issues/512 | ||||
|   // eslint-disable-next-line react/display-name | ||||
|   const component = class extends React.Component { | ||||
|     getChildContext() { | ||||
|       return { | ||||
|         drone: client | ||||
|       }; | ||||
|     } | ||||
|  | ||||
| 		render() { | ||||
| 			return <Component {...this.state} {...this.props} />; | ||||
| 		} | ||||
| 	}; | ||||
|     render() { | ||||
|       return <Component {...this.state} {...this.props} />; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| 	component.childContextTypes = { | ||||
| 		drone: (props, propName) => {}, | ||||
| 	}; | ||||
|   component.childContextTypes = { | ||||
|     drone: (props, propName) => {} | ||||
|   }; | ||||
|  | ||||
| 	return component; | ||||
|   return component; | ||||
| }; | ||||
|  | ||||
| export const inject = Component => { | ||||
| 	// @see https://github.com/yannickcr/eslint-plugin-react/issues/512 | ||||
| 	// eslint-disable-next-line react/display-name | ||||
| 	const component = class extends React.Component { | ||||
| 		render() { | ||||
| 			this.props.drone = this.context.drone; | ||||
| 			return <Component {...this.state} {...this.props} />; | ||||
| 		} | ||||
| 	}; | ||||
|   // @see https://github.com/yannickcr/eslint-plugin-react/issues/512 | ||||
|   // eslint-disable-next-line react/display-name | ||||
|   const component = class extends React.Component { | ||||
|     render() { | ||||
|       this.props.drone = this.context.drone; | ||||
|       return <Component {...this.state} {...this.props} />; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| 	return component; | ||||
|   return component; | ||||
| }; | ||||
|   | ||||
| @@ -4,75 +4,75 @@ const user = window.DRONE_USER; | ||||
| const sync = window.DRONE_SYNC; | ||||
|  | ||||
| const state = { | ||||
| 	follow: false, | ||||
| 	language: "en-US", | ||||
|   follow: false, | ||||
|   language: "en-US", | ||||
|  | ||||
| 	user: { | ||||
| 		data: user, | ||||
| 		error: undefined, | ||||
| 		loaded: true, | ||||
| 		syncing: sync, | ||||
| 	}, | ||||
|   user: { | ||||
|     data: user, | ||||
|     error: undefined, | ||||
|     loaded: true, | ||||
|     syncing: sync | ||||
|   }, | ||||
|  | ||||
| 	feed: { | ||||
| 		loaded: false, | ||||
| 		error: undefined, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   feed: { | ||||
|     loaded: false, | ||||
|     error: undefined, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	repos: { | ||||
| 		loaded: false, | ||||
| 		error: undefined, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   repos: { | ||||
|     loaded: false, | ||||
|     error: undefined, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	secrets: { | ||||
| 		loaded: false, | ||||
| 		error: undefined, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   secrets: { | ||||
|     loaded: false, | ||||
|     error: undefined, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	registry: { | ||||
| 		error: undefined, | ||||
| 		loaded: false, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   registry: { | ||||
|     error: undefined, | ||||
|     loaded: false, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	builds: { | ||||
| 		loaded: false, | ||||
| 		error: undefined, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   builds: { | ||||
|     loaded: false, | ||||
|     error: undefined, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	logs: { | ||||
| 		follow: false, | ||||
| 		loading: true, | ||||
| 		error: false, | ||||
| 		data: {}, | ||||
| 	}, | ||||
|   logs: { | ||||
|     follow: false, | ||||
|     loading: true, | ||||
|     error: false, | ||||
|     data: {} | ||||
|   }, | ||||
|  | ||||
| 	token: { | ||||
| 		value: undefined, | ||||
| 		error: undefined, | ||||
| 		loading: false, | ||||
| 	}, | ||||
|   token: { | ||||
|     value: undefined, | ||||
|     error: undefined, | ||||
|     loading: false | ||||
|   }, | ||||
|  | ||||
| 	message: { | ||||
| 		show: false, | ||||
| 		text: undefined, | ||||
| 		error: false, | ||||
| 	}, | ||||
|   message: { | ||||
|     show: false, | ||||
|     text: undefined, | ||||
|     error: false | ||||
|   }, | ||||
|  | ||||
| 	location: { | ||||
| 		protocol: window.location.protocol, | ||||
| 		host: window.location.host, | ||||
| 	}, | ||||
|   location: { | ||||
|     protocol: window.location.protocol, | ||||
|     host: window.location.host | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const tree = new Baobab(state); | ||||
|  | ||||
| if (window) { | ||||
| 	window.tree = tree; | ||||
|   window.tree = tree; | ||||
| } | ||||
|  | ||||
| export default tree; | ||||
|   | ||||
| @@ -5,8 +5,8 @@ import { render } from "react-dom"; | ||||
| let root; | ||||
|  | ||||
| function init() { | ||||
| 	let App = require("./screens/drone").default; | ||||
| 	root = render(<App />, document.body, root); | ||||
|   let App = require("./screens/drone").default; | ||||
|   root = render(<App />, document.body, root); | ||||
| } | ||||
|  | ||||
| init(); | ||||
|   | ||||
| @@ -16,37 +16,37 @@ import { BrowserRouter, Route, Switch } from "react-router-dom"; | ||||
| import styles from "./drone.less"; | ||||
|  | ||||
| if (module.hot) { | ||||
| 	require("preact/devtools"); | ||||
|   require("preact/devtools"); | ||||
| } | ||||
|  | ||||
| class App extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<BrowserRouter> | ||||
| 				<div> | ||||
| 					<Title /> | ||||
| 					<Switch> | ||||
| 						<Route path="/" exact={true} component={RedirectRoot} /> | ||||
| 						<Route path="/login/form" exact={true} component={LoginForm} /> | ||||
| 						<Route path="/login/error" exact={true} component={LoginError} /> | ||||
| 						<Route path="/" exact={false} component={Layout} /> | ||||
| 					</Switch> | ||||
| 				</div> | ||||
| 			</BrowserRouter> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <BrowserRouter> | ||||
|         <div> | ||||
|           <Title /> | ||||
|           <Switch> | ||||
|             <Route path="/" exact={true} component={RedirectRoot} /> | ||||
|             <Route path="/login/form" exact={true} component={LoginForm} /> | ||||
|             <Route path="/login/error" exact={true} component={LoginError} /> | ||||
|             <Route path="/" exact={false} component={Layout} /> | ||||
|           </Switch> | ||||
|         </div> | ||||
|       </BrowserRouter> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| if (tree.exists(["user", "data"])) { | ||||
| 	fetchFeedOnce(tree, client); | ||||
| 	subscribeToFeedOnce(tree, client); | ||||
|   fetchFeedOnce(tree, client); | ||||
|   subscribeToFeedOnce(tree, client); | ||||
| } | ||||
|  | ||||
| client.onerror = error => { | ||||
| 	console.error(error); | ||||
| 	if (error.status === 401) { | ||||
| 		tree.unset(["user", "data"]); | ||||
| 	} | ||||
|   console.error(error); | ||||
|   if (error.status === 401) { | ||||
|     tree.unset(["user", "data"]); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export default root(tree, drone(client, App)); | ||||
|   | ||||
| @@ -8,48 +8,48 @@ import styles from "./list.less"; | ||||
| import { StarIcon } from "shared/components/icons/index"; | ||||
|  | ||||
| export const List = ({ children }) => ( | ||||
| 	<div className={styles.list}>{children}</div> | ||||
|   <div className={styles.list}>{children}</div> | ||||
| ); | ||||
|  | ||||
| export class Item extends Component { | ||||
| 	constructor(props) { | ||||
| 		super(props); | ||||
|   constructor(props) { | ||||
|     super(props); | ||||
|  | ||||
| 		this.handleFave = this.handleFave.bind(this); | ||||
| 	} | ||||
|     this.handleFave = this.handleFave.bind(this); | ||||
|   } | ||||
|  | ||||
| 	handleFave(e) { | ||||
| 		e.preventDefault(); | ||||
| 		this.props.onFave(this.props.item.full_name); | ||||
| 	} | ||||
|   handleFave(e) { | ||||
|     e.preventDefault(); | ||||
|     this.props.onFave(this.props.item.full_name); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { item, faved } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.item}> | ||||
| 				<div onClick={this.handleFave}> | ||||
| 					<StarIcon filled={faved} size={16} className={styles.star} /> | ||||
| 				</div> | ||||
| 				<div className={styles.header}> | ||||
| 					<div className={styles.title}>{item.full_name}</div> | ||||
| 					<div className={styles.icon}> | ||||
| 						{item.status ? <Status status={item.status} /> : <noscript />} | ||||
| 					</div> | ||||
| 				</div> | ||||
|   render() { | ||||
|     const { item, faved } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.item}> | ||||
|         <div onClick={this.handleFave}> | ||||
|           <StarIcon filled={faved} size={16} className={styles.star} /> | ||||
|         </div> | ||||
|         <div className={styles.header}> | ||||
|           <div className={styles.title}>{item.full_name}</div> | ||||
|           <div className={styles.icon}> | ||||
|             {item.status ? <Status status={item.status} /> : <noscript />} | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.body}> | ||||
| 					<BuildTime | ||||
| 						start={item.started_at || item.created_at} | ||||
| 						finish={item.finished_at} | ||||
| 					/> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <div className={styles.body}> | ||||
|           <BuildTime | ||||
|             start={item.started_at || item.created_at} | ||||
|             finish={item.finished_at} | ||||
|           /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.item !== nextProps.item || this.props.faved !== nextProps.faved | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.item !== nextProps.item || this.props.faved !== nextProps.faved | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -14,173 +14,169 @@ import style from "./index.less"; | ||||
| import Collapsible from "react-collapsible"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { feed: ["feed"] }; | ||||
|   return { feed: ["feed"] }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class Sidebar extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.setState({ | ||||
| 			starred: JSON.parse(localStorage.getItem("starred") || "[]"), | ||||
| 			starredOpen: (localStorage.getItem("starredOpen") || "true") === "true", | ||||
| 			reposOpen: (localStorage.getItem("reposOpen") || "true") === "true", | ||||
| 		}); | ||||
|     this.setState({ | ||||
|       starred: JSON.parse(localStorage.getItem("starred") || "[]"), | ||||
|       starredOpen: (localStorage.getItem("starredOpen") || "true") === "true", | ||||
|       reposOpen: (localStorage.getItem("reposOpen") || "true") === "true" | ||||
|     }); | ||||
|  | ||||
| 		this.handleFilter = this.handleFilter.bind(this); | ||||
| 		this.toggleStarred = this.toggleItem.bind(this, "starredOpen"); | ||||
| 		this.toggleAll = this.toggleItem.bind(this, "reposOpen"); | ||||
| 	} | ||||
|     this.handleFilter = this.handleFilter.bind(this); | ||||
|     this.toggleStarred = this.toggleItem.bind(this, "starredOpen"); | ||||
|     this.toggleAll = this.toggleItem.bind(this, "reposOpen"); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.feed !== nextProps.feed || | ||||
| 			this.state.filter !== nextState.filter || | ||||
| 			this.state.starred.length !== nextState.starred.length | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.feed !== nextProps.feed || | ||||
|       this.state.filter !== nextState.filter || | ||||
|       this.state.starred.length !== nextState.starred.length | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	handleFilter(e) { | ||||
| 		this.setState({ | ||||
| 			filter: e.target.value, | ||||
| 		}); | ||||
| 	} | ||||
|   handleFilter(e) { | ||||
|     this.setState({ | ||||
|       filter: e.target.value | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| 	toggleItem = item => { | ||||
| 		this.setState(state => { | ||||
| 			return { [item]: !state[item] }; | ||||
| 		}); | ||||
|   toggleItem = item => { | ||||
|     this.setState(state => { | ||||
|       return { [item]: !state[item] }; | ||||
|     }); | ||||
|  | ||||
| 		localStorage.setItem(item, this.state[item]); | ||||
| 	}; | ||||
|     localStorage.setItem(item, this.state[item]); | ||||
|   }; | ||||
|  | ||||
| 	renderFeed = (list, renderStarred) => { | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<List>{list.map(item => this.renderItem(item, renderStarred))}</List> | ||||
| 			</div> | ||||
| 		); | ||||
| 	}; | ||||
|   renderFeed = (list, renderStarred) => { | ||||
|     return ( | ||||
|       <div> | ||||
|         <List>{list.map(item => this.renderItem(item, renderStarred))}</List> | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
| 	renderItem = (item, renderStarred) => { | ||||
| 		const starred = this.state.starred; | ||||
| 		if (renderStarred && !starred.includes(item.full_name)) { | ||||
| 			return null; | ||||
| 		} | ||||
| 		return ( | ||||
| 			<Link to={`/${item.full_name}`} key={item.full_name}> | ||||
| 				<Item | ||||
| 					item={item} | ||||
| 					onFave={this.onFave} | ||||
| 					faved={starred.includes(item.full_name)} | ||||
| 				/> | ||||
| 			</Link> | ||||
| 		); | ||||
| 	}; | ||||
|   renderItem = (item, renderStarred) => { | ||||
|     const starred = this.state.starred; | ||||
|     if (renderStarred && !starred.includes(item.full_name)) { | ||||
|       return null; | ||||
|     } | ||||
|     return ( | ||||
|       <Link to={`/${item.full_name}`} key={item.full_name}> | ||||
|         <Item | ||||
|           item={item} | ||||
|           onFave={this.onFave} | ||||
|           faved={starred.includes(item.full_name)} | ||||
|         /> | ||||
|       </Link> | ||||
|     ); | ||||
|   }; | ||||
|  | ||||
| 	onFave = fullName => { | ||||
| 		if (!this.state.starred.includes(fullName)) { | ||||
| 			this.setState(state => { | ||||
| 				const list = state.starred.concat(fullName); | ||||
| 				return { starred: list }; | ||||
| 			}); | ||||
| 		} else { | ||||
| 			this.setState(state => { | ||||
| 				const list = state.starred.filter(v => v !== fullName); | ||||
| 				return { starred: list }; | ||||
| 			}); | ||||
| 		} | ||||
|   onFave = fullName => { | ||||
|     if (!this.state.starred.includes(fullName)) { | ||||
|       this.setState(state => { | ||||
|         const list = state.starred.concat(fullName); | ||||
|         return { starred: list }; | ||||
|       }); | ||||
|     } else { | ||||
|       this.setState(state => { | ||||
|         const list = state.starred.filter(v => v !== fullName); | ||||
|         return { starred: list }; | ||||
|       }); | ||||
|     } | ||||
|  | ||||
| 		localStorage.setItem("starred", JSON.stringify(this.state.starred)); | ||||
| 	}; | ||||
|     localStorage.setItem("starred", JSON.stringify(this.state.starred)); | ||||
|   }; | ||||
|  | ||||
| 	render() { | ||||
| 		const { feed } = this.props; | ||||
| 		const { filter } = this.state; | ||||
|   render() { | ||||
|     const { feed } = this.props; | ||||
|     const { filter } = this.state; | ||||
|  | ||||
| 		const list = feed.data ? Object.values(feed.data) : []; | ||||
|     const list = feed.data ? Object.values(feed.data) : []; | ||||
|  | ||||
| 		const filterFunc = item => { | ||||
| 			return !filter || item.full_name.indexOf(filter) !== -1; | ||||
| 		}; | ||||
|     const filterFunc = item => { | ||||
|       return !filter || item.full_name.indexOf(filter) !== -1; | ||||
|     }; | ||||
|  | ||||
| 		const filtered = list.filter(filterFunc).sort(compareFeedItem); | ||||
| 		const starredOpen = this.state.starredOpen; | ||||
| 		const reposOpen = this.state.reposOpen; | ||||
| 		return ( | ||||
| 			<div className={style.feed}> | ||||
| 				{LOGO} | ||||
| 				<Collapsible | ||||
| 					trigger="Starred" | ||||
| 					triggerTagName="div" | ||||
| 					transitionTime={200} | ||||
| 					open={starredOpen} | ||||
| 					onOpen={this.toggleStarred} | ||||
| 					onClose={this.toggleStarred} | ||||
| 					triggerOpenedClassName={style.Collapsible__trigger} | ||||
| 					triggerClassName={style.Collapsible__trigger} | ||||
| 				> | ||||
| 					{feed.loaded === false ? ( | ||||
| 						LOADING | ||||
| 					) : feed.error ? ( | ||||
| 						ERROR | ||||
| 					) : list.length === 0 ? ( | ||||
| 						EMPTY | ||||
| 					) : ( | ||||
| 						this.renderFeed(list, true) | ||||
| 					)} | ||||
| 				</Collapsible> | ||||
| 				<Collapsible | ||||
| 					trigger="Repos" | ||||
| 					triggerTagName="div" | ||||
| 					transitionTime={200} | ||||
| 					open={reposOpen} | ||||
| 					onOpen={this.toggleAll} | ||||
| 					onClose={this.toggleAll} | ||||
| 					triggerOpenedClassName={style.Collapsible__trigger} | ||||
| 					triggerClassName={style.Collapsible__trigger} | ||||
| 				> | ||||
| 					<input | ||||
| 						type="text" | ||||
| 						placeholder="Search …" | ||||
| 						onChange={this.handleFilter} | ||||
| 					/> | ||||
| 					{feed.loaded === false ? ( | ||||
| 						LOADING | ||||
| 					) : feed.error ? ( | ||||
| 						ERROR | ||||
| 					) : list.length === 0 ? ( | ||||
| 						EMPTY | ||||
| 					) : filtered.length > 0 ? ( | ||||
| 						this.renderFeed(filtered.sort(compareFeedItem), false) | ||||
| 					) : ( | ||||
| 						NO_MATCHES | ||||
| 					)} | ||||
| 				</Collapsible> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     const filtered = list.filter(filterFunc).sort(compareFeedItem); | ||||
|     const starredOpen = this.state.starredOpen; | ||||
|     const reposOpen = this.state.reposOpen; | ||||
|     return ( | ||||
|       <div className={style.feed}> | ||||
|         {LOGO} | ||||
|         <Collapsible | ||||
|           trigger="Starred" | ||||
|           triggerTagName="div" | ||||
|           transitionTime={200} | ||||
|           open={starredOpen} | ||||
|           onOpen={this.toggleStarred} | ||||
|           onClose={this.toggleStarred} | ||||
|           triggerOpenedClassName={style.Collapsible__trigger} | ||||
|           triggerClassName={style.Collapsible__trigger} | ||||
|         > | ||||
|           {feed.loaded === false | ||||
|             ? LOADING | ||||
|             : feed.error | ||||
|             ? ERROR | ||||
|             : list.length === 0 | ||||
|             ? EMPTY | ||||
|             : this.renderFeed(list, true)} | ||||
|         </Collapsible> | ||||
|         <Collapsible | ||||
|           trigger="Repos" | ||||
|           triggerTagName="div" | ||||
|           transitionTime={200} | ||||
|           open={reposOpen} | ||||
|           onOpen={this.toggleAll} | ||||
|           onClose={this.toggleAll} | ||||
|           triggerOpenedClassName={style.Collapsible__trigger} | ||||
|           triggerClassName={style.Collapsible__trigger} | ||||
|         > | ||||
|           <input | ||||
|             type="text" | ||||
|             placeholder="Search …" | ||||
|             onChange={this.handleFilter} | ||||
|           /> | ||||
|           {feed.loaded === false | ||||
|             ? LOADING | ||||
|             : feed.error | ||||
|             ? ERROR | ||||
|             : list.length === 0 | ||||
|             ? EMPTY | ||||
|             : filtered.length > 0 | ||||
|             ? this.renderFeed(filtered.sort(compareFeedItem), false) | ||||
|             : NO_MATCHES} | ||||
|         </Collapsible> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const LOGO = ( | ||||
| 	<div className={style.brand}> | ||||
| 		<DroneIcon /> | ||||
| 		<p> | ||||
| 			Woodpecker<span style="margin-left: 4px;">{window.DRONE_VERSION}</span> | ||||
| 			<br /> | ||||
| 			<span> | ||||
| 				<a | ||||
| 					href="https://woodpecker.laszlo.cloud" | ||||
| 					target="_blank" | ||||
| 					rel="noopener noreferrer" | ||||
| 				> | ||||
| 					Docs | ||||
| 				</a> | ||||
| 			</span> | ||||
| 		</p> | ||||
| 	</div> | ||||
|   <div className={style.brand}> | ||||
|     <DroneIcon /> | ||||
|     <p> | ||||
|       Woodpecker<span style="margin-left: 4px;">{window.DRONE_VERSION}</span> | ||||
|       <br /> | ||||
|       <span> | ||||
|         <a | ||||
|           href="https://woodpecker.laszlo.cloud" | ||||
|           target="_blank" | ||||
|           rel="noopener noreferrer" | ||||
|         > | ||||
|           Docs | ||||
|         </a> | ||||
|       </span> | ||||
|     </p> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| const LOADING = <div className={style.message}>Loading</div>; | ||||
| @@ -190,7 +186,7 @@ const EMPTY = <div className={style.message}>Your build feed is empty</div>; | ||||
| const NO_MATCHES = <div className={style.message}>No results found</div>; | ||||
|  | ||||
| const ERROR = ( | ||||
| 	<div className={style.message}> | ||||
| 		Oops. It looks like there was a problem loading your feed | ||||
| 	</div> | ||||
|   <div className={style.message}> | ||||
|     Oops. It looks like there was a problem loading your feed | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -30,198 +30,195 @@ import { Drawer, DOCK_RIGHT } from "shared/components/drawer/drawer"; | ||||
| import styles from "./layout.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { | ||||
| 		user: ["user"], | ||||
| 		message: ["message"], | ||||
| 		sidebar: ["sidebar"], | ||||
| 		menu: ["menu"], | ||||
| 	}; | ||||
|   return { | ||||
|     user: ["user"], | ||||
|     message: ["message"], | ||||
|     sidebar: ["sidebar"], | ||||
|     menu: ["menu"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| const mapScreenSizeToProps = screenSize => { | ||||
| 	return { | ||||
| 		isTablet: screenSize["small"], | ||||
| 		isMobile: screenSize["mobile"], | ||||
| 		isDesktop: screenSize["> small"], | ||||
| 	}; | ||||
|   return { | ||||
|     isTablet: screenSize["small"], | ||||
|     isMobile: screenSize["mobile"], | ||||
|     isDesktop: screenSize["> small"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| @connectScreenSize(mapScreenSizeToProps) | ||||
| export default class Default extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
| 		this.state = { | ||||
| 			menu: false, | ||||
| 			feed: false, | ||||
| 		}; | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|     this.state = { | ||||
|       menu: false, | ||||
|       feed: false | ||||
|     }; | ||||
|  | ||||
| 		this.openMenu = this.openMenu.bind(this); | ||||
| 		this.closeMenu = this.closeMenu.bind(this); | ||||
| 		this.closeSnackbar = this.closeSnackbar.bind(this); | ||||
| 	} | ||||
|     this.openMenu = this.openMenu.bind(this); | ||||
|     this.closeMenu = this.closeMenu.bind(this); | ||||
|     this.closeSnackbar = this.closeSnackbar.bind(this); | ||||
|   } | ||||
|  | ||||
| 	componentWillReceiveProps(nextProps) { | ||||
| 		if (nextProps.location !== this.props.location) { | ||||
| 			this.closeMenu(true); | ||||
| 		} | ||||
| 	} | ||||
|   componentWillReceiveProps(nextProps) { | ||||
|     if (nextProps.location !== this.props.location) { | ||||
|       this.closeMenu(true); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	openMenu() { | ||||
| 		this.props.dispatch(tree => { | ||||
| 			tree.set(["menu"], true); | ||||
| 		}); | ||||
| 	} | ||||
|   openMenu() { | ||||
|     this.props.dispatch(tree => { | ||||
|       tree.set(["menu"], true); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| 	closeMenu() { | ||||
| 		this.props.dispatch(tree => { | ||||
| 			tree.set(["menu"], false); | ||||
| 		}); | ||||
| 	} | ||||
|   closeMenu() { | ||||
|     this.props.dispatch(tree => { | ||||
|       tree.set(["menu"], false); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { user, message, menu } = this.props; | ||||
|   render() { | ||||
|     const { user, message, menu } = this.props; | ||||
|  | ||||
| 		const classes = classnames(!user || !user.data ? styles.guest : null); | ||||
| 		return ( | ||||
| 			<div className={classes}> | ||||
| 				<div className={styles.left}> | ||||
| 					<Switch> | ||||
| 						<Route path={"/"} component={Feed} /> | ||||
| 					</Switch> | ||||
| 				</div> | ||||
| 				<div className={styles.center}> | ||||
| 					{!user || !user.data ? ( | ||||
| 						<a | ||||
| 							href={"/login?url=" + window.location.href} | ||||
| 							target="_self" | ||||
| 							className={styles.login} | ||||
| 						> | ||||
| 							Click to Login | ||||
| 						</a> | ||||
| 					) : ( | ||||
| 						<noscript /> | ||||
| 					)} | ||||
| 					<div className={styles.title}> | ||||
| 						<Switch> | ||||
| 							<Route path="/account/repos" component={UserRepoTitle} /> | ||||
| 							<Route | ||||
| 								path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
| 								exact={true} | ||||
| 								component={BuildLogsTitle} | ||||
| 							/> | ||||
| 							<Route | ||||
| 								path="/:owner/:repo/:build(\d*)" | ||||
| 								component={BuildLogsTitle} | ||||
| 							/> | ||||
| 							<Route path="/:owner/:repo" component={RepoHeader} /> | ||||
| 						</Switch> | ||||
| 						{user && user.data ? ( | ||||
| 							<div className={styles.avatar}> | ||||
| 								<img src={user.data.avatar_url} /> | ||||
| 							</div> | ||||
| 						) : ( | ||||
| 							undefined | ||||
| 						)} | ||||
| 						{user && user.data ? ( | ||||
| 							<button onClick={this.openMenu}> | ||||
| 								<MenuIcon /> | ||||
| 							</button> | ||||
| 						) : ( | ||||
| 							<noscript /> | ||||
| 						)} | ||||
| 					</div> | ||||
|     const classes = classnames(!user || !user.data ? styles.guest : null); | ||||
|     return ( | ||||
|       <div className={classes}> | ||||
|         <div className={styles.left}> | ||||
|           <Switch> | ||||
|             <Route path={"/"} component={Feed} /> | ||||
|           </Switch> | ||||
|         </div> | ||||
|         <div className={styles.center}> | ||||
|           {!user || !user.data ? ( | ||||
|             <a | ||||
|               href={"/login?url=" + window.location.href} | ||||
|               target="_self" | ||||
|               className={styles.login} | ||||
|             > | ||||
|               Click to Login | ||||
|             </a> | ||||
|           ) : ( | ||||
|             <noscript /> | ||||
|           )} | ||||
|           <div className={styles.title}> | ||||
|             <Switch> | ||||
|               <Route path="/account/repos" component={UserRepoTitle} /> | ||||
|               <Route | ||||
|                 path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
|                 exact={true} | ||||
|                 component={BuildLogsTitle} | ||||
|               /> | ||||
|               <Route | ||||
|                 path="/:owner/:repo/:build(\d*)" | ||||
|                 component={BuildLogsTitle} | ||||
|               /> | ||||
|               <Route path="/:owner/:repo" component={RepoHeader} /> | ||||
|             </Switch> | ||||
|             {user && user.data ? ( | ||||
|               <div className={styles.avatar}> | ||||
|                 <img src={user.data.avatar_url} /> | ||||
|               </div> | ||||
|             ) : ( | ||||
|               undefined | ||||
|             )} | ||||
|             {user && user.data ? ( | ||||
|               <button onClick={this.openMenu}> | ||||
|                 <MenuIcon /> | ||||
|               </button> | ||||
|             ) : ( | ||||
|               <noscript /> | ||||
|             )} | ||||
|           </div> | ||||
|  | ||||
| 					<div className={styles.menu}> | ||||
| 						<Switch> | ||||
| 							<Route | ||||
| 								path="/account/repos" | ||||
| 								exact={true} | ||||
| 								component={UserReposMenu} | ||||
| 							/> | ||||
| 							<Route | ||||
| 								path="/account/" | ||||
| 								exact={false} | ||||
| 								component={undefined} | ||||
| 							/>BuildMenu | ||||
| 							<Route | ||||
| 								path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
| 								exact={true} | ||||
| 								component={BuildMenu} | ||||
| 							/> | ||||
| 							<Route | ||||
| 								path="/:owner/:repo/:build(\d*)" | ||||
| 								exact={true} | ||||
| 								component={BuildMenu} | ||||
| 							/> | ||||
| 							<Route path="/:owner/:repo" exact={false} component={RepoMenu} /> | ||||
| 						</Switch> | ||||
| 					</div> | ||||
|           <div className={styles.menu}> | ||||
|             <Switch> | ||||
|               <Route | ||||
|                 path="/account/repos" | ||||
|                 exact={true} | ||||
|                 component={UserReposMenu} | ||||
|               /> | ||||
|               <Route path="/account/" exact={false} component={undefined} /> | ||||
|               BuildMenu | ||||
|               <Route | ||||
|                 path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
|                 exact={true} | ||||
|                 component={BuildMenu} | ||||
|               /> | ||||
|               <Route | ||||
|                 path="/:owner/:repo/:build(\d*)" | ||||
|                 exact={true} | ||||
|                 component={BuildMenu} | ||||
|               /> | ||||
|               <Route path="/:owner/:repo" exact={false} component={RepoMenu} /> | ||||
|             </Switch> | ||||
|           </div> | ||||
|  | ||||
| 					<Switch> | ||||
| 						<Route path="/account/token" exact={true} component={UserTokens} /> | ||||
| 						<Route path="/account/repos" exact={true} component={UserRepos} /> | ||||
| 						<Route | ||||
| 							path="/:owner/:repo/settings/secrets" | ||||
| 							exact={true} | ||||
| 							component={RepoSecrets} | ||||
| 						/> | ||||
| 						<Route | ||||
| 							path="/:owner/:repo/settings/registry" | ||||
| 							exact={true} | ||||
| 							component={RepoRegistry} | ||||
| 						/> | ||||
| 						<Route | ||||
| 							path="/:owner/:repo/settings" | ||||
| 							exact={true} | ||||
| 							component={RepoSettings} | ||||
| 						/> | ||||
| 						<Route | ||||
| 							path="/:owner/:repo/:build(\d*)" | ||||
| 							exact={true} | ||||
| 							component={BuildLogs} | ||||
| 						/> | ||||
| 						<Route | ||||
| 							path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
| 							exact={true} | ||||
| 							component={BuildLogs} | ||||
| 						/> | ||||
| 						<Route path="/:owner/:repo" exact={true} component={RepoBuilds} /> | ||||
| 						<Route path="/" exact={true} component={RedirectRoot} /> | ||||
| 					</Switch> | ||||
| 				</div> | ||||
|           <Switch> | ||||
|             <Route path="/account/token" exact={true} component={UserTokens} /> | ||||
|             <Route path="/account/repos" exact={true} component={UserRepos} /> | ||||
|             <Route | ||||
|               path="/:owner/:repo/settings/secrets" | ||||
|               exact={true} | ||||
|               component={RepoSecrets} | ||||
|             /> | ||||
|             <Route | ||||
|               path="/:owner/:repo/settings/registry" | ||||
|               exact={true} | ||||
|               component={RepoRegistry} | ||||
|             /> | ||||
|             <Route | ||||
|               path="/:owner/:repo/settings" | ||||
|               exact={true} | ||||
|               component={RepoSettings} | ||||
|             /> | ||||
|             <Route | ||||
|               path="/:owner/:repo/:build(\d*)" | ||||
|               exact={true} | ||||
|               component={BuildLogs} | ||||
|             /> | ||||
|             <Route | ||||
|               path="/:owner/:repo/:build(\d*)/:proc(\d*)" | ||||
|               exact={true} | ||||
|               component={BuildLogs} | ||||
|             /> | ||||
|             <Route path="/:owner/:repo" exact={true} component={RepoBuilds} /> | ||||
|             <Route path="/" exact={true} component={RedirectRoot} /> | ||||
|           </Switch> | ||||
|         </div> | ||||
|  | ||||
| 				<Snackbar message={message.text} onClose={this.closeSnackbar} /> | ||||
|         <Snackbar message={message.text} onClose={this.closeSnackbar} /> | ||||
|  | ||||
| 				<Drawer onClick={this.closeMenu} position={DOCK_RIGHT} open={menu}> | ||||
| 					<section> | ||||
| 						<ul> | ||||
| 							<li> | ||||
| 								<Link to="/account/repos">Repositories</Link> | ||||
| 							</li> | ||||
| 							<li> | ||||
| 								<Link to="/account/token">Token</Link> | ||||
| 							</li> | ||||
| 						</ul> | ||||
| 					</section> | ||||
| 					<section> | ||||
| 						<ul> | ||||
| 							<li> | ||||
| 								<a href="/logout" target="_self"> | ||||
| 									Logout | ||||
| 								</a> | ||||
| 							</li> | ||||
| 						</ul> | ||||
| 					</section> | ||||
| 				</Drawer> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <Drawer onClick={this.closeMenu} position={DOCK_RIGHT} open={menu}> | ||||
|           <section> | ||||
|             <ul> | ||||
|               <li> | ||||
|                 <Link to="/account/repos">Repositories</Link> | ||||
|               </li> | ||||
|               <li> | ||||
|                 <Link to="/account/token">Token</Link> | ||||
|               </li> | ||||
|             </ul> | ||||
|           </section> | ||||
|           <section> | ||||
|             <ul> | ||||
|               <li> | ||||
|                 <a href="/logout" target="_self"> | ||||
|                   Logout | ||||
|                 </a> | ||||
|               </li> | ||||
|             </ul> | ||||
|           </section> | ||||
|         </Drawer> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	closeSnackbar() { | ||||
| 		this.props.dispatch(tree => { | ||||
| 			tree.unset(["message", "text"]); | ||||
| 		}); | ||||
| 	} | ||||
|   closeSnackbar() { | ||||
|     this.props.dispatch(tree => { | ||||
|       tree.unset(["message", "text"]); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,28 +7,28 @@ import styles from "./index.less"; | ||||
| const DEFAULT_ERROR = "The system failed to process your Login request."; | ||||
|  | ||||
| class Error extends Component { | ||||
| 	render() { | ||||
| 		const parsed = queryString.parse(window.location.search); | ||||
| 		let error = DEFAULT_ERROR; | ||||
|   render() { | ||||
|     const parsed = queryString.parse(window.location.search); | ||||
|     let error = DEFAULT_ERROR; | ||||
|  | ||||
| 		switch (parsed.code || parsed.error) { | ||||
| 			case "oauth_error": | ||||
| 				break; | ||||
| 			case "access_denied": | ||||
| 				break; | ||||
| 		} | ||||
|     switch (parsed.code || parsed.error) { | ||||
|       case "oauth_error": | ||||
|         break; | ||||
|       case "access_denied": | ||||
|         break; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<div className={styles.alert}> | ||||
| 					<div> | ||||
| 						<Icon /> | ||||
| 					</div> | ||||
| 					<div>{error}</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <div className={styles.alert}> | ||||
|           <div> | ||||
|             <Icon /> | ||||
|           </div> | ||||
|           <div>{error}</div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export default Error; | ||||
|   | ||||
| @@ -3,19 +3,19 @@ import React from "react"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const LoginForm = props => ( | ||||
| 	<div className={styles.login}> | ||||
| 		<form method="post" action="/authorize"> | ||||
| 			<p>Login with your version control system username and password.</p> | ||||
| 			<input | ||||
| 				placeholder="Username" | ||||
| 				name="username" | ||||
| 				type="text" | ||||
| 				spellCheck="false" | ||||
| 			/> | ||||
| 			<input placeholder="Password" name="password" type="password" /> | ||||
| 			<input value="Login" type="submit" /> | ||||
| 		</form> | ||||
| 	</div> | ||||
|   <div className={styles.login}> | ||||
|     <form method="post" action="/authorize"> | ||||
|       <p>Login with your version control system username and password.</p> | ||||
|       <input | ||||
|         placeholder="Username" | ||||
|         name="username" | ||||
|         type="text" | ||||
|         spellCheck="false" | ||||
|       /> | ||||
|       <input placeholder="Password" name="password" type="password" /> | ||||
|       <input value="Login" type="submit" /> | ||||
|     </form> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| export default LoginForm; | ||||
|   | ||||
| @@ -4,38 +4,38 @@ import { branch } from "baobab-react/higher-order"; | ||||
| import { Message } from "shared/components/sync"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { | ||||
| 		feed: ["feed"], | ||||
| 		user: ["user", "data"], | ||||
| 		syncing: ["user", "syncing"], | ||||
| 	}; | ||||
|   return { | ||||
|     feed: ["feed"], | ||||
|     user: ["user", "data"], | ||||
|     syncing: ["user", "syncing"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @branch(binding) | ||||
| export default class RedirectRoot extends Component { | ||||
| 	componentWillReceiveProps(nextProps) { | ||||
| 		const { user } = nextProps; | ||||
| 		if (!user && window) { | ||||
| 			window.location.href = "/login?url=" + window.location.href; | ||||
| 		} | ||||
| 	} | ||||
|   componentWillReceiveProps(nextProps) { | ||||
|     const { user } = nextProps; | ||||
|     if (!user && window) { | ||||
|       window.location.href = "/login?url=" + window.location.href; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { user, syncing } = this.props; | ||||
| 		const { latest, loaded } = this.props.feed; | ||||
|   render() { | ||||
|     const { user, syncing } = this.props; | ||||
|     const { latest, loaded } = this.props.feed; | ||||
|  | ||||
| 		return !loaded && syncing ? ( | ||||
| 			<Message /> | ||||
| 		) : !loaded ? ( | ||||
| 			undefined | ||||
| 		) : !user ? ( | ||||
| 			undefined | ||||
| 		) : !latest ? ( | ||||
| 			<Redirect to="/account/repos" /> | ||||
| 		) : !latest.number ? ( | ||||
| 			<Redirect to={`/${latest.full_name}`} /> | ||||
| 		) : ( | ||||
| 			<Redirect to={`/${latest.full_name}/${latest.number}`} /> | ||||
| 		); | ||||
| 	} | ||||
|     return !loaded && syncing ? ( | ||||
|       <Message /> | ||||
|     ) : !loaded ? ( | ||||
|       undefined | ||||
|     ) : !user ? ( | ||||
|       undefined | ||||
|     ) : !latest ? ( | ||||
|       <Redirect to="/account/repos" /> | ||||
|     ) : !latest.number ? ( | ||||
|       <Redirect to={`/${latest.full_name}`} /> | ||||
|     ) : ( | ||||
|       <Redirect to={`/${latest.full_name}/${latest.number}`} /> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,9 +2,9 @@ import React from "react"; | ||||
| import style from "./approval.less"; | ||||
|  | ||||
| export const Approval = ({ onapprove, ondecline }) => ( | ||||
| 	<div className={style.root}> | ||||
| 		<p>Pipeline execution is blocked pending administrator approval</p> | ||||
| 		<button onClick={onapprove}>Approve</button> | ||||
| 		<button onClick={ondecline}>Decline</button> | ||||
| 	</div> | ||||
|   <div className={style.root}> | ||||
|     <p>Pipeline execution is blocked pending administrator approval</p> | ||||
|     <button onClick={onapprove}>Approve</button> | ||||
|     <button onClick={ondecline}>Decline</button> | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -7,36 +7,36 @@ import { StatusLabel } from "shared/components/status"; | ||||
| import styles from "./details.less"; | ||||
|  | ||||
| export class Details extends Component { | ||||
| 	render() { | ||||
| 		const { build } = this.props; | ||||
|   render() { | ||||
|     const { build } = this.props; | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.info}> | ||||
| 				<StatusLabel status={build.status} /> | ||||
|     return ( | ||||
|       <div className={styles.info}> | ||||
|         <StatusLabel status={build.status} /> | ||||
|  | ||||
| 				<section className={styles.message} style={{ whiteSpace: "pre-line" }}> | ||||
| 					{build.message} | ||||
| 				</section> | ||||
|         <section className={styles.message} style={{ whiteSpace: "pre-line" }}> | ||||
|           {build.message} | ||||
|         </section> | ||||
|  | ||||
| 				<section> | ||||
| 					<BuildTime | ||||
| 						start={build.started_at || build.created_at} | ||||
| 						finish={build.finished_at} | ||||
| 					/> | ||||
| 				</section> | ||||
|         <section> | ||||
|           <BuildTime | ||||
|             start={build.started_at || build.created_at} | ||||
|             finish={build.finished_at} | ||||
|           /> | ||||
|         </section> | ||||
|  | ||||
| 				<section> | ||||
| 					<BuildMeta | ||||
| 						link={build.link_url} | ||||
| 						event={build.event} | ||||
| 						commit={build.commit} | ||||
| 						branch={build.branch} | ||||
| 						target={build.deploy_to} | ||||
| 						refspec={build.refspec} | ||||
| 						refs={build.ref} | ||||
| 					/> | ||||
| 				</section> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <section> | ||||
|           <BuildMeta | ||||
|             link={build.link_url} | ||||
|             event={build.event} | ||||
|             commit={build.commit} | ||||
|             branch={build.branch} | ||||
|             target={build.deploy_to} | ||||
|             refspec={build.refspec} | ||||
|             refs={build.ref} | ||||
|           /> | ||||
|         </section> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,48 +1,46 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export class Elapsed extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props); | ||||
|   constructor(props, context) { | ||||
|     super(props); | ||||
|  | ||||
| 		this.state = { | ||||
| 			elapsed: 0, | ||||
| 		}; | ||||
|     this.state = { | ||||
|       elapsed: 0 | ||||
|     }; | ||||
|  | ||||
| 		this.tick = this.tick.bind(this); | ||||
| 	} | ||||
|     this.tick = this.tick.bind(this); | ||||
|   } | ||||
|  | ||||
| 	componentDidMount() { | ||||
| 		this.timer = setInterval(this.tick, 1000); | ||||
| 	} | ||||
|   componentDidMount() { | ||||
|     this.timer = setInterval(this.tick, 1000); | ||||
|   } | ||||
|  | ||||
| 	componentWillUnmount() { | ||||
| 		clearInterval(this.timer); | ||||
| 	} | ||||
|   componentWillUnmount() { | ||||
|     clearInterval(this.timer); | ||||
|   } | ||||
|  | ||||
| 	tick() { | ||||
| 		const { start } = this.props; | ||||
| 		const stop = ~~(Date.now() / 1000); | ||||
| 		this.setState({ | ||||
| 			elapsed: stop - start, | ||||
| 		}); | ||||
| 	} | ||||
|   tick() { | ||||
|     const { start } = this.props; | ||||
|     const stop = ~~(Date.now() / 1000); | ||||
|     this.setState({ | ||||
|       elapsed: stop - start | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { elapsed } = this.state; | ||||
| 		const date = new Date(null); | ||||
| 		date.setSeconds(elapsed); | ||||
| 		return ( | ||||
| 			<time> | ||||
| 				{!elapsed ? ( | ||||
| 					undefined | ||||
| 				) : elapsed > 3600 ? ( | ||||
| 					date.toISOString().substr(11, 8) | ||||
| 				) : ( | ||||
| 					date.toISOString().substr(14, 5) | ||||
| 				)} | ||||
| 			</time> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { elapsed } = this.state; | ||||
|     const date = new Date(null); | ||||
|     date.setSeconds(elapsed); | ||||
|     return ( | ||||
|       <time> | ||||
|         {!elapsed | ||||
|           ? undefined | ||||
|           : elapsed > 3600 | ||||
|           ? date.toISOString().substr(11, 8) | ||||
|           : date.toISOString().substr(14, 5)} | ||||
|       </time> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -53,11 +51,11 @@ export class Elapsed extends Component { | ||||
|  * @return {string} | ||||
|  */ | ||||
| export const formatTime = (end, start) => { | ||||
| 	const diff = end - start; | ||||
| 	const date = new Date(null); | ||||
| 	date.setSeconds(diff); | ||||
|   const diff = end - start; | ||||
|   const date = new Date(null); | ||||
|   date.setSeconds(diff); | ||||
|  | ||||
| 	return diff > 3600 | ||||
| 		? date.toISOString().substr(11, 8) | ||||
| 		: date.toISOString().substr(14, 5); | ||||
|   return diff > 3600 | ||||
|     ? date.toISOString().substr(11, 8) | ||||
|     : date.toISOString().substr(14, 5); | ||||
| }; | ||||
|   | ||||
| @@ -8,69 +8,69 @@ import { default as Status, StatusText } from "shared/components/status"; | ||||
| import styles from "./procs.less"; | ||||
|  | ||||
| const renderEnviron = data => { | ||||
| 	return ( | ||||
| 		<div> | ||||
| 			{data[0]}={data[1]} | ||||
| 		</div> | ||||
| 	); | ||||
|   return ( | ||||
|     <div> | ||||
|       {data[0]}={data[1]} | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| const ProcListHolder = ({ vars, renderName, children }) => ( | ||||
| 	<div className={styles.list}> | ||||
| 		{renderName && vars.name !== "drone" ? ( | ||||
| 			<div> | ||||
| 				<StatusText status={vars.state} text={vars.name} /> | ||||
| 			</div> | ||||
| 		) : null} | ||||
| 		{vars.environ ? ( | ||||
| 			<div> | ||||
| 				<StatusText | ||||
| 					status={vars.state} | ||||
| 					text={Object.entries(vars.environ).map(renderEnviron)} | ||||
| 				/> | ||||
| 			</div> | ||||
| 		) : null} | ||||
| 		{children} | ||||
| 	</div> | ||||
|   <div className={styles.list}> | ||||
|     {renderName && vars.name !== "drone" ? ( | ||||
|       <div> | ||||
|         <StatusText status={vars.state} text={vars.name} /> | ||||
|       </div> | ||||
|     ) : null} | ||||
|     {vars.environ ? ( | ||||
|       <div> | ||||
|         <StatusText | ||||
|           status={vars.state} | ||||
|           text={Object.entries(vars.environ).map(renderEnviron)} | ||||
|         /> | ||||
|       </div> | ||||
|     ) : null} | ||||
|     {children} | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| export class ProcList extends Component { | ||||
| 	render() { | ||||
| 		const { repo, build, rootProc, selectedProc, renderName } = this.props; | ||||
| 		return ( | ||||
| 			<ProcListHolder vars={rootProc} renderName={renderName}> | ||||
| 				{this.props.rootProc.children.map(function(child) { | ||||
| 					return ( | ||||
| 						<Link | ||||
| 							to={`/${repo.full_name}/${build.number}/${child.pid}`} | ||||
| 							key={`${repo.full_name}-${build.number}-${child.pid}`} | ||||
| 						> | ||||
| 							<ProcListItem | ||||
| 								key={child.pid} | ||||
| 								name={child.name} | ||||
| 								start={child.start_time} | ||||
| 								finish={child.end_time} | ||||
| 								state={child.state} | ||||
| 								selected={child.pid === selectedProc.pid} | ||||
| 							/> | ||||
| 						</Link> | ||||
| 					); | ||||
| 				})} | ||||
| 			</ProcListHolder> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { repo, build, rootProc, selectedProc, renderName } = this.props; | ||||
|     return ( | ||||
|       <ProcListHolder vars={rootProc} renderName={renderName}> | ||||
|         {this.props.rootProc.children.map(function(child) { | ||||
|           return ( | ||||
|             <Link | ||||
|               to={`/${repo.full_name}/${build.number}/${child.pid}`} | ||||
|               key={`${repo.full_name}-${build.number}-${child.pid}`} | ||||
|             > | ||||
|               <ProcListItem | ||||
|                 key={child.pid} | ||||
|                 name={child.name} | ||||
|                 start={child.start_time} | ||||
|                 finish={child.end_time} | ||||
|                 state={child.state} | ||||
|                 selected={child.pid === selectedProc.pid} | ||||
|               /> | ||||
|             </Link> | ||||
|           ); | ||||
|         })} | ||||
|       </ProcListHolder> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const ProcListItem = ({ name, start, finish, state, selected }) => ( | ||||
| 	<div className={classnames(styles.item, selected ? styles.selected : null)}> | ||||
| 		<h3>{name}</h3> | ||||
| 		{finish ? ( | ||||
| 			<time>{formatTime(finish, start)}</time> | ||||
| 		) : ( | ||||
| 			<Elapsed start={start} /> | ||||
| 		)} | ||||
| 		<div> | ||||
| 			<Status status={state} /> | ||||
| 		</div> | ||||
| 	</div> | ||||
|   <div className={classnames(styles.item, selected ? styles.selected : null)}> | ||||
|     <h3>{name}</h3> | ||||
|     {finish ? ( | ||||
|       <time>{formatTime(finish, start)}</time> | ||||
|     ) : ( | ||||
|       <Elapsed start={start} /> | ||||
|     )} | ||||
|     <div> | ||||
|       <Status status={state} /> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -3,9 +3,9 @@ import { Link } from "react-router-dom"; | ||||
|  | ||||
| import { fetchBuild, approveBuild, declineBuild } from "shared/utils/build"; | ||||
| import { | ||||
| 	STATUS_BLOCKED, | ||||
| 	STATUS_DECLINED, | ||||
| 	STATUS_ERROR, | ||||
|   STATUS_BLOCKED, | ||||
|   STATUS_DECLINED, | ||||
|   STATUS_ERROR | ||||
| } from "shared/constants/status"; | ||||
|  | ||||
| import { findChildProcess } from "shared/utils/proc"; | ||||
| @@ -23,235 +23,233 @@ import Output from "./logs"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo, build } = props.match.params; | ||||
| 	const slug = `${owner}/${repo}`; | ||||
| 	const number = parseInt(build); | ||||
|   const { owner, repo, build } = props.match.params; | ||||
|   const slug = `${owner}/${repo}`; | ||||
|   const number = parseInt(build); | ||||
|  | ||||
| 	return { | ||||
| 		repo: ["repos", "data", slug], | ||||
| 		build: ["builds", "data", slug, number], | ||||
| 	}; | ||||
|   return { | ||||
|     repo: ["repos", "data", slug], | ||||
|     build: ["builds", "data", slug, number] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class BuildLogs extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleApprove = this.handleApprove.bind(this); | ||||
| 		this.handleDecline = this.handleDecline.bind(this); | ||||
| 	} | ||||
|     this.handleApprove = this.handleApprove.bind(this); | ||||
|     this.handleDecline = this.handleDecline.bind(this); | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		this.synchronize(this.props); | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     this.synchronize(this.props); | ||||
|   } | ||||
|  | ||||
| 	handleApprove() { | ||||
| 		const { repo, build, drone } = this.props; | ||||
| 		this.props.dispatch( | ||||
| 			approveBuild, | ||||
| 			drone, | ||||
| 			repo.owner, | ||||
| 			repo.name, | ||||
| 			build.number, | ||||
| 		); | ||||
| 	} | ||||
|   handleApprove() { | ||||
|     const { repo, build, drone } = this.props; | ||||
|     this.props.dispatch( | ||||
|       approveBuild, | ||||
|       drone, | ||||
|       repo.owner, | ||||
|       repo.name, | ||||
|       build.number | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	handleDecline() { | ||||
| 		const { repo, build, drone } = this.props; | ||||
| 		this.props.dispatch( | ||||
| 			declineBuild, | ||||
| 			drone, | ||||
| 			repo.owner, | ||||
| 			repo.name, | ||||
| 			build.number, | ||||
| 		); | ||||
| 	} | ||||
|   handleDecline() { | ||||
|     const { repo, build, drone } = this.props; | ||||
|     this.props.dispatch( | ||||
|       declineBuild, | ||||
|       drone, | ||||
|       repo.owner, | ||||
|       repo.name, | ||||
|       build.number | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	componentWillUpdate(nextProps) { | ||||
| 		if (this.props.match.url !== nextProps.match.url) { | ||||
| 			this.synchronize(nextProps); | ||||
| 		} | ||||
| 	} | ||||
|   componentWillUpdate(nextProps) { | ||||
|     if (this.props.match.url !== nextProps.match.url) { | ||||
|       this.synchronize(nextProps); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	synchronize(props) { | ||||
| 		if (!props.repo) { | ||||
| 			this.props.dispatch( | ||||
| 				fetchRepository, | ||||
| 				props.drone, | ||||
| 				props.match.params.owner, | ||||
| 				props.match.params.repo, | ||||
| 			); | ||||
| 		} | ||||
| 		if (!props.build || !props.build.procs) { | ||||
| 			this.props.dispatch( | ||||
| 				fetchBuild, | ||||
| 				props.drone, | ||||
| 				props.match.params.owner, | ||||
| 				props.match.params.repo, | ||||
| 				props.match.params.build, | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
|   synchronize(props) { | ||||
|     if (!props.repo) { | ||||
|       this.props.dispatch( | ||||
|         fetchRepository, | ||||
|         props.drone, | ||||
|         props.match.params.owner, | ||||
|         props.match.params.repo | ||||
|       ); | ||||
|     } | ||||
|     if (!props.build || !props.build.procs) { | ||||
|       this.props.dispatch( | ||||
|         fetchBuild, | ||||
|         props.drone, | ||||
|         props.match.params.owner, | ||||
|         props.match.params.repo, | ||||
|         props.match.params.build | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return this.props !== nextProps; | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return this.props !== nextProps; | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { repo, build } = this.props; | ||||
|   render() { | ||||
|     const { repo, build } = this.props; | ||||
|  | ||||
| 		if (!build || !repo) { | ||||
| 			return this.renderLoading(); | ||||
| 		} | ||||
|     if (!build || !repo) { | ||||
|       return this.renderLoading(); | ||||
|     } | ||||
|  | ||||
| 		if (build.status === STATUS_DECLINED || build.status === STATUS_ERROR) { | ||||
| 			return this.renderError(); | ||||
| 		} | ||||
|     if (build.status === STATUS_DECLINED || build.status === STATUS_ERROR) { | ||||
|       return this.renderError(); | ||||
|     } | ||||
|  | ||||
| 		if (build.status === STATUS_BLOCKED) { | ||||
| 			return this.renderBlocked(); | ||||
| 		} | ||||
|     if (build.status === STATUS_BLOCKED) { | ||||
|       return this.renderBlocked(); | ||||
|     } | ||||
|  | ||||
| 		if (!build.procs) { | ||||
| 			return this.renderLoading(); | ||||
| 		} | ||||
|     if (!build.procs) { | ||||
|       return this.renderLoading(); | ||||
|     } | ||||
|  | ||||
| 		return this.renderSimple(); | ||||
| 	} | ||||
|     return this.renderSimple(); | ||||
|   } | ||||
|  | ||||
| 	renderLoading() { | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.columns}> | ||||
| 					<div className={styles.right}>Loading ...</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   renderLoading() { | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.columns}> | ||||
|           <div className={styles.right}>Loading ...</div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	renderBlocked() { | ||||
| 		const { build } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.columns}> | ||||
| 					<div className={styles.right}> | ||||
| 						<Details build={build} /> | ||||
| 					</div> | ||||
| 					<div className={styles.left}> | ||||
| 						<Approval | ||||
| 							onapprove={this.handleApprove} | ||||
| 							ondecline={this.handleDecline} | ||||
| 						/> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   renderBlocked() { | ||||
|     const { build } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.columns}> | ||||
|           <div className={styles.right}> | ||||
|             <Details build={build} /> | ||||
|           </div> | ||||
|           <div className={styles.left}> | ||||
|             <Approval | ||||
|               onapprove={this.handleApprove} | ||||
|               ondecline={this.handleDecline} | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	renderError() { | ||||
| 		const { build } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.columns}> | ||||
| 					<div className={styles.right}> | ||||
| 						<Details build={build} /> | ||||
| 					</div> | ||||
| 					<div className={styles.left}> | ||||
| 						<div className={styles.logerror}> | ||||
| 							{build.status === STATUS_ERROR ? ( | ||||
| 								build.error | ||||
| 							) : ( | ||||
| 								"Pipeline execution was declined" | ||||
| 							)} | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   renderError() { | ||||
|     const { build } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.columns}> | ||||
|           <div className={styles.right}> | ||||
|             <Details build={build} /> | ||||
|           </div> | ||||
|           <div className={styles.left}> | ||||
|             <div className={styles.logerror}> | ||||
|               {build.status === STATUS_ERROR | ||||
|                 ? build.error | ||||
|                 : "Pipeline execution was declined"} | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	highlightedLine() { | ||||
| 		if (location.hash.startsWith("#L")) { | ||||
| 			return parseInt(location.hash.substr(2)) - 1; | ||||
| 		} | ||||
|   highlightedLine() { | ||||
|     if (location.hash.startsWith("#L")) { | ||||
|       return parseInt(location.hash.substr(2)) - 1; | ||||
|     } | ||||
|  | ||||
| 		return undefined; | ||||
| 	} | ||||
|     return undefined; | ||||
|   } | ||||
|  | ||||
| 	renderSimple() { | ||||
| 		// if (nextProps.build.procs[0].children !== undefined){ | ||||
| 		// 	return null; | ||||
| 		// } | ||||
|   renderSimple() { | ||||
|     // if (nextProps.build.procs[0].children !== undefined){ | ||||
|     // 	return null; | ||||
|     // } | ||||
|  | ||||
| 		const { repo, build, match } = this.props; | ||||
| 		const selectedProc = match.params.proc | ||||
| 			? findChildProcess(build.procs, match.params.proc) | ||||
| 			: build.procs[0].children[0]; | ||||
| 		const selectedProcParent = findChildProcess(build.procs, selectedProc.ppid); | ||||
| 		const highlighted = this.highlightedLine(); | ||||
|     const { repo, build, match } = this.props; | ||||
|     const selectedProc = match.params.proc | ||||
|       ? findChildProcess(build.procs, match.params.proc) | ||||
|       : build.procs[0].children[0]; | ||||
|     const selectedProcParent = findChildProcess(build.procs, selectedProc.ppid); | ||||
|     const highlighted = this.highlightedLine(); | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.columns}> | ||||
| 					<div className={styles.right}> | ||||
| 						<Details build={build} /> | ||||
| 						<section className={styles.sticky}> | ||||
| 							{build.procs.map(function(rootProc) { | ||||
| 								return ( | ||||
| 									<div style="padding-bottom: 50px;" key={rootProc.pid}> | ||||
| 										<ProcList | ||||
| 											key={rootProc.pid} | ||||
| 											repo={repo} | ||||
| 											build={build} | ||||
| 											rootProc={rootProc} | ||||
| 											selectedProc={selectedProc} | ||||
| 											renderName={build.procs.length > 1} | ||||
| 										/> | ||||
| 									</div> | ||||
| 								); | ||||
| 							})} | ||||
| 						</section> | ||||
| 					</div> | ||||
| 					<div className={styles.left}> | ||||
| 						{selectedProc && selectedProc.error ? ( | ||||
| 							<div className={styles.logerror}>{selectedProc.error}</div> | ||||
| 						) : null} | ||||
| 						{selectedProcParent && selectedProcParent.error ? ( | ||||
| 							<div className={styles.logerror}>{selectedProcParent.error}</div> | ||||
| 						) : null} | ||||
| 						<Output | ||||
| 							match={this.props.match} | ||||
| 							build={this.props.build} | ||||
| 							proc={selectedProc} | ||||
| 							highlighted={highlighted} | ||||
| 						/> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.columns}> | ||||
|           <div className={styles.right}> | ||||
|             <Details build={build} /> | ||||
|             <section className={styles.sticky}> | ||||
|               {build.procs.map(function(rootProc) { | ||||
|                 return ( | ||||
|                   <div style="padding-bottom: 50px;" key={rootProc.pid}> | ||||
|                     <ProcList | ||||
|                       key={rootProc.pid} | ||||
|                       repo={repo} | ||||
|                       build={build} | ||||
|                       rootProc={rootProc} | ||||
|                       selectedProc={selectedProc} | ||||
|                       renderName={build.procs.length > 1} | ||||
|                     /> | ||||
|                   </div> | ||||
|                 ); | ||||
|               })} | ||||
|             </section> | ||||
|           </div> | ||||
|           <div className={styles.left}> | ||||
|             {selectedProc && selectedProc.error ? ( | ||||
|               <div className={styles.logerror}>{selectedProc.error}</div> | ||||
|             ) : null} | ||||
|             {selectedProcParent && selectedProcParent.error ? ( | ||||
|               <div className={styles.logerror}>{selectedProcParent.error}</div> | ||||
|             ) : null} | ||||
|             <Output | ||||
|               match={this.props.match} | ||||
|               build={this.props.build} | ||||
|               proc={selectedProc} | ||||
|               highlighted={highlighted} | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class BuildLogsTitle extends Component { | ||||
| 	render() { | ||||
| 		const { owner, repo, build } = this.props.match.params; | ||||
| 		return ( | ||||
| 			<Breadcrumb | ||||
| 				elements={[ | ||||
| 					<Link to={`/${owner}/${repo}`} key={`${owner}-${repo}`}> | ||||
| 						{owner} / {repo} | ||||
| 					</Link>, | ||||
| 					SEPARATOR, | ||||
| 					<Link | ||||
| 						to={`/${owner}/${repo}/${build}`} | ||||
| 						key={`${owner}-${repo}-${build}`} | ||||
| 					> | ||||
| 						{build} | ||||
| 					</Link>, | ||||
| 				]} | ||||
| 			/> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { owner, repo, build } = this.props.match.params; | ||||
|     return ( | ||||
|       <Breadcrumb | ||||
|         elements={[ | ||||
|           <Link to={`/${owner}/${repo}`} key={`${owner}-${repo}`}> | ||||
|             {owner} / {repo} | ||||
|           </Link>, | ||||
|           SEPARATOR, | ||||
|           <Link | ||||
|             to={`/${owner}/${repo}/${build}`} | ||||
|             key={`${owner}-${repo}-${build}`} | ||||
|           > | ||||
|             {build} | ||||
|           </Link> | ||||
|         ]} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,9 +7,9 @@ export const Top = () => <div className={styles.top} />; | ||||
| export const Bottom = () => <div className={styles.bottom} />; | ||||
|  | ||||
| export const scrollToTop = () => { | ||||
| 	document.querySelector(`.${styles.top}`).scrollIntoView(); | ||||
|   document.querySelector(`.${styles.top}`).scrollIntoView(); | ||||
| }; | ||||
|  | ||||
| export const scrollToBottom = () => { | ||||
| 	document.querySelector(`.${styles.bottom}`).scrollIntoView(); | ||||
|   document.querySelector(`.${styles.bottom}`).scrollIntoView(); | ||||
| }; | ||||
|   | ||||
| @@ -7,81 +7,81 @@ let formatter = new AnsiUp(); | ||||
| formatter.use_classes = true; | ||||
|  | ||||
| class Term extends Component { | ||||
| 	render() { | ||||
| 		const { lines, exitcode, highlighted } = this.props; | ||||
| 		return ( | ||||
| 			<div className={style.term}> | ||||
| 				{lines.map(line => renderTermLine(line, highlighted))} | ||||
| 				{exitcode !== undefined ? renderExitCode(exitcode) : undefined} | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { lines, exitcode, highlighted } = this.props; | ||||
|     return ( | ||||
|       <div className={style.term}> | ||||
|         {lines.map(line => renderTermLine(line, highlighted))} | ||||
|         {exitcode !== undefined ? renderExitCode(exitcode) : undefined} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.lines !== nextProps.lines || | ||||
| 			this.props.exitcode !== nextProps.exitcode || | ||||
| 			this.props.highlighted !== nextProps.highlighted | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.lines !== nextProps.lines || | ||||
|       this.props.exitcode !== nextProps.exitcode || | ||||
|       this.props.highlighted !== nextProps.highlighted | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class TermLine extends Component { | ||||
| 	render() { | ||||
| 		const { line, highlighted } = this.props; | ||||
| 		return ( | ||||
| 			<div | ||||
| 				className={highlighted === line.pos ? style.highlight : style.line} | ||||
| 				key={line.pos} | ||||
| 				ref={highlighted === line.pos ? ref => (this.ref = ref) : null} | ||||
| 			> | ||||
| 				<div> | ||||
| 					<Link to={`#L${line.pos + 1}`} key={line.pos + 1}> | ||||
| 						{line.pos + 1} | ||||
| 					</Link> | ||||
| 				</div> | ||||
| 				<div dangerouslySetInnerHTML={{ __html: this.colored }} /> | ||||
| 				<div>{line.time || 0}s</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { line, highlighted } = this.props; | ||||
|     return ( | ||||
|       <div | ||||
|         className={highlighted === line.pos ? style.highlight : style.line} | ||||
|         key={line.pos} | ||||
|         ref={highlighted === line.pos ? ref => (this.ref = ref) : null} | ||||
|       > | ||||
|         <div> | ||||
|           <Link to={`#L${line.pos + 1}`} key={line.pos + 1}> | ||||
|             {line.pos + 1} | ||||
|           </Link> | ||||
|         </div> | ||||
|         <div dangerouslySetInnerHTML={{ __html: this.colored }} /> | ||||
|         <div>{line.time || 0}s</div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	componentDidMount() { | ||||
| 		if (this.ref !== undefined) { | ||||
| 			scrollToRef(this.ref); | ||||
| 		} | ||||
| 	} | ||||
|   componentDidMount() { | ||||
|     if (this.ref !== undefined) { | ||||
|       scrollToRef(this.ref); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	get colored() { | ||||
| 		return formatter.ansi_to_html(this.props.line.out || ""); | ||||
| 	} | ||||
|   get colored() { | ||||
|     return formatter.ansi_to_html(this.props.line.out || ""); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.line.out !== nextProps.line.out || | ||||
| 			this.props.highlighted !== nextProps.highlighted | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.line.out !== nextProps.line.out || | ||||
|       this.props.highlighted !== nextProps.highlighted | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const renderTermLine = (line, highlighted) => { | ||||
| 	return <TermLine line={line} highlighted={highlighted} />; | ||||
|   return <TermLine line={line} highlighted={highlighted} />; | ||||
| }; | ||||
|  | ||||
| const renderExitCode = code => { | ||||
| 	return <div className={style.exitcode}>exit code {code}</div>; | ||||
|   return <div className={style.exitcode}>exit code {code}</div>; | ||||
| }; | ||||
|  | ||||
| const TermError = () => { | ||||
| 	return ( | ||||
| 		<div className={style.error}> | ||||
| 			Oops. There was a problem loading the logs. | ||||
| 		</div> | ||||
| 	); | ||||
|   return ( | ||||
|     <div className={style.error}> | ||||
|       Oops. There was a problem loading the logs. | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| const TermLoading = () => { | ||||
| 	return <div className={style.loading}>Loading ...</div>; | ||||
|   return <div className={style.loading}>Loading ...</div>; | ||||
| }; | ||||
|  | ||||
| const scrollToRef = ref => window.scrollTo(0, ref.offsetTop - 100); | ||||
|   | ||||
| @@ -14,104 +14,104 @@ import { ExpandIcon, PauseIcon, PlayIcon } from "shared/components/icons/index"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo, build } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	const number = parseInt(build); | ||||
| 	const pid = parseInt(props.proc.pid); | ||||
|   const { owner, repo, build } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   const number = parseInt(build); | ||||
|   const pid = parseInt(props.proc.pid); | ||||
|  | ||||
| 	return { | ||||
| 		logs: ["logs", "data", slug, number, pid, "data"], | ||||
| 		eof: ["logs", "data", slug, number, pid, "eof"], | ||||
| 		loading: ["logs", "data", slug, number, pid, "loading"], | ||||
| 		error: ["logs", "data", slug, number, pid, "error"], | ||||
| 		follow: ["logs", "follow"], | ||||
| 	}; | ||||
|   return { | ||||
|     logs: ["logs", "data", slug, number, pid, "data"], | ||||
|     eof: ["logs", "data", slug, number, pid, "eof"], | ||||
|     loading: ["logs", "data", slug, number, pid, "loading"], | ||||
|     error: ["logs", "data", slug, number, pid, "error"], | ||||
|     follow: ["logs", "follow"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class Output extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
| 		this.handleFollow = this.handleFollow.bind(this); | ||||
| 	} | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|     this.handleFollow = this.handleFollow.bind(this); | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		if (this.props.proc) { | ||||
| 			this.componentWillUpdate(this.props); | ||||
| 		} | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     if (this.props.proc) { | ||||
|       this.componentWillUpdate(this.props); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	componentWillUpdate(nextProps) { | ||||
| 		const { loading, logs, eof, error } = nextProps; | ||||
| 		const routeChange = this.props.match.url !== nextProps.match.url; | ||||
|   componentWillUpdate(nextProps) { | ||||
|     const { loading, logs, eof, error } = nextProps; | ||||
|     const routeChange = this.props.match.url !== nextProps.match.url; | ||||
|  | ||||
| 		if (loading || error || (logs && eof)) { | ||||
| 			return; | ||||
| 		} | ||||
|     if (loading || error || (logs && eof)) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
| 		if (assertProcFinished(nextProps.proc)) { | ||||
| 			return this.props.dispatch( | ||||
| 				fetchLogs, | ||||
| 				nextProps.drone, | ||||
| 				nextProps.match.params.owner, | ||||
| 				nextProps.match.params.repo, | ||||
| 				nextProps.build.number, | ||||
| 				nextProps.proc.pid, | ||||
| 			); | ||||
| 		} | ||||
|     if (assertProcFinished(nextProps.proc)) { | ||||
|       return this.props.dispatch( | ||||
|         fetchLogs, | ||||
|         nextProps.drone, | ||||
|         nextProps.match.params.owner, | ||||
|         nextProps.match.params.repo, | ||||
|         nextProps.build.number, | ||||
|         nextProps.proc.pid | ||||
|       ); | ||||
|     } | ||||
|  | ||||
| 		if (assertProcRunning(nextProps.proc) && (!logs || routeChange)) { | ||||
| 			this.props.dispatch( | ||||
| 				subscribeToLogs, | ||||
| 				nextProps.drone, | ||||
| 				nextProps.match.params.owner, | ||||
| 				nextProps.match.params.repo, | ||||
| 				nextProps.build.number, | ||||
| 				nextProps.proc, | ||||
| 			); | ||||
| 		} | ||||
| 	} | ||||
|     if (assertProcRunning(nextProps.proc) && (!logs || routeChange)) { | ||||
|       this.props.dispatch( | ||||
|         subscribeToLogs, | ||||
|         nextProps.drone, | ||||
|         nextProps.match.params.owner, | ||||
|         nextProps.match.params.repo, | ||||
|         nextProps.build.number, | ||||
|         nextProps.proc | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	componentDidUpdate() { | ||||
| 		if (this.props.follow) { | ||||
| 			scrollToBottom(); | ||||
| 		} | ||||
| 	} | ||||
|   componentDidUpdate() { | ||||
|     if (this.props.follow) { | ||||
|       scrollToBottom(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	handleFollow() { | ||||
| 		this.props.dispatch(toggleLogs, !this.props.follow); | ||||
| 	} | ||||
|   handleFollow() { | ||||
|     this.props.dispatch(toggleLogs, !this.props.follow); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { logs, error, proc, loading, follow, highlighted } = this.props; | ||||
|   render() { | ||||
|     const { logs, error, proc, loading, follow, highlighted } = this.props; | ||||
|  | ||||
| 		if (loading || !proc) { | ||||
| 			return <Term.Loading />; | ||||
| 		} | ||||
|     if (loading || !proc) { | ||||
|       return <Term.Loading />; | ||||
|     } | ||||
|  | ||||
| 		if (error) { | ||||
| 			return <Term.Error />; | ||||
| 		} | ||||
|     if (error) { | ||||
|       return <Term.Error />; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<Top /> | ||||
| 				<Term | ||||
| 					lines={logs || []} | ||||
| 					highlighted={highlighted} | ||||
| 					exitcode={assertProcFinished(proc) ? proc.exit_code : undefined} | ||||
| 				/> | ||||
| 				<Bottom /> | ||||
| 				<Actions | ||||
| 					running={assertProcRunning(proc)} | ||||
| 					following={follow} | ||||
| 					onfollow={this.handleFollow} | ||||
| 					onunfollow={this.handleFollow} | ||||
| 				/> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div> | ||||
|         <Top /> | ||||
|         <Term | ||||
|           lines={logs || []} | ||||
|           highlighted={highlighted} | ||||
|           exitcode={assertProcFinished(proc) ? proc.exit_code : undefined} | ||||
|         /> | ||||
|         <Bottom /> | ||||
|         <Actions | ||||
|           running={assertProcRunning(proc)} | ||||
|           following={follow} | ||||
|           onfollow={this.handleFollow} | ||||
|           onunfollow={this.handleFollow} | ||||
|         /> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -119,25 +119,25 @@ export default class Output extends Component { | ||||
|  * to follow, unfollow, scroll to top and scroll to bottom. | ||||
|  */ | ||||
| const Actions = ({ following, running, onfollow, onunfollow }) => ( | ||||
| 	<div className={styles.actions}> | ||||
| 		{running && !following ? ( | ||||
| 			<button onClick={onfollow} className={styles.follow}> | ||||
| 				<PlayIcon /> | ||||
| 			</button> | ||||
| 		) : null} | ||||
|   <div className={styles.actions}> | ||||
|     {running && !following ? ( | ||||
|       <button onClick={onfollow} className={styles.follow}> | ||||
|         <PlayIcon /> | ||||
|       </button> | ||||
|     ) : null} | ||||
|  | ||||
| 		{running && following ? ( | ||||
| 			<button onClick={onunfollow} className={styles.unfollow}> | ||||
| 				<PauseIcon /> | ||||
| 			</button> | ||||
| 		) : null} | ||||
|     {running && following ? ( | ||||
|       <button onClick={onunfollow} className={styles.unfollow}> | ||||
|         <PauseIcon /> | ||||
|       </button> | ||||
|     ) : null} | ||||
|  | ||||
| 		<button onClick={scrollToTop} className={styles.bottom}> | ||||
| 			<ExpandIcon /> | ||||
| 		</button> | ||||
|     <button onClick={scrollToTop} className={styles.bottom}> | ||||
|       <ExpandIcon /> | ||||
|     </button> | ||||
|  | ||||
| 		<button onClick={scrollToBottom} className={styles.top}> | ||||
| 			<ExpandIcon /> | ||||
| 		</button> | ||||
| 	</div> | ||||
|     <button onClick={scrollToBottom} className={styles.top}> | ||||
|       <ExpandIcon /> | ||||
|     </button> | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -10,69 +10,69 @@ import { branch } from "baobab-react/higher-order"; | ||||
| import { inject } from "config/client/inject"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo, build } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	const number = parseInt(build); | ||||
| 	return { | ||||
| 		repo: ["repos", "data", slug], | ||||
| 		build: ["builds", "data", slug, number], | ||||
| 	}; | ||||
|   const { owner, repo, build } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   const number = parseInt(build); | ||||
|   return { | ||||
|     repo: ["repos", "data", slug], | ||||
|     build: ["builds", "data", slug, number] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class BuildMenu extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleCancel = this.handleCancel.bind(this); | ||||
| 		this.handleRestart = this.handleRestart.bind(this); | ||||
| 	} | ||||
|     this.handleCancel = this.handleCancel.bind(this); | ||||
|     this.handleRestart = this.handleRestart.bind(this); | ||||
|   } | ||||
|  | ||||
| 	handleRestart() { | ||||
| 		const { dispatch, drone, repo, build } = this.props; | ||||
| 		dispatch(restartBuild, drone, repo.owner, repo.name, build.number); | ||||
| 	} | ||||
|   handleRestart() { | ||||
|     const { dispatch, drone, repo, build } = this.props; | ||||
|     dispatch(restartBuild, drone, repo.owner, repo.name, build.number); | ||||
|   } | ||||
|  | ||||
| 	handleCancel() { | ||||
| 		const { dispatch, drone, repo, build, match } = this.props; | ||||
| 		const proc = findChildProcess(build.procs, match.params.proc || 2); | ||||
|   handleCancel() { | ||||
|     const { dispatch, drone, repo, build, match } = this.props; | ||||
|     const proc = findChildProcess(build.procs, match.params.proc || 2); | ||||
|  | ||||
| 		dispatch( | ||||
| 			cancelBuild, | ||||
| 			drone, | ||||
| 			repo.owner, | ||||
| 			repo.name, | ||||
| 			build.number, | ||||
| 			proc.ppid, | ||||
| 		); | ||||
| 	} | ||||
|     dispatch( | ||||
|       cancelBuild, | ||||
|       drone, | ||||
|       repo.owner, | ||||
|       repo.name, | ||||
|       build.number, | ||||
|       proc.ppid | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { build } = this.props; | ||||
|   render() { | ||||
|     const { build } = this.props; | ||||
|  | ||||
| 		const rightSide = !build ? ( | ||||
| 			undefined | ||||
| 		) : ( | ||||
| 			<section> | ||||
| 				{build.status === "pending" || build.status === "running" ? ( | ||||
| 					<button onClick={this.handleCancel}> | ||||
| 						<CloseIcon /> | ||||
| 						<span>Cancel</span> | ||||
| 					</button> | ||||
| 				) : ( | ||||
| 					<button onClick={this.handleRestart}> | ||||
| 						<RefreshIcon /> | ||||
| 						<span>Restart Build</span> | ||||
| 					</button> | ||||
| 				)} | ||||
| 			</section> | ||||
| 		); | ||||
|     const rightSide = !build ? ( | ||||
|       undefined | ||||
|     ) : ( | ||||
|       <section> | ||||
|         {build.status === "pending" || build.status === "running" ? ( | ||||
|           <button onClick={this.handleCancel}> | ||||
|             <CloseIcon /> | ||||
|             <span>Cancel</span> | ||||
|           </button> | ||||
|         ) : ( | ||||
|           <button onClick={this.handleRestart}> | ||||
|             <RefreshIcon /> | ||||
|             <span>Restart Build</span> | ||||
|           </button> | ||||
|         )} | ||||
|       </section> | ||||
|     ); | ||||
|  | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<RepoMenu {...this.props} right={rightSide} /> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div> | ||||
|         <RepoMenu {...this.props} right={rightSide} /> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -8,48 +8,48 @@ import BuildMeta from "shared/components/build_event"; | ||||
| import styles from "./list.less"; | ||||
|  | ||||
| export const List = ({ children }) => ( | ||||
| 	<div className={styles.list}>{children}</div> | ||||
|   <div className={styles.list}>{children}</div> | ||||
| ); | ||||
|  | ||||
| export class Item extends Component { | ||||
| 	render() { | ||||
| 		const { build } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.item}> | ||||
| 				<div className={styles.icon}> | ||||
| 					<img src={build.author_avatar} /> | ||||
| 				</div> | ||||
|   render() { | ||||
|     const { build } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.item}> | ||||
|         <div className={styles.icon}> | ||||
|           <img src={build.author_avatar} /> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.body}> | ||||
| 					<h3>{build.message.split("\n")[0]}</h3> | ||||
| 				</div> | ||||
|         <div className={styles.body}> | ||||
|           <h3>{build.message.split("\n")[0]}</h3> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.meta}> | ||||
| 					<BuildMeta | ||||
| 						link={build.link_url} | ||||
| 						event={build.event} | ||||
| 						commit={build.commit} | ||||
| 						branch={build.branch} | ||||
| 						target={build.deploy_to} | ||||
| 						refspec={build.refspec} | ||||
| 						refs={build.ref} | ||||
| 					/> | ||||
| 				</div> | ||||
|         <div className={styles.meta}> | ||||
|           <BuildMeta | ||||
|             link={build.link_url} | ||||
|             event={build.event} | ||||
|             commit={build.commit} | ||||
|             branch={build.branch} | ||||
|             target={build.deploy_to} | ||||
|             refspec={build.refspec} | ||||
|             refs={build.ref} | ||||
|           /> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.break} /> | ||||
|         <div className={styles.break} /> | ||||
|  | ||||
| 				<div className={styles.time}> | ||||
| 					<BuildTime | ||||
| 						start={build.started_at || build.created_at} | ||||
| 						finish={build.finished_at} | ||||
| 					/> | ||||
| 				</div> | ||||
|         <div className={styles.time}> | ||||
|           <BuildTime | ||||
|             start={build.started_at || build.created_at} | ||||
|             finish={build.finished_at} | ||||
|           /> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.status}> | ||||
| 					<StatusNumber status={build.status} number={build.number} /> | ||||
| 					<Status status={build.status} /> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <div className={styles.status}> | ||||
|           <StatusNumber status={build.status} number={build.number} /> | ||||
|           <Status status={build.status} /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,18 +3,18 @@ import { Link } from "react-router-dom"; | ||||
| import Breadcrumb from "shared/components/breadcrumb"; | ||||
|  | ||||
| export default class Header extends Component { | ||||
| 	render() { | ||||
| 		const { owner, repo } = this.props.match.params; | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<Breadcrumb | ||||
| 					elements={[ | ||||
| 						<Link to={`/${owner}/${repo}`} key={`${owner}-${repo}`}> | ||||
| 							{owner} / {repo} | ||||
| 						</Link>, | ||||
| 					]} | ||||
| 				/> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { owner, repo } = this.props.match.params; | ||||
|     return ( | ||||
|       <div> | ||||
|         <Breadcrumb | ||||
|           elements={[ | ||||
|             <Link to={`/${owner}/${repo}`} key={`${owner}-${repo}`}> | ||||
|               {owner} / {repo} | ||||
|             </Link> | ||||
|           ]} | ||||
|         /> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -11,114 +11,114 @@ import { inject } from "config/client/inject"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	return { | ||||
| 		repo: ["repos", "data", slug], | ||||
| 		builds: ["builds", "data", slug], | ||||
| 		loaded: ["builds", "loaded"], | ||||
| 		error: ["builds", "error"], | ||||
| 	}; | ||||
|   const { owner, repo } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   return { | ||||
|     repo: ["repos", "data", slug], | ||||
|     builds: ["builds", "data", slug], | ||||
|     loaded: ["builds", "loaded"], | ||||
|     error: ["builds", "error"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class Main extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.fetchNextBuildPage = this.fetchNextBuildPage.bind(this); | ||||
| 	} | ||||
|     this.fetchNextBuildPage = this.fetchNextBuildPage.bind(this); | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		this.synchronize(this.props); | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     this.synchronize(this.props); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.repo !== nextProps.repo || | ||||
| 			(nextProps.builds !== undefined && | ||||
| 				this.props.builds !== nextProps.builds) || | ||||
| 			this.props.error !== nextProps.error || | ||||
| 			this.props.loaded !== nextProps.loaded | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.repo !== nextProps.repo || | ||||
|       (nextProps.builds !== undefined && | ||||
|         this.props.builds !== nextProps.builds) || | ||||
|       this.props.error !== nextProps.error || | ||||
|       this.props.loaded !== nextProps.loaded | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	componentWillUpdate(nextProps) { | ||||
| 		if (this.props.match.url !== nextProps.match.url) { | ||||
| 			this.synchronize(nextProps); | ||||
| 		} | ||||
| 	} | ||||
|   componentWillUpdate(nextProps) { | ||||
|     if (this.props.match.url !== nextProps.match.url) { | ||||
|       this.synchronize(nextProps); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	componentDidUpdate(prevProps) { | ||||
| 		if (this.props.location !== prevProps.location) { | ||||
| 			window.scrollTo(0, 0); | ||||
| 		} | ||||
| 	} | ||||
|   componentDidUpdate(prevProps) { | ||||
|     if (this.props.location !== prevProps.location) { | ||||
|       window.scrollTo(0, 0); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	synchronize(props) { | ||||
| 		const { drone, dispatch, match, repo } = props; | ||||
|   synchronize(props) { | ||||
|     const { drone, dispatch, match, repo } = props; | ||||
|  | ||||
| 		if (!repo) { | ||||
| 			dispatch(fetchRepository, drone, match.params.owner, match.params.repo); | ||||
| 		} | ||||
|     if (!repo) { | ||||
|       dispatch(fetchRepository, drone, match.params.owner, match.params.repo); | ||||
|     } | ||||
|  | ||||
| 		dispatch(fetchBuildList, drone, match.params.owner, match.params.repo); | ||||
| 	} | ||||
|     dispatch(fetchBuildList, drone, match.params.owner, match.params.repo); | ||||
|   } | ||||
|  | ||||
| 	fetchNextBuildPage(buildList) { | ||||
| 		const { drone, dispatch, match } = this.props; | ||||
| 		const page = Math.floor(buildList.length / 50) + 1; | ||||
|   fetchNextBuildPage(buildList) { | ||||
|     const { drone, dispatch, match } = this.props; | ||||
|     const page = Math.floor(buildList.length / 50) + 1; | ||||
|  | ||||
| 		dispatch( | ||||
| 			fetchBuildList, | ||||
| 			drone, | ||||
| 			match.params.owner, | ||||
| 			match.params.repo, | ||||
| 			page, | ||||
| 		); | ||||
| 	} | ||||
|     dispatch( | ||||
|       fetchBuildList, | ||||
|       drone, | ||||
|       match.params.owner, | ||||
|       match.params.repo, | ||||
|       page | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { repo, builds, loaded, error } = this.props; | ||||
| 		const list = Object.values(builds || {}); | ||||
|   render() { | ||||
|     const { repo, builds, loaded, error } = this.props; | ||||
|     const list = Object.values(builds || {}); | ||||
|  | ||||
| 		function renderBuild(build) { | ||||
| 			return ( | ||||
| 				<Link to={`/${repo.full_name}/${build.number}`} key={build.number}> | ||||
| 					<Item build={build} /> | ||||
| 				</Link> | ||||
| 			); | ||||
| 		} | ||||
|     function renderBuild(build) { | ||||
|       return ( | ||||
|         <Link to={`/${repo.full_name}/${build.number}`} key={build.number}> | ||||
|           <Item build={build} /> | ||||
|         </Link> | ||||
|       ); | ||||
|     } | ||||
|  | ||||
| 		if (error) { | ||||
| 			return <div>Not Found</div>; | ||||
| 		} | ||||
|     if (error) { | ||||
|       return <div>Not Found</div>; | ||||
|     } | ||||
|  | ||||
| 		if (!loaded && list.length === 0) { | ||||
| 			return <div>Loading</div>; | ||||
| 		} | ||||
|     if (!loaded && list.length === 0) { | ||||
|       return <div>Loading</div>; | ||||
|     } | ||||
|  | ||||
| 		if (!repo) { | ||||
| 			return <div>Loading</div>; | ||||
| 		} | ||||
|     if (!repo) { | ||||
|       return <div>Loading</div>; | ||||
|     } | ||||
|  | ||||
| 		if (list.length === 0) { | ||||
| 			return <div>Build list is empty</div>; | ||||
| 		} | ||||
|     if (list.length === 0) { | ||||
|       return <div>Build list is empty</div>; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<List>{list.sort(compareBuild).map(renderBuild)}</List> | ||||
| 				{list.length < repo.last_build && ( | ||||
| 					<button | ||||
| 						onClick={() => this.fetchNextBuildPage(list)} | ||||
| 						className={styles.more} | ||||
| 					> | ||||
| 						Show more builds | ||||
| 					</button> | ||||
| 				)} | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <List>{list.sort(compareBuild).map(renderBuild)}</List> | ||||
|         {list.length < repo.last_build && ( | ||||
|           <button | ||||
|             onClick={() => this.fetchNextBuildPage(list)} | ||||
|             className={styles.more} | ||||
|           > | ||||
|             Show more builds | ||||
|           </button> | ||||
|         )} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,14 +2,14 @@ import React, { Component } from "react"; | ||||
| import Menu from "shared/components/menu"; | ||||
|  | ||||
| export default class RepoMenu extends Component { | ||||
| 	render() { | ||||
| 		const { owner, repo } = this.props.match.params; | ||||
| 		const menu = [ | ||||
| 			{ to: `/${owner}/${repo}`, label: "Builds" }, | ||||
| 			{ to: `/${owner}/${repo}/settings/secrets`, label: "Secrets" }, | ||||
| 			{ to: `/${owner}/${repo}/settings/registry`, label: "Registry" }, | ||||
| 			{ to: `/${owner}/${repo}/settings`, label: "Settings" }, | ||||
| 		]; | ||||
| 		return <Menu items={menu} {...this.props} />; | ||||
| 	} | ||||
|   render() { | ||||
|     const { owner, repo } = this.props.match.params; | ||||
|     const menu = [ | ||||
|       { to: `/${owner}/${repo}`, label: "Builds" }, | ||||
|       { to: `/${owner}/${repo}/settings/secrets`, label: "Secrets" }, | ||||
|       { to: `/${owner}/${repo}/settings/registry`, label: "Registry" }, | ||||
|       { to: `/${owner}/${repo}/settings`, label: "Settings" } | ||||
|     ]; | ||||
|     return <Menu items={menu} {...this.props} />; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,79 +2,79 @@ import React, { Component } from "react"; | ||||
| import styles from "./form.less"; | ||||
|  | ||||
| export class Form extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.state = { | ||||
| 			address: "", | ||||
| 			username: "", | ||||
| 			password: "", | ||||
| 		}; | ||||
|     this.state = { | ||||
|       address: "", | ||||
|       username: "", | ||||
|       password: "" | ||||
|     }; | ||||
|  | ||||
| 		this._handleAddressChange = this._handleAddressChange.bind(this); | ||||
| 		this._handleUsernameChange = this._handleUsernameChange.bind(this); | ||||
| 		this._handlePasswordChange = this._handlePasswordChange.bind(this); | ||||
| 		this._handleSubmit = this._handleSubmit.bind(this); | ||||
|     this._handleAddressChange = this._handleAddressChange.bind(this); | ||||
|     this._handleUsernameChange = this._handleUsernameChange.bind(this); | ||||
|     this._handlePasswordChange = this._handlePasswordChange.bind(this); | ||||
|     this._handleSubmit = this._handleSubmit.bind(this); | ||||
|  | ||||
| 		this.clear = this.clear.bind(this); | ||||
| 	} | ||||
|     this.clear = this.clear.bind(this); | ||||
|   } | ||||
|  | ||||
| 	_handleAddressChange(event) { | ||||
| 		this.setState({ address: event.target.value }); | ||||
| 	} | ||||
|   _handleAddressChange(event) { | ||||
|     this.setState({ address: event.target.value }); | ||||
|   } | ||||
|  | ||||
| 	_handleUsernameChange(event) { | ||||
| 		this.setState({ username: event.target.value }); | ||||
| 	} | ||||
|   _handleUsernameChange(event) { | ||||
|     this.setState({ username: event.target.value }); | ||||
|   } | ||||
|  | ||||
| 	_handlePasswordChange(event) { | ||||
| 		this.setState({ password: event.target.value }); | ||||
| 	} | ||||
|   _handlePasswordChange(event) { | ||||
|     this.setState({ password: event.target.value }); | ||||
|   } | ||||
|  | ||||
| 	_handleSubmit() { | ||||
| 		const { onsubmit } = this.props; | ||||
|   _handleSubmit() { | ||||
|     const { onsubmit } = this.props; | ||||
|  | ||||
| 		const detail = { | ||||
| 			address: this.state.address, | ||||
| 			username: this.state.username, | ||||
| 			password: this.state.password, | ||||
| 		}; | ||||
|     const detail = { | ||||
|       address: this.state.address, | ||||
|       username: this.state.username, | ||||
|       password: this.state.password | ||||
|     }; | ||||
|  | ||||
| 		onsubmit({ detail }); | ||||
| 		this.clear(); | ||||
| 	} | ||||
|     onsubmit({ detail }); | ||||
|     this.clear(); | ||||
|   } | ||||
|  | ||||
| 	clear() { | ||||
| 		this.setState({ address: "" }); | ||||
| 		this.setState({ username: "" }); | ||||
| 		this.setState({ password: "" }); | ||||
| 	} | ||||
|   clear() { | ||||
|     this.setState({ address: "" }); | ||||
|     this.setState({ username: "" }); | ||||
|     this.setState({ password: "" }); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<div className={styles.form}> | ||||
| 				<input | ||||
| 					type="text" | ||||
| 					value={this.state.address} | ||||
| 					onChange={this._handleAddressChange} | ||||
| 					placeholder="Registry Address (e.g. docker.io)" | ||||
| 				/> | ||||
| 				<input | ||||
| 					type="text" | ||||
| 					value={this.state.username} | ||||
| 					onChange={this._handleUsernameChange} | ||||
| 					placeholder="Registry Username" | ||||
| 				/> | ||||
| 				<textarea | ||||
| 					rows="1" | ||||
| 					value={this.state.password} | ||||
| 					onChange={this._handlePasswordChange} | ||||
| 					placeholder="Registry Password" | ||||
| 				/> | ||||
| 				<div className={styles.actions}> | ||||
| 					<button onClick={this._handleSubmit}>Save</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <div className={styles.form}> | ||||
|         <input | ||||
|           type="text" | ||||
|           value={this.state.address} | ||||
|           onChange={this._handleAddressChange} | ||||
|           placeholder="Registry Address (e.g. docker.io)" | ||||
|         /> | ||||
|         <input | ||||
|           type="text" | ||||
|           value={this.state.username} | ||||
|           onChange={this._handleUsernameChange} | ||||
|           placeholder="Registry Username" | ||||
|         /> | ||||
|         <textarea | ||||
|           rows="1" | ||||
|           value={this.state.password} | ||||
|           onChange={this._handlePasswordChange} | ||||
|           placeholder="Registry Password" | ||||
|         /> | ||||
|         <div className={styles.actions}> | ||||
|           <button onClick={this._handleSubmit}>Save</button> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,14 +2,14 @@ import React from "react"; | ||||
| import styles from "./list.less"; | ||||
|  | ||||
| export const List = ({ children }) => ( | ||||
| 	<div className={styles.list}>{children}</div> | ||||
|   <div className={styles.list}>{children}</div> | ||||
| ); | ||||
|  | ||||
| export const Item = props => ( | ||||
| 	<div className={styles.item} key={props.name}> | ||||
| 		<div>{props.name}</div> | ||||
| 		<div> | ||||
| 			<button onClick={props.ondelete}>delete</button> | ||||
| 		</div> | ||||
| 	</div> | ||||
|   <div className={styles.item} key={props.name}> | ||||
|     <div>{props.name}</div> | ||||
|     <div> | ||||
|       <button onClick={props.ondelete}>delete</button> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -2,9 +2,9 @@ import React, { Component } from "react"; | ||||
|  | ||||
| import { repositorySlug } from "shared/utils/repository"; | ||||
| import { | ||||
| 	fetchRegistryList, | ||||
| 	createRegistry, | ||||
| 	deleteRegistry, | ||||
|   fetchRegistryList, | ||||
|   createRegistry, | ||||
|   deleteRegistry | ||||
| } from "shared/utils/registry"; | ||||
|  | ||||
| import { branch } from "baobab-react/higher-order"; | ||||
| @@ -15,89 +15,89 @@ import { List, Item, Form } from "./components"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	return { | ||||
| 		loaded: ["registry", "loaded"], | ||||
| 		registries: ["registry", "data", slug], | ||||
| 	}; | ||||
|   const { owner, repo } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   return { | ||||
|     loaded: ["registry", "loaded"], | ||||
|     registries: ["registry", "data", slug] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class RepoRegistry extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleDelete = this.handleDelete.bind(this); | ||||
| 		this.handleSave = this.handleSave.bind(this); | ||||
| 	} | ||||
|     this.handleDelete = this.handleDelete.bind(this); | ||||
|     this.handleSave = this.handleSave.bind(this); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return this.props.registries !== nextProps.registries; | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return this.props.registries !== nextProps.registries; | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		const { dispatch, drone, match } = this.props; | ||||
| 		const { owner, repo } = match.params; | ||||
| 		dispatch(fetchRegistryList, drone, owner, repo); | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     const { dispatch, drone, match } = this.props; | ||||
|     const { owner, repo } = match.params; | ||||
|     dispatch(fetchRegistryList, drone, owner, repo); | ||||
|   } | ||||
|  | ||||
| 	handleSave(e) { | ||||
| 		const { dispatch, drone, match } = this.props; | ||||
| 		const { owner, repo } = match.params; | ||||
| 		const registry = { | ||||
| 			address: e.detail.address, | ||||
| 			username: e.detail.username, | ||||
| 			password: e.detail.password, | ||||
| 		}; | ||||
|   handleSave(e) { | ||||
|     const { dispatch, drone, match } = this.props; | ||||
|     const { owner, repo } = match.params; | ||||
|     const registry = { | ||||
|       address: e.detail.address, | ||||
|       username: e.detail.username, | ||||
|       password: e.detail.password | ||||
|     }; | ||||
|  | ||||
| 		dispatch(createRegistry, drone, owner, repo, registry); | ||||
| 	} | ||||
|     dispatch(createRegistry, drone, owner, repo, registry); | ||||
|   } | ||||
|  | ||||
| 	handleDelete(registry) { | ||||
| 		const { dispatch, drone, match } = this.props; | ||||
| 		const { owner, repo } = match.params; | ||||
| 		dispatch(deleteRegistry, drone, owner, repo, registry.address); | ||||
| 	} | ||||
|   handleDelete(registry) { | ||||
|     const { dispatch, drone, match } = this.props; | ||||
|     const { owner, repo } = match.params; | ||||
|     dispatch(deleteRegistry, drone, owner, repo, registry.address); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { registries, loaded } = this.props; | ||||
|   render() { | ||||
|     const { registries, loaded } = this.props; | ||||
|  | ||||
| 		if (!loaded) { | ||||
| 			return LOADING; | ||||
| 		} | ||||
|     if (!loaded) { | ||||
|       return LOADING; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<div className={styles.left}> | ||||
| 					{Object.keys(registries || {}).length === 0 ? EMPTY : undefined} | ||||
| 					<List> | ||||
| 						{Object.values(registries || {}).map(renderRegistry.bind(this))} | ||||
| 					</List> | ||||
| 				</div> | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <div className={styles.left}> | ||||
|           {Object.keys(registries || {}).length === 0 ? EMPTY : undefined} | ||||
|           <List> | ||||
|             {Object.values(registries || {}).map(renderRegistry.bind(this))} | ||||
|           </List> | ||||
|         </div> | ||||
|  | ||||
| 				<div className={styles.right}> | ||||
| 					<Form onsubmit={this.handleSave} /> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <div className={styles.right}> | ||||
|           <Form onsubmit={this.handleSave} /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function renderRegistry(registry) { | ||||
| 	return ( | ||||
| 		<Item | ||||
| 			name={registry.address} | ||||
| 			ondelete={this.handleDelete.bind(this, registry)} | ||||
| 		/> | ||||
| 	); | ||||
|   return ( | ||||
|     <Item | ||||
|       name={registry.address} | ||||
|       ondelete={this.handleDelete.bind(this, registry)} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| const LOADING = <div className={styles.loading}>Loading</div>; | ||||
|  | ||||
| const EMPTY = ( | ||||
| 	<div className={styles.empty}> | ||||
| 		There are no registry credentials for this repository. | ||||
| 	</div> | ||||
|   <div className={styles.empty}> | ||||
|     There are no registry credentials for this repository. | ||||
|   </div> | ||||
| ); | ||||
|   | ||||
| @@ -1,140 +1,140 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| import { | ||||
| 	EVENT_PUSH, | ||||
| 	EVENT_TAG, | ||||
| 	EVENT_PULL_REQUEST, | ||||
| 	EVENT_DEPLOY, | ||||
|   EVENT_PUSH, | ||||
|   EVENT_TAG, | ||||
|   EVENT_PULL_REQUEST, | ||||
|   EVENT_DEPLOY | ||||
| } from "shared/constants/events"; | ||||
|  | ||||
| import styles from "./form.less"; | ||||
|  | ||||
| export class Form extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.state = { | ||||
| 			name: "", | ||||
| 			value: "", | ||||
| 			event: [EVENT_PUSH, EVENT_TAG, EVENT_DEPLOY], | ||||
| 		}; | ||||
|     this.state = { | ||||
|       name: "", | ||||
|       value: "", | ||||
|       event: [EVENT_PUSH, EVENT_TAG, EVENT_DEPLOY] | ||||
|     }; | ||||
|  | ||||
| 		this._handleNameChange = this._handleNameChange.bind(this); | ||||
| 		this._handleValueChange = this._handleValueChange.bind(this); | ||||
| 		this._handleEventChange = this._handleEventChange.bind(this); | ||||
| 		this._handleSubmit = this._handleSubmit.bind(this); | ||||
|     this._handleNameChange = this._handleNameChange.bind(this); | ||||
|     this._handleValueChange = this._handleValueChange.bind(this); | ||||
|     this._handleEventChange = this._handleEventChange.bind(this); | ||||
|     this._handleSubmit = this._handleSubmit.bind(this); | ||||
|  | ||||
| 		this.clear = this.clear.bind(this); | ||||
| 	} | ||||
|     this.clear = this.clear.bind(this); | ||||
|   } | ||||
|  | ||||
| 	_handleNameChange(event) { | ||||
| 		this.setState({ name: event.target.value }); | ||||
| 	} | ||||
|   _handleNameChange(event) { | ||||
|     this.setState({ name: event.target.value }); | ||||
|   } | ||||
|  | ||||
| 	_handleValueChange(event) { | ||||
| 		this.setState({ value: event.target.value }); | ||||
| 	} | ||||
|   _handleValueChange(event) { | ||||
|     this.setState({ value: event.target.value }); | ||||
|   } | ||||
|  | ||||
| 	_handleEventChange(event) { | ||||
| 		const selected = this.state.event; | ||||
| 		let index; | ||||
|   _handleEventChange(event) { | ||||
|     const selected = this.state.event; | ||||
|     let index; | ||||
|  | ||||
| 		if (event.target.checked) { | ||||
| 			selected.push(event.target.value); | ||||
| 		} else { | ||||
| 			index = selected.indexOf(event.target.value); | ||||
| 			selected.splice(index, 1); | ||||
| 		} | ||||
|     if (event.target.checked) { | ||||
|       selected.push(event.target.value); | ||||
|     } else { | ||||
|       index = selected.indexOf(event.target.value); | ||||
|       selected.splice(index, 1); | ||||
|     } | ||||
|  | ||||
| 		this.setState({ event: selected }); | ||||
| 	} | ||||
|     this.setState({ event: selected }); | ||||
|   } | ||||
|  | ||||
| 	_handleSubmit() { | ||||
| 		const { onsubmit } = this.props; | ||||
|   _handleSubmit() { | ||||
|     const { onsubmit } = this.props; | ||||
|  | ||||
| 		const detail = { | ||||
| 			name: this.state.name, | ||||
| 			value: this.state.value, | ||||
| 			event: this.state.event, | ||||
| 		}; | ||||
|     const detail = { | ||||
|       name: this.state.name, | ||||
|       value: this.state.value, | ||||
|       event: this.state.event | ||||
|     }; | ||||
|  | ||||
| 		onsubmit({ detail }); | ||||
| 		this.clear(); | ||||
| 	} | ||||
|     onsubmit({ detail }); | ||||
|     this.clear(); | ||||
|   } | ||||
|  | ||||
| 	clear() { | ||||
| 		this.setState({ name: "" }); | ||||
| 		this.setState({ value: "" }); | ||||
| 		this.setState({ event: [EVENT_PUSH, EVENT_TAG, EVENT_DEPLOY] }); | ||||
| 	} | ||||
|   clear() { | ||||
|     this.setState({ name: "" }); | ||||
|     this.setState({ value: "" }); | ||||
|     this.setState({ event: [EVENT_PUSH, EVENT_TAG, EVENT_DEPLOY] }); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		let checked = this.state.event.reduce((map, event) => { | ||||
| 			map[event] = true; | ||||
| 			return map; | ||||
| 		}, {}); | ||||
|   render() { | ||||
|     let checked = this.state.event.reduce((map, event) => { | ||||
|       map[event] = true; | ||||
|       return map; | ||||
|     }, {}); | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.form}> | ||||
| 				<input | ||||
| 					type="text" | ||||
| 					name="name" | ||||
| 					value={this.state.name} | ||||
| 					placeholder="Secret Name" | ||||
| 					onChange={this._handleNameChange} | ||||
| 				/> | ||||
| 				<textarea | ||||
| 					rows="1" | ||||
| 					name="value" | ||||
| 					value={this.state.value} | ||||
| 					placeholder="Secret Value" | ||||
| 					onChange={this._handleValueChange} | ||||
| 				/> | ||||
| 				<section> | ||||
| 					<h2>Events</h2> | ||||
| 					<div> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={checked[EVENT_PUSH]} | ||||
| 								value={EVENT_PUSH} | ||||
| 								onChange={this._handleEventChange} | ||||
| 							/> | ||||
| 							<span>push</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={checked[EVENT_TAG]} | ||||
| 								value={EVENT_TAG} | ||||
| 								onChange={this._handleEventChange} | ||||
| 							/> | ||||
| 							<span>tag</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={checked[EVENT_PULL_REQUEST]} | ||||
| 								value={EVENT_PULL_REQUEST} | ||||
| 								onChange={this._handleEventChange} | ||||
| 							/> | ||||
| 							<span>pull request</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={checked[EVENT_DEPLOY]} | ||||
| 								value={EVENT_DEPLOY} | ||||
| 								onChange={this._handleEventChange} | ||||
| 							/> | ||||
| 							<span>deploy</span> | ||||
| 						</label> | ||||
| 					</div> | ||||
| 				</section> | ||||
| 				<div className={styles.actions}> | ||||
| 					<button onClick={this._handleSubmit}>Save</button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.form}> | ||||
|         <input | ||||
|           type="text" | ||||
|           name="name" | ||||
|           value={this.state.name} | ||||
|           placeholder="Secret Name" | ||||
|           onChange={this._handleNameChange} | ||||
|         /> | ||||
|         <textarea | ||||
|           rows="1" | ||||
|           name="value" | ||||
|           value={this.state.value} | ||||
|           placeholder="Secret Value" | ||||
|           onChange={this._handleValueChange} | ||||
|         /> | ||||
|         <section> | ||||
|           <h2>Events</h2> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={checked[EVENT_PUSH]} | ||||
|                 value={EVENT_PUSH} | ||||
|                 onChange={this._handleEventChange} | ||||
|               /> | ||||
|               <span>push</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={checked[EVENT_TAG]} | ||||
|                 value={EVENT_TAG} | ||||
|                 onChange={this._handleEventChange} | ||||
|               /> | ||||
|               <span>tag</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={checked[EVENT_PULL_REQUEST]} | ||||
|                 value={EVENT_PULL_REQUEST} | ||||
|                 onChange={this._handleEventChange} | ||||
|               /> | ||||
|               <span>pull request</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={checked[EVENT_DEPLOY]} | ||||
|                 value={EVENT_DEPLOY} | ||||
|                 onChange={this._handleEventChange} | ||||
|               /> | ||||
|               <span>deploy</span> | ||||
|             </label> | ||||
|           </div> | ||||
|         </section> | ||||
|         <div className={styles.actions}> | ||||
|           <button onClick={this._handleSubmit}>Save</button> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,17 +4,17 @@ import styles from "./list.less"; | ||||
| export const List = ({ children }) => <div>{children}</div>; | ||||
|  | ||||
| export const Item = props => ( | ||||
| 	<div className={styles.item} key={props.name}> | ||||
| 		<div> | ||||
| 			{props.name} | ||||
| 			<ul>{props.event ? props.event.map(renderEvent) : null}</ul> | ||||
| 		</div> | ||||
| 		<div> | ||||
| 			<button onClick={props.ondelete}>delete</button> | ||||
| 		</div> | ||||
| 	</div> | ||||
|   <div className={styles.item} key={props.name}> | ||||
|     <div> | ||||
|       {props.name} | ||||
|       <ul>{props.event ? props.event.map(renderEvent) : null}</ul> | ||||
|     </div> | ||||
|     <div> | ||||
|       <button onClick={props.ondelete}>delete</button> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| const renderEvent = event => { | ||||
| 	return <li>{event}</li>; | ||||
|   return <li>{event}</li>; | ||||
| }; | ||||
|   | ||||
| @@ -2,9 +2,9 @@ import React, { Component } from "react"; | ||||
|  | ||||
| import { repositorySlug } from "shared/utils/repository"; | ||||
| import { | ||||
| 	fetchSecretList, | ||||
| 	createSecret, | ||||
| 	deleteSecret, | ||||
|   fetchSecretList, | ||||
|   createSecret, | ||||
|   deleteSecret | ||||
| } from "shared/utils/secrets"; | ||||
|  | ||||
| import { branch } from "baobab-react/higher-order"; | ||||
| @@ -15,85 +15,85 @@ import { List, Item, Form } from "./components"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	return { | ||||
| 		loaded: ["secrets", "loaded"], | ||||
| 		secrets: ["secrets", "data", slug], | ||||
| 	}; | ||||
|   const { owner, repo } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   return { | ||||
|     loaded: ["secrets", "loaded"], | ||||
|     secrets: ["secrets", "data", slug] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class RepoSecrets extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleSave = this.handleSave.bind(this); | ||||
| 	} | ||||
|     this.handleSave = this.handleSave.bind(this); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return this.props.secrets !== nextProps.secrets; | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return this.props.secrets !== nextProps.secrets; | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		const { owner, repo } = this.props.match.params; | ||||
| 		this.props.dispatch(fetchSecretList, this.props.drone, owner, repo); | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     const { owner, repo } = this.props.match.params; | ||||
|     this.props.dispatch(fetchSecretList, this.props.drone, owner, repo); | ||||
|   } | ||||
|  | ||||
| 	handleSave(e) { | ||||
| 		const { dispatch, drone, match } = this.props; | ||||
| 		const { owner, repo } = match.params; | ||||
| 		const secret = { | ||||
| 			name: e.detail.name, | ||||
| 			value: e.detail.value, | ||||
| 			event: e.detail.event, | ||||
| 		}; | ||||
|   handleSave(e) { | ||||
|     const { dispatch, drone, match } = this.props; | ||||
|     const { owner, repo } = match.params; | ||||
|     const secret = { | ||||
|       name: e.detail.name, | ||||
|       value: e.detail.value, | ||||
|       event: e.detail.event | ||||
|     }; | ||||
|  | ||||
| 		dispatch(createSecret, drone, owner, repo, secret); | ||||
| 	} | ||||
|     dispatch(createSecret, drone, owner, repo, secret); | ||||
|   } | ||||
|  | ||||
| 	handleDelete(secret) { | ||||
| 		const { dispatch, drone, match } = this.props; | ||||
| 		const { owner, repo } = match.params; | ||||
| 		dispatch(deleteSecret, drone, owner, repo, secret.name); | ||||
| 	} | ||||
|   handleDelete(secret) { | ||||
|     const { dispatch, drone, match } = this.props; | ||||
|     const { owner, repo } = match.params; | ||||
|     dispatch(deleteSecret, drone, owner, repo, secret.name); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { secrets, loaded } = this.props; | ||||
|   render() { | ||||
|     const { secrets, loaded } = this.props; | ||||
|  | ||||
| 		if (!loaded) { | ||||
| 			return LOADING; | ||||
| 		} | ||||
|     if (!loaded) { | ||||
|       return LOADING; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<div className={styles.left}> | ||||
| 					{Object.keys(secrets || {}).length === 0 ? EMPTY : undefined} | ||||
| 					<List> | ||||
| 						{Object.values(secrets || {}).map(renderSecret.bind(this))} | ||||
| 					</List> | ||||
| 				</div> | ||||
| 				<div className={styles.right}> | ||||
| 					<Form onsubmit={this.handleSave} /> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <div className={styles.left}> | ||||
|           {Object.keys(secrets || {}).length === 0 ? EMPTY : undefined} | ||||
|           <List> | ||||
|             {Object.values(secrets || {}).map(renderSecret.bind(this))} | ||||
|           </List> | ||||
|         </div> | ||||
|         <div className={styles.right}> | ||||
|           <Form onsubmit={this.handleSave} /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| function renderSecret(secret) { | ||||
| 	return ( | ||||
| 		<Item | ||||
| 			name={secret.name} | ||||
| 			event={secret.event} | ||||
| 			ondelete={this.handleDelete.bind(this, secret)} | ||||
| 		/> | ||||
| 	); | ||||
|   return ( | ||||
|     <Item | ||||
|       name={secret.name} | ||||
|       event={secret.event} | ||||
|       ondelete={this.handleDelete.bind(this, secret)} | ||||
|     /> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| const LOADING = <div className={styles.loading}>Loading</div>; | ||||
|  | ||||
| const EMPTY = ( | ||||
| 	<div className={styles.empty}>There are no secrets for this repository.</div> | ||||
|   <div className={styles.empty}>There are no secrets for this repository.</div> | ||||
| ); | ||||
|   | ||||
| @@ -4,241 +4,241 @@ import { branch } from "baobab-react/higher-order"; | ||||
| import { inject } from "config/client/inject"; | ||||
|  | ||||
| import { | ||||
| 	fetchRepository, | ||||
| 	updateRepository, | ||||
| 	repositorySlug, | ||||
|   fetchRepository, | ||||
|   updateRepository, | ||||
|   repositorySlug | ||||
| } from "shared/utils/repository"; | ||||
|  | ||||
| import { | ||||
| 	VISIBILITY_PUBLIC, | ||||
| 	VISIBILITY_PRIVATE, | ||||
| 	VISIBILITY_INTERNAL, | ||||
|   VISIBILITY_PUBLIC, | ||||
|   VISIBILITY_PRIVATE, | ||||
|   VISIBILITY_INTERNAL | ||||
| } from "shared/constants/visibility"; | ||||
|  | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	const { owner, repo } = props.match.params; | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	return { | ||||
| 		user: ["user", "data"], | ||||
| 		repo: ["repos", "data", slug], | ||||
| 	}; | ||||
|   const { owner, repo } = props.match.params; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   return { | ||||
|     user: ["user", "data"], | ||||
|     repo: ["repos", "data", slug] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class Settings extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handlePushChange = this.handlePushChange.bind(this); | ||||
| 		this.handlePullChange = this.handlePullChange.bind(this); | ||||
| 		this.handleTagChange = this.handleTagChange.bind(this); | ||||
| 		this.handleDeployChange = this.handleDeployChange.bind(this); | ||||
| 		this.handleTrustedChange = this.handleTrustedChange.bind(this); | ||||
| 		this.handleProtectedChange = this.handleProtectedChange.bind(this); | ||||
| 		this.handleVisibilityChange = this.handleVisibilityChange.bind(this); | ||||
| 		this.handleTimeoutChange = this.handleTimeoutChange.bind(this); | ||||
| 		this.handlePathChange = this.handlePathChange.bind(this); | ||||
| 		this.handleFallbackChange = this.handleFallbackChange.bind(this); | ||||
| 		this.handleChange = this.handleChange.bind(this); | ||||
| 	} | ||||
|     this.handlePushChange = this.handlePushChange.bind(this); | ||||
|     this.handlePullChange = this.handlePullChange.bind(this); | ||||
|     this.handleTagChange = this.handleTagChange.bind(this); | ||||
|     this.handleDeployChange = this.handleDeployChange.bind(this); | ||||
|     this.handleTrustedChange = this.handleTrustedChange.bind(this); | ||||
|     this.handleProtectedChange = this.handleProtectedChange.bind(this); | ||||
|     this.handleVisibilityChange = this.handleVisibilityChange.bind(this); | ||||
|     this.handleTimeoutChange = this.handleTimeoutChange.bind(this); | ||||
|     this.handlePathChange = this.handlePathChange.bind(this); | ||||
|     this.handleFallbackChange = this.handleFallbackChange.bind(this); | ||||
|     this.handleChange = this.handleChange.bind(this); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return this.props.repo !== nextProps.repo; | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return this.props.repo !== nextProps.repo; | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		const { drone, dispatch, match, repo } = this.props; | ||||
|   componentWillMount() { | ||||
|     const { drone, dispatch, match, repo } = this.props; | ||||
|  | ||||
| 		if (!repo) { | ||||
| 			dispatch(fetchRepository, drone, match.params.owner, match.params.repo); | ||||
| 		} | ||||
| 	} | ||||
|     if (!repo) { | ||||
|       dispatch(fetchRepository, drone, match.params.owner, match.params.repo); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { repo } = this.props; | ||||
|   render() { | ||||
|     const { repo } = this.props; | ||||
|  | ||||
| 		if (!repo) { | ||||
| 			return undefined; | ||||
| 		} | ||||
|     if (!repo) { | ||||
|       return undefined; | ||||
|     } | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<section> | ||||
| 					<h2>Pipeline Path</h2> | ||||
| 					<div> | ||||
| 						<input | ||||
| 							type="text" | ||||
| 							value={repo.config_file} | ||||
| 							onBlur={this.handlePathChange} | ||||
| 						/> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.fallback} | ||||
| 								onChange={this.handleFallbackChange} | ||||
| 							/> | ||||
| 							<span>Fallback to .drone.yml if path not exists</span> | ||||
| 						</label> | ||||
| 					</div> | ||||
| 				</section> | ||||
| 				<section> | ||||
| 					<h2>Repository Hooks</h2> | ||||
| 					<div> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.allow_push} | ||||
| 								onChange={this.handlePushChange} | ||||
| 							/> | ||||
| 							<span>push</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.allow_pr} | ||||
| 								onChange={this.handlePullChange} | ||||
| 							/> | ||||
| 							<span>pull request</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.allow_tags} | ||||
| 								onChange={this.handleTagChange} | ||||
| 							/> | ||||
| 							<span>tag</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.allow_deploys} | ||||
| 								onChange={this.handleDeployChange} | ||||
| 							/> | ||||
| 							<span>deployment</span> | ||||
| 						</label> | ||||
| 					</div> | ||||
| 				</section> | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <section> | ||||
|           <h2>Pipeline Path</h2> | ||||
|           <div> | ||||
|             <input | ||||
|               type="text" | ||||
|               value={repo.config_file} | ||||
|               onBlur={this.handlePathChange} | ||||
|             /> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.fallback} | ||||
|                 onChange={this.handleFallbackChange} | ||||
|               /> | ||||
|               <span>Fallback to .drone.yml if path not exists</span> | ||||
|             </label> | ||||
|           </div> | ||||
|         </section> | ||||
|         <section> | ||||
|           <h2>Repository Hooks</h2> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.allow_push} | ||||
|                 onChange={this.handlePushChange} | ||||
|               /> | ||||
|               <span>push</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.allow_pr} | ||||
|                 onChange={this.handlePullChange} | ||||
|               /> | ||||
|               <span>pull request</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.allow_tags} | ||||
|                 onChange={this.handleTagChange} | ||||
|               /> | ||||
|               <span>tag</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.allow_deploys} | ||||
|                 onChange={this.handleDeployChange} | ||||
|               /> | ||||
|               <span>deployment</span> | ||||
|             </label> | ||||
|           </div> | ||||
|         </section> | ||||
|  | ||||
| 				<section> | ||||
| 					<h2>Project Settings</h2> | ||||
| 					<div> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.gated} | ||||
| 								onChange={this.handleProtectedChange} | ||||
| 							/> | ||||
| 							<span>Protected</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="checkbox" | ||||
| 								checked={repo.trusted} | ||||
| 								onChange={this.handleTrustedChange} | ||||
| 							/> | ||||
| 							<span>Trusted</span> | ||||
| 						</label> | ||||
| 					</div> | ||||
| 				</section> | ||||
|         <section> | ||||
|           <h2>Project Settings</h2> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.gated} | ||||
|                 onChange={this.handleProtectedChange} | ||||
|               /> | ||||
|               <span>Protected</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="checkbox" | ||||
|                 checked={repo.trusted} | ||||
|                 onChange={this.handleTrustedChange} | ||||
|               /> | ||||
|               <span>Trusted</span> | ||||
|             </label> | ||||
|           </div> | ||||
|         </section> | ||||
|  | ||||
| 				<section> | ||||
| 					<h2>Project Visibility</h2> | ||||
| 					<div> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="radio" | ||||
| 								name="visibility" | ||||
| 								value="public" | ||||
| 								checked={repo.visibility === VISIBILITY_PUBLIC} | ||||
| 								onChange={this.handleVisibilityChange} | ||||
| 							/> | ||||
| 							<span>Public</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="radio" | ||||
| 								name="visibility" | ||||
| 								value="private" | ||||
| 								checked={repo.visibility === VISIBILITY_PRIVATE} | ||||
| 								onChange={this.handleVisibilityChange} | ||||
| 							/> | ||||
| 							<span>Private</span> | ||||
| 						</label> | ||||
| 						<label> | ||||
| 							<input | ||||
| 								type="radio" | ||||
| 								name="visibility" | ||||
| 								value="internal" | ||||
| 								checked={repo.visibility === VISIBILITY_INTERNAL} | ||||
| 								onChange={this.handleVisibilityChange} | ||||
| 							/> | ||||
| 							<span>Internal</span> | ||||
| 						</label> | ||||
| 					</div> | ||||
| 				</section> | ||||
|         <section> | ||||
|           <h2>Project Visibility</h2> | ||||
|           <div> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 name="visibility" | ||||
|                 value="public" | ||||
|                 checked={repo.visibility === VISIBILITY_PUBLIC} | ||||
|                 onChange={this.handleVisibilityChange} | ||||
|               /> | ||||
|               <span>Public</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 name="visibility" | ||||
|                 value="private" | ||||
|                 checked={repo.visibility === VISIBILITY_PRIVATE} | ||||
|                 onChange={this.handleVisibilityChange} | ||||
|               /> | ||||
|               <span>Private</span> | ||||
|             </label> | ||||
|             <label> | ||||
|               <input | ||||
|                 type="radio" | ||||
|                 name="visibility" | ||||
|                 value="internal" | ||||
|                 checked={repo.visibility === VISIBILITY_INTERNAL} | ||||
|                 onChange={this.handleVisibilityChange} | ||||
|               /> | ||||
|               <span>Internal</span> | ||||
|             </label> | ||||
|           </div> | ||||
|         </section> | ||||
|  | ||||
| 				<section> | ||||
| 					<h2>Timeout</h2> | ||||
| 					<div> | ||||
| 						<input | ||||
| 							type="number" | ||||
| 							value={repo.timeout} | ||||
| 							onBlur={this.handleTimeoutChange} | ||||
| 						/> | ||||
| 						<span className={styles.minutes}>minutes</span> | ||||
| 					</div> | ||||
| 				</section> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|         <section> | ||||
|           <h2>Timeout</h2> | ||||
|           <div> | ||||
|             <input | ||||
|               type="number" | ||||
|               value={repo.timeout} | ||||
|               onBlur={this.handleTimeoutChange} | ||||
|             /> | ||||
|             <span className={styles.minutes}>minutes</span> | ||||
|           </div> | ||||
|         </section> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	handlePushChange(e) { | ||||
| 		this.handleChange("allow_push", e.target.checked); | ||||
| 	} | ||||
|   handlePushChange(e) { | ||||
|     this.handleChange("allow_push", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handlePullChange(e) { | ||||
| 		this.handleChange("allow_pr", e.target.checked); | ||||
| 	} | ||||
|   handlePullChange(e) { | ||||
|     this.handleChange("allow_pr", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleTagChange(e) { | ||||
| 		this.handleChange("allow_tag", e.target.checked); | ||||
| 	} | ||||
|   handleTagChange(e) { | ||||
|     this.handleChange("allow_tag", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleDeployChange(e) { | ||||
| 		this.handleChange("allow_deploy", e.target.checked); | ||||
| 	} | ||||
|   handleDeployChange(e) { | ||||
|     this.handleChange("allow_deploy", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleTrustedChange(e) { | ||||
| 		this.handleChange("trusted", e.target.checked); | ||||
| 	} | ||||
|   handleTrustedChange(e) { | ||||
|     this.handleChange("trusted", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleProtectedChange(e) { | ||||
| 		this.handleChange("gated", e.target.checked); | ||||
| 	} | ||||
|   handleProtectedChange(e) { | ||||
|     this.handleChange("gated", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleVisibilityChange(e) { | ||||
| 		this.handleChange("visibility", e.target.value); | ||||
| 	} | ||||
|   handleVisibilityChange(e) { | ||||
|     this.handleChange("visibility", e.target.value); | ||||
|   } | ||||
|  | ||||
| 	handleTimeoutChange(e) { | ||||
| 		this.handleChange("timeout", parseInt(e.target.value)); | ||||
| 	} | ||||
|   handleTimeoutChange(e) { | ||||
|     this.handleChange("timeout", parseInt(e.target.value)); | ||||
|   } | ||||
|  | ||||
| 	handlePathChange(e) { | ||||
| 		this.handleChange("config_file", e.target.value); | ||||
| 	} | ||||
|   handlePathChange(e) { | ||||
|     this.handleChange("config_file", e.target.value); | ||||
|   } | ||||
|  | ||||
| 	handleFallbackChange(e) { | ||||
| 		this.handleChange("fallback", e.target.checked); | ||||
| 	} | ||||
|   handleFallbackChange(e) { | ||||
|     this.handleChange("fallback", e.target.checked); | ||||
|   } | ||||
|  | ||||
| 	handleChange(prop, value) { | ||||
| 		const { dispatch, drone, repo } = this.props; | ||||
| 		let data = {}; | ||||
| 		data[prop] = value; | ||||
| 		dispatch(updateRepository, drone, repo.owner, repo.name, data); | ||||
| 	} | ||||
|   handleChange(prop, value) { | ||||
|     const { dispatch, drone, repo } = this.props; | ||||
|     let data = {}; | ||||
|     data[prop] = value; | ||||
|     dispatch(updateRepository, drone, repo.owner, repo.name, data); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,15 +5,15 @@ import Title from "react-title-component"; | ||||
| // @see https://github.com/yannickcr/eslint-plugin-react/issues/512 | ||||
| // eslint-disable-next-line react/display-name | ||||
| export default function() { | ||||
| 	return ( | ||||
| 		<Switch> | ||||
| 			<Route path="/account/tokens" exact={true} component={accountTitle} /> | ||||
| 			<Route path="/account/repos" exact={true} component={accountRepos} /> | ||||
| 			<Route path="/login" exact={false} component={loginTitle} /> | ||||
| 			<Route path="/:owner/:repo" exact={false} component={repoTitle} /> | ||||
| 			<Route path="/" exact={false} component={defautTitle} /> | ||||
| 		</Switch> | ||||
| 	); | ||||
|   return ( | ||||
|     <Switch> | ||||
|       <Route path="/account/tokens" exact={true} component={accountTitle} /> | ||||
|       <Route path="/account/repos" exact={true} component={accountRepos} /> | ||||
|       <Route path="/login" exact={false} component={loginTitle} /> | ||||
|       <Route path="/:owner/:repo" exact={false} component={repoTitle} /> | ||||
|       <Route path="/" exact={false} component={defautTitle} /> | ||||
|     </Switch> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| const accountTitle = () => <Title render="Tokens | drone" />; | ||||
| @@ -23,7 +23,7 @@ const accountRepos = () => <Title render="Repositories | drone" />; | ||||
| const loginTitle = () => <Title render="Login | drone" />; | ||||
|  | ||||
| const repoTitle = ({ match }) => ( | ||||
| 	<Title render={`${match.params.owner}/${match.params.repo} | drone`} /> | ||||
|   <Title render={`${match.params.owner}/${match.params.repo} | drone`} /> | ||||
| ); | ||||
|  | ||||
| const defautTitle = () => <Title render="Welcome | drone" />; | ||||
|   | ||||
| @@ -7,34 +7,34 @@ import { Switch } from "./switch"; | ||||
| import styles from "./list.less"; | ||||
|  | ||||
| export const List = ({ children }) => ( | ||||
| 	<div className={styles.list}>{children}</div> | ||||
|   <div className={styles.list}>{children}</div> | ||||
| ); | ||||
|  | ||||
| export class Item extends Component { | ||||
| 	render() { | ||||
| 		const { owner, name, active, link, onchange } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.item}> | ||||
| 				<div> | ||||
| 					{owner}/{name} | ||||
| 				</div> | ||||
| 				<div className={active ? styles.active : styles.inactive}> | ||||
| 					<Link to={link}> | ||||
| 						<LaunchIcon /> | ||||
| 					</Link> | ||||
| 				</div> | ||||
| 				<div> | ||||
| 					<Switch onchange={onchange} checked={active} /> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { owner, name, active, link, onchange } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.item}> | ||||
|         <div> | ||||
|           {owner}/{name} | ||||
|         </div> | ||||
|         <div className={active ? styles.active : styles.inactive}> | ||||
|           <Link to={link}> | ||||
|             <LaunchIcon /> | ||||
|           </Link> | ||||
|         </div> | ||||
|         <div> | ||||
|           <Switch onchange={onchange} checked={active} /> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps) { | ||||
| 		return ( | ||||
| 			this.props.owner !== nextProps.owner || | ||||
| 			this.props.name !== nextProps.name || | ||||
| 			this.props.active !== nextProps.active | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps) { | ||||
|     return ( | ||||
|       this.props.owner !== nextProps.owner || | ||||
|       this.props.name !== nextProps.name || | ||||
|       this.props.active !== nextProps.active | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,12 +2,12 @@ import React, { Component } from "react"; | ||||
| import styles from "./switch.less"; | ||||
|  | ||||
| export class Switch extends Component { | ||||
| 	render() { | ||||
| 		const { checked, onchange } = this.props; | ||||
| 		return ( | ||||
| 			<label className={styles.switch}> | ||||
| 				<input type="checkbox" checked={checked} onChange={onchange} /> | ||||
| 			</label> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { checked, onchange } = this.props; | ||||
|     return ( | ||||
|       <label className={styles.switch}> | ||||
|         <input type="checkbox" checked={checked} onChange={onchange} /> | ||||
|       </label> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,9 +4,9 @@ import { branch } from "baobab-react/higher-order"; | ||||
| import { inject } from "config/client/inject"; | ||||
|  | ||||
| import { | ||||
| 	fetchRepostoryList, | ||||
| 	disableRepository, | ||||
| 	enableRepository, | ||||
|   fetchRepostoryList, | ||||
|   disableRepository, | ||||
|   enableRepository | ||||
| } from "shared/utils/repository"; | ||||
|  | ||||
| import { List, Item } from "./components"; | ||||
| @@ -15,105 +15,105 @@ import Breadcrumb, { SEPARATOR } from "shared/components/breadcrumb"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { | ||||
| 		repos: ["repos", "data"], | ||||
| 		loaded: ["repos", "loaded"], | ||||
| 		error: ["repos", "error"], | ||||
| 	}; | ||||
|   return { | ||||
|     repos: ["repos", "data"], | ||||
|     loaded: ["repos", "loaded"], | ||||
|     error: ["repos", "error"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class UserRepos extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleFilter = this.handleFilter.bind(this); | ||||
| 		this.renderItem = this.renderItem.bind(this); | ||||
| 		this.handleToggle = this.handleToggle.bind(this); | ||||
| 	} | ||||
|     this.handleFilter = this.handleFilter.bind(this); | ||||
|     this.renderItem = this.renderItem.bind(this); | ||||
|     this.handleToggle = this.handleToggle.bind(this); | ||||
|   } | ||||
|  | ||||
| 	handleFilter(e) { | ||||
| 		this.setState({ | ||||
| 			search: e.target.value, | ||||
| 		}); | ||||
| 	} | ||||
|   handleFilter(e) { | ||||
|     this.setState({ | ||||
|       search: e.target.value | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| 	handleToggle(repo, e) { | ||||
| 		const { dispatch, drone } = this.props; | ||||
| 		if (e.target.checked) { | ||||
| 			dispatch(enableRepository, drone, repo.owner, repo.name); | ||||
| 		} else { | ||||
| 			dispatch(disableRepository, drone, repo.owner, repo.name); | ||||
| 		} | ||||
| 	} | ||||
|   handleToggle(repo, e) { | ||||
|     const { dispatch, drone } = this.props; | ||||
|     if (e.target.checked) { | ||||
|       dispatch(enableRepository, drone, repo.owner, repo.name); | ||||
|     } else { | ||||
|       dispatch(disableRepository, drone, repo.owner, repo.name); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		if (!this._dispatched) { | ||||
| 			this._dispatched = true; | ||||
| 			this.props.dispatch(fetchRepostoryList, this.props.drone); | ||||
| 		} | ||||
| 	} | ||||
|   componentWillMount() { | ||||
|     if (!this._dispatched) { | ||||
|       this._dispatched = true; | ||||
|       this.props.dispatch(fetchRepostoryList, this.props.drone); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.repos !== nextProps.repos || | ||||
| 			this.state.search !== nextState.search | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.repos !== nextProps.repos || | ||||
|       this.state.search !== nextState.search | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { repos, loaded, error } = this.props; | ||||
| 		const { search } = this.state; | ||||
| 		const list = Object.values(repos || {}); | ||||
|   render() { | ||||
|     const { repos, loaded, error } = this.props; | ||||
|     const { search } = this.state; | ||||
|     const list = Object.values(repos || {}); | ||||
|  | ||||
| 		if (error) { | ||||
| 			return ERROR; | ||||
| 		} | ||||
|     if (error) { | ||||
|       return ERROR; | ||||
|     } | ||||
|  | ||||
| 		if (!loaded) { | ||||
| 			return LOADING; | ||||
| 		} | ||||
|     if (!loaded) { | ||||
|       return LOADING; | ||||
|     } | ||||
|  | ||||
| 		if (list.length === 0) { | ||||
| 			return EMPTY; | ||||
| 		} | ||||
|     if (list.length === 0) { | ||||
|       return EMPTY; | ||||
|     } | ||||
|  | ||||
| 		const filter = repo => { | ||||
| 			return !search || repo.full_name.indexOf(search) !== -1; | ||||
| 		}; | ||||
|     const filter = repo => { | ||||
|       return !search || repo.full_name.indexOf(search) !== -1; | ||||
|     }; | ||||
|  | ||||
| 		const filtered = list.filter(filter); | ||||
|     const filtered = list.filter(filter); | ||||
|  | ||||
| 		return ( | ||||
| 			<div> | ||||
| 				<div className={styles.search}> | ||||
| 					<input | ||||
| 						type="text" | ||||
| 						placeholder="Search …" | ||||
| 						onChange={this.handleFilter} | ||||
| 					/> | ||||
| 				</div> | ||||
| 				<div className={styles.root}> | ||||
| 					{filtered.length === 0 ? NO_MATCHES : null} | ||||
| 					<List>{list.filter(filter).map(this.renderItem)}</List> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div> | ||||
|         <div className={styles.search}> | ||||
|           <input | ||||
|             type="text" | ||||
|             placeholder="Search …" | ||||
|             onChange={this.handleFilter} | ||||
|           /> | ||||
|         </div> | ||||
|         <div className={styles.root}> | ||||
|           {filtered.length === 0 ? NO_MATCHES : null} | ||||
|           <List>{list.filter(filter).map(this.renderItem)}</List> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	renderItem(repo) { | ||||
| 		return ( | ||||
| 			<Item | ||||
| 				key={repo.full_name} | ||||
| 				owner={repo.owner} | ||||
| 				name={repo.name} | ||||
| 				active={repo.active} | ||||
| 				link={`/${repo.full_name}`} | ||||
| 				onchange={this.handleToggle.bind(this, repo)} | ||||
| 			/> | ||||
| 		); | ||||
| 	} | ||||
|   renderItem(repo) { | ||||
|     return ( | ||||
|       <Item | ||||
|         key={repo.full_name} | ||||
|         owner={repo.owner} | ||||
|         name={repo.name} | ||||
|         active={repo.active} | ||||
|         link={`/${repo.full_name}`} | ||||
|         onchange={this.handleToggle.bind(this, repo)} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const LOADING = <div>Loading</div>; | ||||
| @@ -126,12 +126,12 @@ const ERROR = <div>Error</div>; | ||||
|  | ||||
| /* eslint-disable react/jsx-key */ | ||||
| export class UserRepoTitle extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<Breadcrumb | ||||
| 				elements={[<span>Account</span>, SEPARATOR, <span>Repositories</span>]} | ||||
| 			/> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <Breadcrumb | ||||
|         elements={[<span>Account</span>, SEPARATOR, <span>Repositories</span>]} | ||||
|       /> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| /* eslint-enable react/jsx-key */ | ||||
|   | ||||
| @@ -6,36 +6,36 @@ import { SyncIcon } from "shared/components/icons"; | ||||
| import Menu from "shared/components/menu"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { | ||||
| 		repos: ["repos"], | ||||
| 	}; | ||||
|   return { | ||||
|     repos: ["repos"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class UserReposMenu extends Component { | ||||
| 	constructor(props, context) { | ||||
| 		super(props, context); | ||||
|   constructor(props, context) { | ||||
|     super(props, context); | ||||
|  | ||||
| 		this.handleClick = this.handleClick.bind(this); | ||||
| 	} | ||||
|     this.handleClick = this.handleClick.bind(this); | ||||
|   } | ||||
|  | ||||
| 	handleClick() { | ||||
| 		const { dispatch, drone } = this.props; | ||||
| 		dispatch(syncRepostoryList, drone); | ||||
| 	} | ||||
|   handleClick() { | ||||
|     const { dispatch, drone } = this.props; | ||||
|     dispatch(syncRepostoryList, drone); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { loaded } = this.props.repos; | ||||
| 		const right = ( | ||||
| 			<section> | ||||
| 				<button disabled={!loaded} onClick={this.handleClick}> | ||||
| 					<SyncIcon /> | ||||
| 					<span>Synchronize</span> | ||||
| 				</button> | ||||
| 			</section> | ||||
| 		); | ||||
|   render() { | ||||
|     const { loaded } = this.props.repos; | ||||
|     const right = ( | ||||
|       <section> | ||||
|         <button disabled={!loaded} onClick={this.handleClick}> | ||||
|           <SyncIcon /> | ||||
|           <span>Synchronize</span> | ||||
|         </button> | ||||
|       </section> | ||||
|     ); | ||||
|  | ||||
| 		return <Menu items={[]} right={right} />; | ||||
| 	} | ||||
|     return <Menu items={[]} right={right} />; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -6,53 +6,55 @@ import { inject } from "config/client/inject"; | ||||
| import styles from "./index.less"; | ||||
|  | ||||
| const binding = (props, context) => { | ||||
| 	return { | ||||
| 		location: ["location"], | ||||
| 		token: ["token"], | ||||
| 	}; | ||||
|   return { | ||||
|     location: ["location"], | ||||
|     token: ["token"] | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @inject | ||||
| @branch(binding) | ||||
| export default class Tokens extends Component { | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return ( | ||||
| 			this.props.location !== nextProps.location || | ||||
| 			this.props.token !== nextProps.token | ||||
| 		); | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return ( | ||||
|       this.props.location !== nextProps.location || | ||||
|       this.props.token !== nextProps.token | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		const { drone, dispatch } = this.props; | ||||
|   componentWillMount() { | ||||
|     const { drone, dispatch } = this.props; | ||||
|  | ||||
| 		dispatch(generateToken, drone); | ||||
| 	} | ||||
|     dispatch(generateToken, drone); | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { location, token } = this.props; | ||||
|   render() { | ||||
|     const { location, token } = this.props; | ||||
|  | ||||
| 		if (!location || !token) { | ||||
| 			return <div>Loading</div>; | ||||
| 		} | ||||
| 		return ( | ||||
| 			<div className={styles.root}> | ||||
| 				<h2>Your Personal Token:</h2> | ||||
| 				<pre>{token}</pre> | ||||
| 				<h2>Example API Usage:</h2> | ||||
| 				<pre>{usageWithCURL(location, token)}</pre> | ||||
| 				<h2>Example CLI Usage:</h2> | ||||
| 				<pre>{usageWithCLI(location, token)}</pre> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     if (!location || !token) { | ||||
|       return <div>Loading</div>; | ||||
|     } | ||||
|     return ( | ||||
|       <div className={styles.root}> | ||||
|         <h2>Your Personal Token:</h2> | ||||
|         <pre>{token}</pre> | ||||
|         <h2>Example API Usage:</h2> | ||||
|         <pre>{usageWithCURL(location, token)}</pre> | ||||
|         <h2>Example CLI Usage:</h2> | ||||
|         <pre>{usageWithCLI(location, token)}</pre> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const usageWithCURL = (location, token) => { | ||||
| 	return `curl -i ${location.protocol}//${location.host}/api/user -H "Authorization: Bearer ${token}"`; | ||||
|   return `curl -i ${location.protocol}//${ | ||||
|     location.host | ||||
|   }/api/user -H "Authorization: Bearer ${token}"`; | ||||
| }; | ||||
|  | ||||
| const usageWithCLI = (location, token) => { | ||||
| 	return `export DRONE_SERVER=${location.protocol}//${location.host} | ||||
|   return `export DRONE_SERVER=${location.protocol}//${location.host} | ||||
| 		export DRONE_TOKEN=${token} | ||||
|  | ||||
| 		drone info`; | ||||
|   | ||||
| @@ -3,30 +3,30 @@ import { mount } from "enzyme"; | ||||
|  | ||||
| import Status from "../status"; | ||||
| import { | ||||
| 	STATUS_FAILURE, | ||||
| 	STATUS_RUNNING, | ||||
| 	STATUS_SUCCESS, | ||||
|   STATUS_FAILURE, | ||||
|   STATUS_RUNNING, | ||||
|   STATUS_SUCCESS | ||||
| } from "shared/constants/status"; | ||||
|  | ||||
| jest.dontMock("../status"); | ||||
|  | ||||
| describe("Status component", () => { | ||||
| 	test("updates on status change", () => { | ||||
| 		const status = mount(<Status status={STATUS_FAILURE} />); | ||||
| 		const instance = status.instance(); | ||||
|   test("updates on status change", () => { | ||||
|     const status = mount(<Status status={STATUS_FAILURE} />); | ||||
|     const instance = status.instance(); | ||||
|  | ||||
| 		expect( | ||||
| 			instance.shouldComponentUpdate({ status: STATUS_FAILURE }), | ||||
| 		).toBeFalsy(); | ||||
| 		expect( | ||||
| 			instance.shouldComponentUpdate({ status: STATUS_SUCCESS }), | ||||
| 		).toBeTruthy(); | ||||
| 		expect(status.hasClass("failure")).toBeTruthy(); | ||||
| 	}); | ||||
|     expect( | ||||
|       instance.shouldComponentUpdate({ status: STATUS_FAILURE }) | ||||
|     ).toBeFalsy(); | ||||
|     expect( | ||||
|       instance.shouldComponentUpdate({ status: STATUS_SUCCESS }) | ||||
|     ).toBeTruthy(); | ||||
|     expect(status.hasClass("failure")).toBeTruthy(); | ||||
|   }); | ||||
|  | ||||
| 	test("uses the status as the class name", () => { | ||||
| 		const status = mount(<Status status={STATUS_RUNNING} />); | ||||
|   test("uses the status as the class name", () => { | ||||
|     const status = mount(<Status status={STATUS_RUNNING} />); | ||||
|  | ||||
| 		expect(status.hasClass("running")).toBeTruthy(); | ||||
| 	}); | ||||
|     expect(status.hasClass("running")).toBeTruthy(); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -2,11 +2,11 @@ import React, { Component } from "react"; | ||||
| import styles from "./avatar.less"; | ||||
|  | ||||
| export default class Avatar extends Component { | ||||
| 	render() { | ||||
| 		const image = this.props.image; | ||||
| 		const style = { | ||||
| 			backgroundImage: `url(${image})`, | ||||
| 		}; | ||||
| 		return <div className={styles.avatar} style={style} />; | ||||
| 	} | ||||
|   render() { | ||||
|     const image = this.props.image; | ||||
|     const style = { | ||||
|       backgroundImage: `url(${image})` | ||||
|     }; | ||||
|     return <div className={styles.avatar} style={style} />; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -10,12 +10,12 @@ export const BACK_BUTTON = <BackIcon size={18} className={style.back} />; | ||||
|  | ||||
| // helper function to render a list item. | ||||
| const renderItem = (element, index) => { | ||||
| 	return <li key={index}>{element}</li>; | ||||
|   return <li key={index}>{element}</li>; | ||||
| }; | ||||
|  | ||||
| export default class Breadcrumb extends Component { | ||||
| 	render() { | ||||
| 		const { elements } = this.props; | ||||
| 		return <ol className={style.breadcrumb}>{elements.map(renderItem)}</ol>; | ||||
| 	} | ||||
|   render() { | ||||
|     const { elements } = this.props; | ||||
|     return <ol className={style.breadcrumb}>{elements.map(renderItem)}</ol>; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,70 +1,68 @@ | ||||
| import React, { Component } from "react"; | ||||
| import { | ||||
| 	BranchIcon, | ||||
| 	CommitIcon, | ||||
| 	DeployIcon, | ||||
| 	LaunchIcon, | ||||
| 	MergeIcon, | ||||
| 	TagIcon, | ||||
|   BranchIcon, | ||||
|   CommitIcon, | ||||
|   DeployIcon, | ||||
|   LaunchIcon, | ||||
|   MergeIcon, | ||||
|   TagIcon | ||||
| } from "shared/components/icons/index"; | ||||
| import { | ||||
| 	EVENT_TAG, | ||||
| 	EVENT_PULL_REQUEST, | ||||
| 	EVENT_DEPLOY, | ||||
|   EVENT_TAG, | ||||
|   EVENT_PULL_REQUEST, | ||||
|   EVENT_DEPLOY | ||||
| } from "shared/constants/events"; | ||||
|  | ||||
| import styles from "./build_event.less"; | ||||
|  | ||||
| export default class BuildEvent extends Component { | ||||
| 	render() { | ||||
| 		const { event, branch, commit, refs, refspec, link, target } = this.props; | ||||
|   render() { | ||||
|     const { event, branch, commit, refs, refspec, link, target } = this.props; | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.row}> | ||||
| 					<div> | ||||
| 						<CommitIcon /> | ||||
| 					</div> | ||||
| 					<div>{commit && commit.substr(0, 10)}</div> | ||||
| 				</div> | ||||
| 				<div className={styles.row}> | ||||
| 					<div> | ||||
| 						{event === EVENT_TAG ? ( | ||||
| 							<TagIcon /> | ||||
| 						) : event === EVENT_PULL_REQUEST ? ( | ||||
| 							<MergeIcon /> | ||||
| 						) : event === EVENT_DEPLOY ? ( | ||||
| 							<DeployIcon /> | ||||
| 						) : ( | ||||
| 							<BranchIcon /> | ||||
| 						)} | ||||
| 					</div> | ||||
| 					<div> | ||||
| 						{event === EVENT_TAG && refs ? ( | ||||
| 							trimTagRef(refs) | ||||
| 						) : event === EVENT_PULL_REQUEST && refspec ? ( | ||||
| 							trimMergeRef(refs) | ||||
| 						) : event === EVENT_DEPLOY && target ? ( | ||||
| 							target | ||||
| 						) : ( | ||||
| 							branch | ||||
| 						)} | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<a href={link} target="_blank"> | ||||
| 					<LaunchIcon /> | ||||
| 				</a> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.row}> | ||||
|           <div> | ||||
|             <CommitIcon /> | ||||
|           </div> | ||||
|           <div>{commit && commit.substr(0, 10)}</div> | ||||
|         </div> | ||||
|         <div className={styles.row}> | ||||
|           <div> | ||||
|             {event === EVENT_TAG ? ( | ||||
|               <TagIcon /> | ||||
|             ) : event === EVENT_PULL_REQUEST ? ( | ||||
|               <MergeIcon /> | ||||
|             ) : event === EVENT_DEPLOY ? ( | ||||
|               <DeployIcon /> | ||||
|             ) : ( | ||||
|               <BranchIcon /> | ||||
|             )} | ||||
|           </div> | ||||
|           <div> | ||||
|             {event === EVENT_TAG && refs | ||||
|               ? trimTagRef(refs) | ||||
|               : event === EVENT_PULL_REQUEST && refspec | ||||
|               ? trimMergeRef(refs) | ||||
|               : event === EVENT_DEPLOY && target | ||||
|               ? target | ||||
|               : branch} | ||||
|           </div> | ||||
|         </div> | ||||
|         <a href={link} target="_blank"> | ||||
|           <LaunchIcon /> | ||||
|         </a> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const trimMergeRef = ref => { | ||||
| 	return ref.match(/\d/g) || ref; | ||||
|   return ref.match(/\d/g) || ref; | ||||
| }; | ||||
|  | ||||
| const trimTagRef = ref => { | ||||
| 	return ref.startsWith("refs/tags/") ? ref.substr(10) : ref; | ||||
|   return ref.startsWith("refs/tags/") ? ref.substr(10) : ref; | ||||
| }; | ||||
|  | ||||
| // push | ||||
|   | ||||
| @@ -7,31 +7,31 @@ import Duration from "./duration"; | ||||
| import styles from "./build_time.less"; | ||||
|  | ||||
| export default class Runtime extends Component { | ||||
| 	render() { | ||||
| 		const { start, finish } = this.props; | ||||
| 		return ( | ||||
| 			<div className={styles.host}> | ||||
| 				<div className={styles.row}> | ||||
| 					<div> | ||||
| 						<ScheduleIcon /> | ||||
| 					</div> | ||||
| 					<div>{start ? <TimeAgo date={start * 1000} /> : <span>--</span>}</div> | ||||
| 				</div> | ||||
| 				<div className={styles.row}> | ||||
| 					<div> | ||||
| 						<TimelapseIcon /> | ||||
| 					</div> | ||||
| 					<div> | ||||
| 						{finish ? ( | ||||
| 							<Duration start={start} finished={finish} /> | ||||
| 						) : start ? ( | ||||
| 							<TimeAgo date={start * 1000} /> | ||||
| 						) : ( | ||||
| 							<span>--</span> | ||||
| 						)} | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     const { start, finish } = this.props; | ||||
|     return ( | ||||
|       <div className={styles.host}> | ||||
|         <div className={styles.row}> | ||||
|           <div> | ||||
|             <ScheduleIcon /> | ||||
|           </div> | ||||
|           <div>{start ? <TimeAgo date={start * 1000} /> : <span>--</span>}</div> | ||||
|         </div> | ||||
|         <div className={styles.row}> | ||||
|           <div> | ||||
|             <TimelapseIcon /> | ||||
|           </div> | ||||
|           <div> | ||||
|             {finish ? ( | ||||
|               <Duration start={start} finished={finish} /> | ||||
|             ) : start ? ( | ||||
|               <TimeAgo date={start * 1000} /> | ||||
|             ) : ( | ||||
|               <span>--</span> | ||||
|             )} | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -7,56 +7,56 @@ export const DOCK_LEFT = styles.left; | ||||
| export const DOCK_RIGHT = styles.right; | ||||
|  | ||||
| export class Drawer extends Component { | ||||
| 	render() { | ||||
| 		const { open, position } = this.props; | ||||
|   render() { | ||||
|     const { open, position } = this.props; | ||||
|  | ||||
| 		let classes = [styles.drawer]; | ||||
| 		if (open) { | ||||
| 			classes.push(styles.open); | ||||
| 		} | ||||
| 		if (position) { | ||||
| 			classes.push(position); | ||||
| 		} | ||||
|     let classes = [styles.drawer]; | ||||
|     if (open) { | ||||
|       classes.push(styles.open); | ||||
|     } | ||||
|     if (position) { | ||||
|       classes.push(position); | ||||
|     } | ||||
|  | ||||
| 		var child = open ? ( | ||||
| 			<div key={0} onClick={this.props.onClick} className={styles.backdrop} /> | ||||
| 		) : null; | ||||
|     var child = open ? ( | ||||
|       <div key={0} onClick={this.props.onClick} className={styles.backdrop} /> | ||||
|     ) : null; | ||||
|  | ||||
| 		return ( | ||||
| 			<div className={classes.join(" ")}> | ||||
| 				<CSSTransitionGroup | ||||
| 					transitionName="fade" | ||||
| 					transitionEnterTimeout={150} | ||||
| 					transitionLeaveTimeout={150} | ||||
| 					transitionAppearTimeout={150} | ||||
| 					transitionAppear={true} | ||||
| 					transitionEnter={true} | ||||
| 					transitionLeave={true} | ||||
| 				> | ||||
| 					{child} | ||||
| 				</CSSTransitionGroup> | ||||
| 				<div className={styles.inner}>{this.props.children}</div> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <div className={classes.join(" ")}> | ||||
|         <CSSTransitionGroup | ||||
|           transitionName="fade" | ||||
|           transitionEnterTimeout={150} | ||||
|           transitionLeaveTimeout={150} | ||||
|           transitionAppearTimeout={150} | ||||
|           transitionAppear={true} | ||||
|           transitionEnter={true} | ||||
|           transitionLeave={true} | ||||
|         > | ||||
|           {child} | ||||
|         </CSSTransitionGroup> | ||||
|         <div className={styles.inner}>{this.props.children}</div> | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class CloseButton extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<button className={styles.close} onClick={this.props.onClick}> | ||||
| 				<CloseIcon /> | ||||
| 			</button> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <button className={styles.close} onClick={this.props.onClick}> | ||||
|         <CloseIcon /> | ||||
|       </button> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class MenuButton extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<button className={styles.close} onClick={this.props.onClick}> | ||||
| 				Show Menu | ||||
| 			</button> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <button className={styles.close} onClick={this.props.onClick}> | ||||
|         Show Menu | ||||
|       </button> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -2,9 +2,9 @@ import humanizeDuration from "humanize-duration"; | ||||
| import React from "react"; | ||||
|  | ||||
| export default class Duration extends React.Component { | ||||
| 	render() { | ||||
| 		const { start, finished } = this.props; | ||||
|   render() { | ||||
|     const { start, finished } = this.props; | ||||
|  | ||||
| 		return <time>{humanizeDuration((finished - start) * 1000)}</time>; | ||||
| 	} | ||||
|     return <time>{humanizeDuration((finished - start) * 1000)}</time>; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class BackIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class BranchIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg viewBox="0 0 24 24"> | ||||
| 				<path d="M6,2A3,3 0 0,1 9,5C9,6.28 8.19,7.38 7.06,7.81C7.15,8.27 7.39,8.83 8,9.63C9,10.92 11,12.83 12,14.17C13,12.83 15,10.92 16,9.63C16.61,8.83 16.85,8.27 16.94,7.81C15.81,7.38 15,6.28 15,5A3,3 0 0,1 18,2A3,3 0 0,1 21,5C21,6.32 20.14,7.45 18.95,7.85C18.87,8.37 18.64,9 18,9.83C17,11.17 15,13.08 14,14.38C13.39,15.17 13.15,15.73 13.06,16.19C14.19,16.62 15,17.72 15,19A3,3 0 0,1 12,22A3,3 0 0,1 9,19C9,17.72 9.81,16.62 10.94,16.19C10.85,15.73 10.61,15.17 10,14.38C9,13.08 7,11.17 6,9.83C5.36,9 5.13,8.37 5.05,7.85C3.86,7.45 3,6.32 3,5A3,3 0 0,1 6,2M6,4A1,1 0 0,0 5,5A1,1 0 0,0 6,6A1,1 0 0,0 7,5A1,1 0 0,0 6,4M18,4A1,1 0 0,0 17,5A1,1 0 0,0 18,6A1,1 0 0,0 19,5A1,1 0 0,0 18,4M12,18A1,1 0 0,0 11,19A1,1 0 0,0 12,20A1,1 0 0,0 13,19A1,1 0 0,0 12,18Z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg viewBox="0 0 24 24"> | ||||
|         <path d="M6,2A3,3 0 0,1 9,5C9,6.28 8.19,7.38 7.06,7.81C7.15,8.27 7.39,8.83 8,9.63C9,10.92 11,12.83 12,14.17C13,12.83 15,10.92 16,9.63C16.61,8.83 16.85,8.27 16.94,7.81C15.81,7.38 15,6.28 15,5A3,3 0 0,1 18,2A3,3 0 0,1 21,5C21,6.32 20.14,7.45 18.95,7.85C18.87,8.37 18.64,9 18,9.83C17,11.17 15,13.08 14,14.38C13.39,15.17 13.15,15.73 13.06,16.19C14.19,16.62 15,17.72 15,19A3,3 0 0,1 12,22A3,3 0 0,1 9,19C9,17.72 9.81,16.62 10.94,16.19C10.85,15.73 10.61,15.17 10,14.38C9,13.08 7,11.17 6,9.83C5.36,9 5.13,8.37 5.05,7.85C3.86,7.45 3,6.32 3,5A3,3 0 0,1 6,2M6,4A1,1 0 0,0 5,5A1,1 0 0,0 6,6A1,1 0 0,0 7,5A1,1 0 0,0 6,4M18,4A1,1 0 0,0 17,5A1,1 0 0,0 18,6A1,1 0 0,0 19,5A1,1 0 0,0 18,4M12,18A1,1 0 0,0 11,19A1,1 0 0,0 12,20A1,1 0 0,0 13,19A1,1 0 0,0 12,18Z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class CheckIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class ClockIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class CloseIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,16 +1,16 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class CommitIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M17,12C17,14.42 15.28,16.44 13,16.9V21H11V16.9C8.72,16.44 7,14.42 7,12C7,9.58 8.72,7.56 11,7.1V3H13V7.1C15.28,7.56 17,9.58 17,12M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9Z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M17,12C17,14.42 15.28,16.44 13,16.9V21H11V16.9C8.72,16.44 7,14.42 7,12C7,9.58 8.72,7.56 11,7.1V3H13V7.1C15.28,7.56 17,9.58 17,12M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9Z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class DeployIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M19,18H6A4,4 0 0,1 2,14A4,4 0 0,1 6,10H6.71C7.37,7.69 9.5,6 12,6A5.5,5.5 0 0,1 17.5,11.5V12H19A3,3 0 0,1 22,15A3,3 0 0,1 19,18M19.35,10.03C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.03C2.34,8.36 0,10.9 0,14A6,6 0 0,0 6,20H19A5,5 0 0,0 24,15C24,12.36 21.95,10.22 19.35,10.03Z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M19,18H6A4,4 0 0,1 2,14A4,4 0 0,1 6,10H6.71C7.37,7.69 9.5,6 12,6A5.5,5.5 0 0,1 17.5,11.5V12H19A3,3 0 0,1 22,15A3,3 0 0,1 19,18M19.35,10.03C18.67,6.59 15.64,4 12,4C9.11,4 6.6,5.64 5.35,8.03C2.34,8.36 0,10.9 0,14A6,6 0 0,0 6,20H19A5,5 0 0,0 24,15C24,12.36 21.95,10.22 19.35,10.03Z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class ExpandIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" /> | ||||
| 				<path d="M0-.75h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M7.41 7.84L12 12.42l4.59-4.58L18 9.25l-6 6-6-6z" /> | ||||
|         <path d="M0-.75h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -21,25 +21,25 @@ import TagIcon from "./tag"; | ||||
| import TimelapseIcon from "./timelapse"; | ||||
|  | ||||
| export { | ||||
| 	BackIcon, | ||||
| 	BranchIcon, | ||||
| 	CheckIcon, | ||||
| 	CloseIcon, | ||||
| 	ClockIcon, | ||||
| 	CommitIcon, | ||||
| 	DeployIcon, | ||||
| 	ExpandIcon, | ||||
| 	LaunchIcon, | ||||
| 	LinkIcon, | ||||
| 	MenuIcon, | ||||
| 	MergeIcon, | ||||
| 	PauseIcon, | ||||
| 	PlayIcon, | ||||
| 	RefreshIcon, | ||||
| 	RemoveIcon, | ||||
| 	ScheduleIcon, | ||||
| 	StarIcon, | ||||
| 	SyncIcon, | ||||
| 	TagIcon, | ||||
| 	TimelapseIcon, | ||||
|   BackIcon, | ||||
|   BranchIcon, | ||||
|   CheckIcon, | ||||
|   CloseIcon, | ||||
|   ClockIcon, | ||||
|   CommitIcon, | ||||
|   DeployIcon, | ||||
|   ExpandIcon, | ||||
|   LaunchIcon, | ||||
|   LinkIcon, | ||||
|   MenuIcon, | ||||
|   MergeIcon, | ||||
|   PauseIcon, | ||||
|   PlayIcon, | ||||
|   RefreshIcon, | ||||
|   RemoveIcon, | ||||
|   ScheduleIcon, | ||||
|   StarIcon, | ||||
|   SyncIcon, | ||||
|   TagIcon, | ||||
|   TimelapseIcon | ||||
| }; | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class LaunchIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class LinkIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class MenuIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class MergeIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M5.41,21L6.12,17H2.12L2.47,15H6.47L7.53,9H3.53L3.88,7H7.88L8.59,3H10.59L9.88,7H15.88L16.59,3H18.59L17.88,7H21.88L21.53,9H17.53L16.47,15H20.47L20.12,17H16.12L15.41,21H13.41L14.12,17H8.12L7.41,21H5.41M9.53,9L8.47,15H14.47L15.53,9H9.53Z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M5.41,21L6.12,17H2.12L2.47,15H6.47L7.53,9H3.53L3.88,7H7.88L8.59,3H10.59L9.88,7H15.88L16.59,3H18.59L17.88,7H21.88L21.53,9H17.53L16.47,15H20.47L20.12,17H16.12L15.41,21H13.41L14.12,17H8.12L7.41,21H5.41M9.53,9L8.47,15H14.47L15.53,9H9.53Z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // <svg class={this.props.className} viewBox="0 0 54.5 68"> | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class PauseIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class PlayIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M8 5v14l11-7z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M8 5v14l11-7z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class RefreshIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class CheckIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M19 13H5v-2h14v2z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M19 13H5v-2h14v2z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class ReportIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15.73 3zM12 17.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2V7h2v6z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M15.73 3H8.27L3 8.27v7.46L8.27 21h7.46L21 15.73V8.27L15.73 3zM12 17.3c-.72 0-1.3-.58-1.3-1.3 0-.72.58-1.3 1.3-1.3.72 0 1.3.58 1.3 1.3 0 .72-.58 1.3-1.3 1.3zm1-4.3h-2V7h2v6z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,18 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class ScheduleIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M12.5 7H11v6l5.25 3.15.75-1.23-4.5-2.67z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,20 +1,20 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class StarIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 512 512" | ||||
| 			> | ||||
| 				{this.props.filled === true ? ( | ||||
| 					<path d="M256 372.686L380.83 448l-33.021-142.066L458 210.409l-145.267-12.475L256 64l-56.743 133.934L54 210.409l110.192 95.525L131.161 448z" /> | ||||
| 				) : ( | ||||
| 					<path d="M458 210.409l-145.267-12.476L256 64l-56.743 133.934L54 210.409l110.192 95.524L131.161 448 256 372.686 380.83 448l-33.021-142.066L458 210.409zM272.531 345.286L256 335.312l-16.53 9.973-59.988 36.191 15.879-68.296 4.369-18.79-14.577-12.637-52.994-45.939 69.836-5.998 19.206-1.65 7.521-17.75 27.276-64.381 27.27 64.379 7.52 17.751 19.208 1.65 69.846 5.998-52.993 45.939-14.576 12.636 4.367 18.788 15.875 68.299-59.984-36.189z" /> | ||||
| 				)} | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 512 512" | ||||
|       > | ||||
|         {this.props.filled === true ? ( | ||||
|           <path d="M256 372.686L380.83 448l-33.021-142.066L458 210.409l-145.267-12.475L256 64l-56.743 133.934L54 210.409l110.192 95.525L131.161 448z" /> | ||||
|         ) : ( | ||||
|           <path d="M458 210.409l-145.267-12.476L256 64l-56.743 133.934L54 210.409l110.192 95.524L131.161 448 256 372.686 380.83 448l-33.021-142.066L458 210.409zM272.531 345.286L256 335.312l-16.53 9.973-59.988 36.191 15.879-68.296 4.369-18.79-14.577-12.637-52.994-45.939 69.836-5.998 19.206-1.65 7.521-17.75 27.276-64.381 27.27 64.379 7.52 17.751 19.208 1.65 69.846 5.998-52.993 45.939-14.576 12.636 4.367 18.788 15.875 68.299-59.984-36.189z" /> | ||||
|         )} | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class SyncIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" /> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M12 4V1L8 5l4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.03 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8v3l4-4-4-4v3z" /> | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class TagIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg className={this.props.className} viewBox="0 0 24 24"> | ||||
| 				<path d="M5.5,7A1.5,1.5 0 0,0 7,5.5A1.5,1.5 0 0,0 5.5,4A1.5,1.5 0 0,0 4,5.5A1.5,1.5 0 0,0 5.5,7M21.41,11.58C21.77,11.94 22,12.44 22,13C22,13.55 21.78,14.05 21.41,14.41L14.41,21.41C14.05,21.77 13.55,22 13,22C12.45,22 11.95,21.77 11.58,21.41L2.59,12.41C2.22,12.05 2,11.55 2,11V4C2,2.89 2.89,2 4,2H11C11.55,2 12.05,2.22 12.41,2.58L21.41,11.58M13,20L20,13L11.5,4.5L4.5,11.5L13,20Z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg className={this.props.className} viewBox="0 0 24 24"> | ||||
|         <path d="M5.5,7A1.5,1.5 0 0,0 7,5.5A1.5,1.5 0 0,0 5.5,4A1.5,1.5 0 0,0 4,5.5A1.5,1.5 0 0,0 5.5,7M21.41,11.58C21.77,11.94 22,12.44 22,13C22,13.55 21.78,14.05 21.41,14.41L14.41,21.41C14.05,21.77 13.55,22 13,22C12.45,22 11.95,21.77 11.58,21.41L2.59,12.41C2.22,12.05 2,11.55 2,11V4C2,2.89 2.89,2 4,2H11C11.55,2 12.05,2.22 12.41,2.58L21.41,11.58M13,20L20,13L11.5,4.5L4.5,11.5L13,20Z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class TimelapseIcon extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg | ||||
| 				className={this.props.className} | ||||
| 				width={this.props.size || 24} | ||||
| 				height={this.props.size || 24} | ||||
| 				viewBox="0 0 24 24" | ||||
| 			> | ||||
| 				<path d="M0 0h24v24H0z" fill="none" /> | ||||
| 				<path d="M16.24 7.76C15.07 6.59 13.54 6 12 6v6l-4.24 4.24c2.34 2.34 6.14 2.34 8.49 0 2.34-2.34 2.34-6.14-.01-8.48zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg | ||||
|         className={this.props.className} | ||||
|         width={this.props.size || 24} | ||||
|         height={this.props.size || 24} | ||||
|         viewBox="0 0 24 24" | ||||
|       > | ||||
|         <path d="M0 0h24v24H0z" fill="none" /> | ||||
|         <path d="M16.24 7.76C15.07 6.59 13.54 6 12 6v6l-4.24 4.24c2.34 2.34 6.14 2.34 8.49 0 2.34-2.34 2.34-6.14-.01-8.48zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z" /> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,17 +1,17 @@ | ||||
| import React, { Component } from "react"; | ||||
|  | ||||
| export default class Logo extends Component { | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<svg viewBox="0 0 50 62.5" preserveAspectRatio="xMidYMid"> | ||||
| 				<g> | ||||
| 					<path | ||||
| 						fillRule="evenodd" | ||||
| 						clipRule="evenodd" | ||||
| 						d="M15.872,0.468c1.148,1.088,1.582,2.188,2.855,2.337l0.036,0.007c-0.588,0.606-1.089,1.402-1.443,2.423c-0.379,1.096-0.488,2.285-0.614,3.659c-0.189,2.046-0.401,4.364-1.556,7.269   c-2.486,6.258-1.119,11.631,0.332,17.317c0.664,2.604,1.348,5.297,1.642,8.107c0.035,0.355,0.287,0.652,0.633,0.744   c0.346,0.095,0.709-0.035,0.922-0.323c0.227-0.313,0.524-0.797,0.86-1.424c0.84,3.323,1.355,6.131,1.783,8.697   c0.126,0.73,1.048,0.973,1.517,0.41c2.881-3.463,3.763-8.636,2.184-12.674c0.459-2.433,1.402-4.45,2.398-6.583   c0.536-1.15,1.08-2.318,1.55-3.566c0.228-0.084,0.569-0.314,0.791-0.441l1.706-0.981l-0.256,1.052   c-0.112,0.461,0.171,0.929,0.635,1.04c0.457,0.118,0.93-0.173,1.043-0.632l0.68-2.858l1.285-2.95   c0.19-0.436-0.009-0.943-0.446-1.135c-0.44-0.189-0.947,0.01-1.135,0.448l-1.152,2.669l-2.383,1.372   c0.235-0.932,0.414-1.919,0.508-2.981c0.432-4.859-0.718-9.074-3.066-11.266c-0.163-0.157-0.208-0.281-0.247-0.26   c0.095-0.119,0.249-0.26,0.358-0.374c2.283-1.693,6.047-0.147,8.319,0.751c0.589,0.231,0.876-0.338,0.316-0.67   c-1.949-1.154-5.948-4.197-8.188-6.194c-0.313-0.275-0.527-0.607-0.89-0.913c-2.415-4.266-8.168-1.764-10.885-2.252   C15.862,0.275,15.798,0.396,15.872,0.468 M26.852,6.367c-0.059,1.242-0.603,1.8-0.999,2.208c-0.218,0.224-0.427,0.436-0.525,0.738   c-0.236,0.714,0.008,1.51,0.66,2.143c1.974,1.84,2.925,5.527,2.538,9.861c-0.291,3.287-1.448,5.762-2.671,8.384   c-1.031,2.207-2.096,4.489-2.577,7.259c-0.027,0.161-0.01,0.33,0.056,0.481c1.021,2.433,1.135,6.196-0.672,9.46   c-0.461-2.553-1.053-5.385-1.97-8.712c1.964-4.488,4.203-11.75,2.919-17.668c-0.325-1.497-1.304-3.276-2.387-4.207   c-0.208-0.179-0.402-0.237-0.495-0.167c-0.084,0.061-0.151,0.238-0.062,0.444c0.55,1.266,0.879,2.599,1.226,4.276   c1.125,5.443-0.956,12.49-2.835,16.782l-0.116,0.259l-0.457,0.982c-0.356-2.014-0.849-3.95-1.33-5.839   c-1.379-5.407-2.679-10.516-0.401-16.255c1.247-3.137,1.483-5.692,1.672-7.746c0.116-1.263,0.216-2.355,0.526-3.252   c0.905-2.605,3.062-3.178,4.744-2.852C25.328,3.262,26.936,4.539,26.852,6.367z M23.984,6.988c0.617,0.204,1.283-0.131,1.487-0.75   c0.202-0.617-0.134-1.283-0.751-1.487c-0.618-0.204-1.285,0.134-1.487,0.751C23.029,6.12,23.366,6.786,23.984,6.988z" | ||||
| 					/> | ||||
| 				</g> | ||||
| 			</svg> | ||||
| 		); | ||||
| 	} | ||||
|   render() { | ||||
|     return ( | ||||
|       <svg viewBox="0 0 50 62.5" preserveAspectRatio="xMidYMid"> | ||||
|         <g> | ||||
|           <path | ||||
|             fillRule="evenodd" | ||||
|             clipRule="evenodd" | ||||
|             d="M15.872,0.468c1.148,1.088,1.582,2.188,2.855,2.337l0.036,0.007c-0.588,0.606-1.089,1.402-1.443,2.423c-0.379,1.096-0.488,2.285-0.614,3.659c-0.189,2.046-0.401,4.364-1.556,7.269   c-2.486,6.258-1.119,11.631,0.332,17.317c0.664,2.604,1.348,5.297,1.642,8.107c0.035,0.355,0.287,0.652,0.633,0.744   c0.346,0.095,0.709-0.035,0.922-0.323c0.227-0.313,0.524-0.797,0.86-1.424c0.84,3.323,1.355,6.131,1.783,8.697   c0.126,0.73,1.048,0.973,1.517,0.41c2.881-3.463,3.763-8.636,2.184-12.674c0.459-2.433,1.402-4.45,2.398-6.583   c0.536-1.15,1.08-2.318,1.55-3.566c0.228-0.084,0.569-0.314,0.791-0.441l1.706-0.981l-0.256,1.052   c-0.112,0.461,0.171,0.929,0.635,1.04c0.457,0.118,0.93-0.173,1.043-0.632l0.68-2.858l1.285-2.95   c0.19-0.436-0.009-0.943-0.446-1.135c-0.44-0.189-0.947,0.01-1.135,0.448l-1.152,2.669l-2.383,1.372   c0.235-0.932,0.414-1.919,0.508-2.981c0.432-4.859-0.718-9.074-3.066-11.266c-0.163-0.157-0.208-0.281-0.247-0.26   c0.095-0.119,0.249-0.26,0.358-0.374c2.283-1.693,6.047-0.147,8.319,0.751c0.589,0.231,0.876-0.338,0.316-0.67   c-1.949-1.154-5.948-4.197-8.188-6.194c-0.313-0.275-0.527-0.607-0.89-0.913c-2.415-4.266-8.168-1.764-10.885-2.252   C15.862,0.275,15.798,0.396,15.872,0.468 M26.852,6.367c-0.059,1.242-0.603,1.8-0.999,2.208c-0.218,0.224-0.427,0.436-0.525,0.738   c-0.236,0.714,0.008,1.51,0.66,2.143c1.974,1.84,2.925,5.527,2.538,9.861c-0.291,3.287-1.448,5.762-2.671,8.384   c-1.031,2.207-2.096,4.489-2.577,7.259c-0.027,0.161-0.01,0.33,0.056,0.481c1.021,2.433,1.135,6.196-0.672,9.46   c-0.461-2.553-1.053-5.385-1.97-8.712c1.964-4.488,4.203-11.75,2.919-17.668c-0.325-1.497-1.304-3.276-2.387-4.207   c-0.208-0.179-0.402-0.237-0.495-0.167c-0.084,0.061-0.151,0.238-0.062,0.444c0.55,1.266,0.879,2.599,1.226,4.276   c1.125,5.443-0.956,12.49-2.835,16.782l-0.116,0.259l-0.457,0.982c-0.356-2.014-0.849-3.95-1.33-5.839   c-1.379-5.407-2.679-10.516-0.401-16.255c1.247-3.137,1.483-5.692,1.672-7.746c0.116-1.263,0.216-2.355,0.526-3.252   c0.905-2.605,3.062-3.178,4.744-2.852C25.328,3.262,26.936,4.539,26.852,6.367z M23.984,6.988c0.617,0.204,1.283-0.131,1.487-0.75   c0.202-0.617-0.134-1.283-0.751-1.487c-0.618-0.204-1.285,0.134-1.487,0.751C23.029,6.12,23.366,6.786,23.984,6.988z" | ||||
|           /> | ||||
|         </g> | ||||
|       </svg> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -5,28 +5,28 @@ import PropTypes from "prop-types"; | ||||
| import styles from "./menu.less"; | ||||
|  | ||||
| export default class Menu extends Component { | ||||
| 	propTypes = { items: PropTypes.array, right: PropTypes.any }; | ||||
| 	render() { | ||||
| 		const items = this.props.items; | ||||
| 		const right = this.props.right ? ( | ||||
| 			<div className={styles.right}>{this.props.right}</div> | ||||
| 		) : null; | ||||
| 		return ( | ||||
| 			<section className={styles.root}> | ||||
| 				<div className={styles.left}> | ||||
| 					{items.map(i => ( | ||||
| 						<Link | ||||
| 							key={i.to + i.label} | ||||
| 							to={i.to} | ||||
| 							exact={true} | ||||
| 							activeClassName={styles["link-active"]} | ||||
| 						> | ||||
| 							{i.label} | ||||
| 						</Link> | ||||
| 					))} | ||||
| 				</div> | ||||
| 				{right} | ||||
| 			</section> | ||||
| 		); | ||||
| 	} | ||||
|   propTypes = { items: PropTypes.array, right: PropTypes.any }; | ||||
|   render() { | ||||
|     const items = this.props.items; | ||||
|     const right = this.props.right ? ( | ||||
|       <div className={styles.right}>{this.props.right}</div> | ||||
|     ) : null; | ||||
|     return ( | ||||
|       <section className={styles.root}> | ||||
|         <div className={styles.left}> | ||||
|           {items.map(i => ( | ||||
|             <Link | ||||
|               key={i.to + i.label} | ||||
|               to={i.to} | ||||
|               exact={true} | ||||
|               activeClassName={styles["link-active"]} | ||||
|             > | ||||
|               {i.label} | ||||
|             </Link> | ||||
|           ))} | ||||
|         </div> | ||||
|         {right} | ||||
|       </section> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,38 +4,38 @@ import CloseIcon from "shared/components/icons/close"; | ||||
| import { CSSTransitionGroup } from "react-transition-group"; | ||||
|  | ||||
| export class Snackbar extends React.Component { | ||||
| 	render() { | ||||
| 		const { message } = this.props; | ||||
|   render() { | ||||
|     const { message } = this.props; | ||||
|  | ||||
| 		let classes = [styles.snackbar]; | ||||
| 		if (message) { | ||||
| 			classes.push(styles.open); | ||||
| 		} | ||||
|     let classes = [styles.snackbar]; | ||||
|     if (message) { | ||||
|       classes.push(styles.open); | ||||
|     } | ||||
|  | ||||
| 		const content = message ? ( | ||||
| 			<div className={classes.join(" ")} key={message}> | ||||
| 				<div>{message}</div> | ||||
| 				<button onClick={this.props.onClose}> | ||||
| 					<CloseIcon /> | ||||
| 				</button> | ||||
| 			</div> | ||||
| 		) : null; | ||||
|     const content = message ? ( | ||||
|       <div className={classes.join(" ")} key={message}> | ||||
|         <div>{message}</div> | ||||
|         <button onClick={this.props.onClose}> | ||||
|           <CloseIcon /> | ||||
|         </button> | ||||
|       </div> | ||||
|     ) : null; | ||||
|  | ||||
| 		return ( | ||||
| 			<CSSTransitionGroup | ||||
| 				transitionName="slideup" | ||||
| 				transitionEnterTimeout={200} | ||||
| 				transitionLeaveTimeout={200} | ||||
| 				transitionAppearTimeout={200} | ||||
| 				transitionAppear={true} | ||||
| 				transitionEnter={true} | ||||
| 				transitionLeave={true} | ||||
| 				className={classes.root} | ||||
| 			> | ||||
| 				{content} | ||||
| 			</CSSTransitionGroup> | ||||
| 		); | ||||
| 	} | ||||
|     return ( | ||||
|       <CSSTransitionGroup | ||||
|         transitionName="slideup" | ||||
|         transitionEnterTimeout={200} | ||||
|         transitionLeaveTimeout={200} | ||||
|         transitionAppearTimeout={200} | ||||
|         transitionAppear={true} | ||||
|         transitionEnter={true} | ||||
|         transitionLeave={true} | ||||
|         className={classes.root} | ||||
|       > | ||||
|         {content} | ||||
|       </CSSTransitionGroup> | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| // const SnackbarContent = ({ children, ...props }) => { | ||||
|   | ||||
| @@ -1,100 +1,100 @@ | ||||
| import React, { Component } from "react"; | ||||
| import classnames from "classnames"; | ||||
| import { | ||||
| 	STATUS_BLOCKED, | ||||
| 	STATUS_DECLINED, | ||||
| 	STATUS_ERROR, | ||||
| 	STATUS_FAILURE, | ||||
| 	STATUS_KILLED, | ||||
| 	STATUS_PENDING, | ||||
| 	STATUS_RUNNING, | ||||
| 	STATUS_SKIPPED, | ||||
| 	STATUS_STARTED, | ||||
| 	STATUS_SUCCESS, | ||||
|   STATUS_BLOCKED, | ||||
|   STATUS_DECLINED, | ||||
|   STATUS_ERROR, | ||||
|   STATUS_FAILURE, | ||||
|   STATUS_KILLED, | ||||
|   STATUS_PENDING, | ||||
|   STATUS_RUNNING, | ||||
|   STATUS_SKIPPED, | ||||
|   STATUS_STARTED, | ||||
|   STATUS_SUCCESS | ||||
| } from "shared/constants/status"; | ||||
| import style from "./status.less"; | ||||
|  | ||||
| import { | ||||
| 	CheckIcon, | ||||
| 	CloseIcon, | ||||
| 	ClockIcon, | ||||
| 	RefreshIcon, | ||||
| 	RemoveIcon, | ||||
|   CheckIcon, | ||||
|   CloseIcon, | ||||
|   ClockIcon, | ||||
|   RefreshIcon, | ||||
|   RemoveIcon | ||||
| } from "./icons/index"; | ||||
|  | ||||
| const defaultIconSize = 15; | ||||
|  | ||||
| const statusLabel = status => { | ||||
| 	switch (status) { | ||||
| 		case STATUS_BLOCKED: | ||||
| 			return "Pending Approval"; | ||||
| 		case STATUS_DECLINED: | ||||
| 			return "Declined"; | ||||
| 		case STATUS_ERROR: | ||||
| 			return "Error"; | ||||
| 		case STATUS_FAILURE: | ||||
| 			return "Failure"; | ||||
| 		case STATUS_KILLED: | ||||
| 			return "Cancelled"; | ||||
| 		case STATUS_PENDING: | ||||
| 			return "Pending"; | ||||
| 		case STATUS_RUNNING: | ||||
| 			return "Running"; | ||||
| 		case STATUS_SKIPPED: | ||||
| 			return "Skipped"; | ||||
| 		case STATUS_STARTED: | ||||
| 			return "Running"; | ||||
| 		case STATUS_SUCCESS: | ||||
| 			return "Successful"; | ||||
| 		default: | ||||
| 			return ""; | ||||
| 	} | ||||
|   switch (status) { | ||||
|     case STATUS_BLOCKED: | ||||
|       return "Pending Approval"; | ||||
|     case STATUS_DECLINED: | ||||
|       return "Declined"; | ||||
|     case STATUS_ERROR: | ||||
|       return "Error"; | ||||
|     case STATUS_FAILURE: | ||||
|       return "Failure"; | ||||
|     case STATUS_KILLED: | ||||
|       return "Cancelled"; | ||||
|     case STATUS_PENDING: | ||||
|       return "Pending"; | ||||
|     case STATUS_RUNNING: | ||||
|       return "Running"; | ||||
|     case STATUS_SKIPPED: | ||||
|       return "Skipped"; | ||||
|     case STATUS_STARTED: | ||||
|       return "Running"; | ||||
|     case STATUS_SUCCESS: | ||||
|       return "Successful"; | ||||
|     default: | ||||
|       return ""; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const renderIcon = (status, size) => { | ||||
| 	switch (status) { | ||||
| 		case STATUS_SKIPPED: | ||||
| 			return <RemoveIcon size={size} />; | ||||
| 		case STATUS_PENDING: | ||||
| 			return <ClockIcon size={size} />; | ||||
| 		case STATUS_RUNNING: | ||||
| 		case STATUS_STARTED: | ||||
| 			return <RefreshIcon size={size} />; | ||||
| 		case STATUS_SUCCESS: | ||||
| 			return <CheckIcon size={size} />; | ||||
| 		default: | ||||
| 			return <CloseIcon size={size} />; | ||||
| 	} | ||||
|   switch (status) { | ||||
|     case STATUS_SKIPPED: | ||||
|       return <RemoveIcon size={size} />; | ||||
|     case STATUS_PENDING: | ||||
|       return <ClockIcon size={size} />; | ||||
|     case STATUS_RUNNING: | ||||
|     case STATUS_STARTED: | ||||
|       return <RefreshIcon size={size} />; | ||||
|     case STATUS_SUCCESS: | ||||
|       return <CheckIcon size={size} />; | ||||
|     default: | ||||
|       return <CloseIcon size={size} />; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export default class Status extends Component { | ||||
| 	shouldComponentUpdate(nextProps, nextState) { | ||||
| 		return this.props.status !== nextProps.status; | ||||
| 	} | ||||
|   shouldComponentUpdate(nextProps, nextState) { | ||||
|     return this.props.status !== nextProps.status; | ||||
|   } | ||||
|  | ||||
| 	render() { | ||||
| 		const { status } = this.props; | ||||
| 		const icon = renderIcon(status, defaultIconSize); | ||||
| 		const classes = classnames(style.root, style[status]); | ||||
| 		return <div className={classes}>{icon}</div>; | ||||
| 	} | ||||
|   render() { | ||||
|     const { status } = this.props; | ||||
|     const icon = renderIcon(status, defaultIconSize); | ||||
|     const classes = classnames(style.root, style[status]); | ||||
|     return <div className={classes}>{icon}</div>; | ||||
|   } | ||||
| } | ||||
|  | ||||
| export const StatusLabel = ({ status }) => { | ||||
| 	return ( | ||||
| 		<div className={classnames(style.label, style[status])}> | ||||
| 			<div>{statusLabel(status)}</div> | ||||
| 		</div> | ||||
| 	); | ||||
|   return ( | ||||
|     <div className={classnames(style.label, style[status])}> | ||||
|       <div>{statusLabel(status)}</div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|  | ||||
| export const StatusText = ({ status, text }) => { | ||||
| 	return ( | ||||
| 		<div | ||||
| 			className={classnames(style.label, style[status])} | ||||
| 			style="text-transform: capitalize;padding: 5px 10px;" | ||||
| 		> | ||||
| 			<div>{text}</div> | ||||
| 		</div> | ||||
| 	); | ||||
|   return ( | ||||
|     <div | ||||
|       className={classnames(style.label, style[status])} | ||||
|       style="text-transform: capitalize;padding: 5px 10px;" | ||||
|     > | ||||
|       <div>{text}</div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -4,9 +4,9 @@ import classnames from "classnames"; | ||||
| import styles from "./status_number.less"; | ||||
|  | ||||
| export default class StatusNumber extends Component { | ||||
| 	render() { | ||||
| 		const { status, number } = this.props; | ||||
| 		const className = classnames(styles.root, styles[status]); | ||||
| 		return <div className={className}>{number}</div>; | ||||
| 	} | ||||
|   render() { | ||||
|     const { status, number } = this.props; | ||||
|     const className = classnames(styles.root, styles[status]); | ||||
|     return <div className={className}>{number}</div>; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,14 +3,14 @@ import Icon from "./icons/refresh"; | ||||
| import styles from "./sync.less"; | ||||
|  | ||||
| export const Message = () => { | ||||
| 	return ( | ||||
| 		<div className={styles.root}> | ||||
| 			<div className={styles.alert}> | ||||
| 				<div> | ||||
| 					<Icon /> | ||||
| 				</div> | ||||
| 				<div>Account synchronization in progress</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	); | ||||
|   return ( | ||||
|     <div className={styles.root}> | ||||
|       <div className={styles.alert}> | ||||
|         <div> | ||||
|           <Icon /> | ||||
|         </div> | ||||
|         <div>Account synchronization in progress</div> | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -10,14 +10,14 @@ const STATUS_STARTED = "started"; | ||||
| const STATUS_SUCCESS = "success"; | ||||
|  | ||||
| export { | ||||
| 	STATUS_BLOCKED, | ||||
| 	STATUS_DECLINED, | ||||
| 	STATUS_ERROR, | ||||
| 	STATUS_FAILURE, | ||||
| 	STATUS_KILLED, | ||||
| 	STATUS_PENDING, | ||||
| 	STATUS_RUNNING, | ||||
| 	STATUS_SKIPPED, | ||||
| 	STATUS_SUCCESS, | ||||
| 	STATUS_STARTED, | ||||
|   STATUS_BLOCKED, | ||||
|   STATUS_DECLINED, | ||||
|   STATUS_ERROR, | ||||
|   STATUS_FAILURE, | ||||
|   STATUS_KILLED, | ||||
|   STATUS_PENDING, | ||||
|   STATUS_RUNNING, | ||||
|   STATUS_SKIPPED, | ||||
|   STATUS_SUCCESS, | ||||
|   STATUS_STARTED | ||||
| }; | ||||
|   | ||||
| @@ -13,26 +13,26 @@ import { STATUS_PENDING, STATUS_RUNNING } from "shared/constants/status"; | ||||
|  * @param {number|string} number - The build number. | ||||
|  */ | ||||
| export const fetchBuild = (tree, client, owner, name, number) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	tree.unset(["builds", "loaded"]); | ||||
| 	client | ||||
| 		.getBuild(owner, name, number) | ||||
| 		.then(build => { | ||||
| 			const path = ["builds", "data", slug, build.number]; | ||||
|   tree.unset(["builds", "loaded"]); | ||||
|   client | ||||
|     .getBuild(owner, name, number) | ||||
|     .then(build => { | ||||
|       const path = ["builds", "data", slug, build.number]; | ||||
|  | ||||
| 			if (tree.exists(path)) { | ||||
| 				tree.deepMerge(path, build); | ||||
| 			} else { | ||||
| 				tree.set(path, build); | ||||
| 			} | ||||
|       if (tree.exists(path)) { | ||||
|         tree.deepMerge(path, build); | ||||
|       } else { | ||||
|         tree.set(path, build); | ||||
|       } | ||||
|  | ||||
| 			tree.set(["builds", "loaded"], true); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			tree.set(["builds", "loaded"], true); | ||||
| 			tree.set(["builds", "error"], error); | ||||
| 		}); | ||||
|       tree.set(["builds", "loaded"], true); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       tree.set(["builds", "loaded"], true); | ||||
|       tree.set(["builds", "error"], error); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -45,33 +45,33 @@ export const fetchBuild = (tree, client, owner, name, number) => { | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const fetchBuildList = (tree, client, owner, name, page = 1) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	tree.unset(["builds", "loaded"]); | ||||
| 	tree.unset(["builds", "error"]); | ||||
|   tree.unset(["builds", "loaded"]); | ||||
|   tree.unset(["builds", "error"]); | ||||
|  | ||||
| 	client | ||||
| 		.getBuildList(owner, name, { page: page }) | ||||
| 		.then(results => { | ||||
| 			let list = {}; | ||||
| 			results.map(build => { | ||||
| 				list[build.number] = build; | ||||
| 			}); | ||||
|   client | ||||
|     .getBuildList(owner, name, { page: page }) | ||||
|     .then(results => { | ||||
|       let list = {}; | ||||
|       results.map(build => { | ||||
|         list[build.number] = build; | ||||
|       }); | ||||
|  | ||||
| 			const path = ["builds", "data", slug]; | ||||
| 			if (tree.exists(path)) { | ||||
| 				tree.deepMerge(path, list); | ||||
| 			} else { | ||||
| 				tree.set(path, list); | ||||
| 			} | ||||
|       const path = ["builds", "data", slug]; | ||||
|       if (tree.exists(path)) { | ||||
|         tree.deepMerge(path, list); | ||||
|       } else { | ||||
|         tree.set(path, list); | ||||
|       } | ||||
|  | ||||
| 			tree.unset(["builds", "error"]); | ||||
| 			tree.set(["builds", "loaded"], true); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			tree.set(["builds", "error"], error); | ||||
| 			tree.set(["builds", "loaded"], true); | ||||
| 		}); | ||||
|       tree.unset(["builds", "error"]); | ||||
|       tree.set(["builds", "loaded"], true); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       tree.set(["builds", "error"], error); | ||||
|       tree.set(["builds", "loaded"], true); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -85,14 +85,14 @@ export const fetchBuildList = (tree, client, owner, name, page = 1) => { | ||||
|  * @param {number} proc - The process number. | ||||
|  */ | ||||
| export const cancelBuild = (tree, client, owner, repo, build, proc) => { | ||||
| 	client | ||||
| 		.cancelBuild(owner, repo, build, proc) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully cancelled your build"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to cancel your build"); | ||||
| 		}); | ||||
|   client | ||||
|     .cancelBuild(owner, repo, build, proc) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully cancelled your build"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to cancel your build"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -105,14 +105,14 @@ export const cancelBuild = (tree, client, owner, repo, build, proc) => { | ||||
|  * @param {number} build - The build number. | ||||
|  */ | ||||
| export const restartBuild = (tree, client, owner, repo, build) => { | ||||
| 	client | ||||
| 		.restartBuild(owner, repo, build, { fork: true }) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully restarted your build"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to restart your build"); | ||||
| 		}); | ||||
|   client | ||||
|     .restartBuild(owner, repo, build, { fork: true }) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully restarted your build"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to restart your build"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -125,14 +125,14 @@ export const restartBuild = (tree, client, owner, repo, build) => { | ||||
|  * @param {number} build - The build number. | ||||
|  */ | ||||
| export const approveBuild = (tree, client, owner, repo, build) => { | ||||
| 	client | ||||
| 		.approveBuild(owner, repo, build) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully processed your approval decision"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to process your approval decision"); | ||||
| 		}); | ||||
|   client | ||||
|     .approveBuild(owner, repo, build) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully processed your approval decision"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to process your approval decision"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -145,14 +145,14 @@ export const approveBuild = (tree, client, owner, repo, build) => { | ||||
|  * @param {number} build - The build number. | ||||
|  */ | ||||
| export const declineBuild = (tree, client, owner, repo, build) => { | ||||
| 	client | ||||
| 		.declineBuild(owner, repo, build) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully processed your decline decision"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to process your decline decision"); | ||||
| 		}); | ||||
|   client | ||||
|     .declineBuild(owner, repo, build) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully processed your decline decision"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to process your decline decision"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -163,7 +163,7 @@ export const declineBuild = (tree, client, owner, repo, build) => { | ||||
|  * @returns {number} | ||||
|  */ | ||||
| export const compareBuild = (a, b) => { | ||||
| 	return b.number - a.number; | ||||
|   return b.number - a.number; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -173,7 +173,7 @@ export const compareBuild = (a, b) => { | ||||
|  * @returns {boolean} | ||||
|  */ | ||||
| export const assertBuildFinished = build => { | ||||
| 	return build.status !== STATUS_RUNNING && build.status !== STATUS_PENDING; | ||||
|   return build.status !== STATUS_RUNNING && build.status !== STATUS_PENDING; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -183,5 +183,5 @@ export const assertBuildFinished = build => { | ||||
|  * @returns {boolean} | ||||
|  */ | ||||
| export const assertBuildMatrix = build => { | ||||
| 	return build && build.procs && build.procs.length > 1; | ||||
|   return build && build.procs && build.procs.length > 1; | ||||
| }; | ||||
|   | ||||
| @@ -6,24 +6,24 @@ | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export const fetchFeed = (tree, client) => { | ||||
| 	client | ||||
| 		.getBuildFeed({ latest: true }) | ||||
| 		.then(results => { | ||||
| 			let list = {}; | ||||
| 			let sorted = results.sort(compareFeedItem); | ||||
| 			sorted.map(repo => { | ||||
| 				list[repo.full_name] = repo; | ||||
| 			}); | ||||
| 			if (sorted && sorted.length > 0) { | ||||
| 				tree.set(["feed", "latest"], sorted[0]); | ||||
| 			} | ||||
| 			tree.set(["feed", "loaded"], true); | ||||
| 			tree.set(["feed", "data"], list); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			tree.set(["feed", "loaded"], true); | ||||
| 			tree.set(["feed", "error"], error); | ||||
| 		}); | ||||
|   client | ||||
|     .getBuildFeed({ latest: true }) | ||||
|     .then(results => { | ||||
|       let list = {}; | ||||
|       let sorted = results.sort(compareFeedItem); | ||||
|       sorted.map(repo => { | ||||
|         list[repo.full_name] = repo; | ||||
|       }); | ||||
|       if (sorted && sorted.length > 0) { | ||||
|         tree.set(["feed", "latest"], sorted[0]); | ||||
|       } | ||||
|       tree.set(["feed", "loaded"], true); | ||||
|       tree.set(["feed", "data"], list); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       tree.set(["feed", "loaded"], true); | ||||
|       tree.set(["feed", "error"], error); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -34,11 +34,11 @@ export const fetchFeed = (tree, client) => { | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export function fetchFeedOnce(tree, client) { | ||||
| 	if (fetchFeedOnce.fired) { | ||||
| 		return; | ||||
| 	} | ||||
| 	fetchFeedOnce.fired = true; | ||||
| 	return fetchFeed(tree, client); | ||||
|   if (fetchFeedOnce.fired) { | ||||
|     return; | ||||
|   } | ||||
|   fetchFeedOnce.fired = true; | ||||
|   return fetchFeed(tree, client); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -49,18 +49,18 @@ export function fetchFeedOnce(tree, client) { | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export const subscribeToFeed = (tree, client) => { | ||||
| 	return client.on(data => { | ||||
| 		const { repo, build } = data; | ||||
|   return client.on(data => { | ||||
|     const { repo, build } = data; | ||||
|  | ||||
| 		if (tree.exists("feed", "data", repo.full_name)) { | ||||
| 			const cursor = tree.select(["feed", "data", repo.full_name]); | ||||
| 			cursor.merge(build); | ||||
| 		} | ||||
|     if (tree.exists("feed", "data", repo.full_name)) { | ||||
|       const cursor = tree.select(["feed", "data", repo.full_name]); | ||||
|       cursor.merge(build); | ||||
|     } | ||||
|  | ||||
| 		if (tree.exists("builds", "data", repo.full_name)) { | ||||
| 			tree.set(["builds", "data", repo.full_name, build.number], build); | ||||
| 		} | ||||
| 	}); | ||||
|     if (tree.exists("builds", "data", repo.full_name)) { | ||||
|       tree.set(["builds", "data", repo.full_name, build.number], build); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -71,11 +71,11 @@ export const subscribeToFeed = (tree, client) => { | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export function subscribeToFeedOnce(tree, client) { | ||||
| 	if (subscribeToFeedOnce.fired) { | ||||
| 		return; | ||||
| 	} | ||||
| 	subscribeToFeedOnce.fired = true; | ||||
| 	return subscribeToFeed(tree, client); | ||||
|   if (subscribeToFeedOnce.fired) { | ||||
|     return; | ||||
|   } | ||||
|   subscribeToFeedOnce.fired = true; | ||||
|   return subscribeToFeed(tree, client); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -85,7 +85,7 @@ export function subscribeToFeedOnce(tree, client) { | ||||
|  * @returns {number} | ||||
|  */ | ||||
| export const compareFeedItem = (a, b) => { | ||||
| 	return ( | ||||
| 		(b.started_at || b.created_at || -1) - (a.started_at || a.created_at || -1) | ||||
| 	); | ||||
|   return ( | ||||
|     (b.started_at || b.created_at || -1) - (a.started_at || a.created_at || -1) | ||||
|   ); | ||||
| }; | ||||
|   | ||||
| @@ -1,41 +1,41 @@ | ||||
| import { repositorySlug } from "./repository"; | ||||
|  | ||||
| export function subscribeToLogs(tree, client, owner, repo, build, proc) { | ||||
| 	if (subscribeToLogs.ws) { | ||||
| 		subscribeToLogs.ws.close(); | ||||
| 	} | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	const init = { data: [] }; | ||||
|   if (subscribeToLogs.ws) { | ||||
|     subscribeToLogs.ws.close(); | ||||
|   } | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   const init = { data: [] }; | ||||
|  | ||||
| 	tree.set(["logs", "data", slug, build, proc.pid], init); | ||||
|   tree.set(["logs", "data", slug, build, proc.pid], init); | ||||
|  | ||||
| 	subscribeToLogs.ws = client.stream(owner, repo, build, proc.ppid, item => { | ||||
| 		if (item.proc === proc.name) { | ||||
| 			tree.push(["logs", "data", slug, build, proc.pid, "data"], item); | ||||
| 		} | ||||
| 	}); | ||||
|   subscribeToLogs.ws = client.stream(owner, repo, build, proc.ppid, item => { | ||||
|     if (item.proc === proc.name) { | ||||
|       tree.push(["logs", "data", slug, build, proc.pid, "data"], item); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| export function fetchLogs(tree, client, owner, repo, build, proc) { | ||||
| 	const slug = repositorySlug(owner, repo); | ||||
| 	const init = { | ||||
| 		data: [], | ||||
| 		loading: true, | ||||
| 	}; | ||||
|   const slug = repositorySlug(owner, repo); | ||||
|   const init = { | ||||
|     data: [], | ||||
|     loading: true | ||||
|   }; | ||||
|  | ||||
| 	tree.set(["logs", "data", slug, build, proc], init); | ||||
|   tree.set(["logs", "data", slug, build, proc], init); | ||||
|  | ||||
| 	client | ||||
| 		.getLogs(owner, repo, build, proc) | ||||
| 		.then(results => { | ||||
| 			tree.set(["logs", "data", slug, build, proc, "data"], results || []); | ||||
| 			tree.set(["logs", "data", slug, build, proc, "loading"], false); | ||||
| 			tree.set(["logs", "data", slug, build, proc, "eof"], true); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			tree.set(["logs", "data", slug, build, proc, "loading"], false); | ||||
| 			tree.set(["logs", "data", slug, build, proc, "eof"], true); | ||||
| 		}); | ||||
|   client | ||||
|     .getLogs(owner, repo, build, proc) | ||||
|     .then(results => { | ||||
|       tree.set(["logs", "data", slug, build, proc, "data"], results || []); | ||||
|       tree.set(["logs", "data", slug, build, proc, "loading"], false); | ||||
|       tree.set(["logs", "data", slug, build, proc, "eof"], true); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       tree.set(["logs", "data", slug, build, proc, "loading"], false); | ||||
|       tree.set(["logs", "data", slug, build, proc, "eof"], true); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -45,5 +45,5 @@ export function fetchLogs(tree, client, owner, repo, build, proc) { | ||||
|  * @param {boolean} follow - Follow the logs. | ||||
|  */ | ||||
| export const toggleLogs = (tree, follow) => { | ||||
| 	tree.set(["logs", "follow"], follow); | ||||
|   tree.set(["logs", "follow"], follow); | ||||
| }; | ||||
|   | ||||
| @@ -5,11 +5,11 @@ | ||||
|  * @param {string} message - The message text. | ||||
|  */ | ||||
| export const displayMessage = (tree, message) => { | ||||
| 	tree.set(["message", "text"], message); | ||||
|   tree.set(["message", "text"], message); | ||||
|  | ||||
| 	setTimeout(() => { | ||||
| 		hideMessage(tree); | ||||
| 	}, 5000); | ||||
|   setTimeout(() => { | ||||
|     hideMessage(tree); | ||||
|   }, 5000); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -18,5 +18,5 @@ export const displayMessage = (tree, message) => { | ||||
|  * @param {Object} tree - The drone state tree. | ||||
|  */ | ||||
| export const hideMessage = tree => { | ||||
| 	tree.unset(["message", "text"]); | ||||
|   tree.unset(["message", "text"]); | ||||
| }; | ||||
|   | ||||
| @@ -9,20 +9,20 @@ import { STATUS_PENDING, STATUS_RUNNING } from "shared/constants/status"; | ||||
|  * @returns {Object} | ||||
|  */ | ||||
| export const findChildProcess = (tree, pid) => { | ||||
| 	for (var i = 0; i < tree.length; i++) { | ||||
| 		const parent = tree[i]; | ||||
| 		// eslint-disable-next-line | ||||
| 		if (parent.pid == pid) { | ||||
| 			return parent; | ||||
| 		} | ||||
| 		for (var ii = 0; ii < parent.children.length; ii++) { | ||||
| 			const child = parent.children[ii]; | ||||
| 			// eslint-disable-next-line | ||||
| 			if (child.pid == pid) { | ||||
| 				return child; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   for (var i = 0; i < tree.length; i++) { | ||||
|     const parent = tree[i]; | ||||
|     // eslint-disable-next-line | ||||
|     if (parent.pid == pid) { | ||||
|       return parent; | ||||
|     } | ||||
|     for (var ii = 0; ii < parent.children.length; ii++) { | ||||
|       const child = parent.children[ii]; | ||||
|       // eslint-disable-next-line | ||||
|       if (child.pid == pid) { | ||||
|         return child; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -32,7 +32,7 @@ export const findChildProcess = (tree, pid) => { | ||||
|  * @returns {boolean} | ||||
|  */ | ||||
| export const assertProcFinished = proc => { | ||||
| 	return proc.state !== STATUS_RUNNING && proc.state !== STATUS_PENDING; | ||||
|   return proc.state !== STATUS_RUNNING && proc.state !== STATUS_PENDING; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -42,5 +42,5 @@ export const assertProcFinished = proc => { | ||||
|  * @returns {boolean} | ||||
|  */ | ||||
| export const assertProcRunning = proc => { | ||||
| 	return proc.state === STATUS_RUNNING; | ||||
|   return proc.state === STATUS_RUNNING; | ||||
| }; | ||||
|   | ||||
| @@ -11,19 +11,19 @@ import { repositorySlug } from "./repository"; | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const fetchRegistryList = (tree, client, owner, name) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	tree.unset(["registry", "loaded"]); | ||||
| 	tree.unset(["registry", "error"]); | ||||
|   tree.unset(["registry", "loaded"]); | ||||
|   tree.unset(["registry", "error"]); | ||||
|  | ||||
| 	client.getRegistryList(owner, name).then(results => { | ||||
| 		let list = {}; | ||||
| 		results.map(registry => { | ||||
| 			list[registry.address] = registry; | ||||
| 		}); | ||||
| 		tree.set(["registry", "data", slug], list); | ||||
| 		tree.set(["registry", "loaded"], true); | ||||
| 	}); | ||||
|   client.getRegistryList(owner, name).then(results => { | ||||
|     let list = {}; | ||||
|     results.map(registry => { | ||||
|       list[registry.address] = registry; | ||||
|     }); | ||||
|     tree.set(["registry", "data", slug], list); | ||||
|     tree.set(["registry", "loaded"], true); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -37,17 +37,17 @@ export const fetchRegistryList = (tree, client, owner, name) => { | ||||
|  * @param {Object} registry - The registry hostname. | ||||
|  */ | ||||
| export const createRegistry = (tree, client, owner, name, registry) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	client | ||||
| 		.createRegistry(owner, name, registry) | ||||
| 		.then(result => { | ||||
| 			tree.set(["registry", "data", slug, registry.address], result); | ||||
| 			displayMessage(tree, "Successfully stored the registry credentials"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to store the registry credentials"); | ||||
| 		}); | ||||
|   client | ||||
|     .createRegistry(owner, name, registry) | ||||
|     .then(result => { | ||||
|       tree.set(["registry", "data", slug, registry.address], result); | ||||
|       displayMessage(tree, "Successfully stored the registry credentials"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to store the registry credentials"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -61,15 +61,15 @@ export const createRegistry = (tree, client, owner, name, registry) => { | ||||
|  * @param {Object} registry - The registry hostname. | ||||
|  */ | ||||
| export const deleteRegistry = (tree, client, owner, name, registry) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	client | ||||
| 		.deleteRegistry(owner, name, registry) | ||||
| 		.then(result => { | ||||
| 			tree.unset(["registry", "data", slug, registry]); | ||||
| 			displayMessage(tree, "Successfully deleted the registry credentials"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to delete the registry credentials"); | ||||
| 		}); | ||||
|   client | ||||
|     .deleteRegistry(owner, name, registry) | ||||
|     .then(result => { | ||||
|       tree.unset(["registry", "data", slug, registry]); | ||||
|       displayMessage(tree, "Successfully deleted the registry credentials"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to delete the registry credentials"); | ||||
|     }); | ||||
| }; | ||||
|   | ||||
| @@ -11,19 +11,19 @@ import { fetchFeed } from "shared/utils/feed"; | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const fetchRepository = (tree, client, owner, name) => { | ||||
| 	tree.unset(["repo", "error"]); | ||||
| 	tree.unset(["repo", "loaded"]); | ||||
|   tree.unset(["repo", "error"]); | ||||
|   tree.unset(["repo", "loaded"]); | ||||
|  | ||||
| 	client | ||||
| 		.getRepo(owner, name) | ||||
| 		.then(repo => { | ||||
| 			tree.set(["repos", "data", repo.full_name], repo); | ||||
| 			tree.set(["repo", "loaded"], true); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			tree.set(["repo", "error"], error); | ||||
| 			tree.set(["repo", "loaded"], true); | ||||
| 		}); | ||||
|   client | ||||
|     .getRepo(owner, name) | ||||
|     .then(repo => { | ||||
|       tree.set(["repos", "data", repo.full_name], repo); | ||||
|       tree.set(["repo", "loaded"], true); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       tree.set(["repo", "error"], error); | ||||
|       tree.set(["repo", "loaded"], true); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -34,30 +34,30 @@ export const fetchRepository = (tree, client, owner, name) => { | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export const fetchRepostoryList = (tree, client) => { | ||||
| 	tree.unset(["repos", "loaded"]); | ||||
| 	tree.unset(["repos", "error"]); | ||||
|   tree.unset(["repos", "loaded"]); | ||||
|   tree.unset(["repos", "error"]); | ||||
|  | ||||
| 	client | ||||
| 		.getRepoList({ all: true }) | ||||
| 		.then(results => { | ||||
| 			let list = {}; | ||||
| 			results.map(repo => { | ||||
| 				list[repo.full_name] = repo; | ||||
| 			}); | ||||
|   client | ||||
|     .getRepoList({ all: true }) | ||||
|     .then(results => { | ||||
|       let list = {}; | ||||
|       results.map(repo => { | ||||
|         list[repo.full_name] = repo; | ||||
|       }); | ||||
|  | ||||
| 			const path = ["repos", "data"]; | ||||
| 			if (tree.exists(path)) { | ||||
| 				tree.deepMerge(path, list); | ||||
| 			} else { | ||||
| 				tree.set(path, list); | ||||
| 			} | ||||
|       const path = ["repos", "data"]; | ||||
|       if (tree.exists(path)) { | ||||
|         tree.deepMerge(path, list); | ||||
|       } else { | ||||
|         tree.set(path, list); | ||||
|       } | ||||
|  | ||||
| 			tree.set(["repos", "loaded"], true); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			tree.set(["repos", "loaded"], true); | ||||
| 			tree.set(["repos", "error"], error); | ||||
| 		}); | ||||
|       tree.set(["repos", "loaded"], true); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       tree.set(["repos", "loaded"], true); | ||||
|       tree.set(["repos", "error"], error); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -68,32 +68,32 @@ export const fetchRepostoryList = (tree, client) => { | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export const syncRepostoryList = (tree, client) => { | ||||
| 	tree.unset(["repos", "loaded"]); | ||||
| 	tree.unset(["repos", "error"]); | ||||
|   tree.unset(["repos", "loaded"]); | ||||
|   tree.unset(["repos", "error"]); | ||||
|  | ||||
| 	client | ||||
| 		.getRepoList({ all: true, flush: true }) | ||||
| 		.then(results => { | ||||
| 			let list = {}; | ||||
| 			results.map(repo => { | ||||
| 				list[repo.full_name] = repo; | ||||
| 			}); | ||||
|   client | ||||
|     .getRepoList({ all: true, flush: true }) | ||||
|     .then(results => { | ||||
|       let list = {}; | ||||
|       results.map(repo => { | ||||
|         list[repo.full_name] = repo; | ||||
|       }); | ||||
|  | ||||
| 			const path = ["repos", "data"]; | ||||
| 			if (tree.exists(path)) { | ||||
| 				tree.deepMerge(path, list); | ||||
| 			} else { | ||||
| 				tree.set(path, list); | ||||
| 			} | ||||
|       const path = ["repos", "data"]; | ||||
|       if (tree.exists(path)) { | ||||
|         tree.deepMerge(path, list); | ||||
|       } else { | ||||
|         tree.set(path, list); | ||||
|       } | ||||
|  | ||||
| 			displayMessage(tree, "Successfully synchronized your repository list"); | ||||
| 			tree.set(["repos", "loaded"], true); | ||||
| 		}) | ||||
| 		.catch(error => { | ||||
| 			displayMessage(tree, "Failed to synchronize your repository list"); | ||||
| 			tree.set(["repos", "loaded"], true); | ||||
| 			tree.set(["repos", "error"], error); | ||||
| 		}); | ||||
|       displayMessage(tree, "Successfully synchronized your repository list"); | ||||
|       tree.set(["repos", "loaded"], true); | ||||
|     }) | ||||
|     .catch(error => { | ||||
|       displayMessage(tree, "Failed to synchronize your repository list"); | ||||
|       tree.set(["repos", "loaded"], true); | ||||
|       tree.set(["repos", "error"], error); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -107,15 +107,15 @@ export const syncRepostoryList = (tree, client) => { | ||||
|  * @param {Object} data - The repository updates. | ||||
|  */ | ||||
| export const updateRepository = (tree, client, owner, name, data) => { | ||||
| 	client | ||||
| 		.updateRepo(owner, name, data) | ||||
| 		.then(repo => { | ||||
| 			tree.set(["repos", "data", repo.full_name], repo); | ||||
| 			displayMessage(tree, "Successfully updated the repository settings"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to update the repository settings"); | ||||
| 		}); | ||||
|   client | ||||
|     .updateRepo(owner, name, data) | ||||
|     .then(repo => { | ||||
|       tree.set(["repos", "data", repo.full_name], repo); | ||||
|       displayMessage(tree, "Successfully updated the repository settings"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to update the repository settings"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -128,16 +128,16 @@ export const updateRepository = (tree, client, owner, name, data) => { | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const enableRepository = (tree, client, owner, name) => { | ||||
| 	client | ||||
| 		.activateRepo(owner, name) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully activated your repository"); | ||||
| 			tree.set(["repos", "data", result.full_name, "active"], true); | ||||
| 			fetchFeed(tree, client); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to activate your repository"); | ||||
| 		}); | ||||
|   client | ||||
|     .activateRepo(owner, name) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully activated your repository"); | ||||
|       tree.set(["repos", "data", result.full_name, "active"], true); | ||||
|       fetchFeed(tree, client); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to activate your repository"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -150,16 +150,16 @@ export const enableRepository = (tree, client, owner, name) => { | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const disableRepository = (tree, client, owner, name) => { | ||||
| 	client | ||||
| 		.deleteRepo(owner, name) | ||||
| 		.then(result => { | ||||
| 			displayMessage(tree, "Successfully disabled your repository"); | ||||
| 			tree.set(["repos", "data", result.full_name, "active"], false); | ||||
| 			fetchFeed(tree, client); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to disabled your repository"); | ||||
| 		}); | ||||
|   client | ||||
|     .deleteRepo(owner, name) | ||||
|     .then(result => { | ||||
|       displayMessage(tree, "Successfully disabled your repository"); | ||||
|       tree.set(["repos", "data", result.full_name, "active"], false); | ||||
|       fetchFeed(tree, client); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to disabled your repository"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -170,9 +170,9 @@ export const disableRepository = (tree, client, owner, name) => { | ||||
|  * @returns {number} | ||||
|  */ | ||||
| export const compareRepository = (a, b) => { | ||||
| 	if (a.full_name < b.full_name) return -1; | ||||
| 	if (a.full_name > b.full_name) return 1; | ||||
| 	return 0; | ||||
|   if (a.full_name < b.full_name) return -1; | ||||
|   if (a.full_name > b.full_name) return 1; | ||||
|   return 0; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -182,5 +182,5 @@ export const compareRepository = (a, b) => { | ||||
|  * @param {string} name - The process name. | ||||
|  */ | ||||
| export const repositorySlug = (owner, name) => { | ||||
| 	return `${owner}/${name}`; | ||||
|   return `${owner}/${name}`; | ||||
| }; | ||||
|   | ||||
| @@ -11,19 +11,19 @@ import { repositorySlug } from "./repository"; | ||||
|  * @param {string} name - The repository name. | ||||
|  */ | ||||
| export const fetchSecretList = (tree, client, owner, name) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	tree.unset(["secrets", "loaded"]); | ||||
| 	tree.unset(["secrets", "error"]); | ||||
|   tree.unset(["secrets", "loaded"]); | ||||
|   tree.unset(["secrets", "error"]); | ||||
|  | ||||
| 	client.getSecretList(owner, name).then(results => { | ||||
| 		let list = {}; | ||||
| 		results.map(secret => { | ||||
| 			list[secret.name] = secret; | ||||
| 		}); | ||||
| 		tree.set(["secrets", "data", slug], list); | ||||
| 		tree.set(["secrets", "loaded"], true); | ||||
| 	}); | ||||
|   client.getSecretList(owner, name).then(results => { | ||||
|     let list = {}; | ||||
|     results.map(secret => { | ||||
|       list[secret.name] = secret; | ||||
|     }); | ||||
|     tree.set(["secrets", "data", slug], list); | ||||
|     tree.set(["secrets", "loaded"], true); | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -37,17 +37,17 @@ export const fetchSecretList = (tree, client, owner, name) => { | ||||
|  * @param {Object} secret - The secret object. | ||||
|  */ | ||||
| export const createSecret = (tree, client, owner, name, secret) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	client | ||||
| 		.createSecret(owner, name, secret) | ||||
| 		.then(result => { | ||||
| 			tree.set(["secrets", "data", slug, secret.name], result); | ||||
| 			displayMessage(tree, "Successfully added the secret"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to create the secret"); | ||||
| 		}); | ||||
|   client | ||||
|     .createSecret(owner, name, secret) | ||||
|     .then(result => { | ||||
|       tree.set(["secrets", "data", slug, secret.name], result); | ||||
|       displayMessage(tree, "Successfully added the secret"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to create the secret"); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -61,15 +61,15 @@ export const createSecret = (tree, client, owner, name, secret) => { | ||||
|  * @param {string} secret - The secret name. | ||||
|  */ | ||||
| export const deleteSecret = (tree, client, owner, name, secret) => { | ||||
| 	const slug = repositorySlug(owner, name); | ||||
|   const slug = repositorySlug(owner, name); | ||||
|  | ||||
| 	client | ||||
| 		.deleteSecret(owner, name, secret) | ||||
| 		.then(result => { | ||||
| 			tree.unset(["secrets", "data", slug, secret]); | ||||
| 			displayMessage(tree, "Successfully removed the secret"); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to remove the secret"); | ||||
| 		}); | ||||
|   client | ||||
|     .deleteSecret(owner, name, secret) | ||||
|     .then(result => { | ||||
|       tree.unset(["secrets", "data", slug, secret]); | ||||
|       displayMessage(tree, "Successfully removed the secret"); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to remove the secret"); | ||||
|     }); | ||||
| }; | ||||
|   | ||||
| @@ -1,19 +1,19 @@ | ||||
| import { displayMessage } from "./message"; | ||||
|  | ||||
| /** | ||||
| * Generates a personal access token and stores the results in | ||||
| * the state tree. | ||||
|  * Generates a personal access token and stores the results in | ||||
|  * the state tree. | ||||
|  * | ||||
|  * @param {Object} tree - The drone state tree. | ||||
|  * @param {Object} client - The drone client. | ||||
|  */ | ||||
| export const generateToken = (tree, client) => { | ||||
| 	client | ||||
| 		.getToken() | ||||
| 		.then(token => { | ||||
| 			tree.set(["token"], token); | ||||
| 		}) | ||||
| 		.catch(() => { | ||||
| 			displayMessage(tree, "Failed to retrieve your personal access token"); | ||||
| 		}); | ||||
|   client | ||||
|     .getToken() | ||||
|     .then(token => { | ||||
|       tree.set(["token"], token); | ||||
|     }) | ||||
|     .catch(() => { | ||||
|       displayMessage(tree, "Failed to retrieve your personal access token"); | ||||
|     }); | ||||
| }; | ||||
|   | ||||
							
								
								
									
										713
									
								
								web/vendor/drone-js/index.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										713
									
								
								web/vendor/drone-js/index.js
									
									
									
									
										vendored
									
									
								
							| @@ -1,306 +1,431 @@ | ||||
| (function (global, factory) { | ||||
| 	if (typeof define === "function" && define.amd) { | ||||
| 		define(["exports"], factory); | ||||
| 	} else if (typeof exports !== "undefined") { | ||||
| 		factory(exports); | ||||
| 	} else { | ||||
| 		var mod = { | ||||
| 			exports: {} | ||||
| 		}; | ||||
| 		factory(mod.exports); | ||||
| 		global.index = mod.exports; | ||||
| 	} | ||||
| })(this, function (exports) { | ||||
| 	"use strict"; | ||||
| (function(global, factory) { | ||||
|   if (typeof define === "function" && define.amd) { | ||||
|     define(["exports"], factory); | ||||
|   } else if (typeof exports !== "undefined") { | ||||
|     factory(exports); | ||||
|   } else { | ||||
|     var mod = { | ||||
|       exports: {} | ||||
|     }; | ||||
|     factory(mod.exports); | ||||
|     global.index = mod.exports; | ||||
|   } | ||||
| })(this, function(exports) { | ||||
|   "use strict"; | ||||
|  | ||||
| 	Object.defineProperty(exports, "__esModule", { | ||||
| 		value: true | ||||
| 	}); | ||||
|   Object.defineProperty(exports, "__esModule", { | ||||
|     value: true | ||||
|   }); | ||||
|  | ||||
| 	function _classCallCheck(instance, Constructor) { | ||||
| 		if (!(instance instanceof Constructor)) { | ||||
| 			throw new TypeError("Cannot call a class as a function"); | ||||
| 		} | ||||
| 	} | ||||
|   function _classCallCheck(instance, Constructor) { | ||||
|     if (!(instance instanceof Constructor)) { | ||||
|       throw new TypeError("Cannot call a class as a function"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| 	var _createClass = function () { | ||||
| 		function defineProperties(target, props) { | ||||
| 			for (var i = 0; i < props.length; i++) { | ||||
| 				var descriptor = props[i]; | ||||
| 				descriptor.enumerable = descriptor.enumerable || false; | ||||
| 				descriptor.configurable = true; | ||||
| 				if ("value" in descriptor) descriptor.writable = true; | ||||
| 				Object.defineProperty(target, descriptor.key, descriptor); | ||||
| 			} | ||||
| 		} | ||||
|   var _createClass = (function() { | ||||
|     function defineProperties(target, props) { | ||||
|       for (var i = 0; i < props.length; i++) { | ||||
|         var descriptor = props[i]; | ||||
|         descriptor.enumerable = descriptor.enumerable || false; | ||||
|         descriptor.configurable = true; | ||||
|         if ("value" in descriptor) descriptor.writable = true; | ||||
|         Object.defineProperty(target, descriptor.key, descriptor); | ||||
|       } | ||||
|     } | ||||
|  | ||||
| 		return function (Constructor, protoProps, staticProps) { | ||||
| 			if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||||
| 			if (staticProps) defineProperties(Constructor, staticProps); | ||||
| 			return Constructor; | ||||
| 		}; | ||||
| 	}(); | ||||
|     return function(Constructor, protoProps, staticProps) { | ||||
|       if (protoProps) defineProperties(Constructor.prototype, protoProps); | ||||
|       if (staticProps) defineProperties(Constructor, staticProps); | ||||
|       return Constructor; | ||||
|     }; | ||||
|   })(); | ||||
|  | ||||
| 	var DroneClient = function () { | ||||
| 		function DroneClient(server, token, csrf) { | ||||
| 			_classCallCheck(this, DroneClient); | ||||
|   var DroneClient = (function() { | ||||
|     function DroneClient(server, token, csrf) { | ||||
|       _classCallCheck(this, DroneClient); | ||||
|  | ||||
| 			this.server = server || ""; | ||||
| 			this.token = token; | ||||
| 			this.csrf = csrf; | ||||
| 		} | ||||
|       this.server = server || ""; | ||||
|       this.token = token; | ||||
|       this.csrf = csrf; | ||||
|     } | ||||
|  | ||||
| 		_createClass(DroneClient, [{ | ||||
| 			key: "getRepoList", | ||||
| 			value: function getRepoList(opts) { | ||||
| 				var query = encodeQueryString(opts); | ||||
| 				return this._get("/api/user/repos?" + query); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getRepo", | ||||
| 			value: function getRepo(owner, repo) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "activateRepo", | ||||
| 			value: function activateRepo(owner, repo) { | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "updateRepo", | ||||
| 			value: function updateRepo(owner, repo, data) { | ||||
| 				return this._patch("/api/repos/" + owner + "/" + repo, data); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "deleteRepo", | ||||
| 			value: function deleteRepo(owner, repo) { | ||||
| 				return this._delete("/api/repos/" + owner + "/" + repo); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getBuildList", | ||||
| 			value: function getBuildList(owner, repo, opts) { | ||||
| 				var query = encodeQueryString(opts); | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/builds?" + query); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getBuild", | ||||
| 			value: function getBuild(owner, repo, number) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/builds/" + number); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getBuildFeed", | ||||
| 			value: function getBuildFeed(opts) { | ||||
| 				var query = encodeQueryString(opts); | ||||
| 				return this._get("/api/user/feed?" + query); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "cancelBuild", | ||||
| 			value: function cancelBuild(owner, repo, number, ppid) { | ||||
| 				return this._delete("/api/repos/" + owner + "/" + repo + "/builds/" + number + "/" + ppid); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "approveBuild", | ||||
| 			value: function approveBuild(owner, repo, build) { | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo + "/builds/" + build + "/approve"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "declineBuild", | ||||
| 			value: function declineBuild(owner, repo, build) { | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo + "/builds/" + build + "/decline"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "restartBuild", | ||||
| 			value: function restartBuild(owner, repo, build, opts) { | ||||
| 				var query = encodeQueryString(opts); | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo + "/builds/" + build + "?" + query); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getLogs", | ||||
| 			value: function getLogs(owner, repo, build, proc) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/logs/" + build + "/" + proc); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getArtifact", | ||||
| 			value: function getArtifact(owner, repo, build, proc, file) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/files/" + build + "/" + proc + "/" + file + "?raw=true"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getArtifactList", | ||||
| 			value: function getArtifactList(owner, repo, build) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/files/" + build); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getSecretList", | ||||
| 			value: function getSecretList(owner, repo) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/secrets"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "createSecret", | ||||
| 			value: function createSecret(owner, repo, secret) { | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo + "/secrets", secret); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "deleteSecret", | ||||
| 			value: function deleteSecret(owner, repo, secret) { | ||||
| 				return this._delete("/api/repos/" + owner + "/" + repo + "/secrets/" + secret); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getRegistryList", | ||||
| 			value: function getRegistryList(owner, repo) { | ||||
| 				return this._get("/api/repos/" + owner + "/" + repo + "/registry"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "createRegistry", | ||||
| 			value: function createRegistry(owner, repo, registry) { | ||||
| 				return this._post("/api/repos/" + owner + "/" + repo + "/registry", registry); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "deleteRegistry", | ||||
| 			value: function deleteRegistry(owner, repo, address) { | ||||
| 				return this._delete("/api/repos/" + owner + "/" + repo + "/registry/" + address); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getSelf", | ||||
| 			value: function getSelf() { | ||||
| 				return this._get("/api/user"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "getToken", | ||||
| 			value: function getToken() { | ||||
| 				return this._post("/api/user/token"); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "on", | ||||
| 			value: function on(callback) { | ||||
| 				return this._subscribe("/stream/events", callback, { | ||||
| 					reconnect: true | ||||
| 				}); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "stream", | ||||
| 			value: function stream(owner, repo, build, proc, callback) { | ||||
| 				return this._subscribe("/stream/logs/" + owner + "/" + repo + "/" + build + "/" + proc, callback, { | ||||
| 					reconnect: false | ||||
| 				}); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_get", | ||||
| 			value: function _get(path) { | ||||
| 				return this._request("GET", path, null); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_post", | ||||
| 			value: function _post(path, data) { | ||||
| 				return this._request("POST", path, data); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_patch", | ||||
| 			value: function _patch(path, data) { | ||||
| 				return this._request("PATCH", path, data); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_delete", | ||||
| 			value: function _delete(path) { | ||||
| 				return this._request("DELETE", path, null); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_subscribe", | ||||
| 			value: function _subscribe(path, callback, opts) { | ||||
| 				var query = encodeQueryString({ | ||||
| 					access_token: this.token | ||||
| 				}); | ||||
| 				path = this.server ? this.server + path : path; | ||||
| 				path = this.token ? path + "?" + query : path; | ||||
|     _createClass( | ||||
|       DroneClient, | ||||
|       [ | ||||
|         { | ||||
|           key: "getRepoList", | ||||
|           value: function getRepoList(opts) { | ||||
|             var query = encodeQueryString(opts); | ||||
|             return this._get("/api/user/repos?" + query); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getRepo", | ||||
|           value: function getRepo(owner, repo) { | ||||
|             return this._get("/api/repos/" + owner + "/" + repo); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "activateRepo", | ||||
|           value: function activateRepo(owner, repo) { | ||||
|             return this._post("/api/repos/" + owner + "/" + repo); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "updateRepo", | ||||
|           value: function updateRepo(owner, repo, data) { | ||||
|             return this._patch("/api/repos/" + owner + "/" + repo, data); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "deleteRepo", | ||||
|           value: function deleteRepo(owner, repo) { | ||||
|             return this._delete("/api/repos/" + owner + "/" + repo); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getBuildList", | ||||
|           value: function getBuildList(owner, repo, opts) { | ||||
|             var query = encodeQueryString(opts); | ||||
|             return this._get( | ||||
|               "/api/repos/" + owner + "/" + repo + "/builds?" + query | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getBuild", | ||||
|           value: function getBuild(owner, repo, number) { | ||||
|             return this._get( | ||||
|               "/api/repos/" + owner + "/" + repo + "/builds/" + number | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getBuildFeed", | ||||
|           value: function getBuildFeed(opts) { | ||||
|             var query = encodeQueryString(opts); | ||||
|             return this._get("/api/user/feed?" + query); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "cancelBuild", | ||||
|           value: function cancelBuild(owner, repo, number, ppid) { | ||||
|             return this._delete( | ||||
|               "/api/repos/" + | ||||
|                 owner + | ||||
|                 "/" + | ||||
|                 repo + | ||||
|                 "/builds/" + | ||||
|                 number + | ||||
|                 "/" + | ||||
|                 ppid | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "approveBuild", | ||||
|           value: function approveBuild(owner, repo, build) { | ||||
|             return this._post( | ||||
|               "/api/repos/" + | ||||
|                 owner + | ||||
|                 "/" + | ||||
|                 repo + | ||||
|                 "/builds/" + | ||||
|                 build + | ||||
|                 "/approve" | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "declineBuild", | ||||
|           value: function declineBuild(owner, repo, build) { | ||||
|             return this._post( | ||||
|               "/api/repos/" + | ||||
|                 owner + | ||||
|                 "/" + | ||||
|                 repo + | ||||
|                 "/builds/" + | ||||
|                 build + | ||||
|                 "/decline" | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "restartBuild", | ||||
|           value: function restartBuild(owner, repo, build, opts) { | ||||
|             var query = encodeQueryString(opts); | ||||
|             return this._post( | ||||
|               "/api/repos/" + | ||||
|                 owner + | ||||
|                 "/" + | ||||
|                 repo + | ||||
|                 "/builds/" + | ||||
|                 build + | ||||
|                 "?" + | ||||
|                 query | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getLogs", | ||||
|           value: function getLogs(owner, repo, build, proc) { | ||||
|             return this._get( | ||||
|               "/api/repos/" + owner + "/" + repo + "/logs/" + build + "/" + proc | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getArtifact", | ||||
|           value: function getArtifact(owner, repo, build, proc, file) { | ||||
|             return this._get( | ||||
|               "/api/repos/" + | ||||
|                 owner + | ||||
|                 "/" + | ||||
|                 repo + | ||||
|                 "/files/" + | ||||
|                 build + | ||||
|                 "/" + | ||||
|                 proc + | ||||
|                 "/" + | ||||
|                 file + | ||||
|                 "?raw=true" | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getArtifactList", | ||||
|           value: function getArtifactList(owner, repo, build) { | ||||
|             return this._get( | ||||
|               "/api/repos/" + owner + "/" + repo + "/files/" + build | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getSecretList", | ||||
|           value: function getSecretList(owner, repo) { | ||||
|             return this._get("/api/repos/" + owner + "/" + repo + "/secrets"); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "createSecret", | ||||
|           value: function createSecret(owner, repo, secret) { | ||||
|             return this._post( | ||||
|               "/api/repos/" + owner + "/" + repo + "/secrets", | ||||
|               secret | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "deleteSecret", | ||||
|           value: function deleteSecret(owner, repo, secret) { | ||||
|             return this._delete( | ||||
|               "/api/repos/" + owner + "/" + repo + "/secrets/" + secret | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getRegistryList", | ||||
|           value: function getRegistryList(owner, repo) { | ||||
|             return this._get("/api/repos/" + owner + "/" + repo + "/registry"); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "createRegistry", | ||||
|           value: function createRegistry(owner, repo, registry) { | ||||
|             return this._post( | ||||
|               "/api/repos/" + owner + "/" + repo + "/registry", | ||||
|               registry | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "deleteRegistry", | ||||
|           value: function deleteRegistry(owner, repo, address) { | ||||
|             return this._delete( | ||||
|               "/api/repos/" + owner + "/" + repo + "/registry/" + address | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getSelf", | ||||
|           value: function getSelf() { | ||||
|             return this._get("/api/user"); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "getToken", | ||||
|           value: function getToken() { | ||||
|             return this._post("/api/user/token"); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "on", | ||||
|           value: function on(callback) { | ||||
|             return this._subscribe("/stream/events", callback, { | ||||
|               reconnect: true | ||||
|             }); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "stream", | ||||
|           value: function stream(owner, repo, build, proc, callback) { | ||||
|             return this._subscribe( | ||||
|               "/stream/logs/" + owner + "/" + repo + "/" + build + "/" + proc, | ||||
|               callback, | ||||
|               { | ||||
|                 reconnect: false | ||||
|               } | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_get", | ||||
|           value: function _get(path) { | ||||
|             return this._request("GET", path, null); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_post", | ||||
|           value: function _post(path, data) { | ||||
|             return this._request("POST", path, data); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_patch", | ||||
|           value: function _patch(path, data) { | ||||
|             return this._request("PATCH", path, data); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_delete", | ||||
|           value: function _delete(path) { | ||||
|             return this._request("DELETE", path, null); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_subscribe", | ||||
|           value: function _subscribe(path, callback, opts) { | ||||
|             var query = encodeQueryString({ | ||||
|               access_token: this.token | ||||
|             }); | ||||
|             path = this.server ? this.server + path : path; | ||||
|             path = this.token ? path + "?" + query : path; | ||||
|  | ||||
| 				var events = new EventSource(path); | ||||
| 				events.onmessage = function (event) { | ||||
| 					var data = JSON.parse(event.data); | ||||
| 					callback(data); | ||||
| 				}; | ||||
| 				if (!opts.reconnect) { | ||||
| 					events.onerror = function (err) { | ||||
| 						if (err.data === "eof") { | ||||
| 							events.close(); | ||||
| 						} | ||||
| 					}; | ||||
| 				} | ||||
| 				return events; | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "_request", | ||||
| 			value: function _request(method, path, data) { | ||||
| 				var endpoint = [this.server, path].join(""); | ||||
| 				var xhr = new XMLHttpRequest(); | ||||
| 				xhr.open(method, endpoint, true); | ||||
| 				if (this.token) { | ||||
| 					xhr.setRequestHeader("Authorization", "Bearer " + this.token); | ||||
| 				} | ||||
| 				if (method !== "GET" && this.csrf) { | ||||
| 					xhr.setRequestHeader("X-CSRF-TOKEN", this.csrf); | ||||
| 				} | ||||
| 				return new Promise(function (resolve, reject) { | ||||
| 					xhr.onload = function () { | ||||
| 						if (xhr.readyState === 4) { | ||||
| 							if (xhr.status >= 300) { | ||||
| 								var error = { | ||||
| 									status: xhr.status, | ||||
| 									message: xhr.response | ||||
| 								}; | ||||
| 								if (this.onerror) { | ||||
| 									this.onerror(error); | ||||
| 								} | ||||
| 								reject(error); | ||||
| 								return; | ||||
| 							} | ||||
| 							var contentType = xhr.getResponseHeader("Content-Type"); | ||||
| 							if (contentType && contentType.startsWith("application/json")) { | ||||
| 								resolve(JSON.parse(xhr.response)); | ||||
| 							} else { | ||||
| 								resolve(xhr.response); | ||||
| 							} | ||||
| 						} | ||||
| 					}.bind(this); | ||||
| 					xhr.onerror = function (e) { | ||||
| 						reject(e); | ||||
| 					}; | ||||
| 					if (data) { | ||||
| 						xhr.setRequestHeader("Content-Type", "application/json"); | ||||
| 						xhr.send(JSON.stringify(data)); | ||||
| 					} else { | ||||
| 						xhr.send(); | ||||
| 					} | ||||
| 				}.bind(this)); | ||||
| 			} | ||||
| 		}], [{ | ||||
| 			key: "fromEnviron", | ||||
| 			value: function fromEnviron() { | ||||
| 				return new DroneClient(process && process.env && process.env.DRONE_SERVER, process && process.env && process.env.DRONE_TOKEN, process && process.env && process.env.DRONE_CSRF); | ||||
| 			} | ||||
| 		}, { | ||||
| 			key: "fromWindow", | ||||
| 			value: function fromWindow() { | ||||
| 				return new DroneClient(window && window.DRONE_SERVER, window && window.DRONE_TOKEN, window && window.DRONE_CSRF); | ||||
| 			} | ||||
| 		}]); | ||||
|             var events = new EventSource(path); | ||||
|             events.onmessage = function(event) { | ||||
|               var data = JSON.parse(event.data); | ||||
|               callback(data); | ||||
|             }; | ||||
|             if (!opts.reconnect) { | ||||
|               events.onerror = function(err) { | ||||
|                 if (err.data === "eof") { | ||||
|                   events.close(); | ||||
|                 } | ||||
|               }; | ||||
|             } | ||||
|             return events; | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "_request", | ||||
|           value: function _request(method, path, data) { | ||||
|             var endpoint = [this.server, path].join(""); | ||||
|             var xhr = new XMLHttpRequest(); | ||||
|             xhr.open(method, endpoint, true); | ||||
|             if (this.token) { | ||||
|               xhr.setRequestHeader("Authorization", "Bearer " + this.token); | ||||
|             } | ||||
|             if (method !== "GET" && this.csrf) { | ||||
|               xhr.setRequestHeader("X-CSRF-TOKEN", this.csrf); | ||||
|             } | ||||
|             return new Promise( | ||||
|               function(resolve, reject) { | ||||
|                 xhr.onload = function() { | ||||
|                   if (xhr.readyState === 4) { | ||||
|                     if (xhr.status >= 300) { | ||||
|                       var error = { | ||||
|                         status: xhr.status, | ||||
|                         message: xhr.response | ||||
|                       }; | ||||
|                       if (this.onerror) { | ||||
|                         this.onerror(error); | ||||
|                       } | ||||
|                       reject(error); | ||||
|                       return; | ||||
|                     } | ||||
|                     var contentType = xhr.getResponseHeader("Content-Type"); | ||||
|                     if ( | ||||
|                       contentType && | ||||
|                       contentType.startsWith("application/json") | ||||
|                     ) { | ||||
|                       resolve(JSON.parse(xhr.response)); | ||||
|                     } else { | ||||
|                       resolve(xhr.response); | ||||
|                     } | ||||
|                   } | ||||
|                 }.bind(this); | ||||
|                 xhr.onerror = function(e) { | ||||
|                   reject(e); | ||||
|                 }; | ||||
|                 if (data) { | ||||
|                   xhr.setRequestHeader("Content-Type", "application/json"); | ||||
|                   xhr.send(JSON.stringify(data)); | ||||
|                 } else { | ||||
|                   xhr.send(); | ||||
|                 } | ||||
|               }.bind(this) | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|       ], | ||||
|       [ | ||||
|         { | ||||
|           key: "fromEnviron", | ||||
|           value: function fromEnviron() { | ||||
|             return new DroneClient( | ||||
|               process && process.env && process.env.DRONE_SERVER, | ||||
|               process && process.env && process.env.DRONE_TOKEN, | ||||
|               process && process.env && process.env.DRONE_CSRF | ||||
|             ); | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           key: "fromWindow", | ||||
|           value: function fromWindow() { | ||||
|             return new DroneClient( | ||||
|               window && window.DRONE_SERVER, | ||||
|               window && window.DRONE_TOKEN, | ||||
|               window && window.DRONE_CSRF | ||||
|             ); | ||||
|           } | ||||
|         } | ||||
|       ] | ||||
|     ); | ||||
|  | ||||
| 		return DroneClient; | ||||
| 	}(); | ||||
|     return DroneClient; | ||||
|   })(); | ||||
|  | ||||
| 	exports.default = DroneClient; | ||||
|   exports.default = DroneClient; | ||||
|  | ||||
|   /** | ||||
|    * Encodes the values into url encoded form sorted by key. | ||||
|    * | ||||
|    * @param {object} query parameters in key value object. | ||||
|    * @return {string} query parameter string | ||||
|    */ | ||||
|   var encodeQueryString = (exports.encodeQueryString = function encodeQueryString() { | ||||
|     var params = | ||||
|       arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||||
|  | ||||
| 	/** | ||||
|   * Encodes the values into url encoded form sorted by key. | ||||
|   * | ||||
|   * @param {object} query parameters in key value object. | ||||
|   * @return {string} query parameter string | ||||
|   */ | ||||
| 	var encodeQueryString = exports.encodeQueryString = function encodeQueryString() { | ||||
| 		var params = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||||
|  | ||||
| 		return params ? Object.keys(params).sort().map(function (key) { | ||||
| 			var val = params[key]; | ||||
| 			return encodeURIComponent(key) + "=" + encodeURIComponent(val); | ||||
| 		}).join("&") : ""; | ||||
| 	}; | ||||
| }); | ||||
|     return params | ||||
|       ? Object.keys(params) | ||||
|           .sort() | ||||
|           .map(function(key) { | ||||
|             var val = params[key]; | ||||
|             return encodeURIComponent(key) + "=" + encodeURIComponent(val); | ||||
|           }) | ||||
|           .join("&") | ||||
|       : ""; | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -7,154 +7,154 @@ var HtmlWebpackPlugin = require("html-webpack-plugin"); | ||||
| const ENV = process.env.NODE_ENV || "development"; | ||||
|  | ||||
| module.exports = { | ||||
| 	entry: { | ||||
| 		app: "./src", | ||||
| 		vendor: [ | ||||
| 			"ansi_up", | ||||
| 			"babel-polyfill", | ||||
| 			"baobab", | ||||
| 			"baobab-react", | ||||
| 			"classnames", | ||||
| 			"drone-js", | ||||
| 			"humanize-duration", | ||||
| 			"preact", | ||||
| 			"preact-compat", | ||||
| 			"query-string", | ||||
| 			"react-router", | ||||
| 			"react-router-dom", | ||||
| 			"react-screen-size", | ||||
| 			"react-timeago", | ||||
| 			"react-title-component", | ||||
| 			"react-transition-group" | ||||
| 		] | ||||
| 	}, | ||||
|   entry: { | ||||
|     app: "./src", | ||||
|     vendor: [ | ||||
|       "ansi_up", | ||||
|       "babel-polyfill", | ||||
|       "baobab", | ||||
|       "baobab-react", | ||||
|       "classnames", | ||||
|       "drone-js", | ||||
|       "humanize-duration", | ||||
|       "preact", | ||||
|       "preact-compat", | ||||
|       "query-string", | ||||
|       "react-router", | ||||
|       "react-router-dom", | ||||
|       "react-screen-size", | ||||
|       "react-timeago", | ||||
|       "react-title-component", | ||||
|       "react-transition-group" | ||||
|     ] | ||||
|   }, | ||||
|  | ||||
| 	// where to dump the output of a production build | ||||
| 	output: { | ||||
| 		publicPath: "/", | ||||
| 		path: path.join(__dirname, "dist/files"), | ||||
| 		filename: "static/bundle.[chunkhash].js" | ||||
| 	}, | ||||
|   // where to dump the output of a production build | ||||
|   output: { | ||||
|     publicPath: "/", | ||||
|     path: path.join(__dirname, "dist/files"), | ||||
|     filename: "static/bundle.[chunkhash].js" | ||||
|   }, | ||||
|  | ||||
| 	resolve: { | ||||
| 		alias: { | ||||
| 			client: path.resolve(__dirname, "src/client/"), | ||||
| 			config: path.resolve(__dirname, "src/config/"), | ||||
| 			components: path.resolve(__dirname, "src/components/"), | ||||
| 			layouts: path.resolve(__dirname, "src/layouts/"), | ||||
| 			pages: path.resolve(__dirname, "src/pages/"), | ||||
| 			screens: path.resolve(__dirname, "src/screens/"), | ||||
| 			shared: path.resolve(__dirname, "src/shared/"), | ||||
|   resolve: { | ||||
|     alias: { | ||||
|       client: path.resolve(__dirname, "src/client/"), | ||||
|       config: path.resolve(__dirname, "src/config/"), | ||||
|       components: path.resolve(__dirname, "src/components/"), | ||||
|       layouts: path.resolve(__dirname, "src/layouts/"), | ||||
|       pages: path.resolve(__dirname, "src/pages/"), | ||||
|       screens: path.resolve(__dirname, "src/screens/"), | ||||
|       shared: path.resolve(__dirname, "src/shared/"), | ||||
|  | ||||
| 			react: "preact-compat/dist/preact-compat", | ||||
| 			"react-dom": "preact-compat/dist/preact-compat", | ||||
| 			"create-react-class": "preact-compat/lib/create-react-class" | ||||
| 		} | ||||
| 	}, | ||||
|       react: "preact-compat/dist/preact-compat", | ||||
|       "react-dom": "preact-compat/dist/preact-compat", | ||||
|       "create-react-class": "preact-compat/lib/create-react-class" | ||||
|     } | ||||
|   }, | ||||
|  | ||||
| 	module: { | ||||
| 		rules: [ | ||||
| 			{ | ||||
| 				test: /\.jsx?/i, | ||||
| 				exclude: /node_modules/, | ||||
| 				loader: "babel-loader" | ||||
| 			}, | ||||
|   module: { | ||||
|     rules: [ | ||||
|       { | ||||
|         test: /\.jsx?/i, | ||||
|         exclude: /node_modules/, | ||||
|         loader: "babel-loader" | ||||
|       }, | ||||
|  | ||||
| 			{ | ||||
| 				test: /\.(less|css)$/, | ||||
| 				loader: "style-loader" | ||||
| 			}, | ||||
|       { | ||||
|         test: /\.(less|css)$/, | ||||
|         loader: "style-loader" | ||||
|       }, | ||||
|  | ||||
| 			{ | ||||
| 				test: /\.(less|css)$/, | ||||
| 				loader: "css-loader", | ||||
| 				query: { | ||||
| 					modules: true, | ||||
| 					localIdentName: "[name]__[local]___[hash:base64:5]" | ||||
| 				} | ||||
| 			}, | ||||
|       { | ||||
|         test: /\.(less|css)$/, | ||||
|         loader: "css-loader", | ||||
|         query: { | ||||
|           modules: true, | ||||
|           localIdentName: "[name]__[local]___[hash:base64:5]" | ||||
|         } | ||||
|       }, | ||||
|  | ||||
| 			{ | ||||
| 				test: /\.(less|css)$/, | ||||
| 				loader: "less-loader" | ||||
| 			} | ||||
| 		] | ||||
| 	}, | ||||
|       { | ||||
|         test: /\.(less|css)$/, | ||||
|         loader: "less-loader" | ||||
|       } | ||||
|     ] | ||||
|   }, | ||||
|  | ||||
| 	plugins: [ | ||||
| 		new webpack.optimize.CommonsChunkPlugin({ | ||||
| 			name: "vendor", | ||||
| 			filename: "static/vendor.[hash].js" | ||||
| 		}), | ||||
| 		new HtmlWebpackPlugin({ | ||||
| 			favicon: "src/public/favicon.svg", | ||||
| 			template: "src/index.html" | ||||
| 		}) | ||||
| 	].concat( | ||||
| 		ENV === "production" | ||||
| 			? [ | ||||
| 					new webpack.optimize.UglifyJsPlugin({ | ||||
| 						output: { | ||||
| 							comments: false | ||||
| 						}, | ||||
| 						exclude: [/bundle/], | ||||
| 						compress: { | ||||
| 							unsafe_comps: true, | ||||
| 							properties: true, | ||||
| 							keep_fargs: false, | ||||
| 							pure_getters: true, | ||||
| 							collapse_vars: true, | ||||
| 							unsafe: true, | ||||
| 							warnings: false, | ||||
| 							screw_ie8: true, | ||||
| 							sequences: true, | ||||
| 							dead_code: true, | ||||
| 							drop_debugger: true, | ||||
| 							comparisons: true, | ||||
| 							conditionals: true, | ||||
| 							evaluate: true, | ||||
| 							booleans: true, | ||||
| 							loops: true, | ||||
| 							unused: true, | ||||
| 							hoist_funs: true, | ||||
| 							if_return: true, | ||||
| 							join_vars: true, | ||||
| 							cascade: true, | ||||
| 							drop_console: true | ||||
| 						} | ||||
| 					}) | ||||
| 				] | ||||
| 			: [ | ||||
| 					new webpack.DefinePlugin({ | ||||
| 						// drone server uses authorization cookies, but the client can | ||||
| 						// optionally source the authorization token from the environment. | ||||
| 						// this should be used for the test server only. | ||||
| 						"window.DRONE_TOKEN": JSON.stringify(process.env.DRONE_TOKEN), | ||||
| 						"window.DRONE_SERVER": JSON.stringify(process.env.DRONE_SERVER), | ||||
|   plugins: [ | ||||
|     new webpack.optimize.CommonsChunkPlugin({ | ||||
|       name: "vendor", | ||||
|       filename: "static/vendor.[hash].js" | ||||
|     }), | ||||
|     new HtmlWebpackPlugin({ | ||||
|       favicon: "src/public/favicon.svg", | ||||
|       template: "src/index.html" | ||||
|     }) | ||||
|   ].concat( | ||||
|     ENV === "production" | ||||
|       ? [ | ||||
|           new webpack.optimize.UglifyJsPlugin({ | ||||
|             output: { | ||||
|               comments: false | ||||
|             }, | ||||
|             exclude: [/bundle/], | ||||
|             compress: { | ||||
|               unsafe_comps: true, | ||||
|               properties: true, | ||||
|               keep_fargs: false, | ||||
|               pure_getters: true, | ||||
|               collapse_vars: true, | ||||
|               unsafe: true, | ||||
|               warnings: false, | ||||
|               screw_ie8: true, | ||||
|               sequences: true, | ||||
|               dead_code: true, | ||||
|               drop_debugger: true, | ||||
|               comparisons: true, | ||||
|               conditionals: true, | ||||
|               evaluate: true, | ||||
|               booleans: true, | ||||
|               loops: true, | ||||
|               unused: true, | ||||
|               hoist_funs: true, | ||||
|               if_return: true, | ||||
|               join_vars: true, | ||||
|               cascade: true, | ||||
|               drop_console: true | ||||
|             } | ||||
|           }) | ||||
|         ] | ||||
|       : [ | ||||
|           new webpack.DefinePlugin({ | ||||
|             // drone server uses authorization cookies, but the client can | ||||
|             // optionally source the authorization token from the environment. | ||||
|             // this should be used for the test server only. | ||||
|             "window.DRONE_TOKEN": JSON.stringify(process.env.DRONE_TOKEN), | ||||
|             "window.DRONE_SERVER": JSON.stringify(process.env.DRONE_SERVER), | ||||
|  | ||||
| 						// drone server provides the currently authenticated user in the | ||||
| 						// index.html file. For testing purposes we simulate this and provides | ||||
| 						// a dummy user object. | ||||
| 						"window.DRONE_USER": { | ||||
| 							login: JSON.stringify("octocat"), | ||||
| 							avatar_url: JSON.stringify( | ||||
| 								"https://avatars3.githubusercontent.com/u/583231" | ||||
| 							) | ||||
| 						} | ||||
| 					}) | ||||
| 				] | ||||
| 	), | ||||
|             // drone server provides the currently authenticated user in the | ||||
|             // index.html file. For testing purposes we simulate this and provides | ||||
|             // a dummy user object. | ||||
|             "window.DRONE_USER": { | ||||
|               login: JSON.stringify("octocat"), | ||||
|               avatar_url: JSON.stringify( | ||||
|                 "https://avatars3.githubusercontent.com/u/583231" | ||||
|               ) | ||||
|             } | ||||
|           }) | ||||
|         ] | ||||
|   ), | ||||
|  | ||||
| 	devServer: { | ||||
| 		port: process.env.PORT || 9999, | ||||
|   devServer: { | ||||
|     port: process.env.PORT || 9999, | ||||
|  | ||||
| 		// serve up any static files from src/ | ||||
| 		contentBase: path.join(__dirname, "src"), | ||||
|     // serve up any static files from src/ | ||||
|     contentBase: path.join(__dirname, "src"), | ||||
|  | ||||
| 		// enable gzip compression: | ||||
| 		compress: true, | ||||
|     // enable gzip compression: | ||||
|     compress: true, | ||||
|  | ||||
| 		// enable pushState() routing, as used by preact-router et al: | ||||
| 		historyApiFallback: true | ||||
| 	} | ||||
|     // enable pushState() routing, as used by preact-router et al: | ||||
|     historyApiFallback: true | ||||
|   } | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user