import React from 'react';
import Button from 'widgets/button/rw.button.js';
-import _ from 'lodash';
+import _cloneDeep from 'lodash/cloneDeep';
+import _isEmpty from 'lodash/isEmpty';
import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
import Crouton from 'react-crouton';
import TextInput from 'widgets/form_controls/textInput.jsx';
import {AccountConnectivityStatus} from '../account_sidebar/accountSidebar.jsx';
+import Utils from 'utils/utils.js';
import 'style/common.scss';
import './account.scss';
+
+function isAccessDenied (error) {
+ const rpcResult = Utils.rpcError(error);
+ return rpcResult && rpcResult['rpc-reply']['rpc-error']['error-tag'] === 'access-denied';
+}
+
class Account extends React.Component {
constructor(props) {
super(props);
- this.state = {};
- this.state.account = {};
+
+ // console.log(this.state.account)
}
storeListener = (state) => {
- if(!state.account) {
- this.setUp(this.props)
+ if(state.socket) {
+ if((!state.account || _isEmpty(state.account)) && state.userProfile) {
+ this.setUp(this.props, state.savedData)
+ }
+ state.account && state.account.params && this.setState({
+ account: state.account,
+ accountType: state.accountType,
+ types: state.types,
+ sdnOptions: state.sdnOptions,
+ savedData: state.savedData,
+ userProfile: state.userProfile
+ })
}
- state.account && this.setState({account: state.account,accountType: state.accountType, types: state.types, sdnOptions: state.sdnOptions})
}
componentWillMount() {
+ this.state = this.props.store.getState();
this.props.store.listen(this.storeListener);
- this.setUp(this.props);
+ }
+ componentWillUpdate(nextProps, nextState, nextContext) {
+ if(!_isEmpty(nextContext.userProfile) && !nextState.userProfile) {
+ this.props.store.getTransientAccountForUser(nextContext.userProfile)
+ }
}
componentWillReceiveProps(nextProps) {
if(JSON.stringify(nextProps.params) != JSON.stringify(this.props.params)){
}
}
componentWillUnmount() {
+ console.log('unmounting')
+ // this.setState({account: null, accountType: null, types: []})
this.props.store.unlisten(this.storeListener);
}
- setUp(props){
- if(props.params.name != 'create') {
- this.props.store.viewAccount({type: props.params.type, name: props.params.name});
+ setUp(props, savedData){
+ console.log('Setting up');
+ var SD = savedData || this.state.savedData;
+ if(props.params.name && props.params.name != 'create') {
+ if (SD && SD == props.params.name) {
+ this.props.store.viewAccount({type: props.params.type, name: props.params.name}, SD);
+ } else {
+ this.props.store.viewAccount({type: props.params.type, name: props.params.name});
+ }
+
} else {
- this.props.store.setAccountTemplate(props.params.type);
+ this.props.store.setAccountTemplate(props.params.type, null, SD);
}
}
create(e) {
self.props.flux.actions.global.showNotification("Please give the account a name");
return;
} else {
- var type = Account['account-type'];
- var params = Account.params;
-
- if(params) {
- for (var i = 0; i < params.length; i++) {
- var param = params[i].ref;
- if (typeof(Account[type]) == 'undefined' || typeof(Account[type][param]) == 'undefined' || Account[type][param] == "") {
- if (!params[i].optional) {
- self.props.flux.actions.global.showNotification("Please fill all account details");
- return;
- }
- }
- }
- }
-
- let nestedParams = Account.nestedParams && Account.nestedParams;
- if (nestedParams && nestedParams.params) {
- for (let i = 0; i < nestedParams.params.length; i++) {
- let nestedParam = nestedParams.params[i].ref;
- if (typeof(Account[type]) == 'undefined' || typeof(Account[type][nestedParams['container-name']][nestedParam]) == 'undefined' || Account[type][nestedParams['container-name']][nestedParam] == "") {
- if (!nestedParams.params[i].optional) {
- self.props.flux.actions.global.showNotification("Please fill all account details");
- return;
- }
- }
- }
+ if(!wasAllDetailsFilled(Account)) {
+ self.props.flux.actions.global.showNotification("Please fill all account details");
+ return;
}
}
- let newAccount = _.cloneDeep(removeTrailingWhitespace(Account));
+ let newAccount = _cloneDeep(removeTrailingWhitespace(Account));
+
delete newAccount.params;
+
newAccount.nestedParams &&
- newAccount.nestedParams['container-name'] &&
- delete newAccount[newAccount.nestedParams['container-name']];
+ newAccount.nestedParams['container-name'] &&
+ delete newAccount[newAccount.nestedParams['container-name']];
+
delete newAccount.nestedParams;
+ if(AccountType == 'resource-orchestrator') {
+ newAccount['ro-account-type'] = newAccount['account-type'] || newAccount['ro-account-type'];
+ delete newAccount['account-type'];
+ }
+ if(AccountType == 'cloud' && self.props.vduInstanceTimeout != '') {
+ newAccount['vdu-instance-timeout'] = self.props.vduInstanceTimeout;
+ }
this.props.flux.actions.global.showScreenLoader();
- this.props.store.create(newAccount, AccountType).then(function() {
- self.props.router.push({pathname:'accounts'});
- self.props.flux.actions.global.hideScreenLoader.defer();
- },
- function() {
- self.props.flux.actions.global.showNotification("There was an error creating your account. Please contact your system administrator.");
- self.props.flux.actions.global.hideScreenLoader.defer();
- });
+ this.props.store.create(newAccount, AccountType).then(
+ function() {
+ self.props.router.push({pathname:'accounts'});
+ self.props.flux.actions.global.hideScreenLoader.defer();
+ },
+ function(error) {
+ self.props.flux.actions.global.showNotification(error);
+ self.props.flux.actions.global.hideScreenLoader.defer();
+ }
+ );
}
update(e) {
e.preventDefault();
var self = this;
var Account = this.state.account;
let AccountType = this.state.accountType;
- this.props.flux.actions.global.showScreenLoader();
- this.props.store.update(Account, AccountType).then(function() {
- self.props.router.push({pathname:'accounts'});
- self.props.flux.actions.global.hideScreenLoader();
- },
- function() {
- });
+ if(!wasAllDetailsFilled(Account)) {
+ self.props.flux.actions.global.showNotification("Please fill all account details");
+ return;
+ }
+
+ if(AccountType == 'cloud' && self.props.vduInstanceTimeout != '') {
+ Account['vdu-instance-timeout'] = self.props.vduInstanceTimeout;
+ }
+ this.props.flux.actions.global.showScreenLoader();
+ this.props.store.update(Account, AccountType).then(
+ function() {
+ self.props.router.push({pathname:'accounts'});
+ self.props.flux.actions.global.hideScreenLoader();
+ },
+ function(error){
+ let msg = isAccessDenied(error) ?
+ "Update of account failed. No authorization to modify accounts."
+ : "Update of account failed. This could be because the account is in use or no longer exists.";
+ self.props.flux.actions.global.hideScreenLoader.defer();
+ self.props.flux.actions.global.showNotification.defer(msg);
+ }
+ );
}
cancel = (e) => {
e.preventDefault();
e.stopPropagation();
+ this.props.flux.actions.global.handleCancelAccount();
this.props.router.push({pathname:'accounts'});
}
handleDelete = () => {
let msg = 'Preparing to delete "' + self.state.account.name + '"' +
' Are you sure you want to delete this ' + self.state.accountType + ' account?"';
if (window.confirm(msg)) {
- this.props.store.delete(self.state.accountType, self.state.account.name).then(function() {
- self.props.flux.actions.global.hideScreenLoader();
- self.props.router.push({pathname:'accounts'});
- }, function(){
- // self.props.flux.actions.global.hideScreenLoader.defer();
- // console.log('Delete Account Fail');
- });
- } else {
- self.props.flux.actions.global.hideScreenLoader();
+ this.props.flux.actions.global.showScreenLoader();
+ this.props.store.delete(self.state.accountType, self.state.account.name).then(
+ function() {
+ self.props.flux.actions.global.hideScreenLoader();
+ self.props.router.push({pathname:'accounts'});
+ },
+ function(error){
+ let msg = isAccessDenied(error) ?
+ "Deletion of account failed. No authorization to delete accounts."
+ : "Deletion of account failed. This could be because the account is in use or has already been deleted.";
+ self.props.flux.actions.global.hideScreenLoader.defer();
+ self.props.flux.actions.global.showNotification.defer(msg);
+ }
+ );
}
}
handleNameChange(event) {
this.props.store.handleNameChange(event);
}
- handleAccountTypeChange(node, event) {
- this.props.store.handleAccountTypeChange(node, event);
+ handleAccountTypeChange(node, isRo, event) {
+ this.props.store.handleAccountTypeChange(node, isRo, event);
}
handleSelectSdnAccount = (e) => {
var tmp = this.state.account;
}
console.log(e, tmp)
}
+ updateVduInstanceTimeout(event) {
+ this.props.store.updateVduTimeout(event)
+ }
preventDefault = (e) => {
e.preventDefault();
e.stopPropagation();
}
evaluateSubmit = (e) => {
if (e.keyCode == 13) {
- if (this.props.edit) {
+ if (this.props.params.name != 'create') {
this.update(e);
} else {
this.create(e);
let {store, ...props} = this.props;
// This section builds elements that only show up on the create page.
// var name = <label>Name <input type="text" onChange={this.handleNameChange.bind(this)} style={{'textAlign':'left'}} /></label>;
- var name = <TextInput label="Name" onChange={this.handleNameChange.bind(this)} required={true} />;
+ let Account = this.state.account || {};
+ var name = <TextInput label="Name" onChange={this.handleNameChange.bind(this)} required={true} value={Account &&Account.name || ''} />;
let params = null;
let selectAccount = null;
let resfreshStatus = null;
- let Account = this.state.account;
// AccountType is for the view, not the data account-type value;
let AccountType = this.state.accountType;
let Types = this.state.types;
var buttons;
let cloudResources = Account['cloud-resources-state'] && Account['cloud-resources-state'][Account['account-type']];
let cloudResourcesStateHTML = null;
-
// Account Type Radio
var selectAccountStack = [];
+ let setVduTimeout = null;
if (!isEdit) {
buttons = [
<Button key="0" onClick={this.cancel} className="cancel light" label="Cancel"></Button>,
]
for (var i = 0; i < Types.length; i++) {
var node = Types[i];
- var isSelected = (Account['account-type'] == node['account-type']);
+ const isRo = node.hasOwnProperty('ro-account-type');
+ var isSelected = (Account['account-type'] || Account['ro-account-type']) == (node['account-type'] || node['ro-account-type']);
selectAccountStack.push(
<label key={i} className={"accountSelection " + (isSelected ? "accountSelection--isSelected" : "")}>
<div className={"accountSelection-overlay" + (isSelected ? "accountSelection-overlay--isSelected" : "")}></div>
<div className="accountSelection-imageWrapper">
- <img src={store.getImage(node['account-type'])}/>
+ <img src={store.getImage(node['account-type'] || node['ro-account-type'])}/>
</div>
- <input type="radio" name="account" onChange={this.handleAccountTypeChange.bind(this, node)} defaultChecked={node.name == Types[0].name} value={node['account-type']} />{node.name}
+ <input type="radio" name="account" onChange={this.handleAccountTypeChange.bind(this, node, isRo)} defaultChecked={node.name == Types[0].name} value={node['account-type'] || node['ro-account-type']} />{node.name}
</label>
)
}
}
}
//END Cloud Account: SDN Account Option
+
+ setVduTimeout = <TextInput
+ className="accountForm-input"
+ label="VIM Instantiation Timeout (Seconds)"
+ onChange={this.updateVduInstanceTimeout.bind(this)}
+ value={this.props.vduInstanceTimeout}
+ readonly={self.props.readonly}
+ placeholder={300}
+ />
+
//
// This sections builds the parameters for the account details.
if (Account.params) {
var paramsStack = [];
var optionalField = '';
+ var isRo = Account.hasOwnProperty('ro-account-type');
for (var i = 0; i < Account.params.length; i++) {
var node = Account.params[i];
var value = ""
- if (Account[Account['account-type']]) {
- value = Account[Account['account-type']][node.ref]
+ if(isRo) {
+ if (Account[Account['ro-account-type']] && Account[Account['ro-account-type']][node.ref]) {
+ value = Account[Account['ro-account-type']][node.ref]
+ }
+ } else {
+ if (Account[Account['account-type']] && Account[Account['account-type']][node.ref]) {
+ value = Account[Account['account-type']][node.ref]
+ }
}
if (this.props.edit && Account.params) {
value = Account.params[node.ref];
}
- paramsStack.push(
- <TextInput key={node.label} className="accountForm-input" label={node.label} required={!node.optional} onChange={this.props.store.handleParamChange(node)} value={value} />
- );
+ if(node.ref == "password" || node.ref == "secret") {
+ let displayValue = value;
+ if (self.props.readonly) {
+ displayValue = new Array(value.length + 1).join( '*' );
+ }
+ paramsStack.push(
+ <TextInput
+ key={node.label}
+ className="accountForm-input"
+ label={node.label}
+ required={!node.optional}
+ onChange={this.props.store.handleParamChange(node, isRo)}
+ value={displayValue}
+ readonly={self.props.readonly}
+ type="password"
+ />
+ );
+ } else {
+ paramsStack.push(
+ <TextInput
+ key={node.label}
+ className="accountForm-input"
+ label={node.label}
+ required={!node.optional}
+ onChange={this.props.store.handleParamChange(node, isRo)}
+ value={value}
+ readonly={self.props.readonly}
+ />
+ );
+ }
}
let nestedParamsStack = null;
// <input className="create-fleet-pool-input" type="text" onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)} value={value}/>
// </label>
// );
- nestedParamsStack.push(
- <TextInput key={node.label} label={node.label} required={!node.optional} className="create-fleet-pool-input" type="text" onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)} value={value}/>
- );
+ if(node.ref == "password" || node.ref == "secret") {
+ let displayValue = value;
+ if (self.props.readonly) {
+ displayValue = new Array(value.length + 1).join( '*' );
+ }
+ nestedParamsStack.push(
+ <TextInput
+ key={node.label}
+ label={node.label}
+ required={!node.optional}
+ className="create-fleet-pool-input"
+ type="password"
+ onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)}
+ value={displayValue}
+ readonly={self.props.readonly}
+ />
+ );
+ } else {
+ nestedParamsStack.push(
+ <TextInput
+ key={node.label}
+ label={node.label}
+ required={!node.optional}
+ className="create-fleet-pool-input"
+ type="text"
+ onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)}
+ value={value}
+ readonly={self.props.readonly}
+ />
+ );
+ }
}
}
<AccountConnectivityStatus status={Account['connection-status'].status} />
{Account['connection-status'] && Account['connection-status'].status && Account['connection-status'].status.toUpperCase()}
</div>
- <Button className="refreshList light" onClick={this.props.store.refreshAccount.bind(this, Account.name, AccountType)} label="REFRESH STATUS"></Button>
+ { self.props.readonly ? null :
+ <Button is-disabled={self.props.readonly} className="refreshList light" onClick={this.props.store.refreshAccount.bind(this, Account.name, AccountType)} label="REFRESH STATUS" />
+ }
</div>
{
(Account['connection-status'] && Account['connection-status'].status && Account['connection-status'].status.toUpperCase()) === 'FAILURE' ?
}
</div>
) : null;
- // cloudResourcesStateHTML = (
- // <div className="accountForm">
- // <h3 className="accountForm-title">Resources Status</h3>
- // <div className="accountForm-content" >
- // <ul>
- // {
- // cloudResources && props.AccountMeta.resources[Account['account-type']].map(function(r, i) {
-
- // return (
- // <li key={i}>
- // {r}: {cloudResources[r]}
- // </li>
- // )
- // }) || 'No Additional Resources'
- // }
- // </ul>
- // </div>
- // </div>
- // )
+
}
var html = (
<div className="associateSdnAccount accountForm">
<h3 className="accountForm-title">Account</h3>
<div className="accountForm-content" style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
- <h4 style={{flex: '1'}}>{name}</h4>
+ {name}
{ isEdit ?
(
<div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
- <img src={store.getImage(Account['account-type'])}/> {props.AccountMeta.labelByType[Account['account-type']]}
+ <img src={store.getImage(Account['account-type'] || Account['ro-account-type'])}/> {props.AccountMeta.labelByType[Account['account-type'] || Account['ro-account-type']]}
</div>)
: null
}
</div>
+ {
+ AccountType == 'cloud' ? (
+ <div className="accountForm-content">
+ {setVduTimeout}
+ </div>
+ )
+ : null
+ }
</div>
{selectAccount}
{params}
</ol>
<div className="form-actions">
- {buttons}
+ {!self.props.readonly ? buttons : null}
</div>
</form>
)
- return html;
+ return Types.length ? html : null;
}
}
+Account.contextTypes = {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+}
+
function displayFailureMessage(msg) {
return (
<div className="accountForm-content" style={{maxWidth: '600px'}}>
}
}
+function wasAllDetailsFilled(Account) {
+ var type = Account['account-type'] || Account['ro-account-type'];
+ var params = Account.params;
+
+ if(params) {
+ for (var i = 0; i < params.length; i++) {
+ var param = params[i].ref;
+ if (typeof(Account[type]) == 'undefined' || typeof(Account[type][param]) == 'undefined' || Account[type][param] == "") {
+ if (!params[i].optional) {
+ return false;
+ }
+ }
+ }
+ }
+
+ let nestedParams = Account.nestedParams && Account.nestedParams;
+ if (nestedParams && nestedParams.params) {
+ for (let i = 0; i < nestedParams.params.length; i++) {
+ let nestedParam = nestedParams.params[i].ref;
+ if (typeof(Account[type]) == 'undefined' || typeof(Account[type][nestedParams['container-name']][nestedParam]) == 'undefined' || Account[type][nestedParams['container-name']][nestedParam] == "") {
+ if (!nestedParams.params[i].optional) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
function removeTrailingWhitespace(Account) {
- var type = Account['account-type'];
+ var type = Account['account-type'] || Account['ro-account-type'];
var params = Account.params;
if(params) {