diff options
Diffstat (limited to 'ui/app/components/wizard')
-rw-r--r-- | ui/app/components/wizard/add_provider_modal.js | 94 | ||||
-rw-r--r-- | ui/app/components/wizard/index.js | 38 | ||||
-rw-r--r-- | ui/app/components/wizard/provider_select_stage.js | 86 | ||||
-rw-r--r-- | ui/app/components/wizard/stage_layout.js | 37 | ||||
-rw-r--r-- | ui/app/components/wizard/wizard.less | 44 |
5 files changed, 299 insertions, 0 deletions
diff --git a/ui/app/components/wizard/add_provider_modal.js b/ui/app/components/wizard/add_provider_modal.js new file mode 100644 index 0000000..bc5e023 --- /dev/null +++ b/ui/app/components/wizard/add_provider_modal.js @@ -0,0 +1,94 @@ +// +// A modal popup to add a new provider. +// + +import React from 'react' +import { FormGroup, ControlLabel, FormControl, HelpBlock, Button, Modal } from 'react-bootstrap' +import Spinner from '../spinner' +import Validate from '../../lib/validate' +import App from '../../app' + +class AddProviderModal extends React.Component { + + static get defaultProps() {return{ + title: 'Add a provider', + onClose: null + }} + + constructor(props) { + super(props) + this.state = { + validationState: null, + errorMsg: null, + domain: "" + } + this.accept = this.accept.bind(this) + this.cancel = this.cancel.bind(this) + this.changed = this.changed.bind(this) + } + + accept() { + if (this.state.domain) { + App.providers.add(this.state.domain) + } + this.props.onClose() + } + + cancel() { + this.props.onClose() + } + + changed(e) { + let domain = e.target.value + let newState = null + let newMsg = null + + if (domain.length > 0) { + let error = Validate.domain(domain) + newState = error ? 'error' : 'success' + newMsg = error + } + this.setState({ + domain: domain, + validationState: newState, + errorMsg: newMsg + }) + } + + render() { + let help = null + if (this.state.errorMsg) { + help = <HelpBlock>{this.state.errorMsg}</HelpBlock> + } else { + help = <HelpBlock> </HelpBlock> + } + let form = <form onSubmit={this.accept} autoComplete="off"> + <FormGroup controlId="addprovider" validationState={this.state.validationState}> + <ControlLabel>Domain</ControlLabel> + <FormControl + type="text" + ref="domain" + autoFocus + value={this.state.domain} + onChange={this.changed} + onBlur={this.changed} /> + <FormControl.Feedback/> + {help} + </FormGroup> + <Button onClick={this.accept}>Add</Button> + </form> + + return( + <Modal show={true} onHide={this.cancel}> + <Modal.Header closeButton> + <Modal.Title>{this.props.title}</Modal.Title> + </Modal.Header> + <Modal.Body> + {form} + </Modal.Body> + </Modal> + ) + } +} + +export default AddProviderModal
\ No newline at end of file diff --git a/ui/app/components/wizard/index.js b/ui/app/components/wizard/index.js new file mode 100644 index 0000000..613b88f --- /dev/null +++ b/ui/app/components/wizard/index.js @@ -0,0 +1,38 @@ +// +// The provider setup wizard +// + +import React from 'react' +import App from 'app' + +import ProviderSelectStage from './provider_select_stage' +import './wizard.less' + +export default class Wizard extends React.Component { + + constructor(props) { + super(props) + this.state = { + stage: 'provider' + } + } + + setStage(stage) { + this.setState({stage: stage}) + } + + render() { + let stage = null + switch(this.state.stage) { + case 'provider': + stage = <ProviderSelectStage /> + break + } + return( + <div className="wizard"> + {stage} + </div> + ) + } + +} diff --git a/ui/app/components/wizard/provider_select_stage.js b/ui/app/components/wizard/provider_select_stage.js new file mode 100644 index 0000000..20674be --- /dev/null +++ b/ui/app/components/wizard/provider_select_stage.js @@ -0,0 +1,86 @@ +import React from 'react' +import {Button, ButtonGroup, ButtonToolbar, Glyphicon} from 'react-bootstrap' + +import App from 'app' +import ListEdit from 'components/list_edit' +import StageLayout from './stage_layout' +import AddProviderModal from './add_provider_modal' + +export default class ProviderSelectStage extends React.Component { + + static get defaultProps() {return{ + title: "Choose a provider", + subtitle: "This doesn't work yet" + }} + + constructor(props) { + super(props) + let domains = this.currentDomains() + this.state = { + domains: domains, + showModal: false + } + this.add = this.add.bind(this) + this.remove = this.remove.bind(this) + this.close = this.close.bind(this) + this.previous = this.previous.bind(this) + } + + currentDomains() { + // return(App.providers.domains().slice() || []) + return ['domain1', 'domain2', 'domain3'] + } + + add() { + this.setState({showModal: true}) + } + + remove(provider) { + // App.providers.remove(provider) + this.setState({domains: this.currentDomains()}) + } + + close() { + let domains = this.currentDomains() + if (domains.length != this.state.domains.length) { + // this is ugly, but i could not get selection working + // by passing it as a property + this.refs.list.setSelected(0) + } + this.setState({ + domains: domains, + showModal: false + }) + } + + previous() { + App.start() + } + + render() { + let modal = null + if (this.state.showModal) { + modal = <AddProviderModal onClose={this.close} /> + } + let buttons = ( + <ButtonToolbar className="pull-right"> + <Button onClick={this.previous}> + <Glyphicon glyph="chevron-left" /> + Previous + </Button> + <Button> + Next + <Glyphicon glyph="chevron-right" /> + </Button> + </ButtonToolbar> + ) + let select = <ListEdit ref="list" items={this.state.domains} + onRemove={this.remove} onAdd={this.add} /> + return( + <StageLayout title={this.props.title} subtitle={this.props.subtitle} buttons={buttons}> + {select} + {modal} + </StageLayout> + ) + } +} diff --git a/ui/app/components/wizard/stage_layout.js b/ui/app/components/wizard/stage_layout.js new file mode 100644 index 0000000..3154022 --- /dev/null +++ b/ui/app/components/wizard/stage_layout.js @@ -0,0 +1,37 @@ +import React from 'react' + +class StageLayout extends React.Component { + + static get defaultProps() {return{ + title: 'untitled', + subtitle: null, + buttons: null + }} + + constructor(props) { + super(props) + } + + render() { + let subtitle = null + if (this.props.subtitle) { + subtitle = <span>{this.props.subtitle}</span> + } + return( + <div className="stage"> + <div className="header"> + {this.props.title} + {subtitle} + </div> + <div className="body"> + {this.props.children} + </div> + <div className="footer"> + {this.props.buttons} + </div> + </div> + ) + } +} + +export default StageLayout
\ No newline at end of file diff --git a/ui/app/components/wizard/wizard.less b/ui/app/components/wizard/wizard.less new file mode 100644 index 0000000..29efc20 --- /dev/null +++ b/ui/app/components/wizard/wizard.less @@ -0,0 +1,44 @@ +.wizard .stage { + position: absolute; + height: 100%; + width: 100%; + + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; + -webkit-flex: 1; + flex: 1; +} + +.wizard .stage .footer { + -webkit-flex: 0 0 auto; + flex: 0 0 auto; + background-color: #ddd; + padding: 20px; + text-align: right; +} + +.wizard .stage .header { + -webkit-flex: 0 0 auto; + flex: 0 0 auto; + padding: 20px; + background-color: #333; + color: white; + font-size: 2em; + span { + margin-left: 10px; + font-size: 0.5em; + } +} + +.wizard .stage .body { + -webkit-flex: 1 1 auto; + flex: 1 1 auto; + padding: 20px; + overflow: auto; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; +}
\ No newline at end of file |