// require('../tests/stories/sshKeyCard');
// require('../tests/stories/button');
// require('../tests/stories/sq-input-slider');
- require('../tests/stories/catalogCard');
+ // require('../tests/stories/catalogCard');
+ require('../tests/stories/inputs');
// require as many stories as you need.
}
configure(loadStories, module);
+
+
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var UserManagement = {};
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+
+UserManagement.get = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/operational/user-config/users',
+ method: 'GET',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.get('Authorization')
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data']['users'] = JSON.parse(result[0].body)['rw-user:users'];
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with UserManagement.get', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to get UserManagement' + error
+ };
+ reject(response);
+ });
+ });
+};
+UserManagement.create = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var data = req.body;
+ data = {
+ "users":[data]
+ }
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/config/user-config',
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.get('Authorization')
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with UserManagement.create', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to create user' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+UserManagement.delete = function(req) {
+ var self = this;
+ var username = req.params.username;
+ var domain = req.params.domain;
+ var api_server = req.query["api_server"];
+ var requestHeaders = {};
+ var url = `${utils.confdPort(api_server)}/api/config/user-config/users/${username},${domain}`
+ return new Promise(function(resolve, reject) {
+ _.extend(requestHeaders,
+ constants.HTTP_HEADERS.accept.data,
+ constants.HTTP_HEADERS.content_type.data, {
+ 'Authorization': req.get('Authorization')
+ });
+ rp({
+ url: url,
+ method: 'DELETE',
+ headers: requestHeaders,
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ }, function(error, response, body) {
+ if (utils.validateResponse('UserManagement.DELETE', error, response, body, resolve, reject)) {
+ return resolve({
+ statusCode: response.statusCode,
+ data: JSON.stringify(response.body)
+ });
+ };
+ });
+ })
+}
+module.exports = UserManagement;
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
if (!NAVIGATION[plugin_name]) {
NAVIGATION[plugin_name] = {};
}
-
if (!NAVIGATION[plugin_name].routes) {
NAVIGATION[plugin_name].routes = routes;
} else {
--- /dev/null
+
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * inactivity routes module. Provides a RESTful API for this
+ * skyquake instance's inactivity state.
+ * @module framework/core/modules/routes/inactivity
+ * @author Laurence Maultsby <laurence.maultsby@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var UserManagementAPI = require('../api/UserManagementAPI.js');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+ extended: true
+}));
+
+Router.get('/user', cors(), function(req, res) {
+ UserManagementAPI.get(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.post('/user', cors(), function(req, res) {
+ UserManagementAPI.create(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.delete('/user/:username/:domain', cors(), function(req, res) {
+ UserManagementAPI.delete(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+
+module.exports = Router;
+
+
+
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
$error-red:#FF5F5F;
-//PC
+/*PC*/
$black: #000;
$gray-lightest: #f1f1f1;
$gray-darker: #666;
$gray-darkest: #333;
$white: #FFF;
-//
-// Brand Colors
-//
+/**/
+/* Brand Colors*/
+/**/
$brand-blue-light: #30baef;
$brand-blue: #00acee;
$brand-blue-dark: #147ca3;
$neutral-dark-1: hsl(360, 100%, 50%);
$neutral-dark-2: hsl(360, 100%, 50%);
-$neutral-dark-3: hsl(360, 100%, 50%);
-$neutral-dark-4: hsl(360, 100%, 50%);
-$neutral-dark-5: hsl(360, 100%, 50%);
+$neutral-dark-3: hsl(0, 0%, 49.7%);
+$neutral-dark-4: hsl(0, 0%, 42.7%);
+$neutral-dark-5: hsl(0, 0%, 35.7%);
$netral-black: hsl(0, 100%, 0%);
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
############################################################################ */
.SqButton {
- align-items: center;
+ -ms-flex-align: center;
+ align-items: center;
border-style: solid;
border-radius: 3px;
border-width: 0px;
cursor: pointer;
+ display: -ms-inline-flexbox;
display: inline-flex;
font-size: 1rem;
height: 50px;
- justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
margin: 0 10px;
outline: none;
padding: 0 15px;
/* Focus */
&:focus {
- // box-shadow: $focus-shadow;
+ /* box-shadow: $focus-shadow;*/
border: 1px solid red;
}
fill: $primaryForeground;
}
}
-
-
}
-
+.sqButtonGroup {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
Class += " is-disabled";
}
return (
- <div style={{display: 'flex'}}>
+ <div style={{display: 'flex'}} onClick={this.props.onClick}>
<div className={Class} tabIndex="0">
- {svgHTML}
- <div className="SqButton-content">{label}</div>
+ {svgHTML}
+ <div className="SqButton-content">{label}</div>
</div>
+ </div>
+ )
+ }
+}
+
+export class ButtonGroup extends React.Component {
+ render() {
+ let className = "sqButtonGroup";
+ if (this.props.className) {
+ className = `${className} ${this.props.className}`
+ }
+ return (
+ <div className={className} style={this.props.style}>
+ {this.props.children}
</div>
)
}
}
+
SqButton.defaultProps = {
+ onClick: function(e) {
+ console.log('Clicked')
+ },
icon: false,
primary: false,
disabled: false,
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
border:0px;
height: 100%;
}
+ &.checkbox {
+ -ms-flex-direction:row;
+ flex-direction:row;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-bottom:0;
+ >span {
+ -ms-flex-order: 1;
+ order: 1;
+ padding-left:1rem;
+ }
+ >input {
+ -ms-flex-order: 0;
+ order: 0;
+
+ box-shadow:none;
+ height:25px;
+ }
+ }
}
+
+
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import './formControls.scss';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+
+import React, {Component} from 'react';
+
+export default class Input extends Component {
+ render() {
+ let {label, value, defaultValue, ...props} = this.props;
+ let inputProperties = {
+ value: value
+ }
+ let isRequired;
+ let inputType;
+ let className = `sqTextInput ${props.className}`;
+
+ if(this.props.required) {
+ isRequired = <span className="required">*</span>
+ }
+ if (defaultValue) {
+ inputProperties.defaultValue = defaultValue;
+ }
+ if (props.pattern) {
+ inputProperties.pattern = props.pattern;
+ }
+ if(props.hasOwnProperty('type') && (props.type.toLowerCase() == 'checkbox')) {
+ inputProperties.checked = props.checked;
+ className = `${className} checkbox`;
+ }
+ if (value == undefined) {
+ value = defaultValue;
+ }
+ switch(props.type) {
+ case 'textarea':
+ inputType = <textarea key={props.key} {...inputProperties} value={value} onChange={props.onChange} />
+ break;
+ case 'select':
+ inputType = <SelectOption
+ key={props.key}
+ initial={props.initial}
+ defaultValue={defaultValue}
+ options={props.options}
+ onChange={props.onChange}
+ />
+ break;
+ default:
+ inputType = <input key={props.key} type={props.type} {...inputProperties} onChange={props.onChange} placeholder={props.placeholder}/>;
+ }
+ let html = (
+ <label className={className} style={props.style}>
+ <span> { label } {isRequired}</span>
+ {
+ !props.readonly ? inputType : <div className="readonly">{value}</div>
+ }
+
+ </label>
+ );
+ return html;
+ }
+}
+
+
+function buildDropDown() {
+
+}
+
+Input.defaultProps = {
+ onChange: function(e) {
+ console.log(e.target.value, e);
+ console.dir(e.target);
+ },
+ label: '',
+ defaultValue: null,
+ type: 'text',
+ readonly: false,
+ style:{},
+ className: ''
+
+}
+
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
let html;
let defaultValue = this.props.defaultValue;
let options = this.props.options.map(function(op, i) {
- let value = JSON.stringify(op.value);
- return <option key={i} value={JSON.stringify(op.value)}>{op.label}</option>
+ let value;
+ let label;
+ if(typeof(op) == 'object') {
+ value = JSON.stringify(op.value);
+ label = op.label;
+ } else {
+ value = op;
+ label = op;
+ }
+
+ return <option key={i} value={JSON.stringify(value)}>{label}</option>
});
if (this.props.initial) {
options.unshift(<option key='blank' value={JSON.stringify(this.props.defaultValue)}></option>);
}
html = (
- <label>
+ <label key={this.props.key}>
{this.props.label}
<select className={this.props.className} onChange={this.handleOnChange} defaultValue={JSON.stringify(defaultValue)} >
{
}
}
SelectOption.defaultProps = {
+ /**
+ * [options description]
+ * @type {Array} - Expects items to contain objects with the properties 'label' and 'value' which are both string types. Hint: JSON.stringify()
+ */
options: [],
onChange: function(e) {
+ console.log(e.target.value)
console.dir(e)
},
- defaultValue: false,
+ /**
+ * Selected or default value
+​
+ * @type {[type]}
+ */
+ defaultValue: null,
+ /**
+ * True if first entry in dropdown should be blank
+ * @type {Boolean}
+ */
initial: false,
label: null
}
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import './formControls.scss';
import React, {Component} from 'react';
-
-export default class TextInput extends Component {
- render() {
- let {label, onChange, value, defaultValue, ...props} = this.props;
- let inputProperties = {
- value: value,
- onChange: onChange
- }
- let isRequired;
- let inputType;
- if(this.props.required) {
- isRequired = <span className="required">*</span>
- }
- if (defaultValue) {
- inputProperties.defaultValue = defaultValue;
- }
- if (props.pattern) {
- inputProperties.pattern = props.pattern;
- }
- if (value == undefined) {
- value = defaultValue;
- }
- switch(props.type) {
- case 'textarea':
- inputType = <textarea {...inputProperties} value={value}/>
-
- break;
- default:
- inputType = <input type={props.type} {...inputProperties} placeholder={props.placeholder}/>;
- }
- let html = (
- <label className={"sqTextInput " + props.className} style={props.style}>
- <span> { label } {isRequired}</span>
- {
- !props.readonly ? inputType : <div className="readonly">{value}</div>
- }
-
- </label>
- );
- return html;
+import Input from './input.jsx';
+class TextInput extends Input {
+ constructor(props) {
+ super(props);
+ console.warn('TextInput is deprecated. Use Input component instead')
}
}
-
-TextInput.defaultProps = {
- onChange: function(e) {
- console.log(e.target.value);
- },
- label: '',
- defaultValue: undefined,
- type: 'text',
- readonly: false,
- style:{}
-
-}
+export default TextInput;
import React, {Component} from 'react';
import 'style/core.css';
import './panel.scss';
+import circleXImage from '../../../node_modules/open-iconic/svg/circle-x.svg';
export class Panel extends Component {
constructor(props) {
super(props)
let classRoot = className ? ' ' + className : ' ';
let hasCorners = this.props['no-corners'];
let titleTag = title ? <header className="skyquakePanel-title">{title}</header> : '';
+ let closeButton = (
+ <a onClick={self.props.hasCloseButton}
+ className={"close-btn"}>
+ <img src={circleXImage} title="Close card" />
+ </a>
+ );
return (
<section className={'skyquakePanel' + classRoot} style={props.style}>
+ { self.props.hasCloseButton ? closeButton : null}
{ !hasCorners ? <i className="corner-accent top left"></i> : null }
{ !hasCorners ? <i className="corner-accent top right"></i> : null }
{titleTag}
width:100%;
height:100%;
}
+ .close-btn {
+ cursor:pointer;
+ position: absolute;
+ right: -0.5rem;
+ top: -0.5rem;
+ img {
+ width: 1rem;
+ }
+ }
}
.skyquakePanelWrapper.column {
+ -ms-flex-direction:column;
+ flex-direction:column;
+ display:-ms-flexbox;
+ display:flex;
.skyquakePanel-wrapper {
height:auto;
}
currentPlugin={this.state.currentPlugin}
store={SkyquakeContainerStore} />
<div className="titleBar">
- <h1>{this.state.currentPlugin + tag}</h1>
+ <h1>{(this.state.nav.name ? this.state.nav.name : this.state.currentPlugin) + tag}</h1>
</div>
<div className={"application " + routeName}>
{this.props.children}
// write the current choice value into the state
let choiceObject = utils.resolvePath(this.model, [name, selected].join('.'));
let isTopCase = false;
- if (!choiceObject) {
+ if (choiceObject) {
isTopCase = true;
choiceObject = utils.resolvePath(this.model, [selected].join('.'));
}
"normalizr": "^2.1.0",
"open-iconic": "^1.1.1",
"prismjs": "^1.4.1",
- "react": "^0.14.8",
"react-awesome-modal": "^0.3.3",
"react-breadcrumbs": "^1.3.9",
"react-crouton": "^0.2.7",
- "react-dom": "^0.14.6",
"react-router": "^2.0.1",
"react-slick": "^0.11.1",
"react-tabs": "^0.8.0",
"react-treeview": "^0.4.2",
+ "react": ">=15.0.1",
+ "react-dom": ">=15.0.1"
"request-promise": "^3.0.0",
"underscore": "^1.8.3"
},
--- /dev/null
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(BEGIN)
+# Author(s): Kiran Kashalkar
+# Creation Date: 08/18/2015
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(END)
+
+##
+# DEPENDENCY ALERT
+# The submodule dependencies must be specified in the
+# .gitmodules.dep file at the top level (supermodule) directory
+# If this submodule depends other submodules remember to update
+# the .gitmodules.dep
+##
+
+cmake_minimum_required(VERSION 2.8)
+
+##
+# Submodule specific includes will go here,
+# These are specified here, since these variables are accessed
+# from multiple sub directories. If the variable is subdirectory
+# specific it must be declared in the subdirectory.
+##
+
+rift_externalproject_add(
+ config
+ DEPENDS skyquake
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+ CONFIGURE_COMMAND echo
+ BUILD_COMMAND
+ ${CMAKE_CURRENT_BINARY_DIR}/config/config-build/scripts/build.sh
+ INSTALL_COMMAND
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install.sh
+ ${CMAKE_CURRENT_BINARY_DIR}/config/config-build
+ ${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+ ${RIFT_SUBMODULE_INSTALL_PREFIX}/skyquake/${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+
+ BCACHE_COMMAND echo
+)
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var request = require('request');
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var utils = require('../../../framework/core/api_utils/utils.js');
+var constants = require('../../../framework/core/api_utils/constants.js');
+var _ = require('underscore');
+var RO = {}
+RO.get = function(req) {
+return new Promise(function(resolve, reject) {
+ var self = this;
+ var api_server = req.query["api_server"];
+ var requestHeaders = {};
+ var url = utils.confdPort(api_server) + '/api/running/resource-orchestrator';
+ _.extend(
+ requestHeaders,
+ id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
+ 'Authorization': req.get('Authorization')
+ }
+ );
+
+ request({
+ url: url + '?deep',
+ type: 'GET',
+ headers: requestHeaders,
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false
+ },
+ function(error, response, body) {
+ var data;
+ if (utils.validateResponse('RO.get', error, response, body, resolve, reject)) {
+ try {
+ data = JSON.parse(response.body);
+ if (!id) {
+ data = data.collection;
+ }
+
+ data = data[objKey]
+ } catch (e) {
+ console.log('Problem with "' + type.toUpperCase() + '.get"', e);
+ var err = {};
+ err.statusCode = 500;
+ err.errorMessage = {
+ error: 'Problem with "' + type.toUpperCase() + '.get": ' + e
+ }
+ return reject(err);
+ }
+ return resolve({
+ statusCode: response.statusCode,
+ data: data
+ });
+ };
+ });
+ });
+}
+
+RO.update = updateAccount;
+
+function updateAccount(req) {
+ var self = this;
+ var api_server = req.query["api_server"];
+ var data = req.body;
+ var requestHeaders = {};
+ var url = utils.confdPort(api_server) + '/api/config/resource-orchestrator';
+ var method = 'PUT'
+
+ return new Promise(function(resolve, reject) {
+ _.extend(requestHeaders,
+ constants.HTTP_HEADERS.accept.data,
+ constants.HTTP_HEADERS.content_type.data, {
+ 'Authorization': req.get('Authorization')
+ });
+ request({
+ url: url,
+ method: method,
+ headers: requestHeaders,
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ json: data,
+ }, function(error, response, body) {
+ if (utils.validateResponse('RO.update', error, response, body, resolve, reject)) {
+ return resolve({
+ statusCode: response.statusCode,
+ data: JSON.stringify(response.body)
+ });
+ };
+ });
+ })
+}
+
+module.exports = RO;
--- /dev/null
+{
+ "root": "public",
+ "name": "User Management",
+ "dashboard": "./dashboard/dashboard.jsx",
+ "order": 1,
+ "priority":1,
+ "routes": [
+ {
+ "label": "User Management Dashboard",
+ "route": "user-management",
+ "component": "./dashboard/dashboard.jsx",
+ "type": "internal"
+ }]
+}
--- /dev/null
+{
+ "name": "config",
+ "version": "1.0.0",
+ "description": "",
+ "main": "routes.js",
+ "scripts": {
+ "start": "rm -rf public/ && mkdir public && cd public && mkdir build && cp ../src/index.html ./ && node ../server.js"
+ },
+ "author": "RIFT.io",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "alt": "^0.18.3",
+ "bluebird": "^3.4.1",
+ "express": "^4.13.3",
+ "history": "^1.17.0",
+ "jquery": "^2.2.1",
+ "json-loader": "^0.5.4",
+ "lodash": "^4.10.0",
+ "normalizr": "^2.1.0",
+ "open-iconic": "^1.1.1",
+ "prismjs": "^1.4.1",
+ "react": "^0.14.8",
+ "react-breadcrumbs": "^1.3.9",
+ "react-crouton": "^0.2.7",
+ "react-dom": "^0.14.6",
+ "react-router": "^2.0.1",
+ "react-slick": "^0.11.1",
+ "react-tabs": "^0.5.3",
+ "react-treeview": "^0.4.2",
+ "request-promise": "^3.0.0",
+ "underscore": "^1.8.3"
+ },
+ "devDependencies": {
+ "babel-core": "^6.4.5",
+ "babel-loader": "^6.2.1",
+ "babel-polyfill": "^6.9.1",
+ "babel-preset-es2015": "^6.6.0",
+ "babel-preset-react": "^6.5.0",
+ "babel-preset-stage-0": "^6.3.13",
+ "babel-runtime": "^6.3.19",
+ "cors": "^2.7.1",
+ "css-loader": "^0.23.1",
+ "file-loader": "^0.8.5",
+ "html-webpack-plugin": "^2.9.0",
+ "http-proxy": "^1.12.0",
+ "loaders.css": "^0.1.2",
+ "node-sass": "^3.4.2",
+ "react-addons-css-transition-group": "^0.14.7",
+ "sass-loader": "^3.1.2",
+ "style-loader": "^0.13.0",
+ "webpack": "^1.3.0",
+ "webpack-dev-server": "^1.16.3"
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var app = require('express').Router();
+var cors = require('cors');
+var utils = require('../../framework/core/api_utils/utils.js')
+var ro = require('./api/ro.js')
+ // Begin Accounts API
+ app.get('/resource-orchestrator', cors(), function(req, res) {
+ ro.get(req).then(function(data) {
+ utils.sendSuccessResponse(data, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+ });
+ app.put('/resource-orchestrator', cors(), function(req, res) {
+ ro.update(req).then(function(data) {
+ utils.sendSuccessResponse(data, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+ })
+
+ utils.passThroughConstructor(app);
+
+module.exports = app;
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+PLUGIN_NAME=user-management
+# change to the directory of this script
+THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd $THIS_DIR
+cd ..
+
+echo 'Building plugin '$PLUGIN_NAME
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME
+npm install
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME'...done'
+echo 'Packaging '$PLUGIN_NAME' using webpack'
+ui_plugin_cmake_build=true ./node_modules/.bin/webpack --progress --config webpack.production.config.js
+echo 'Packaging '$PLUGIN_NAME' using webpack... done'
+echo 'Building plugin '$PLUGIN_NAME'... done'
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+plugin=user-management
+source_dir=$1
+dest_dir=$2
+bcache_dir=$3
+
+# Create destination and build cache directories
+mkdir -p $dest_dir
+mkdir -p $bcache_dir
+
+# Create necessary directories under dest and cache dirs
+mkdir -p $dest_dir/framework
+mkdir -p $dest_dir/plugins
+mkdir -p $bcache_dir/framework
+mkdir -p $bcache_dir/plugins
+
+# Copy over built plugin's public folder, config.json, routes.js and api folder as per installed_plugins.txt
+mkdir -p $dest_dir/plugins/$plugin
+cp -Lrf $source_dir/public $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $dest_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $dest_dir/plugins/$plugin/.
+tar -cf $dest_dir/plugins/$plugin/node_modules.tar node_modules package.json -C $source_dir
+#cp -Lrp $source_dir/node_modules $dest_dir/plugins/$plugin/.
+mkdir -p $bcache_dir/plugins/$plugin
+cp -Lrf $source_dir/public $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $bcache_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $bcache_dir/plugins/$plugin/.
+tar -cf $bcache_dir/plugins/$plugin/node_modules.tar $source_dir/node_modules $source_dir/package.json
+#cp -Lrp $source_dir/node_modules $bcache_dir/plugins/$plugin/.
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var express = require('express');
+var path = require('path');
+var httpProxy = require('http-proxy');
+var bodyParser = require('body-parser');
+var cors = require('cors');
+var session = require('express-session');
+var proxy = httpProxy.createProxyServer();
+var app = express();
+
+var isProduction = process.env.NODE_ENV === 'production';
+var port = isProduction ? 8080 : 8888;
+var publicPath = path.resolve(__dirname, 'public');
+
+if (!isProduction) {
+
+ //Routes for local development
+ var lpRoutes = require('./routes.js');
+
+ app.use(express.static(publicPath));
+ app.use(session({
+ secret: 'ritio rocks',
+ }));
+ app.use(bodyParser.urlencoded({
+ extended: true
+ }));
+ app.use(bodyParser.json());
+ app.use(cors());
+ app.use('/', lpRoutes);
+ var bundle = require('./server/bundle.js');
+ bundle();
+
+ app.all('/build/*', function (req, res) {
+ proxy.web(req, res, {
+ target: 'http://localhost:8080'
+ });
+ });
+
+}
+proxy.on('error', function(e) {
+ console.log('Could not connect to proxy, please try again...');
+});
+
+app.listen(port, function () {
+ console.log('Server running on port ' + port);
+});
+
+app.get('/*')
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import UserManagementStore from './userMgmtStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import './userMgmt.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+
+
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import 'widgets/form_controls/formControls.scss';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
+
+class UserManagementDashboard extends React.Component {
+ constructor(props) {
+ super(props);
+ this.Store = this.props.flux.stores.hasOwnProperty('UserManagementStore') ? this.props.flux.stores.UserManagementStore : this.props.flux.createStore(UserManagementStore);
+ this.Store.getUsers();
+ this.state = this.Store.getState();
+ this.actions = this.state.actions;
+ }
+ componentDidUpdate() {
+
+ ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
+ }
+ componentWillMount() {
+ this.Store.listen(this.updateState);
+ }
+ componentWillUnmount() {
+ this.Store.unlisten(this.updateState);
+ }
+ updateState = (state) => {
+ this.setState(state);
+ }
+ updateInput = (key, e) => {
+ let property = key;
+ this.actions.handleUpdateInput({
+ [property]:e.target.value
+ })
+ }
+ disabledChange = (e) => {
+ this.actions.handleDisabledChange(e.target.checked);
+ }
+ platformChange = (platformRole, e) => {
+ this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
+ }
+ addProjectRole = (e) => {
+ this.actions.handleAddProjectItem();
+ }
+ removeProjectRole = (i, e) => {
+ this.actions.handleRemoveProjectItem(i);
+ }
+ updateProjectRole = (i, e) => {
+ this.actions.handleUpdateProjectRole(i, e)
+ }
+ addUser = () => {
+ this.actions.handleAddUser();
+ }
+ viewUser = (un, index) => {
+ console.log(un)
+ this.actions.viewUser(un, index);
+ }
+ closePanel = () => {
+ this.actions.handleCloseUserPanel();
+ }
+ updateUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.Store.updateUser();
+ }
+ deleteUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.Store.deleteUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain']
+ });
+ }
+ createUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if(this.state['new-password'] != this.state['confirm-password']) {
+ this.props.actions.showNotification('Passwords do not match')
+ } else {
+ this.Store.createUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain'],
+ 'password': this.state['new-password']
+ // 'confirm-password': this.state['confirm-password']
+ });
+ }
+ }
+
+ onTransitionEnd = (e) => {
+ this.actions.handleHideColumns(e);
+ console.log('transition end')
+ }
+ render() {
+ let self = this;
+ let html;
+ let props = this.props;
+ let state = this.state;
+ html = (
+ <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
+ <PanelWrapper ref={(div) => { this.UserList = div}} className={`column userList expanded ${this.state.userOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
+ <Panel title="User List" style={{marginBottom: 0}} no-corners>
+ <div className="tableRow tableRow--header">
+ <div className="userName">
+ Username
+ </div>
+ <div>
+ Domain
+ </div>
+ </div>
+ {state.users.map((u, k) => {
+ let platformRoles = [];
+ for(let role in u.platformRoles) {
+ platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
+ }
+ return (
+ <div className={`tableRow tableRow--data ${((self.state.activeIndex == k) && !self.state.userOpen) ? 'tableRow--data-active' : ''}`} key={k}>
+ <div
+ className={`userName userName-header ${((self.state.activeIndex == k) && self.state.userOpen) ? 'activeUser' : ''}`}
+ onClick={self.viewUser.bind(null, u, k)}>
+ {u['user-name']}
+ </div>
+ <div>
+ {u['user-domain']}
+ </div>
+
+
+ </div>
+ )
+ })}
+ </Panel>
+ <ButtonGroup className="buttonGroup" style={{margin: '0 0.5rem 0.5rem', background: '#ddd', paddingBottom: '0.5rem'}}>
+ <Button label="Add User" onClick={this.addUser} />
+ </ButtonGroup>
+ </PanelWrapper>
+ <PanelWrapper
+ className={`userAdmin column`}>
+ <Panel
+ title={state.isEdit ? state['user-name'] : 'Create User'}
+ style={{marginBottom: 0}}
+ hasCloseButton={this.closePanel}
+ no-corners>
+ <FormSection title="USER INFO">
+ {
+ this.state.isEdit ?
+ null
+ : <Input label="Username" value={state['user-name']} onChange={this.updateInput.bind(null, 'user-name')} />
+ }
+ <Input label="Domain" value={state['user-domain']} onChange={this.updateInput.bind(null, 'user-domain')}></Input>
+ <Input label="Disabled" onChange={this.disabledChange} checked={state.disabled} type="checkbox" />
+ </FormSection>
+ <FormSection title="PLATFORM ROLES">
+ <Input label="Super Admin" onChange={this.platformChange.bind(null, 'super_admin')} checked={state.platformRoles.super_admin} type="checkbox" />
+ <Input label="Platform Admin" onChange={this.platformChange.bind(null, 'platform_admin')} checked={state.platformRoles.platform_admin} type="checkbox" />
+ <Input label="Platform Oper" onChange={this.platformChange.bind(null, 'platform_oper')} checked={state.platformRoles.platform_oper} type="checkbox" />
+ </FormSection>
+ <FormSection title="PROJECT ROLES">
+ <InputCollection
+ inital={true}
+ type='select'
+ options={state.projectRolesOptions}
+ collection={state.projectRoles}
+ onChange={this.updateProjectRole}
+ AddItemFn={this.addProjectRole}
+ RemoveItemFn={this.removeProjectRole}
+ />
+ </FormSection>
+ { this.state.isEdit ?
+ (
+ <FormSection title="PASSWORD CHANGE">
+ <Input label="OLD PASSWORD" type="password" value={state['old-password']} onChange={this.updateInput.bind(null, 'old-password')} />
+ <Input label="NEW PASSWORD" type="password" value={state['new-password']} onChange={this.updateInput.bind(null, 'new-password')}/>
+ <Input label="REPEAT NEW PASSWORD" type="password" value={state['confirm-password']} onChange={this.updateInput.bind(null, 'confirm-password')}/>
+ </FormSection>
+ ) :
+ (
+ <FormSection title="CREATE PASSWORD">
+ <Input label="CREATE PASSWORD" type="password" value={state.newPassword} onChange={this.updateInput.bind(null, 'new-password')}/>
+ <Input label="REPEAT PASSWORD" type="password" value={state.repeatNewPassword} onChange={this.updateInput.bind(null, 'confirm-password')}/>
+ </FormSection>
+ )
+ }
+
+ </Panel>
+
+ {
+ state.isEdit ?
+ (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Update" onClick={this.updateUser} />
+ <Button label="Delete" onClick={this.deleteUser} />
+ </ButtonGroup>
+ )
+ : (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Create" onClick={this.createUser} />
+ </ButtonGroup>
+ )
+ }
+
+ </PanelWrapper>
+
+ </PanelWrapper>
+ );
+ return html;
+ }
+}
+// onClick={this.Store.update.bind(null, Account)}
+UserManagementDashboard.contextTypes = {
+ router: React.PropTypes.object
+};
+
+UserManagementDashboard.defaultProps = {
+ userList: [],
+ selectedUser: {}
+}
+
+export default SkyquakeComponent(UserManagementDashboard);
+
+
+
+
+/**
+ * AddItemFn:
+ */
+class InputCollection extends React.Component {
+ constructor(props) {
+ super(props);
+ this.collection = props.collection;
+ }
+ buildTextInput(onChange, v, i) {
+ return (
+ <Input
+ style={{flex: '1 1'}}
+ key={i}
+ value={v}
+ onChange= {onChange.bind(null, i)}
+ />
+ )
+ }
+ buildSelectOption(initial, options, onChange, v, i) {
+ return (
+ <SelectOption
+ key={`${i}-${v.replace(' ', '_')}`}
+ intial={initial}
+ defaultValue={v}
+ options={options}
+ onChange={onChange.bind(null, i)}
+ />
+ );
+ }
+ showInput() {
+
+ }
+ render() {
+ const props = this.props;
+ let inputType;
+ let className = "InputCollection";
+ if (props.className) {
+ className = `${className} ${props.className}`;
+ }
+ if (props.type == 'select') {
+ inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
+ } else {
+ inputType = this.buildTextInput.bind(this, props.onChange)
+ }
+ let html = (
+ <div className="InputCollection-wrapper">
+ {props.collection.map((v,i) => {
+ return (
+ <div key={i} className={className} >
+ {inputType(v, i)}
+ <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>
+ </div>
+ )
+ })}
+ <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>
+ </div>
+ );
+ return html;
+ }
+}
+
+InputCollection.defaultProps = {
+ input: Input,
+ collection: [],
+ onChange: function(i, e) {
+ console.log(`
+ Updating with: ${e.target.value}
+ At index of: ${i}
+ `)
+ },
+ AddItemFn: function(e) {
+ console.log(`Adding a new item to collection`)
+ },
+ RemoveItemFn: function(i, e) {
+ console.log(`Removing item from collection at index of: ${i}`)
+ }
+}
+
+class FormSection extends React.Component {
+ render() {
+ let className = 'FormSection ' + this.props.className;
+ let html = (
+ <div
+ style={this.props.style}
+ className={className}
+ >
+ <div className="FormSection-title">
+ {this.props.title}
+ </div>
+ <div className="FormSection-body">
+ {this.props.children}
+ </div>
+ </div>
+ );
+ return html;
+ }
+}
+
+FormSection.defaultProps = {
+ className: ''
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.userManagement {
+ .skyquakePanel-wrapper {
+ overflow-x: hidden;
+ }
+ .userList {
+
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+
+ .activeUser {
+ font-weight:bold;
+ }
+
+ /* transition: all 2s;*/
+ &.expanded {
+ -ms-flex: 1 1 100%;
+ flex: 1 1 100%;
+ /* transition: all 300ms;*/
+ .tableRow>div:not(.userName) {
+ opacity: 1;
+ /* width:auto;*/
+ /* transition: width 600ms;*/
+ /* transition: opacity 300ms;*/
+ }
+ &.collapsed {
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+ /* transition: all 2s;*/
+ .tableRow>div:not(.userName) {
+ /* opacity: 0;*/
+ /* width:0px;*/
+ display:none;
+ overflow:hidden;
+ /* transition: all 600ms;*/
+ }
+ }
+ }
+ &.hideColumns {
+ overflow:hidden;
+ >div {
+ overflow:hidden;
+ }
+ .tableRow>div:not(.userName) {
+ width: 0px;
+ /* transition: all 600ms;*/
+ }
+ .userName {
+ &--header {
+ /* display:none;*/
+ }
+ }
+ }
+ .userName {
+ cursor:pointer;
+ }
+
+ }
+
+ .userAdmin {
+ -ms-flex: 0 1 450px;
+ flex: 0 1 450px;
+ width:auto;
+ opacity:1;
+ }
+ &.userList-open {
+ .userAdmin {
+ -ms-flex: 0 1 0px;
+ flex: 0 1 0px;
+ opacity:0;
+ /* width: 0px;*/
+ display:none;
+ /* transition: opacity 300ms;*/
+ /* transition: width 600ms;*/
+
+ }
+ }
+ .buttonGroup {
+ margin: 0 0.5rem 0.5rem;
+ background: #ddd;
+ padding-bottom: 0.5rem;
+ padding: 0.5rem 0;
+ border-top: #d3d3d3 1px solid;
+ }
+}
+
+
+
+.FormSection {
+ &-title {
+ color: #000;
+ background: lightgray;
+ padding: 0.5rem;
+ border-top: 1px solid #f1f1f1;
+ border-bottom: 1px solid #f1f1f1;
+ }
+ &-body {
+ padding: 0.5rem 0.75rem;
+ }
+ label {
+ -ms-flex: 1 0;
+ flex: 1 0;
+ }
+ /* label {*/
+ /* display: -ms-flexbox;*/
+ /* display: flex;*/
+ /* -ms-flex-direction: column;*/
+ /* flex-direction: column;*/
+ /* width: 100%;*/
+ /* margin: 0.5rem 0;*/
+ /* -ms-flex-align: start;*/
+ /* align-items: flex-start;*/
+ /* -ms-flex-pack: start;*/
+ /* justify-content: flex-start;*/
+ /* }*/
+ select {
+ font-size: 1rem;
+ min-width: 75%;
+ height: 35px;
+ }
+}
+
+
+.InputCollection {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -ms-flex-align: center;
+ align-items: center;
+ button {
+ padding: 0.25rem;
+ height: 1.5rem;
+ font-size: 0.75rem;
+ }
+ select {
+ min-width: 100%;
+ }
+ margin-bottom:0.5rem;
+ &-wrapper {
+
+ }
+}
+.tableRow {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ >div {
+ padding:0.25rem 1rem 0.25rem 0;
+ -ms-flex: 1 1 33%;
+ flex: 1 1 33%;
+ }
+ &--header {
+ font-weight:bold;
+ }
+ &--data {
+ &:hover, .activeUser{
+ cursor:pointer;
+ background:$neutral-dark-3;
+ color:white;
+ }
+ }
+}
+
+.addInput, .removeInput {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-left: 1rem;
+
+ font-size:0.75rem;
+ text-transform:uppercase;
+ font-weight:bold;
+
+ cursor:pointer;
+ img {
+ height:0.75rem;
+ margin-right:0.5rem;
+ width:auto;
+ }
+ span {
+ color: #5b5b5b;
+ text-transform: uppercase;
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+ return Alt.generateActions(
+ 'handleUpdateInput',
+ 'handleAddProjectItem',
+ 'handleRemoveProjectItem',
+ 'handleUpdateProjectRole',
+ 'viewUser',
+ 'handleCloseUserPanel',
+ 'handleHideColumns',
+ 'getUsersSuccess',
+ 'getUsersNotification',
+ 'handleDisabledChange',
+ 'handlePlatformRoleUpdate',
+ 'handleAddUser',
+ 'handleCreateUser',
+ 'handleUpdateUser',
+ 'updateUserSuccess',
+ 'createUserSuccess',
+ 'deleteUserSuccess'
+ );
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import $ from 'jquery';
+var Utils = require('utils/utils.js');
+let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
+let HOST = API_SERVER;
+let NODE_PORT = require('utils/rw.js').getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
+let DEV_MODE = require('utils/rw.js').getSearchParams(window.location).dev_mode || false;
+
+if (DEV_MODE) {
+ HOST = window.location.protocol + '//' + window.location.hostname;
+}
+
+
+let Users = mockUsers();
+
+
+module.exports = function(Alt) {
+ return {
+ getUsers: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ // setTimeout(function() {
+ // resolve(Users);
+ // }, 1000)
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.users);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getUsersSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ updateUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ setTimeout(function() {
+ resolve(true);
+ }, 1000)
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the user.'
+ }),
+ success: Alt.actions.global.updateUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ deleteUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ // setTimeout(function() {
+ // resolve(true);
+ // }, 1000)
+ $.ajax({
+ url: `/user/${user['user-name']}/${user['user-domain']}?api_server=${API_SERVER}`,
+ type: 'DELETE',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error deleting the user.'
+ }),
+ success: Alt.actions.global.deleteUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ createUser: {
+ remote: function(state, user) {
+
+ return new Promise(function(resolve, reject) {
+ // setTimeout(function() {
+ // resolve(true);
+ // }, 1000)
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'POST',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the account.'
+ }),
+ success: Alt.actions.global.createUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ }
+ }
+}
+
+function interceptResponse (responses) {
+ return function(data, action, args) {
+ if(responses.hasOwnProperty(data)) {
+ return {
+ type: data,
+ msg: responses[data]
+ }
+ } else {
+ return data;
+ }
+ }
+}
+
+function mockUsers() {
+ let data = [];
+ let count = 10;
+ for(let i = 0; i < 10; i++) {
+ data.push({
+ username: `Tester ${i}`,
+ domain: 'Some Domain',
+ platformRoles: {
+ super_admin: true,
+ platform_admin: false,
+ platform_oper: false
+ },
+ disabled: false,
+ projectRoles: [
+ 'Project:Role'
+ ]
+ })
+ }
+ return data;
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import UserManagementActions from './userMgmtActions.js';
+import UserManagementSource from './userMgmtSource.js';
+import _ from 'lodash';
+export default class UserManagementStore {
+ constructor() {
+ this.actions = UserManagementActions(this.alt);
+ this.bindActions(this.actions);
+ this.registerAsync(UserManagementSource);
+ this.users = [];
+ this['user-name'] = '';
+ this['user-domain'] = '';
+ this.disabled = false;
+ this.platformRoles = {
+ super_admin: false,
+ platform_admin: false,
+ platform_oper: false
+ };
+ this.projectRoles = ['Project:Role'];
+ this.projectRolesOptions = ['Choose your adventure', 'Project:Role', 'Project:Another Role'];
+ this.currentPassword = '';
+ this['old-password'] = '';
+ this['new-password'] = '';
+ this['confirm-password'] = '';
+
+ this.activeIndex = null;
+ this.userOpen = false;
+ this.hideColumns = false;
+ this.isEdit = false;
+ // this.exportPublicMethods({})
+ }
+ /**
+ * [handleFieldUpdate description]
+ * @param {Object} data {
+ * [store_property] : [value]
+ * }
+ * @return {[type]} [description]
+ */
+ handleUpdateInput(data) {
+ this.setState(data);
+ }
+ handleAddProjectItem(item) {
+ let projectRoles = this.projectRoles;
+ projectRoles.push('');
+ this.setState({projectRoles});
+ }
+ handleRemoveProjectItem(i) {
+ let projectRoles = this.projectRoles;
+ projectRoles.splice(i, 1);
+ console.log('Removing', projectRoles)
+ this.setState({projectRoles});
+ }
+ handleUpdateProjectRole(data) {
+ let i = data[0];
+ let e = data[1];
+ let projectRoles = this.projectRoles
+ projectRoles[i] = JSON.parse(e.currentTarget.value);
+ this.setState({
+ projectRoles
+ });
+ }
+ viewUser(data) {
+ let user = data[0];
+ let userIndex = data[1];
+
+ let ActiveUser = {
+ 'user-name': user['user-name'],
+ 'user-domain': user['user-domain'],
+ platformRoles: user.platformRoles || this.platformRoles,
+ disabled: user.disabled || this.disabled,
+ projectRoles: user.projectRoles || this.projectRoles
+ }
+ let state = _.merge({
+ activeIndex: userIndex,
+ userOpen: true,
+ isEdit: true
+ }, ActiveUser);
+ this.setState(state)
+ }
+ handleCloseUserPanel() {
+ this.setState({
+ userOpen: false,
+ isEdit: false
+ })
+ }
+ handleHideColumns(e) {
+ if(this.userOpen && e.currentTarget.classList.contains('hideColumns')) {
+ this.setState({
+ hideColumns: true
+ })
+ } else {
+ this.setState({
+ hideColumns: false
+ })
+ }
+ }
+ handleDisabledChange(isDisabled){
+ this.setState({
+ disabled: isDisabled
+ })
+ }
+ handlePlatformRoleUpdate(data){
+ let platform_role = data[0];
+ let checked = data[1];
+ let platformRoles = this.platformRoles;
+ platformRoles[platform_role] = checked;
+ this.setState({
+ platformRoles
+ })
+ }
+ resetUser() {
+ let username = '';
+ let domain = '';
+ let disabled = false;
+ let platformRoles = {
+ super_admin: false,
+ platform_admin: false,
+ platform_oper: false
+ };
+ let projectRoles = [];
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ 'user-name' : username,
+ 'user-domain' : domain,
+ disabled,
+ platformRoles,
+ projectRoles,
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ resetPassword() {
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ handleAddUser() {
+ this.setState(_.merge( this.resetUser() ,{ isEdit: false, userOpen: true }))
+ }
+ handleCreateUser() {
+
+ }
+ handleUpdateUser() {
+
+ }
+
+ getUsersSuccess(users) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({users});
+ }
+ updateUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users;
+ users[this.activeIndex] = {
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles
+ }
+ this.setState({users})
+ }
+ deleteUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users;
+ users.splice(this.activeIndex, 1);
+ this.setState({users, userOpen: false})
+ }
+ createUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users;
+ users.push({
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles
+ });
+ let newState = {users, isEdit: true};
+ _.merge(newState, this.resetPassword())
+ this.setState(newState);
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import "babel-polyfill";
+import { render } from 'react-dom';
+import SkyquakeRouter from 'widgets/skyquake_container/skyquakeRouter.jsx';
+const config = require('json!../config.json');
+
+let context = require.context('./', true, /^\.\/.*\.jsx$/);
+let router = SkyquakeRouter(config, context);
+let element = document.querySelector('#app');
+
+render(router, element);
+
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+var Webpack = require('webpack');
+var path = require('path');
+var nodeModulesPath = path.resolve(__dirname, 'node_modules');
+var buildPath = path.resolve(__dirname, 'public', 'build');
+var mainPath = path.resolve(__dirname, 'src', 'main.js');
+var uiPluginCmakeBuild = process.env.ui_plugin_cmake_build || false;
+var frameworkPath = uiPluginCmakeBuild?'../../../../skyquake/skyquake-build/framework':'../../framework';
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var CommonsPlugin = new require("webpack/lib/optimize/CommonsChunkPlugin")
+// Added to overcome node-sass bug https://github.com/iam4x/isomorphic-flux-boilerplate/issues/62
+process.env.UV_THREADPOOL_SIZE=64;
+var config = {
+ devtool: 'source-map',
+ entry: mainPath,
+ output: {
+ path: buildPath,
+ filename: 'bundle.js',
+ publicPath: "build/"
+ },
+ resolve: {
+ extensions: ['', '.js', '.jsx', '.css', '.scss'],
+ root: path.resolve(frameworkPath),
+ alias: {
+ 'widgets': path.resolve(frameworkPath) + '/widgets',
+ 'style': path.resolve(frameworkPath) + '/style',
+ 'utils': path.resolve(frameworkPath) + '/utils'
+ }
+ },
+ module: {
+ loaders: [{
+ test: /\.(jpe?g|png|gif|svg|ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/i,
+ loader: "file-loader"
+ },
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /react-treeview/,
+ loader: 'babel-loader',
+ query: {
+ presets: ["es2015", "stage-0", "react"]
+ }
+ }, {
+ test: /\.css$/,
+ loader: 'style!css'
+ }, {
+ test: /\.scss/,
+ loader: 'style!css!sass?includePaths[]='+ path.resolve(frameworkPath)
+ }
+ ]
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ filename: '../index.html'
+ , templateContent: '<div id="app"></div>'
+ }),
+ new Webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity)
+ ]
+};
+module.exports = config;
var descriptor_routes = require('./framework/core/modules/routes/descriptorModel');
var configuration_routes = require('./framework/core/modules/routes/configuration');
var configurationAPI = require('./framework/core/modules/api/configuration');
+ var userManagement_routes = require('./framework/core/modules/routes/userManagement');
/**
* Processing when a plugin is added or modified
* @param {string} plugin_name - Name of the plugin
//Configure descriptor route(s)
app.use(descriptor_routes);
+ //Configure user management route(s)
+ app.use(userManagement_routes);
+
// app.get('/testme', function(req, res) {
// res.sendFile(__dirname + '/index.html');
// });