diff options
Diffstat (limited to 'web/react/components')
-rw-r--r-- | web/react/components/access_history_modal.jsx | 2 | ||||
-rw-r--r-- | web/react/components/activity_log_modal.jsx | 5 | ||||
-rw-r--r-- | web/react/components/command_list.jsx | 17 | ||||
-rw-r--r-- | web/react/components/error_bar.jsx | 42 | ||||
-rw-r--r-- | web/react/components/login.jsx | 12 | ||||
-rw-r--r-- | web/react/components/setting_item_max.jsx | 2 | ||||
-rw-r--r-- | web/react/components/setting_picture.jsx | 6 | ||||
-rw-r--r-- | web/react/components/sidebar_header.jsx | 10 | ||||
-rw-r--r-- | web/react/components/signup_team.jsx | 4 | ||||
-rw-r--r-- | web/react/components/signup_team_complete.jsx | 2 | ||||
-rw-r--r-- | web/react/components/signup_user_complete.jsx | 23 | ||||
-rw-r--r-- | web/react/components/signup_user_oauth.jsx | 84 | ||||
-rw-r--r-- | web/react/components/team_settings.jsx | 3 | ||||
-rw-r--r-- | web/react/components/user_settings.jsx | 78 |
14 files changed, 210 insertions, 80 deletions
diff --git a/web/react/components/access_history_modal.jsx b/web/react/components/access_history_modal.jsx index b23b3213f..462f046f6 100644 --- a/web/react/components/access_history_modal.jsx +++ b/web/react/components/access_history_modal.jsx @@ -64,7 +64,7 @@ module.exports = React.createClass({ <div>{"URL: " + currentAudit.action.replace("/api/v1", "")}</div> </div> : - <a href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> + <a href="#" className="theme" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> } </div> {i < this.state.audits.length - 1 ? diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx index d6f8f40eb..7cce807a9 100644 --- a/web/react/components/activity_log_modal.jsx +++ b/web/react/components/activity_log_modal.jsx @@ -68,6 +68,9 @@ module.exports = React.createClass({ else if (currentSession.props.platform === "Macintosh" || currentSession.props.platform === "iPhone") { devicePicture = "fa fa-apple"; } + else if (currentSession.props.platform === "Linux") { + devicePicture = "fa fa-linux"; + } activityList[i] = ( <div className="activity-log__table"> @@ -83,7 +86,7 @@ module.exports = React.createClass({ <div>{"Session ID: " + currentSession.alt_id}</div> </div> : - <a href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> + <a className="theme" href="#" onClick={this.handleMoreInfo.bind(this, i)}>More info</a> } </div> </div> diff --git a/web/react/components/command_list.jsx b/web/react/components/command_list.jsx index 023f5f760..5efe98dc6 100644 --- a/web/react/components/command_list.jsx +++ b/web/react/components/command_list.jsx @@ -20,12 +20,7 @@ module.exports = React.createClass({ }, getSuggestedCommands: function(cmd) { - if (cmd == "") { - this.setState({ suggestions: [ ], cmd: "" }); - return; - } - - if (cmd.indexOf("/") != 0) { + if (!cmd || cmd.charAt(0) != '/') { this.setState({ suggestions: [ ], cmd: "" }); return; } @@ -35,17 +30,19 @@ module.exports = React.createClass({ cmd, true, function(data) { - if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) data.suggestions = []; + if (data.suggestions.length === 1 && data.suggestions[0].suggestion === cmd) { + data.suggestions = []; + } this.setState({ suggestions: data.suggestions, cmd: cmd }); }.bind(this), function(err){ - }.bind(this) + } ); }, render: function() { if (this.state.suggestions.length == 0) return (<div/>); - var suggestions = [] + var suggestions = []; for (var i = 0; i < this.state.suggestions.length; i++) { if (this.state.suggestions[i].suggestion != this.state.cmd) { @@ -59,7 +56,7 @@ module.exports = React.createClass({ } return ( - <div ref="mentionlist" className="command-box" style={{height:(this.state.suggestions*37)+2}}> + <div ref="mentionlist" className="command-box" style={{height:(this.state.suggestions.length*37)+2}}> { suggestions } </div> ); diff --git a/web/react/components/error_bar.jsx b/web/react/components/error_bar.jsx index d9d91ef51..f7514a009 100644 --- a/web/react/components/error_bar.jsx +++ b/web/react/components/error_bar.jsx @@ -8,21 +8,25 @@ var Constants = require('../utils/constants.jsx'); var ActionTypes = Constants.ActionTypes; function getStateFromStores() { - var error = ErrorStore.getLastError(); - if (error && error.message !== "There appears to be a problem with your internet connection") { - return { message: error.message }; - } else { - return { message: null }; - } + var error = ErrorStore.getLastError(); + if (error && error.message !== "There appears to be a problem with your internet connection") { + return { message: error.message }; + } else { + return { message: null }; + } } module.exports = React.createClass({ + displayName: 'ErrorBar', + componentDidMount: function() { ErrorStore.addChangeListener(this._onChange); - $('body').css('padding-top', $('#error_bar').outerHeight()); - $(window).resize(function(){ - $('body').css('padding-top', $('#error_bar').outerHeight()); - }); + $('body').css('padding-top', $(React.findDOMNode(this)).outerHeight()); + $(window).resize(function() { + if (this.state.message) { + $('body').css('padding-top', $(React.findDOMNode(this)).outerHeight()); + } + }.bind(this)); }, componentWillUnmount: function() { ErrorStore.removeChangeListener(this._onChange); @@ -31,39 +35,39 @@ module.exports = React.createClass({ var newState = getStateFromStores(); if (!utils.areStatesEqual(newState, this.state)) { if (newState.message) { - var self = this; - setTimeout(function(){self.handleClose();}, 10000); + setTimeout(this.handleClose, 10000); } + this.setState(newState); } }, handleClose: function(e) { if (e) e.preventDefault(); + AppDispatcher.handleServerAction({ type: ActionTypes.RECIEVED_ERROR, err: null }); + $('body').css('padding-top', '0'); }, getInitialState: function() { var state = getStateFromStores(); if (state.message) { - var self = this; - setTimeout(function(){self.handleClose();}, 10000); + setTimeout(this.handleClose, 10000); } return state; }, render: function() { - var message = this.state.message; - if (message) { + if (this.state.message) { return ( <div className="error-bar"> - <span className="error-text">{message}</span> - <a href="#" className="error-close pull-right" onClick={this.handleClose}>×</a> + <span>{this.state.message}</span> + <a href="#" className="error-bar__close" onClick={this.handleClose}>×</a> </div> ); } else { return <div/>; } } -}); +});
\ No newline at end of file diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx index 71fefff5b..05918650b 100644 --- a/web/react/components/login.jsx +++ b/web/react/components/login.jsx @@ -90,6 +90,17 @@ module.exports = React.createClass({ focusEmail = true; } + var auth_services = JSON.parse(this.props.authServices); + + var login_message; + if (auth_services.indexOf("gitlab") >= 0) { + login_message = ( + <div className="form-group form-group--small"> + <span><a href={"/"+teamName+"/login/gitlab"}>{"Log in with GitLab"}</a></span> + </div> + ); + } + return ( <div className="signup-team__container"> <div> @@ -112,6 +123,7 @@ module.exports = React.createClass({ <div className="form-group"> <button type="submit" className="btn btn-primary">Sign in</button> </div> + { login_message } <div className="form-group form-group--small"> <span><a href="/find_team">{"Find other " + strings.TeamPlural}</a></span> </div> diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx index b8b667e1a..49eb58773 100644 --- a/web/react/components/setting_item_max.jsx +++ b/web/react/components/setting_item_max.jsx @@ -20,7 +20,7 @@ module.exports = React.createClass({ <hr /> { server_error } { client_error } - <a className="btn btn-sm btn-primary" onClick={this.props.submit}>Submit</a> + { this.props.submit ? <a className="btn btn-sm btn-primary" onClick={this.props.submit}>Submit</a> : "" } <a className="btn btn-sm theme" href="#" onClick={this.props.updateSection}>Cancel</a> </li> </ul> diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx index 62c889b7f..6cfb74d60 100644 --- a/web/react/components/setting_picture.jsx +++ b/web/react/components/setting_picture.jsx @@ -25,9 +25,9 @@ module.exports = React.createClass({ var img = null; if (this.props.picture) { - img = (<img ref="image" className="col-xs-5 profile-img" src=""/>); + img = (<img ref="image" className="profile-img" src=""/>); } else { - img = (<img ref="image" className="col-xs-5 profile-img" src={this.props.src}/>); + img = (<img ref="image" className="profile-img" src={this.props.src}/>); } var self = this; @@ -37,7 +37,7 @@ module.exports = React.createClass({ <li className="col-xs-12 section-title">{this.props.title}</li> <li className="col-xs-offset-3 col-xs-8"> <ul className="setting-list"> - <li className="row setting-list-item"> + <li className="setting-list-item"> {img} </li> <li className="setting-list-item"> diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx index 7a7e92854..859e425a6 100644 --- a/web/react/components/sidebar_header.jsx +++ b/web/react/components/sidebar_header.jsx @@ -101,13 +101,13 @@ module.exports = React.createClass({ getDefaultProps: function() { return { - teamName: config.SiteName + teamDisplayName: config.SiteName }; }, render: function() { - var teamDisplayName = this.props.teamDisplayName ? this.props.teamDisplayName : config.SiteName; - var me = UserStore.getCurrentUser() + var me = UserStore.getCurrentUser(); + if (!me) { return null; } @@ -118,11 +118,11 @@ module.exports = React.createClass({ { me.last_picture_update ? <img className="user__picture" src={"/api/v1/users/" + me.id + "/image?time=" + me.update_at} /> : - <div /> + null } <div className="header__info"> <div className="user__name">{ '@' + me.username}</div> - <div className="team__name">{ teamDisplayName }</div> + <div className="team__name">{ this.props.teamDisplayName }</div> </div> </a> <NavbarDropdown teamType={this.props.teamType} /> diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx index cf982cc1e..362f79163 100644 --- a/web/react/components/signup_team.jsx +++ b/web/react/components/signup_team.jsx @@ -69,7 +69,9 @@ module.exports = React.createClass({ { name_error } </div> { server_error } - <button className="btn btn-md btn-primary" type="submit">Sign up for Free</button> + <div className="form-group"> + <button className="btn btn-md btn-primary" type="submit">Sign up for Free</button> + </div> <div className="form-group form-group--small"> <span><a href="/find_team">{"Find my " + strings.Team}</a></span> </div> diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx index 9ceeb6324..3e8a57308 100644 --- a/web/react/components/signup_team_complete.jsx +++ b/web/react/components/signup_team_complete.jsx @@ -246,7 +246,7 @@ TeamURLPage = React.createClass({ <h2>{utils.toTitleCase(strings.Team) + " URL"}</h2> <div className={ name_error ? "form-group has-error" : "form-group" }> <div className="row"> - <div className="col-sm-9"> + <div className="col-sm-11"> <div className="input-group"> <span className="input-group-addon">{ window.location.origin + "/" }</span> <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" defaultValue={this.props.state.team.name} autoFocus={true} onFocus={this.handleFocus}/> diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index eed323d1f..dc5ba64aa 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -46,7 +46,7 @@ module.exports = React.createClass({ function(data) { client.track('signup', 'signup_user_02_complete'); - client.loginByEmail(this.props.domain, this.state.user.email, this.state.user.password, + client.loginByEmail(this.props.teamName, this.state.user.email, this.state.user.password, function(data) { UserStore.setLastEmail(this.state.user.email); UserStore.setCurrentUser(data); @@ -58,7 +58,7 @@ module.exports = React.createClass({ }.bind(this), function(err) { if (err.message == "Login failed because email address has not been verified") { - window.location.href = "/verify_email?email="+ encodeURIComponent(this.state.user.email) + "&domain=" + encodeURIComponent(this.props.domain); + window.location.href = "/verify_email?email="+ encodeURIComponent(this.state.user.email) + "&domain=" + encodeURIComponent(this.props.teamName); } else { this.state.server_error = err.message; this.setState(this.state); @@ -79,7 +79,7 @@ module.exports = React.createClass({ props = {}; props.wizard = "welcome"; props.user = {}; - props.user.team_id = this.props.team_id; + props.user.team_id = this.props.teamId; props.user.email = this.props.email; props.hash = this.props.hash; props.data = this.props.data; @@ -103,7 +103,7 @@ module.exports = React.createClass({ var yourEmailIs = this.state.user.email == "" ? "" : <span>Your email address is { this.state.user.email }. </span> - var email = + var email = ( <div className={ this.state.original_email == "" ? "" : "hidden"} > <label className="control-label">Email</label> <div className={ email_error ? "form-group has-error" : "form-group" }> @@ -111,12 +111,25 @@ module.exports = React.createClass({ { email_error } </div> </div> + ); + + var auth_services = JSON.parse(this.props.authServices); + + var signup_message; + if (auth_services.indexOf("gitlab") >= 0) { + signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team} <a href={"/"+this.props.teamName+"/signup/gitlab"+window.location.search}>{"or sign up with GitLab."}</a></p>; + } else { + signup_message = <p>{"Choose your username and password for the " + this.props.teamDisplayName + " " + strings.Team + "."}</p>; + } return ( <div> <img className="signup-team-logo" src="/static/images/logo.png" /> <h4>Welcome to { config.SiteName }</h4> - <p>{"Choose your username and password for the " + this.props.team_name + " " + strings.Team +"."}</p> + <div className="form-group form-group--small"> + <span></span> + </div> + { signup_message } <p>Your username can be made of lowercase letters and numbers.</p> <label className="control-label">Username</label> <div className={ name_error ? "form-group has-error" : "form-group" }> diff --git a/web/react/components/signup_user_oauth.jsx b/web/react/components/signup_user_oauth.jsx new file mode 100644 index 000000000..6322aedee --- /dev/null +++ b/web/react/components/signup_user_oauth.jsx @@ -0,0 +1,84 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + + +var utils = require('../utils/utils.jsx'); +var client = require('../utils/client.jsx'); +var UserStore = require('../stores/user_store.jsx'); +var BrowserStore = require('../stores/browser_store.jsx'); + +module.exports = React.createClass({ + handleSubmit: function(e) { + e.preventDefault(); + + if (!this.state.user.username) { + this.setState({name_error: "This field is required", email_error: "", password_error: "", server_error: ""}); + return; + } + + var username_error = utils.isValidUsername(this.state.user.username); + if (username_error === "Cannot use a reserved word as a username.") { + this.setState({name_error: "This username is reserved, please choose a new one.", email_error: "", password_error: "", server_error: ""}); + return; + } else if (username_error) { + this.setState({name_error: "Username must begin with a letter, and contain between 3 to 15 lowercase characters made up of numbers, letters, and the symbols '.', '-' and '_'.", email_error: "", password_error: "", server_error: ""}); + return; + } + + this.setState({name_error: "", server_error: ""}); + + this.state.user.allow_marketing = this.refs.email_service.getDOMNode().checked; + + var user = this.state.user; + client.createUser(user, "", "", + function(data) { + client.track('signup', 'signup_user_oauth_02'); + window.location.href = '/' + this.props.teamName + '/login/'+user.auth_service; + }.bind(this), + function(err) { + this.state.server_error = err.message; + this.setState(this.state); + }.bind(this) + ); + }, + handleChange: function() { + var user = this.state.user; + user.username = this.refs.name.getDOMNode().value; + this.setState({ user: user }); + }, + getInitialState: function() { + var user = JSON.parse(this.props.user); + return { user: user }; + }, + render: function() { + + client.track('signup', 'signup_user_oauth_01'); + + var name_error = this.state.name_error ? <label className='control-label'>{ this.state.name_error }</label> : null; + var server_error = this.state.server_error ? <div className={ "form-group has-error" }><label className='control-label'>{ this.state.server_error }</label></div> : null; + + var yourEmailIs = this.state.user.email == "" ? "" : <span>Your email address is <b>{ this.state.user.email }.</b></span>; + + return ( + <div> + <img className="signup-team-logo" src="/static/images/logo.png" /> + <h4>Welcome to { config.SiteName }</h4> + <p>{"To continue signing up with " + this.state.user.auth_service + ", please register a username."}</p> + <p>Your username can be made of lowercase letters and numbers.</p> + <label className="control-label">Username</label> + <div className={ name_error ? "form-group has-error" : "form-group" }> + <input type="text" ref="name" className="form-control" placeholder="" maxLength="128" value={this.state.user.username} onChange={this.handleChange} /> + { name_error } + </div> + <p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others."}</p> + <p>{ yourEmailIs } You’ll use this address to sign in to {config.SiteName}.</p> + <div className="checkbox"><label><input type="checkbox" ref="email_service" /> It's ok to send me occassional email with updates about the {config.SiteName} service. </label></div> + <p><button onClick={this.handleSubmit} className="btn-primary btn">Create Account</button></p> + { server_error } + <p>By proceeding to create your account and use { config.SiteName }, you agree to our <a href={ config.TermsLink }>Terms of Service</a> and <a href={ config.PrivacyLink }>Privacy Policy</a>. If you do not agree, you cannot use {config.SiteName}.</p> + </div> + ); + } +}); + + diff --git a/web/react/components/team_settings.jsx b/web/react/components/team_settings.jsx index 166b1f38b..3bbb5e892 100644 --- a/web/react/components/team_settings.jsx +++ b/web/react/components/team_settings.jsx @@ -73,13 +73,12 @@ var FeatureTab = React.createClass({ var inputs = []; inputs.push( - <div className="col-sm-12"> + <div> <div className="btn-group" data-toggle="buttons-radio"> <button className={"btn btn-default "+valetActive[0]} onClick={function(){self.handleValetRadio("true")}}>On</button> <button className={"btn btn-default "+valetActive[1]} onClick={function(){self.handleValetRadio("false")}}>Off</button> </div> <div><br/>Valet is a preview feature for enabling a non-user account limited to basic member permissions that can be manipulated by 3rd parties.<br/><br/>IMPORTANT: The preview version of Valet should not be used without a secure connection and a trusted 3rd party, since user credentials are used to connect. OAuth2 will be used in the final release.</div> - <br></br> </div> ); diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx index ad890334e..298f5ee70 100644 --- a/web/react/components/user_settings.jsx +++ b/web/react/components/user_settings.jsx @@ -449,7 +449,7 @@ var SecurityTab = React.createClass({ submitPassword: function(e) { e.preventDefault(); - var user = UserStore.getCurrentUser(); + var user = this.props.user; var currentPassword = this.state.current_password; var newPassword = this.state.new_password; var confirmPassword = this.state.confirm_password; @@ -513,53 +513,69 @@ var SecurityTab = React.createClass({ var self = this; if (this.props.activeSection === 'password') { var inputs = []; + var submit = null; - inputs.push( - <div className="form-group"> - <label className="col-sm-5 control-label">Current Password</label> - <div className="col-sm-7"> - <input className="form-control" type="password" onChange={this.updateCurrentPassword} value={this.state.current_password}/> + if (this.props.user.auth_service === "") { + inputs.push( + <div className="form-group"> + <label className="col-sm-5 control-label">Current Password</label> + <div className="col-sm-7"> + <input className="form-control" type="password" onChange={this.updateCurrentPassword} value={this.state.current_password}/> + </div> </div> - </div> - ); - inputs.push( - <div className="form-group"> - <label className="col-sm-5 control-label">New Password</label> - <div className="col-sm-7"> - <input className="form-control" type="password" onChange={this.updateNewPassword} value={this.state.new_password}/> + ); + inputs.push( + <div className="form-group"> + <label className="col-sm-5 control-label">New Password</label> + <div className="col-sm-7"> + <input className="form-control" type="password" onChange={this.updateNewPassword} value={this.state.new_password}/> + </div> </div> - </div> - ); - inputs.push( - <div className="form-group"> - <label className="col-sm-5 control-label">Retype New Password</label> - <div className="col-sm-7"> - <input className="form-control" type="password" onChange={this.updateConfirmPassword} value={this.state.confirm_password}/> + ); + inputs.push( + <div className="form-group"> + <label className="col-sm-5 control-label">Retype New Password</label> + <div className="col-sm-7"> + <input className="form-control" type="password" onChange={this.updateConfirmPassword} value={this.state.confirm_password}/> + </div> </div> - </div> - ); + ); + + submit = this.submitPassword; + } else { + inputs.push( + <div className="form-group"> + <label className="col-sm-12">Log in occurs through GitLab. Please see your GitLab account settings page to update your password.</label> + </div> + ); + } passwordSection = ( <SettingItemMax title="Password" inputs={inputs} - submit={this.submitPassword} + submit={submit} server_error={server_error} client_error={password_error} updateSection={function(e){self.props.updateSection("");e.preventDefault();}} /> ); } else { - var d = new Date(this.props.user.last_password_update); - var hour = d.getHours() % 12 ? String(d.getHours() % 12) : "12"; - var min = d.getMinutes() < 10 ? "0" + d.getMinutes() : String(d.getMinutes()); - var timeOfDay = d.getHours() >= 12 ? " pm" : " am"; - var dateStr = "Last updated " + Constants.MONTHS[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + " at " + hour + ":" + min + timeOfDay; + var describe; + if (this.props.user.auth_service === "") { + var d = new Date(this.props.user.last_password_update); + var hour = d.getHours() % 12 ? String(d.getHours() % 12) : "12"; + var min = d.getMinutes() < 10 ? "0" + d.getMinutes() : String(d.getMinutes()); + var timeOfDay = d.getHours() >= 12 ? " pm" : " am"; + describe = "Last updated " + Constants.MONTHS[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + " at " + hour + ":" + min + timeOfDay; + } else { + describe = "Log in done through GitLab" + } passwordSection = ( <SettingItemMin title="Password" - describe={dateStr} + describe={describe} updateSection={function(){self.props.updateSection("password");}} /> ); @@ -577,9 +593,9 @@ var SecurityTab = React.createClass({ { passwordSection } <div className="divider-dark"/> <br></br> - <a data-toggle="modal" className="security-links" data-target="#access-history" href="#" onClick={this.handleHistoryOpen}><i className="fa fa-clock-o"></i>View Access History</a> + <a data-toggle="modal" className="security-links theme" data-target="#access-history" href="#" onClick={this.handleHistoryOpen}><i className="fa fa-clock-o"></i>View Access History</a> <b> </b> - <a data-toggle="modal" className="security-links" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Devices</a> + <a data-toggle="modal" className="security-links theme" data-target="#activity-log" href="#" onClick={this.handleDevicesOpen}><i className="fa fa-globe"></i>View and Logout of Active Devices</a> </div> </div> ); |