project-management -> project_management, user-management->user_management
authorLaurence Maultsby <laurence.maultsby@riftio.com>
Thu, 16 Mar 2017 00:52:07 +0000 (20:52 -0400)
committermaultsby <laurence.maultsby@riftio.com>
Thu, 16 Mar 2017 19:13:09 +0000 (20:13 +0100)
Signed-off-by: Laurence Maultsby <laurence.maultsby@riftio.com>
57 files changed:
skyquake/plugins/CMakeLists.txt
skyquake/plugins/project-management/CMakeLists.txt [deleted file]
skyquake/plugins/project-management/config.json [deleted file]
skyquake/plugins/project-management/package.json [deleted file]
skyquake/plugins/project-management/routes.js [deleted file]
skyquake/plugins/project-management/scripts/build.sh [deleted file]
skyquake/plugins/project-management/scripts/install.sh [deleted file]
skyquake/plugins/project-management/server.js [deleted file]
skyquake/plugins/project-management/src/dashboard/dashboard.jsx [deleted file]
skyquake/plugins/project-management/src/dashboard/projectMgmt.scss [deleted file]
skyquake/plugins/project-management/src/dashboard/projectMgmtActions.js [deleted file]
skyquake/plugins/project-management/src/dashboard/projectMgmtSource.js [deleted file]
skyquake/plugins/project-management/src/dashboard/projectMgmtStore.js [deleted file]
skyquake/plugins/project-management/src/main.js [deleted file]
skyquake/plugins/project-management/webpack.production.config.js [deleted file]
skyquake/plugins/project_management/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/project_management/config.json [new file with mode: 0644]
skyquake/plugins/project_management/package.json [new file with mode: 0644]
skyquake/plugins/project_management/routes.js [new file with mode: 0644]
skyquake/plugins/project_management/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/project_management/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/project_management/server.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/dashboard.jsx [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmt.scss [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtActions.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtSource.js [new file with mode: 0644]
skyquake/plugins/project_management/src/dashboard/projectMgmtStore.js [new file with mode: 0644]
skyquake/plugins/project_management/src/main.js [new file with mode: 0644]
skyquake/plugins/project_management/webpack.production.config.js [new file with mode: 0644]
skyquake/plugins/user-management/CMakeLists.txt [deleted file]
skyquake/plugins/user-management/config.json [deleted file]
skyquake/plugins/user-management/package.json [deleted file]
skyquake/plugins/user-management/routes.js [deleted file]
skyquake/plugins/user-management/scripts/build.sh [deleted file]
skyquake/plugins/user-management/scripts/install.sh [deleted file]
skyquake/plugins/user-management/server.js [deleted file]
skyquake/plugins/user-management/src/dashboard/dashboard.jsx [deleted file]
skyquake/plugins/user-management/src/dashboard/userMgmt.scss [deleted file]
skyquake/plugins/user-management/src/dashboard/userMgmtActions.js [deleted file]
skyquake/plugins/user-management/src/dashboard/userMgmtSource.js [deleted file]
skyquake/plugins/user-management/src/dashboard/userMgmtStore.js [deleted file]
skyquake/plugins/user-management/src/main.js [deleted file]
skyquake/plugins/user-management/webpack.production.config.js [deleted file]
skyquake/plugins/user_management/CMakeLists.txt [new file with mode: 0644]
skyquake/plugins/user_management/config.json [new file with mode: 0644]
skyquake/plugins/user_management/package.json [new file with mode: 0644]
skyquake/plugins/user_management/routes.js [new file with mode: 0644]
skyquake/plugins/user_management/scripts/build.sh [new file with mode: 0755]
skyquake/plugins/user_management/scripts/install.sh [new file with mode: 0755]
skyquake/plugins/user_management/server.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/dashboard.jsx [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmt.scss [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtActions.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtSource.js [new file with mode: 0644]
skyquake/plugins/user_management/src/dashboard/userMgmtStore.js [new file with mode: 0644]
skyquake/plugins/user_management/src/main.js [new file with mode: 0644]
skyquake/plugins/user_management/webpack.production.config.js [new file with mode: 0644]

index acfe863..60a8102 100644 (file)
@@ -1,4 +1,4 @@
-# 
+#
 #   Copyright 2016 RIFT.IO Inc
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,7 @@
 #
 # Author(s): Kiran Kashalkar
 # Creation Date: 08/18/2015
-# 
+#
 
 ##
 # DEPENDENCY ALERT
@@ -44,6 +44,8 @@ set(
     composer
     config
     debug
+    project_management
+    user_management
 #    goodbyworld
 #    helloworld
     launchpad
diff --git a/skyquake/plugins/project-management/CMakeLists.txt b/skyquake/plugins/project-management/CMakeLists.txt
deleted file mode 100644 (file)
index e12d4fd..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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
-)
-
diff --git a/skyquake/plugins/project-management/config.json b/skyquake/plugins/project-management/config.json
deleted file mode 100644 (file)
index b78e3b2..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "root": "public",
-    "name": "Project Management",
-    "dashboard": "./dashboard/dashboard.jsx",
-    "order": 1,
-    "priority":1,
-    "routes": [
-    {
-        "label": "Project Management Dashboard",
-        "route": "project-management",
-        "component": "./dashboard/dashboard.jsx",
-        "type": "internal"
-    }]
-}
diff --git a/skyquake/plugins/project-management/package.json b/skyquake/plugins/project-management/package.json
deleted file mode 100644 (file)
index 1d57bf3..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "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"
-  }
-}
diff --git a/skyquake/plugins/project-management/routes.js b/skyquake/plugins/project-management/routes.js
deleted file mode 100644 (file)
index 8640a99..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-
-var app = require('express').Router();
-var cors = require('cors');
-var utils = require('../../framework/core/api_utils/utils.js')
- // Begin Accounts API
-
-    utils.passThroughConstructor(app);
-
-module.exports = app;
diff --git a/skyquake/plugins/project-management/scripts/build.sh b/skyquake/plugins/project-management/scripts/build.sh
deleted file mode 100755 (executable)
index c4389c7..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-# STANDARD_RIFT_IO_COPYRIGHT
-
-PLUGIN_NAME=project-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'
diff --git a/skyquake/plugins/project-management/scripts/install.sh b/skyquake/plugins/project-management/scripts/install.sh
deleted file mode 100755 (executable)
index af71fc5..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-
-# STANDARD_RIFT_IO_COPYRIGHT
-
-plugin=project-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/.
diff --git a/skyquake/plugins/project-management/server.js b/skyquake/plugins/project-management/server.js
deleted file mode 100644 (file)
index eb140b7..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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('/*')
diff --git a/skyquake/plugins/project-management/src/dashboard/dashboard.jsx b/skyquake/plugins/project-management/src/dashboard/dashboard.jsx
deleted file mode 100644 (file)
index 37fa131..0000000
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import AppHeader from 'widgets/header/header.jsx';
-import ProjectManagementStore from './projectMgmtStore.js';
-import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
-import 'style/layout.scss';
-import './projectMgmt.scss';
-import {Panel, PanelWrapper} from 'widgets/panel/panel';
-import {InputCollection, FormSection} from 'widgets/form_controls/formControls.jsx';
-
-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 ProjectManagementDashboard extends React.Component {
-    constructor(props) {
-        super(props);
-        this.Store = this.props.flux.stores.hasOwnProperty('ProjectManagementStore') ? this.props.flux.stores.ProjectManagementStore : this.props.flux.createStore(ProjectManagementStore);
-        this.Store.getProjects();
-        this.Store.getUsers();
-        this.state = this.Store.getState();
-        this.actions = this.state.actions;
-    }
-    componentDidUpdate() {
-        let self = this;
-        ReactDOM.findDOMNode(this.projectList).addEventListener('transitionend', this.onTransitionEnd, false);
-        setTimeout(function() {
-            let element = self[`project-ref-${self.state.activeIndex}`]
-            element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
-        })
-    }
-    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)
-    }
-    addProject = () => {
-        this.actions.handleAddProject();
-    }
-    viewProject = (un, index) => {
-        this.actions.viewProject(un, index);
-    }
-    editProject = () => {
-        this.actions.editProject(false);
-    }
-    cancelEditProject = () => {
-        this.actions.editProject(true)
-    }
-    closePanel = () => {
-        this.actions.handleCloseProjectPanel();
-    }
-
-    deleteProject = (e) => {
-        e.preventDefault();
-        e.stopPropagation();
-        this.Store.deleteProject({
-                'name': this.state['name']
-            });
-    }
-    createProject = (e) => {
-        let self = this;
-        e.preventDefault();
-        e.stopPropagation();
-        let projectUsers = self.state.projectUsers;
-
-        //Remove null values from role
-        projectUsers.map((u) => {
-           u.role && u.role.map((r,i) => {
-             let role = {};
-             //you may add a user without a role or a keys, but if one is present then the other must be as well.
-            if(!r || ((r.role || r['keys']) && (!r.role || !r['keys']))) {
-                projectUsers.splice(i, 1);
-            } else {
-                return u;
-            }
-           })
-        })
-        this.Store.createProject({
-            'name': self.state['name'],
-            'description': self.state.description,
-            'project-config' : {
-                'user': projectUsers
-            }
-        });
-    }
-    updateProject = (e) => {
-        let self = this;
-        e.preventDefault();
-        e.stopPropagation();
-        let projectUsers = self.state.projectUsers;
-
-        //Remove null values from role
-        projectUsers.map((u) => {
-           u.role && u.role.map((r,i) => {
-             let role = {};
-             //you may add a user without a role or a keys, but if one is present then the other must be as well.
-            if(!r || ((r.role || r['keys']) && (!r.role || !r['keys']))) {
-                projectUsers.splice(i, 1);
-            } else {
-                return u;
-            }
-           })
-        })
-
-        this.Store.updateProject(_.merge({
-            'name': self.state['name'],
-            'description': self.state.description,
-            'project-config' : {
-                'user': projectUsers
-            }
-        }));
-    }
-     evaluateSubmit = (e) => {
-        if (e.keyCode == 13) {
-            if (this.props.isEdit) {
-                this.updateProject(e);
-            } else {
-                this.createProject(e);
-            }
-            e.preventDefault();
-            e.stopPropagation();
-        }
-    }
-    updateSelectedUser = (e) => {
-        this.setState({
-            selected
-        })
-    }
-    addUserToProject = (e) => {
-        this.actions.handleAddUser();
-    }
-    removeUserFromProject = (userIndex, e) => {
-        this.actions.handleRemoveUserFromProject(userIndex);
-    }
-    updateUserRoleInProject = (userIndex, roleIndex, e) => {
-        this.actions.handleUpdateUserRoleInProject({
-            userIndex,
-            roleIndex,
-            value: JSON.parse(e.target.value)
-        })
-    }
-    removeRoleFromUserInProject = (userIndex, roleIndex, e) => {
-        this.actions.handleRemoveRoleFromUserInProject({
-            userIndex,
-            roleIndex
-        })
-    }
-    addRoleToUserInProject = (userIndex, e) => {
-        this.actions.addRoleToUserInProject(userIndex);
-    }
-    onTransitionEnd = (e) => {
-        this.actions.handleHideColumns(e);
-        console.log('transition end')
-    }
-    disableChange = (e) => {
-        let value = e.target.value;
-        value = value.toUpperCase();
-        if (value=="TRUE") {
-            value = true;
-        } else {
-            value = false;
-        }
-        console.log(value)
-    }
-    render() {
-        let self = this;
-        let html;
-        let props = this.props;
-        let state = this.state;
-        let passwordSectionHTML = null;
-        let formButtonsHTML = (
-            <ButtonGroup className="buttonGroup">
-                <Button label="EDIT" type="submit" onClick={this.editProject} />
-            </ButtonGroup>
-        );
-        if(!this.state.isReadOnly) {
-            formButtonsHTML = (
-                                state.isEdit ?
-                                (
-                                    <ButtonGroup className="buttonGroup">
-                                        <Button label="Update" type="submit" onClick={this.updateProject} />
-                                        <Button label="Delete" onClick={this.deleteProject} />
-                                        <Button label="Cancel" onClick={this.cancelEditProject} />
-                                    </ButtonGroup>
-                                )
-                                : (
-                                    <ButtonGroup className="buttonGroup">
-                                        <Button label="Create" type="submit" onClick={this.createProject}  />
-                                    </ButtonGroup>
-                                )
-                            )
-        }
-
-        html = (
-            <PanelWrapper className={`row projectManagement ${!this.state.projectOpen ? 'projectList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
-                <PanelWrapper ref={(div) => { this.projectList = div}} className={`column projectList expanded ${this.state.projectOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
-                    <Panel title="Project List" style={{marginBottom: 0}} no-corners>
-                        <div className="tableRow tableRow--header">
-                            <div className="projectName">
-                                projectName
-                            </div>
-                            <div>
-                                Description
-                            </div>
-                        </div>
-                        {state.projects && state.projects.map((u, k) => {
-                            let platformRoles = [];
-                            for(let role in u.platformRoles) {
-                                platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
-                            }
-                            return (
-                                <div ref={(el) => this[`project-ref-${k}`] = el} className={`tableRow tableRow--data ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'tableRow--data-active' : ''}`} key={k}>
-                                    <div
-                                        className={`projectName projectName-header ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'activeProject' : ''}`}
-                                        onClick={self.viewProject.bind(null, u, k)}>
-                                        {u['name']}
-                                    </div>
-                                    <div>
-                                        {u['description']}
-                                    </div>
-
-
-                                </div>
-                            )
-                        })}
-                    </Panel>
-                    <ButtonGroup  className="buttonGroup" style={{margin: '0 0.5rem 0.5rem', background: '#ddd', paddingBottom: '0.5rem'}}>
-                        <Button label="Add Project" onClick={this.addProject} />
-                    </ButtonGroup>
-                </PanelWrapper>
-                <PanelWrapper onKeyUp={this.evaluateSubmit}
-                    className={`ProjectAdmin column`}>
-                    <Panel
-                        title={state.isEdit ? state['name'] : 'Create Project'}
-                        style={{marginBottom: 0}}
-                        hasCloseButton={this.closePanel}
-                        no-corners>
-                        <FormSection title="PROJECT INFO">
-                        {
-                            this.state.isEdit ?
-                                null
-                                : <Input  readonly={state.isReadOnly}  label="Name" value={state['name']} onChange={this.updateInput.bind(null, 'name')} />
-                        }
-                            <Input readonly={state.isReadOnly} type="textarea" label="Description" value={state['description']}  onChange={this.updateInput.bind(null, 'description')}></Input>
-                        </FormSection>
-                        <FormSection title="USER ROLES">
-                        <div className="tableRow tableRow--header">
-                            <div className="projectName">
-                                User Name
-                            </div>
-                            <div>
-                                Role
-                            </div>
-                        </div>
-                            {
-                                state.projectUsers && state.projectUsers.map((u, k) => {
-                                    return (
-                                        <div ref={(el) => this[`project-ref-${k}`] = el} className={`tableRow tableRow--data projectUsers`} key={k}>
-                                            <div className="userName" style={state.isReadOnly ? {paddingTop: '0.25rem'} : {} }>{u['user-name']}</div>
-                                            <div>
-                                                {
-                                                    u.role && u.role.map((r, l) => {
-                                                        return (
-                                                            <div key={l}>
-                                                                <div style={{display: 'flex'}} className="selectRole">
-                                                                    <SelectOption
-                                                                        readonly={state.isReadOnly}
-                                                                        defaultValue={r.role}
-                                                                        options={state.roles}
-                                                                        onChange={self.updateUserRoleInProject.bind(self, k, l)}
-                                                                    />
-                                                                    {!state.isReadOnly ?
-                                                                        <span
-                                                                        className="removeInput"
-                                                                        onClick={self.removeRoleFromUserInProject.bind(self, k, l)}
-                                                                        >
-                                                                            <img src={imgRemove} />
-                                                                            Remove Role
-                                                                        </span>
-                                                                        : null
-                                                                    }
-
-                                                                </div>
-                                                            </div>
-                                                        )
-                                                    })
-                                                }
-                                                {!state.isReadOnly ?
-                                                    <div className="buttonGroup">
-                                                        <span className="addInput addRole" onClick={self.addRoleToUserInProject.bind(self, k)}><img src={imgAdd} />
-                                                            Add Role
-                                                        </span>
-                                                        {
-                                                            (!(u.role && u.role.length)) ?
-                                                                <span
-                                                                    className="removeInput"
-                                                                    onClick={self.removeUserFromProject.bind(self, k)}
-                                                                >
-                                                                    <img src={imgRemove} />
-                                                                    Remove User
-                                                                </span> : null
-                                                        }
-                                                    </div>
-                                                    : null
-                                                }
-                                            </div>
-                                        </div>
-                                    )
-                                })
-                            }
-                            {
-                                !state.isReadOnly ?
-                                    <div className="tableRow tableRow--header">
-                                        <div>
-                                            <div className="addUser">
-                                                <SelectOption
-                                                    onChange={this.actions.handleSelectedUser}
-                                                    defaultValue={state.selectedUser}
-                                                    initial={true}
-                                                    options={state.users && state.users.map((u) => {
-                                                        return {
-                                                            label: u['user-name'],
-                                                            value: u
-                                                        }
-                                                    })}
-                                                />
-                                                <span className="addInput" onClick={this.addUserToProject}><img src={imgAdd} />
-                                                    Add User
-                                                </span>
-                                            </div>
-                                        </div>
-                                    </div> : null
-                            }
-
-                        </FormSection>
-
-                    </Panel>
-                        {formButtonsHTML}
-
-                </PanelWrapper>
-
-
-            </PanelWrapper>
-        );
-        return html;
-    }
-}
-// onClick={this.Store.update.bind(null, Account)}
-ProjectManagementDashboard.contextTypes = {
-    router: React.PropTypes.object
-};
-
-ProjectManagementDashboard.defaultProps = {
-    projectList: [],
-    selectedProject: {}
-}
-
-export default SkyquakeComponent(ProjectManagementDashboard);
-
-
-function isElementInView(el) {
-    var rect = el && el.getBoundingClientRect() || {};
-
-    return (
-        rect.top >= 0 &&
-        rect.left >= 0 &&
-        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
-        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
-    );
-}
-
-
-// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
-
-class isDisabled extends React.Component {
-    constructor(props) {
-        super(props);
-    }
-    render() {
-        let props = this.props;
-        return (<div/>)
-    }
-}
-
-
-
-
diff --git a/skyquake/plugins/project-management/src/dashboard/projectMgmt.scss b/skyquake/plugins/project-management/src/dashboard/projectMgmt.scss
deleted file mode 100644 (file)
index 3c2b58e..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-
-/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
-@import "style/_colors.scss";
-
-.projectManagement {
-        max-width: 900px;
-
-    .skyquakePanel-wrapper {
-        overflow-x: hidden;
-    }
-    .projectList {
-
-        -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(.projectName) {
-                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(.projectName) {
-                    /* opacity: 0;*/
-                    /* width:0px;*/
-                    display:none;
-                    overflow:hidden;
-                    /* transition: all 600ms;*/
-                }
-            }
-        }
-        &.hideColumns {
-            overflow:hidden;
-            >div {
-                overflow:hidden;
-            }
-            .tableRow>div:not(.projectName) {
-                width: 0px;
-                /* transition: all 600ms;*/
-            }
-            .projectName {
-                &--header {
-                    /* display:none;*/
-             }
-            }
-        }
-        .projectName {
-            cursor:pointer;
-        }
-
-
-    }
-
-    .projectAdmin {
-            -ms-flex: 1 1;
-            flex: 1 1;
-            width:auto;
-            opacity:1;
-
-        textarea{
-            height: 100px;
-        }
-    }
-    &.projectList-open {
-        .projectAdmin {
-            -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;
-    }
-    .addUser {
-        display:-ms-flexbox;
-        display:flex;
-        -ms-flex-direction:row;
-            flex-direction:row;
-        label {
-            -ms-flex: 0 1;
-                flex: 0 1;
-                width:150px;
-            select {
-                width:150px;
-            }
-        }
-    }
-    .projectUsers {
-        .userName {
-            -ms-flex-pack: start;
-            justify-content: flex-start;
-            padding-top: 0.75rem;
-        }
-        select {
-            margin-bottom:0.5rem;
-        }
-        .addRole {
-            margin:.25rem 0;
-        }
-        .buttonGroup {
-            display:-ms-flexbox;
-            display:flex;
-        }
-
-    }
-    .projectUsers.tableRow--data:hover {
-            background:none;
-            color: black;
-        }
-}
-
-
-
-.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;
-    padding: 0.25rem;
-    margin: .125rem 0;
-    >div {
-        padding:0.25rem 1rem 0.25rem 0;
-        -ms-flex: 1 1 33%;
-            flex: 1 1 33%;
-        display: -ms-flexbox;
-        display: flex;
-        -ms-flex-direction: column;
-            flex-direction: column;
-        -ms-flex-pack: center;
-            justify-content: center;
-    }
-    &--header {
-        font-weight:bold;
-    }
-    &--data {
-        &:hover:not(&-active) {
-            background:$neutral-dark-1;
-        }
-        &:hover, .activeUser, &-active{
-            cursor:pointer;
-            color:white;
-        }
-        .activeUser, &-active{
-            background: #00acee;
-        }
-    }
-}
-
-.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;
-    }
-}
diff --git a/skyquake/plugins/project-management/src/dashboard/projectMgmtActions.js b/skyquake/plugins/project-management/src/dashboard/projectMgmtActions.js
deleted file mode 100644 (file)
index d0baf61..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-module.exports = function(Alt) {
-   return Alt.generateActions(
-                                       'handleUpdateInput',
-                                       'handleAddProjectItem',
-                                       'handleRemoveProjectItem',
-                                       'handleUpdateProjectRole',
-                                       'viewProject',
-                                       'editProject',
-                                       'handleCloseProjectPanel',
-                                       'handleHideColumns',
-                                       'handleSelectedUser',
-                                       'handleSelectedRole',
-                                       'handleAddUser',
-                                       'handleRemoveUserFromProject',
-                                       'getProjectsSuccess',
-                                       'getUsersSuccess',
-                                       'getProjectsNotification',
-                                       'handleDisabledChange',
-                                       'handlePlatformRoleUpdate',
-                                       'handleAddProject',
-                                       'handleCreateProject',
-                                       'handleUpdateProject',
-                                       'handleUpdateSelectedUser',
-                                       'handleUpdateUserRoleInProject',
-                                       'addRoleToUserInProject',
-                                       'handleRemoveRoleFromUserInProject',
-                                       'updateProjectSuccess',
-                                       'createProjectSuccess',
-                                       'deleteProjectSuccess'
-                                       );
-}
diff --git a/skyquake/plugins/project-management/src/dashboard/projectMgmtSource.js b/skyquake/plugins/project-management/src/dashboard/projectMgmtSource.js
deleted file mode 100644 (file)
index 72fc2d3..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * 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 Projects = mockProjects();
-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
-        },
-        getProjects: {
-          remote: function() {
-              return new Promise(function(resolve, reject) {
-                // setTimeout(function() {
-                //   resolve(Projects);
-                // }, 1000)
-                $.ajax({
-                  url: `/project?api_server=${API_SERVER}`,
-                  type: 'GET',
-                  beforeSend: Utils.addAuthorizationStub,
-                  success: function(data, textStatus, jqXHR) {
-                    resolve(data.project);
-                  }
-                }).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.getProjectsSuccess,
-                    loading: Alt.actions.global.showScreenLoader,
-          error: Alt.actions.global.showNotification
-        },
-        updateProject: {
-          remote: function(state, project) {
-            return new Promise(function(resolve, reject) {
-              $.ajax({
-                  url: `/project?api_server=${API_SERVER}`,
-                  type: 'PUT',
-                  data: project,
-                  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 project.'
-          }),
-          success: Alt.actions.global.updateProjectSuccess,
-          loading: Alt.actions.global.showScreenLoader,
-          error: Alt.actions.global.showNotification
-        },
-        deleteProject: {
-          remote: function(state, project) {
-            return new Promise(function(resolve, reject) {
-              // setTimeout(function() {
-              //     resolve(true);
-              // }, 1000)
-              $.ajax({
-                url: `/project/${project['name']}?api_server=${API_SERVER}`,
-                type: 'DELETE',
-                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.deleteProjectSuccess,
-          loading: Alt.actions.global.showScreenLoader,
-          error: Alt.actions.global.showNotification
-        },
-        createProject: {
-            remote: function(state, project) {
-
-              return new Promise(function(resolve, reject) {
-                // setTimeout(function() {
-                //     resolve(true);
-                // }, 1000)
-                $.ajax({
-                  url: `/project?api_server=${API_SERVER}`,
-                  type: 'POST',
-                  data: project,
-                  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.createProjectSuccess,
-            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 mockProjects() {
-  let data = [];
-  let count = 10;
-  for(let i = 0; i < 3; i++) {
-    data.push({
-      name: `Test Project ${i}`,
-      description: 'Some description',
-      roles: ['Some-Role', 'Some-Other-Role'],
-      users: [
-        {
-          'user-name': 'Some-User',
-          'user-domain': 'system',
-          role: [
-            {
-              'role': 'Some-Role',
-              'key-set' : 'some key'
-            },
-            {
-              'role': 'Some-Other-Role',
-              'key-set' : 'some key'
-            }
-          ]
-        },
-        {
-          'user-name': 'Some-User',
-          'user-domain': 'system',
-          role: [
-            {
-              'role': 'Some-Role',
-              'key-set' : 'some key'
-            }
-          ]
-        }
-      ]
-    })
-  }
-  return data;
-}
-function mockUsers() {
-  let data = [];
-  let count = 10;
-  for(let i = 0; i < 10; i++) {
-    data.push({
-      'user-name': `Tester ${i}`,
-      'user-domain': 'Some Domain',
-      platformRoles: {
-        super_admin: true,
-        platform_admin: false,
-        platform_oper: false
-      },
-      disabled: false,
-      projectRoles: [
-        'Project:Role'
-      ]
-    })
-  }
-  return data;
-}
diff --git a/skyquake/plugins/project-management/src/dashboard/projectMgmtStore.js b/skyquake/plugins/project-management/src/dashboard/projectMgmtStore.js
deleted file mode 100644 (file)
index 92a4395..0000000
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-import ProjectManagementActions from './projectMgmtActions.js';
-import ProjectManagementSource from './projectMgmtSource.js';
-import _ from 'lodash';
-export default class ProjectManagementStore {
-    constructor() {
-        this.actions = ProjectManagementActions(this.alt);
-        this.bindActions(this.actions);
-        this.registerAsync(ProjectManagementSource);
-        this.projects = [];
-        this['name'] = '';
-        this['description'] = 'Some Description';
-        this.projectUsers = [];
-        this.selectedUser = null;
-        this.selectedRole = null;
-        this.roles = ['Assign a role', 'super_admin'];
-        this.users = [];
-        this.activeIndex = null;
-        this.isReadOnly = true;
-        this.projectOpen = 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
-        });
-    }
-    viewProject(data) {
-        let project = data[0];
-        let projectIndex = data[1];
-
-        let ProjectUser = {
-            'name': project['name'],
-            'description': project['description'],
-            'projectUsers': project['project-config'] && project['project-config']['user'] || []
-        }
-        let state = _.merge({
-            activeIndex: projectIndex,
-            projectOpen: true,
-            isEdit: true,
-            isReadOnly: true
-        }, ProjectUser);
-        this.setState(state)
-    }
-    editProject(isEdit) {
-        this.setState({
-            isReadOnly: isEdit
-        })
-    }
-    handleCloseProjectPanel() {
-        this.setState({
-            projectOpen: false,
-            isEdit: false,
-            isReadOnly: true
-        })
-    }
-    handleHideColumns(e) {
-        if(this.projectOpen && 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
-        })
-    }
-    handleSelectedUser(event) {
-        this.setState({
-            selectedUser: JSON.parse(event.currentTarget.value)
-        })
-    }
-
-    handleSelectedRole(event) {
-        this.setState({
-            selectedRole: JSON.parse(event.currentTarget.value)
-        })
-    }
-    resetProject() {
-        let name = '';
-        let description = '';
-        return {
-            'name' : name,
-            'description' : description
-        }
-    }
-    handleAddProject() {
-        this.setState(_.merge( this.resetProject() ,
-              {
-                isEdit: false,
-                projectOpen: true,
-                activeIndex: null,
-                isReadOnly: false,
-                projectUsers: []
-            }
-        ))
-    }
-
-    handleUpdateSelectedUser(user) {
-        this.setState({
-            selectedUser: JSON.parse(user)
-        });
-    }
-    handleAddUser() {
-        let u = JSON.parse(this.selectedUser);
-        let r = this.selectedRole;
-        let projectUsers = this.projectUsers;
-        console.log('adding user')
-        projectUsers.push({
-          'user-name': u['user-name'],
-          'user-domain': u['user-domain'],
-          "role":[{
-                      "role": r,
-                      "keys": r
-            }
-          ]
-        })
-        this.setState({projectUsers})
-    }
-    handleUpdateUserRoleInProject(data) {
-        let {userIndex, roleIndex, value} = data;
-        let projectUsers = this.projectUsers;
-        projectUsers[userIndex].role[roleIndex].role = value;
-        projectUsers[userIndex].role[roleIndex]['keys'] = value;
-
-    }
-    addRoleToUserInProject(userIndex) {
-        let projectUsers = this.projectUsers;
-        if(!projectUsers[userIndex].role) {
-            projectUsers[userIndex].role = [];
-        }
-        projectUsers[userIndex].role.push({
-              'role': null,
-              //temp until we get actual keys
-              'keys' : 'some key'
-            });
-        this.setState({
-            projectUsers
-        })
-    }
-    handleRemoveRoleFromUserInProject (data) {
-        let {userIndex, roleIndex} = data;
-        let projectUsers = this.projectUsers;
-        projectUsers[userIndex].role.splice(roleIndex, 1);
-        this.setState({
-            projectUsers
-        })
-    }
-    handleRemoveUserFromProject (userIndex) {
-        let projectUsers = this.projectUsers;
-        projectUsers.splice(userIndex, 1);
-        this.setState({
-            projectUsers
-        })
-    }
-    getProjectsSuccess(projects) {
-        this.alt.actions.global.hideScreenLoader.defer();
-        this.setState({projects: projects});
-    }
-    getUsersSuccess(users) {
-        console.log(users)
-        this.alt.actions.global.hideScreenLoader.defer();
-        this.setState({users});
-    }
-    updateProjectSuccess() {
-        this.alt.actions.global.hideScreenLoader.defer();
-        let projects = this.projects || [];
-        projects[this.activeIndex] = {
-            'name': this['name'],
-            'description': this['description']
-        }
-        this.setState({
-            projects,
-            isEdit: true,
-            isReadOnly: true
-        })
-    }
-    deleteProjectSuccess() {
-        this.alt.actions.global.hideScreenLoader.defer();
-        let projects = this.projects;
-        projects.splice(this.activeIndex, 1);
-        this.setState({projects, projectOpen: false})
-    }
-    createProjectSuccess() {
-        this.alt.actions.global.hideScreenLoader.defer();
-        let projects = this.projects || [];
-        projects.push({
-            'name': this['name'],
-            'description': this['description']
-         });
-        let newState = {
-            projects,
-            isEdit: true,
-            isReadOnly: true,
-            activeIndex: projects.length - 1
-        };
-        _.merge(newState)
-        this.setState(newState);
-    }
-}
diff --git a/skyquake/plugins/project-management/src/main.js b/skyquake/plugins/project-management/src/main.js
deleted file mode 100644 (file)
index 5dc626f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * 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);
-
-
diff --git a/skyquake/plugins/project-management/webpack.production.config.js b/skyquake/plugins/project-management/webpack.production.config.js
deleted file mode 100644 (file)
index 49ad631..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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;
diff --git a/skyquake/plugins/project_management/CMakeLists.txt b/skyquake/plugins/project_management/CMakeLists.txt
new file mode 100644 (file)
index 0000000..f994a55
--- /dev/null
@@ -0,0 +1,38 @@
+# 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(
+  project_management
+  DEPENDS skyquake
+  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+  CONFIGURE_COMMAND echo
+  BUILD_COMMAND
+    ${CMAKE_CURRENT_BINARY_DIR}/project_management/project_management-build/scripts/build.sh
+  INSTALL_COMMAND
+    ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install.sh
+    ${CMAKE_CURRENT_BINARY_DIR}/project_management/project_management-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
+)
+
diff --git a/skyquake/plugins/project_management/config.json b/skyquake/plugins/project_management/config.json
new file mode 100644 (file)
index 0000000..b78e3b2
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "root": "public",
+    "name": "Project Management",
+    "dashboard": "./dashboard/dashboard.jsx",
+    "order": 1,
+    "priority":1,
+    "routes": [
+    {
+        "label": "Project Management Dashboard",
+        "route": "project-management",
+        "component": "./dashboard/dashboard.jsx",
+        "type": "internal"
+    }]
+}
diff --git a/skyquake/plugins/project_management/package.json b/skyquake/plugins/project_management/package.json
new file mode 100644 (file)
index 0000000..1d57bf3
--- /dev/null
@@ -0,0 +1,54 @@
+{
+  "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"
+  }
+}
diff --git a/skyquake/plugins/project_management/routes.js b/skyquake/plugins/project_management/routes.js
new file mode 100644 (file)
index 0000000..8640a99
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var app = require('express').Router();
+var cors = require('cors');
+var utils = require('../../framework/core/api_utils/utils.js')
+ // Begin Accounts API
+
+    utils.passThroughConstructor(app);
+
+module.exports = app;
diff --git a/skyquake/plugins/project_management/scripts/build.sh b/skyquake/plugins/project_management/scripts/build.sh
new file mode 100755 (executable)
index 0000000..c4389c7
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+PLUGIN_NAME=project-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'
diff --git a/skyquake/plugins/project_management/scripts/install.sh b/skyquake/plugins/project_management/scripts/install.sh
new file mode 100755 (executable)
index 0000000..af71fc5
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+plugin=project-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/.
diff --git a/skyquake/plugins/project_management/server.js b/skyquake/plugins/project_management/server.js
new file mode 100644 (file)
index 0000000..eb140b7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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('/*')
diff --git a/skyquake/plugins/project_management/src/dashboard/dashboard.jsx b/skyquake/plugins/project_management/src/dashboard/dashboard.jsx
new file mode 100644 (file)
index 0000000..37fa131
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import ProjectManagementStore from './projectMgmtStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import './projectMgmt.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+import {InputCollection, FormSection} from 'widgets/form_controls/formControls.jsx';
+
+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 ProjectManagementDashboard extends React.Component {
+    constructor(props) {
+        super(props);
+        this.Store = this.props.flux.stores.hasOwnProperty('ProjectManagementStore') ? this.props.flux.stores.ProjectManagementStore : this.props.flux.createStore(ProjectManagementStore);
+        this.Store.getProjects();
+        this.Store.getUsers();
+        this.state = this.Store.getState();
+        this.actions = this.state.actions;
+    }
+    componentDidUpdate() {
+        let self = this;
+        ReactDOM.findDOMNode(this.projectList).addEventListener('transitionend', this.onTransitionEnd, false);
+        setTimeout(function() {
+            let element = self[`project-ref-${self.state.activeIndex}`]
+            element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
+        })
+    }
+    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)
+    }
+    addProject = () => {
+        this.actions.handleAddProject();
+    }
+    viewProject = (un, index) => {
+        this.actions.viewProject(un, index);
+    }
+    editProject = () => {
+        this.actions.editProject(false);
+    }
+    cancelEditProject = () => {
+        this.actions.editProject(true)
+    }
+    closePanel = () => {
+        this.actions.handleCloseProjectPanel();
+    }
+
+    deleteProject = (e) => {
+        e.preventDefault();
+        e.stopPropagation();
+        this.Store.deleteProject({
+                'name': this.state['name']
+            });
+    }
+    createProject = (e) => {
+        let self = this;
+        e.preventDefault();
+        e.stopPropagation();
+        let projectUsers = self.state.projectUsers;
+
+        //Remove null values from role
+        projectUsers.map((u) => {
+           u.role && u.role.map((r,i) => {
+             let role = {};
+             //you may add a user without a role or a keys, but if one is present then the other must be as well.
+            if(!r || ((r.role || r['keys']) && (!r.role || !r['keys']))) {
+                projectUsers.splice(i, 1);
+            } else {
+                return u;
+            }
+           })
+        })
+        this.Store.createProject({
+            'name': self.state['name'],
+            'description': self.state.description,
+            'project-config' : {
+                'user': projectUsers
+            }
+        });
+    }
+    updateProject = (e) => {
+        let self = this;
+        e.preventDefault();
+        e.stopPropagation();
+        let projectUsers = self.state.projectUsers;
+
+        //Remove null values from role
+        projectUsers.map((u) => {
+           u.role && u.role.map((r,i) => {
+             let role = {};
+             //you may add a user without a role or a keys, but if one is present then the other must be as well.
+            if(!r || ((r.role || r['keys']) && (!r.role || !r['keys']))) {
+                projectUsers.splice(i, 1);
+            } else {
+                return u;
+            }
+           })
+        })
+
+        this.Store.updateProject(_.merge({
+            'name': self.state['name'],
+            'description': self.state.description,
+            'project-config' : {
+                'user': projectUsers
+            }
+        }));
+    }
+     evaluateSubmit = (e) => {
+        if (e.keyCode == 13) {
+            if (this.props.isEdit) {
+                this.updateProject(e);
+            } else {
+                this.createProject(e);
+            }
+            e.preventDefault();
+            e.stopPropagation();
+        }
+    }
+    updateSelectedUser = (e) => {
+        this.setState({
+            selected
+        })
+    }
+    addUserToProject = (e) => {
+        this.actions.handleAddUser();
+    }
+    removeUserFromProject = (userIndex, e) => {
+        this.actions.handleRemoveUserFromProject(userIndex);
+    }
+    updateUserRoleInProject = (userIndex, roleIndex, e) => {
+        this.actions.handleUpdateUserRoleInProject({
+            userIndex,
+            roleIndex,
+            value: JSON.parse(e.target.value)
+        })
+    }
+    removeRoleFromUserInProject = (userIndex, roleIndex, e) => {
+        this.actions.handleRemoveRoleFromUserInProject({
+            userIndex,
+            roleIndex
+        })
+    }
+    addRoleToUserInProject = (userIndex, e) => {
+        this.actions.addRoleToUserInProject(userIndex);
+    }
+    onTransitionEnd = (e) => {
+        this.actions.handleHideColumns(e);
+        console.log('transition end')
+    }
+    disableChange = (e) => {
+        let value = e.target.value;
+        value = value.toUpperCase();
+        if (value=="TRUE") {
+            value = true;
+        } else {
+            value = false;
+        }
+        console.log(value)
+    }
+    render() {
+        let self = this;
+        let html;
+        let props = this.props;
+        let state = this.state;
+        let passwordSectionHTML = null;
+        let formButtonsHTML = (
+            <ButtonGroup className="buttonGroup">
+                <Button label="EDIT" type="submit" onClick={this.editProject} />
+            </ButtonGroup>
+        );
+        if(!this.state.isReadOnly) {
+            formButtonsHTML = (
+                                state.isEdit ?
+                                (
+                                    <ButtonGroup className="buttonGroup">
+                                        <Button label="Update" type="submit" onClick={this.updateProject} />
+                                        <Button label="Delete" onClick={this.deleteProject} />
+                                        <Button label="Cancel" onClick={this.cancelEditProject} />
+                                    </ButtonGroup>
+                                )
+                                : (
+                                    <ButtonGroup className="buttonGroup">
+                                        <Button label="Create" type="submit" onClick={this.createProject}  />
+                                    </ButtonGroup>
+                                )
+                            )
+        }
+
+        html = (
+            <PanelWrapper className={`row projectManagement ${!this.state.projectOpen ? 'projectList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
+                <PanelWrapper ref={(div) => { this.projectList = div}} className={`column projectList expanded ${this.state.projectOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
+                    <Panel title="Project List" style={{marginBottom: 0}} no-corners>
+                        <div className="tableRow tableRow--header">
+                            <div className="projectName">
+                                projectName
+                            </div>
+                            <div>
+                                Description
+                            </div>
+                        </div>
+                        {state.projects && state.projects.map((u, k) => {
+                            let platformRoles = [];
+                            for(let role in u.platformRoles) {
+                                platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
+                            }
+                            return (
+                                <div ref={(el) => this[`project-ref-${k}`] = el} className={`tableRow tableRow--data ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'tableRow--data-active' : ''}`} key={k}>
+                                    <div
+                                        className={`projectName projectName-header ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'activeProject' : ''}`}
+                                        onClick={self.viewProject.bind(null, u, k)}>
+                                        {u['name']}
+                                    </div>
+                                    <div>
+                                        {u['description']}
+                                    </div>
+
+
+                                </div>
+                            )
+                        })}
+                    </Panel>
+                    <ButtonGroup  className="buttonGroup" style={{margin: '0 0.5rem 0.5rem', background: '#ddd', paddingBottom: '0.5rem'}}>
+                        <Button label="Add Project" onClick={this.addProject} />
+                    </ButtonGroup>
+                </PanelWrapper>
+                <PanelWrapper onKeyUp={this.evaluateSubmit}
+                    className={`ProjectAdmin column`}>
+                    <Panel
+                        title={state.isEdit ? state['name'] : 'Create Project'}
+                        style={{marginBottom: 0}}
+                        hasCloseButton={this.closePanel}
+                        no-corners>
+                        <FormSection title="PROJECT INFO">
+                        {
+                            this.state.isEdit ?
+                                null
+                                : <Input  readonly={state.isReadOnly}  label="Name" value={state['name']} onChange={this.updateInput.bind(null, 'name')} />
+                        }
+                            <Input readonly={state.isReadOnly} type="textarea" label="Description" value={state['description']}  onChange={this.updateInput.bind(null, 'description')}></Input>
+                        </FormSection>
+                        <FormSection title="USER ROLES">
+                        <div className="tableRow tableRow--header">
+                            <div className="projectName">
+                                User Name
+                            </div>
+                            <div>
+                                Role
+                            </div>
+                        </div>
+                            {
+                                state.projectUsers && state.projectUsers.map((u, k) => {
+                                    return (
+                                        <div ref={(el) => this[`project-ref-${k}`] = el} className={`tableRow tableRow--data projectUsers`} key={k}>
+                                            <div className="userName" style={state.isReadOnly ? {paddingTop: '0.25rem'} : {} }>{u['user-name']}</div>
+                                            <div>
+                                                {
+                                                    u.role && u.role.map((r, l) => {
+                                                        return (
+                                                            <div key={l}>
+                                                                <div style={{display: 'flex'}} className="selectRole">
+                                                                    <SelectOption
+                                                                        readonly={state.isReadOnly}
+                                                                        defaultValue={r.role}
+                                                                        options={state.roles}
+                                                                        onChange={self.updateUserRoleInProject.bind(self, k, l)}
+                                                                    />
+                                                                    {!state.isReadOnly ?
+                                                                        <span
+                                                                        className="removeInput"
+                                                                        onClick={self.removeRoleFromUserInProject.bind(self, k, l)}
+                                                                        >
+                                                                            <img src={imgRemove} />
+                                                                            Remove Role
+                                                                        </span>
+                                                                        : null
+                                                                    }
+
+                                                                </div>
+                                                            </div>
+                                                        )
+                                                    })
+                                                }
+                                                {!state.isReadOnly ?
+                                                    <div className="buttonGroup">
+                                                        <span className="addInput addRole" onClick={self.addRoleToUserInProject.bind(self, k)}><img src={imgAdd} />
+                                                            Add Role
+                                                        </span>
+                                                        {
+                                                            (!(u.role && u.role.length)) ?
+                                                                <span
+                                                                    className="removeInput"
+                                                                    onClick={self.removeUserFromProject.bind(self, k)}
+                                                                >
+                                                                    <img src={imgRemove} />
+                                                                    Remove User
+                                                                </span> : null
+                                                        }
+                                                    </div>
+                                                    : null
+                                                }
+                                            </div>
+                                        </div>
+                                    )
+                                })
+                            }
+                            {
+                                !state.isReadOnly ?
+                                    <div className="tableRow tableRow--header">
+                                        <div>
+                                            <div className="addUser">
+                                                <SelectOption
+                                                    onChange={this.actions.handleSelectedUser}
+                                                    defaultValue={state.selectedUser}
+                                                    initial={true}
+                                                    options={state.users && state.users.map((u) => {
+                                                        return {
+                                                            label: u['user-name'],
+                                                            value: u
+                                                        }
+                                                    })}
+                                                />
+                                                <span className="addInput" onClick={this.addUserToProject}><img src={imgAdd} />
+                                                    Add User
+                                                </span>
+                                            </div>
+                                        </div>
+                                    </div> : null
+                            }
+
+                        </FormSection>
+
+                    </Panel>
+                        {formButtonsHTML}
+
+                </PanelWrapper>
+
+
+            </PanelWrapper>
+        );
+        return html;
+    }
+}
+// onClick={this.Store.update.bind(null, Account)}
+ProjectManagementDashboard.contextTypes = {
+    router: React.PropTypes.object
+};
+
+ProjectManagementDashboard.defaultProps = {
+    projectList: [],
+    selectedProject: {}
+}
+
+export default SkyquakeComponent(ProjectManagementDashboard);
+
+
+function isElementInView(el) {
+    var rect = el && el.getBoundingClientRect() || {};
+
+    return (
+        rect.top >= 0 &&
+        rect.left >= 0 &&
+        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+    );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+    constructor(props) {
+        super(props);
+    }
+    render() {
+        let props = this.props;
+        return (<div/>)
+    }
+}
+
+
+
+
diff --git a/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss b/skyquake/plugins/project_management/src/dashboard/projectMgmt.scss
new file mode 100644 (file)
index 0000000..3c2b58e
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.projectManagement {
+        max-width: 900px;
+
+    .skyquakePanel-wrapper {
+        overflow-x: hidden;
+    }
+    .projectList {
+
+        -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(.projectName) {
+                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(.projectName) {
+                    /* opacity: 0;*/
+                    /* width:0px;*/
+                    display:none;
+                    overflow:hidden;
+                    /* transition: all 600ms;*/
+                }
+            }
+        }
+        &.hideColumns {
+            overflow:hidden;
+            >div {
+                overflow:hidden;
+            }
+            .tableRow>div:not(.projectName) {
+                width: 0px;
+                /* transition: all 600ms;*/
+            }
+            .projectName {
+                &--header {
+                    /* display:none;*/
+             }
+            }
+        }
+        .projectName {
+            cursor:pointer;
+        }
+
+
+    }
+
+    .projectAdmin {
+            -ms-flex: 1 1;
+            flex: 1 1;
+            width:auto;
+            opacity:1;
+
+        textarea{
+            height: 100px;
+        }
+    }
+    &.projectList-open {
+        .projectAdmin {
+            -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;
+    }
+    .addUser {
+        display:-ms-flexbox;
+        display:flex;
+        -ms-flex-direction:row;
+            flex-direction:row;
+        label {
+            -ms-flex: 0 1;
+                flex: 0 1;
+                width:150px;
+            select {
+                width:150px;
+            }
+        }
+    }
+    .projectUsers {
+        .userName {
+            -ms-flex-pack: start;
+            justify-content: flex-start;
+            padding-top: 0.75rem;
+        }
+        select {
+            margin-bottom:0.5rem;
+        }
+        .addRole {
+            margin:.25rem 0;
+        }
+        .buttonGroup {
+            display:-ms-flexbox;
+            display:flex;
+        }
+
+    }
+    .projectUsers.tableRow--data:hover {
+            background:none;
+            color: black;
+        }
+}
+
+
+
+.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;
+    padding: 0.25rem;
+    margin: .125rem 0;
+    >div {
+        padding:0.25rem 1rem 0.25rem 0;
+        -ms-flex: 1 1 33%;
+            flex: 1 1 33%;
+        display: -ms-flexbox;
+        display: flex;
+        -ms-flex-direction: column;
+            flex-direction: column;
+        -ms-flex-pack: center;
+            justify-content: center;
+    }
+    &--header {
+        font-weight:bold;
+    }
+    &--data {
+        &:hover:not(&-active) {
+            background:$neutral-dark-1;
+        }
+        &:hover, .activeUser, &-active{
+            cursor:pointer;
+            color:white;
+        }
+        .activeUser, &-active{
+            background: #00acee;
+        }
+    }
+}
+
+.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;
+    }
+}
diff --git a/skyquake/plugins/project_management/src/dashboard/projectMgmtActions.js b/skyquake/plugins/project_management/src/dashboard/projectMgmtActions.js
new file mode 100644 (file)
index 0000000..d0baf61
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+   return Alt.generateActions(
+                                       'handleUpdateInput',
+                                       'handleAddProjectItem',
+                                       'handleRemoveProjectItem',
+                                       'handleUpdateProjectRole',
+                                       'viewProject',
+                                       'editProject',
+                                       'handleCloseProjectPanel',
+                                       'handleHideColumns',
+                                       'handleSelectedUser',
+                                       'handleSelectedRole',
+                                       'handleAddUser',
+                                       'handleRemoveUserFromProject',
+                                       'getProjectsSuccess',
+                                       'getUsersSuccess',
+                                       'getProjectsNotification',
+                                       'handleDisabledChange',
+                                       'handlePlatformRoleUpdate',
+                                       'handleAddProject',
+                                       'handleCreateProject',
+                                       'handleUpdateProject',
+                                       'handleUpdateSelectedUser',
+                                       'handleUpdateUserRoleInProject',
+                                       'addRoleToUserInProject',
+                                       'handleRemoveRoleFromUserInProject',
+                                       'updateProjectSuccess',
+                                       'createProjectSuccess',
+                                       'deleteProjectSuccess'
+                                       );
+}
diff --git a/skyquake/plugins/project_management/src/dashboard/projectMgmtSource.js b/skyquake/plugins/project_management/src/dashboard/projectMgmtSource.js
new file mode 100644 (file)
index 0000000..72fc2d3
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * 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 Projects = mockProjects();
+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
+        },
+        getProjects: {
+          remote: function() {
+              return new Promise(function(resolve, reject) {
+                // setTimeout(function() {
+                //   resolve(Projects);
+                // }, 1000)
+                $.ajax({
+                  url: `/project?api_server=${API_SERVER}`,
+                  type: 'GET',
+                  beforeSend: Utils.addAuthorizationStub,
+                  success: function(data, textStatus, jqXHR) {
+                    resolve(data.project);
+                  }
+                }).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.getProjectsSuccess,
+                    loading: Alt.actions.global.showScreenLoader,
+          error: Alt.actions.global.showNotification
+        },
+        updateProject: {
+          remote: function(state, project) {
+            return new Promise(function(resolve, reject) {
+              $.ajax({
+                  url: `/project?api_server=${API_SERVER}`,
+                  type: 'PUT',
+                  data: project,
+                  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 project.'
+          }),
+          success: Alt.actions.global.updateProjectSuccess,
+          loading: Alt.actions.global.showScreenLoader,
+          error: Alt.actions.global.showNotification
+        },
+        deleteProject: {
+          remote: function(state, project) {
+            return new Promise(function(resolve, reject) {
+              // setTimeout(function() {
+              //     resolve(true);
+              // }, 1000)
+              $.ajax({
+                url: `/project/${project['name']}?api_server=${API_SERVER}`,
+                type: 'DELETE',
+                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.deleteProjectSuccess,
+          loading: Alt.actions.global.showScreenLoader,
+          error: Alt.actions.global.showNotification
+        },
+        createProject: {
+            remote: function(state, project) {
+
+              return new Promise(function(resolve, reject) {
+                // setTimeout(function() {
+                //     resolve(true);
+                // }, 1000)
+                $.ajax({
+                  url: `/project?api_server=${API_SERVER}`,
+                  type: 'POST',
+                  data: project,
+                  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.createProjectSuccess,
+            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 mockProjects() {
+  let data = [];
+  let count = 10;
+  for(let i = 0; i < 3; i++) {
+    data.push({
+      name: `Test Project ${i}`,
+      description: 'Some description',
+      roles: ['Some-Role', 'Some-Other-Role'],
+      users: [
+        {
+          'user-name': 'Some-User',
+          'user-domain': 'system',
+          role: [
+            {
+              'role': 'Some-Role',
+              'key-set' : 'some key'
+            },
+            {
+              'role': 'Some-Other-Role',
+              'key-set' : 'some key'
+            }
+          ]
+        },
+        {
+          'user-name': 'Some-User',
+          'user-domain': 'system',
+          role: [
+            {
+              'role': 'Some-Role',
+              'key-set' : 'some key'
+            }
+          ]
+        }
+      ]
+    })
+  }
+  return data;
+}
+function mockUsers() {
+  let data = [];
+  let count = 10;
+  for(let i = 0; i < 10; i++) {
+    data.push({
+      'user-name': `Tester ${i}`,
+      'user-domain': 'Some Domain',
+      platformRoles: {
+        super_admin: true,
+        platform_admin: false,
+        platform_oper: false
+      },
+      disabled: false,
+      projectRoles: [
+        'Project:Role'
+      ]
+    })
+  }
+  return data;
+}
diff --git a/skyquake/plugins/project_management/src/dashboard/projectMgmtStore.js b/skyquake/plugins/project_management/src/dashboard/projectMgmtStore.js
new file mode 100644 (file)
index 0000000..92a4395
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import ProjectManagementActions from './projectMgmtActions.js';
+import ProjectManagementSource from './projectMgmtSource.js';
+import _ from 'lodash';
+export default class ProjectManagementStore {
+    constructor() {
+        this.actions = ProjectManagementActions(this.alt);
+        this.bindActions(this.actions);
+        this.registerAsync(ProjectManagementSource);
+        this.projects = [];
+        this['name'] = '';
+        this['description'] = 'Some Description';
+        this.projectUsers = [];
+        this.selectedUser = null;
+        this.selectedRole = null;
+        this.roles = ['Assign a role', 'super_admin'];
+        this.users = [];
+        this.activeIndex = null;
+        this.isReadOnly = true;
+        this.projectOpen = 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
+        });
+    }
+    viewProject(data) {
+        let project = data[0];
+        let projectIndex = data[1];
+
+        let ProjectUser = {
+            'name': project['name'],
+            'description': project['description'],
+            'projectUsers': project['project-config'] && project['project-config']['user'] || []
+        }
+        let state = _.merge({
+            activeIndex: projectIndex,
+            projectOpen: true,
+            isEdit: true,
+            isReadOnly: true
+        }, ProjectUser);
+        this.setState(state)
+    }
+    editProject(isEdit) {
+        this.setState({
+            isReadOnly: isEdit
+        })
+    }
+    handleCloseProjectPanel() {
+        this.setState({
+            projectOpen: false,
+            isEdit: false,
+            isReadOnly: true
+        })
+    }
+    handleHideColumns(e) {
+        if(this.projectOpen && 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
+        })
+    }
+    handleSelectedUser(event) {
+        this.setState({
+            selectedUser: JSON.parse(event.currentTarget.value)
+        })
+    }
+
+    handleSelectedRole(event) {
+        this.setState({
+            selectedRole: JSON.parse(event.currentTarget.value)
+        })
+    }
+    resetProject() {
+        let name = '';
+        let description = '';
+        return {
+            'name' : name,
+            'description' : description
+        }
+    }
+    handleAddProject() {
+        this.setState(_.merge( this.resetProject() ,
+              {
+                isEdit: false,
+                projectOpen: true,
+                activeIndex: null,
+                isReadOnly: false,
+                projectUsers: []
+            }
+        ))
+    }
+
+    handleUpdateSelectedUser(user) {
+        this.setState({
+            selectedUser: JSON.parse(user)
+        });
+    }
+    handleAddUser() {
+        let u = JSON.parse(this.selectedUser);
+        let r = this.selectedRole;
+        let projectUsers = this.projectUsers;
+        console.log('adding user')
+        projectUsers.push({
+          'user-name': u['user-name'],
+          'user-domain': u['user-domain'],
+          "role":[{
+                      "role": r,
+                      "keys": r
+            }
+          ]
+        })
+        this.setState({projectUsers})
+    }
+    handleUpdateUserRoleInProject(data) {
+        let {userIndex, roleIndex, value} = data;
+        let projectUsers = this.projectUsers;
+        projectUsers[userIndex].role[roleIndex].role = value;
+        projectUsers[userIndex].role[roleIndex]['keys'] = value;
+
+    }
+    addRoleToUserInProject(userIndex) {
+        let projectUsers = this.projectUsers;
+        if(!projectUsers[userIndex].role) {
+            projectUsers[userIndex].role = [];
+        }
+        projectUsers[userIndex].role.push({
+              'role': null,
+              //temp until we get actual keys
+              'keys' : 'some key'
+            });
+        this.setState({
+            projectUsers
+        })
+    }
+    handleRemoveRoleFromUserInProject (data) {
+        let {userIndex, roleIndex} = data;
+        let projectUsers = this.projectUsers;
+        projectUsers[userIndex].role.splice(roleIndex, 1);
+        this.setState({
+            projectUsers
+        })
+    }
+    handleRemoveUserFromProject (userIndex) {
+        let projectUsers = this.projectUsers;
+        projectUsers.splice(userIndex, 1);
+        this.setState({
+            projectUsers
+        })
+    }
+    getProjectsSuccess(projects) {
+        this.alt.actions.global.hideScreenLoader.defer();
+        this.setState({projects: projects});
+    }
+    getUsersSuccess(users) {
+        console.log(users)
+        this.alt.actions.global.hideScreenLoader.defer();
+        this.setState({users});
+    }
+    updateProjectSuccess() {
+        this.alt.actions.global.hideScreenLoader.defer();
+        let projects = this.projects || [];
+        projects[this.activeIndex] = {
+            'name': this['name'],
+            'description': this['description']
+        }
+        this.setState({
+            projects,
+            isEdit: true,
+            isReadOnly: true
+        })
+    }
+    deleteProjectSuccess() {
+        this.alt.actions.global.hideScreenLoader.defer();
+        let projects = this.projects;
+        projects.splice(this.activeIndex, 1);
+        this.setState({projects, projectOpen: false})
+    }
+    createProjectSuccess() {
+        this.alt.actions.global.hideScreenLoader.defer();
+        let projects = this.projects || [];
+        projects.push({
+            'name': this['name'],
+            'description': this['description']
+         });
+        let newState = {
+            projects,
+            isEdit: true,
+            isReadOnly: true,
+            activeIndex: projects.length - 1
+        };
+        _.merge(newState)
+        this.setState(newState);
+    }
+}
diff --git a/skyquake/plugins/project_management/src/main.js b/skyquake/plugins/project_management/src/main.js
new file mode 100644 (file)
index 0000000..5dc626f
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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);
+
+
diff --git a/skyquake/plugins/project_management/webpack.production.config.js b/skyquake/plugins/project_management/webpack.production.config.js
new file mode 100644 (file)
index 0000000..49ad631
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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;
diff --git a/skyquake/plugins/user-management/CMakeLists.txt b/skyquake/plugins/user-management/CMakeLists.txt
deleted file mode 100644 (file)
index e12d4fd..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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
-)
-
diff --git a/skyquake/plugins/user-management/config.json b/skyquake/plugins/user-management/config.json
deleted file mode 100644 (file)
index 930b9cf..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "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"
-    }]
-}
diff --git a/skyquake/plugins/user-management/package.json b/skyquake/plugins/user-management/package.json
deleted file mode 100644 (file)
index 1d57bf3..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-{
-  "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"
-  }
-}
diff --git a/skyquake/plugins/user-management/routes.js b/skyquake/plugins/user-management/routes.js
deleted file mode 100644 (file)
index 8640a99..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-
-var app = require('express').Router();
-var cors = require('cors');
-var utils = require('../../framework/core/api_utils/utils.js')
- // Begin Accounts API
-
-    utils.passThroughConstructor(app);
-
-module.exports = app;
diff --git a/skyquake/plugins/user-management/scripts/build.sh b/skyquake/plugins/user-management/scripts/build.sh
deleted file mode 100755 (executable)
index 04c5221..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/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'
diff --git a/skyquake/plugins/user-management/scripts/install.sh b/skyquake/plugins/user-management/scripts/install.sh
deleted file mode 100755 (executable)
index b883243..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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/.
diff --git a/skyquake/plugins/user-management/server.js b/skyquake/plugins/user-management/server.js
deleted file mode 100644 (file)
index eb140b7..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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('/*')
diff --git a/skyquake/plugins/user-management/src/dashboard/dashboard.jsx b/skyquake/plugins/user-management/src/dashboard/dashboard.jsx
deleted file mode 100644 (file)
index c86d6b1..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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() {
-        let self = this;
-        ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
-        setTimeout(function() {
-            let element = self[`user-ref-${self.state.activeIndex}`]
-            element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
-        })
-    }
-    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) => {
-        this.actions.viewUser(un, index);
-    }
-    editUser = () => {
-        this.actions.editUser(false);
-    }
-    cancelEditUser = () => {
-        this.actions.editUser(true)
-    }
-    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']
-            });
-        }
-    }
-    updateUser = (e) => {
-        let self = this;
-        e.preventDefault();
-        e.stopPropagation();
-        let validatedPasswords = validatePasswordFields(this.state);
-        if(validatedPasswords) {
-            this.Store.updateUser(_.merge({
-                            'user-name': this.state['user-name'],
-                            'user-domain': this.state['user-domain'],
-                            'password': this.state['new-password']
-                        }));
-        }
-        function validatePasswordFields(state) {
-            let oldOne = state['old-password'];
-            let newOne = state['new-password'];
-            let confirmOne = state['confirm-password'];
-            if(true) {
-                if(oldOne == newOne) {
-                    self.props.actions.showNotification('Your new password must not match your old one');
-                    return false;
-                }
-                if(newOne != confirmOne) {
-                    self.props.actions.showNotification('Passwords do not match');
-                    return false;
-                }
-                return {
-                    // 'old-password': oldOne,
-                    'new-password': newOne,
-                    'confirm-password': confirmOne
-                }
-            } else {
-                return {};
-            }
-        }
-    }
-     evaluateSubmit = (e) => {
-        if (e.keyCode == 13) {
-            if (this.props.isEdit) {
-                this.updateUser(e);
-            } else {
-                this.createUser(e);
-            }
-            e.preventDefault();
-            e.stopPropagation();
-        }
-    }
-    onTransitionEnd = (e) => {
-        this.actions.handleHideColumns(e);
-        console.log('transition end')
-    }
-    disableChange = (e) => {
-        let value = e.target.value;
-        value = value.toUpperCase();
-        if (value=="TRUE") {
-            value = true;
-        } else {
-            value = false;
-        }
-        console.log(value)
-    }
-    render() {
-        let self = this;
-        let html;
-        let props = this.props;
-        let state = this.state;
-        let passwordSectionHTML = null;
-        let formButtonsHTML = (
-            <ButtonGroup className="buttonGroup">
-                <Button label="EDIT" type="submit" onClick={this.editUser} />
-            </ButtonGroup>
-        );
-        if(!this.state.isReadOnly) {
-            passwordSectionHTML = ( this.state.isEdit ?
-                                        (
-                                            <FormSection title="PASSWORD CHANGE">
-                                                <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>
-                                        )
-                                    );
-            formButtonsHTML = (
-                                state.isEdit ?
-                                (
-                                    <ButtonGroup className="buttonGroup">
-                                        <Button label="Update" type="submit" onClick={this.updateUser} />
-                                        <Button label="Delete" onClick={this.deleteUser} />
-                                        <Button label="Cancel" onClick={this.cancelEditUser} />
-                                    </ButtonGroup>
-                                )
-                                : (
-                                    <ButtonGroup className="buttonGroup">
-                                        <Button label="Create" type="submit" onClick={this.createUser}  />
-                                    </ButtonGroup>
-                                )
-                            )
-        }
-
-        html = (
-            <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'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 && state.users.map((u, k) => {
-                            let platformRoles = [];
-                            for(let role in u.platformRoles) {
-                                platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
-                            }
-                            return (
-                                <div ref={(el) => this[`user-ref-${k}`] = el} 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 onKeyUp={this.evaluateSubmit}
-                    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  readonly={state.isReadOnly}  label="Username" value={state['user-name']} onChange={this.updateInput.bind(null, 'user-name')} />
-                        }
-                            <Input readonly={true} label="Domain" value={state['user-domain']}  onChange={this.updateInput.bind(null, 'user-domain')}></Input>
-
-                            <Input type="radiogroup" readonly={state.isReadOnly} label="Disabled" value={state.disabled} options={[{value: true, label: 'YES'}, {value: false, label: 'NO'}]}  onChange={this.disableChange} />
-                        </FormSection>
-                        <FormSection title="PLATFORM ROLES" style={{display:'none'}}>
-                            <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" style={{display:'none'}}>
-                            <InputCollection
-                                inital={true}
-                                type='select'
-                                readonly={state.isReadOnly}
-                                options={state.projectRolesOptions}
-                                collection={state.projectRoles}
-                                onChange={this.updateProjectRole}
-                                AddItemFn={this.addProjectRole}
-                                RemoveItemFn={this.removeProjectRole}
-                                />
-                        </FormSection>
-                        {passwordSectionHTML}
-
-                    </Panel>
-                        {formButtonsHTML}
-
-                </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);
-
-
-function isElementInView(el) {
-    var rect = el && el.getBoundingClientRect() || {};
-
-    return (
-        rect.top >= 0 &&
-        rect.left >= 0 &&
-        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
-        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
-    );
-}
-
-
-// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
-
-class isDisabled extends React.Component {
-    constructor(props) {
-        super(props);
-    }
-    render() {
-        let props = this.props;
-        return (<div/>)
-    }
-}
-
-/**
- * AddItemFn:
- */
-class InputCollection extends React.Component {
-    constructor(props) {
-        super(props);
-        this.collection = props.collection;
-    }
-    buildTextInput(onChange, v, i) {
-        return (
-            <Input
-                readonly={this.props.readonly}
-                style={{flex: '1 1'}}
-                key={i}
-                value={v}
-                onChange= {onChange.bind(null, i)}
-            />
-        )
-    }
-    buildSelectOption(initial, options, onChange, v, i) {
-        return (
-            <SelectOption
-                readonly={this.props.readonly}
-                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)}
-                            {
-                                props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
-                        </div>
-                    )
-                })}
-                { props.readonly ? null : <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: ''
-}
diff --git a/skyquake/plugins/user-management/src/dashboard/userMgmt.scss b/skyquake/plugins/user-management/src/dashboard/userMgmt.scss
deleted file mode 100644 (file)
index d00be88..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-
-/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
-@import "style/_colors.scss";
-
-.userManagement {
-        max-width: 900px;
-
-    .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: 1 1;
-            flex: 1 1;
-            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;
-    padding: 0.25rem;
-    margin: .125rem 0;
-    >div {
-        padding:0.25rem 1rem 0.25rem 0;
-        -ms-flex: 1 1 33%;
-            flex: 1 1 33%;
-    }
-    &--header {
-        font-weight:bold;
-    }
-    &--data {
-        &:hover:not(&-active) {
-            background:$neutral-dark-1;
-        }
-        &:hover, .activeUser, &-active{
-            cursor:pointer;
-            color:white;
-        }
-        .activeUser, &-active{
-            background: #00acee;
-        }
-    }
-}
-
-.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;
-    }
-}
diff --git a/skyquake/plugins/user-management/src/dashboard/userMgmtActions.js b/skyquake/plugins/user-management/src/dashboard/userMgmtActions.js
deleted file mode 100644 (file)
index a0a34d9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * STANDARD_RIFT_IO_COPYRIGHT
- */
-module.exports = function(Alt) {
-   return Alt.generateActions(
-                                       'handleUpdateInput',
-                                       'handleAddProjectItem',
-                                       'handleRemoveProjectItem',
-                                       'handleUpdateProjectRole',
-                                       'viewUser',
-                                       'editUser',
-                                       'handleCloseUserPanel',
-                                       'handleHideColumns',
-                                       'getUsersSuccess',
-                                       'getUsersNotification',
-                                       'handleDisabledChange',
-                                       'handlePlatformRoleUpdate',
-                                       'handleAddUser',
-                                       'handleCreateUser',
-                                       'handleUpdateUser',
-                                       'updateUserSuccess',
-                                       'createUserSuccess',
-                                       'deleteUserSuccess'
-                                       );
-}
diff --git a/skyquake/plugins/user-management/src/dashboard/userMgmtSource.js b/skyquake/plugins/user-management/src/dashboard/userMgmtSource.js
deleted file mode 100644 (file)
index 2f922a9..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * 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) {
-              $.ajax({
-                  url: `/user?api_server=${API_SERVER}`,
-                  type: 'PUT',
-                  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 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;
-}
diff --git a/skyquake/plugins/user-management/src/dashboard/userMgmtStore.js b/skyquake/plugins/user-management/src/dashboard/userMgmtStore.js
deleted file mode 100644 (file)
index 19952fb..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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'] = 'system';
-        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.isReadOnly = true;
-        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,
-            isReadOnly: true
-        }, ActiveUser);
-        this.setState(state)
-    }
-    editUser(isEdit) {
-        this.setState({
-            isReadOnly: isEdit
-        })
-    }
-    handleCloseUserPanel() {
-        this.setState({
-            userOpen: false,
-            isEdit: false,
-            isReadOnly: true
-        })
-    }
-    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 = 'system';
-        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,
-                                activeIndex: null,
-                                isReadOnly: false
-                            }
-        ))
-    }
-    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,
-            isEdit: true,
-            isReadOnly: true
-        })
-    }
-    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,
-            isReadOnly: true,
-            activeIndex: users.length - 1
-        };
-        _.merge(newState, this.resetPassword())
-        this.setState(newState);
-    }
-}
diff --git a/skyquake/plugins/user-management/src/main.js b/skyquake/plugins/user-management/src/main.js
deleted file mode 100644 (file)
index 5dc626f..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * 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);
-
-
diff --git a/skyquake/plugins/user-management/webpack.production.config.js b/skyquake/plugins/user-management/webpack.production.config.js
deleted file mode 100644 (file)
index 49ad631..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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;
diff --git a/skyquake/plugins/user_management/CMakeLists.txt b/skyquake/plugins/user_management/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5235092
--- /dev/null
@@ -0,0 +1,38 @@
+# 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(
+  user_management
+  DEPENDS skyquake
+  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+  CONFIGURE_COMMAND echo
+  BUILD_COMMAND
+    ${CMAKE_CURRENT_BINARY_DIR}/user_management/user_management-build/scripts/build.sh
+  INSTALL_COMMAND
+    ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install.sh
+    ${CMAKE_CURRENT_BINARY_DIR}/user_management/user_management-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
+)
+
diff --git a/skyquake/plugins/user_management/config.json b/skyquake/plugins/user_management/config.json
new file mode 100644 (file)
index 0000000..930b9cf
--- /dev/null
@@ -0,0 +1,14 @@
+{
+    "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"
+    }]
+}
diff --git a/skyquake/plugins/user_management/package.json b/skyquake/plugins/user_management/package.json
new file mode 100644 (file)
index 0000000..1d57bf3
--- /dev/null
@@ -0,0 +1,54 @@
+{
+  "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"
+  }
+}
diff --git a/skyquake/plugins/user_management/routes.js b/skyquake/plugins/user_management/routes.js
new file mode 100644 (file)
index 0000000..8640a99
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var app = require('express').Router();
+var cors = require('cors');
+var utils = require('../../framework/core/api_utils/utils.js')
+ // Begin Accounts API
+
+    utils.passThroughConstructor(app);
+
+module.exports = app;
diff --git a/skyquake/plugins/user_management/scripts/build.sh b/skyquake/plugins/user_management/scripts/build.sh
new file mode 100755 (executable)
index 0000000..04c5221
--- /dev/null
@@ -0,0 +1,18 @@
+#!/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'
diff --git a/skyquake/plugins/user_management/scripts/install.sh b/skyquake/plugins/user_management/scripts/install.sh
new file mode 100755 (executable)
index 0000000..b883243
--- /dev/null
@@ -0,0 +1,34 @@
+#!/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/.
diff --git a/skyquake/plugins/user_management/server.js b/skyquake/plugins/user_management/server.js
new file mode 100644 (file)
index 0000000..eb140b7
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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('/*')
diff --git a/skyquake/plugins/user_management/src/dashboard/dashboard.jsx b/skyquake/plugins/user_management/src/dashboard/dashboard.jsx
new file mode 100644 (file)
index 0000000..c86d6b1
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * 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() {
+        let self = this;
+        ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
+        setTimeout(function() {
+            let element = self[`user-ref-${self.state.activeIndex}`]
+            element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
+        })
+    }
+    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) => {
+        this.actions.viewUser(un, index);
+    }
+    editUser = () => {
+        this.actions.editUser(false);
+    }
+    cancelEditUser = () => {
+        this.actions.editUser(true)
+    }
+    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']
+            });
+        }
+    }
+    updateUser = (e) => {
+        let self = this;
+        e.preventDefault();
+        e.stopPropagation();
+        let validatedPasswords = validatePasswordFields(this.state);
+        if(validatedPasswords) {
+            this.Store.updateUser(_.merge({
+                            'user-name': this.state['user-name'],
+                            'user-domain': this.state['user-domain'],
+                            'password': this.state['new-password']
+                        }));
+        }
+        function validatePasswordFields(state) {
+            let oldOne = state['old-password'];
+            let newOne = state['new-password'];
+            let confirmOne = state['confirm-password'];
+            if(true) {
+                if(oldOne == newOne) {
+                    self.props.actions.showNotification('Your new password must not match your old one');
+                    return false;
+                }
+                if(newOne != confirmOne) {
+                    self.props.actions.showNotification('Passwords do not match');
+                    return false;
+                }
+                return {
+                    // 'old-password': oldOne,
+                    'new-password': newOne,
+                    'confirm-password': confirmOne
+                }
+            } else {
+                return {};
+            }
+        }
+    }
+     evaluateSubmit = (e) => {
+        if (e.keyCode == 13) {
+            if (this.props.isEdit) {
+                this.updateUser(e);
+            } else {
+                this.createUser(e);
+            }
+            e.preventDefault();
+            e.stopPropagation();
+        }
+    }
+    onTransitionEnd = (e) => {
+        this.actions.handleHideColumns(e);
+        console.log('transition end')
+    }
+    disableChange = (e) => {
+        let value = e.target.value;
+        value = value.toUpperCase();
+        if (value=="TRUE") {
+            value = true;
+        } else {
+            value = false;
+        }
+        console.log(value)
+    }
+    render() {
+        let self = this;
+        let html;
+        let props = this.props;
+        let state = this.state;
+        let passwordSectionHTML = null;
+        let formButtonsHTML = (
+            <ButtonGroup className="buttonGroup">
+                <Button label="EDIT" type="submit" onClick={this.editUser} />
+            </ButtonGroup>
+        );
+        if(!this.state.isReadOnly) {
+            passwordSectionHTML = ( this.state.isEdit ?
+                                        (
+                                            <FormSection title="PASSWORD CHANGE">
+                                                <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>
+                                        )
+                                    );
+            formButtonsHTML = (
+                                state.isEdit ?
+                                (
+                                    <ButtonGroup className="buttonGroup">
+                                        <Button label="Update" type="submit" onClick={this.updateUser} />
+                                        <Button label="Delete" onClick={this.deleteUser} />
+                                        <Button label="Cancel" onClick={this.cancelEditUser} />
+                                    </ButtonGroup>
+                                )
+                                : (
+                                    <ButtonGroup className="buttonGroup">
+                                        <Button label="Create" type="submit" onClick={this.createUser}  />
+                                    </ButtonGroup>
+                                )
+                            )
+        }
+
+        html = (
+            <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'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 && state.users.map((u, k) => {
+                            let platformRoles = [];
+                            for(let role in u.platformRoles) {
+                                platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
+                            }
+                            return (
+                                <div ref={(el) => this[`user-ref-${k}`] = el} 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 onKeyUp={this.evaluateSubmit}
+                    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  readonly={state.isReadOnly}  label="Username" value={state['user-name']} onChange={this.updateInput.bind(null, 'user-name')} />
+                        }
+                            <Input readonly={true} label="Domain" value={state['user-domain']}  onChange={this.updateInput.bind(null, 'user-domain')}></Input>
+
+                            <Input type="radiogroup" readonly={state.isReadOnly} label="Disabled" value={state.disabled} options={[{value: true, label: 'YES'}, {value: false, label: 'NO'}]}  onChange={this.disableChange} />
+                        </FormSection>
+                        <FormSection title="PLATFORM ROLES" style={{display:'none'}}>
+                            <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" style={{display:'none'}}>
+                            <InputCollection
+                                inital={true}
+                                type='select'
+                                readonly={state.isReadOnly}
+                                options={state.projectRolesOptions}
+                                collection={state.projectRoles}
+                                onChange={this.updateProjectRole}
+                                AddItemFn={this.addProjectRole}
+                                RemoveItemFn={this.removeProjectRole}
+                                />
+                        </FormSection>
+                        {passwordSectionHTML}
+
+                    </Panel>
+                        {formButtonsHTML}
+
+                </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);
+
+
+function isElementInView(el) {
+    var rect = el && el.getBoundingClientRect() || {};
+
+    return (
+        rect.top >= 0 &&
+        rect.left >= 0 &&
+        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+        rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+    );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+    constructor(props) {
+        super(props);
+    }
+    render() {
+        let props = this.props;
+        return (<div/>)
+    }
+}
+
+/**
+ * AddItemFn:
+ */
+class InputCollection extends React.Component {
+    constructor(props) {
+        super(props);
+        this.collection = props.collection;
+    }
+    buildTextInput(onChange, v, i) {
+        return (
+            <Input
+                readonly={this.props.readonly}
+                style={{flex: '1 1'}}
+                key={i}
+                value={v}
+                onChange= {onChange.bind(null, i)}
+            />
+        )
+    }
+    buildSelectOption(initial, options, onChange, v, i) {
+        return (
+            <SelectOption
+                readonly={this.props.readonly}
+                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)}
+                            {
+                                props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
+                        </div>
+                    )
+                })}
+                { props.readonly ? null : <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: ''
+}
diff --git a/skyquake/plugins/user_management/src/dashboard/userMgmt.scss b/skyquake/plugins/user_management/src/dashboard/userMgmt.scss
new file mode 100644 (file)
index 0000000..d00be88
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.userManagement {
+        max-width: 900px;
+
+    .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: 1 1;
+            flex: 1 1;
+            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;
+    padding: 0.25rem;
+    margin: .125rem 0;
+    >div {
+        padding:0.25rem 1rem 0.25rem 0;
+        -ms-flex: 1 1 33%;
+            flex: 1 1 33%;
+    }
+    &--header {
+        font-weight:bold;
+    }
+    &--data {
+        &:hover:not(&-active) {
+            background:$neutral-dark-1;
+        }
+        &:hover, .activeUser, &-active{
+            cursor:pointer;
+            color:white;
+        }
+        .activeUser, &-active{
+            background: #00acee;
+        }
+    }
+}
+
+.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;
+    }
+}
diff --git a/skyquake/plugins/user_management/src/dashboard/userMgmtActions.js b/skyquake/plugins/user_management/src/dashboard/userMgmtActions.js
new file mode 100644 (file)
index 0000000..a0a34d9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+   return Alt.generateActions(
+                                       'handleUpdateInput',
+                                       'handleAddProjectItem',
+                                       'handleRemoveProjectItem',
+                                       'handleUpdateProjectRole',
+                                       'viewUser',
+                                       'editUser',
+                                       'handleCloseUserPanel',
+                                       'handleHideColumns',
+                                       'getUsersSuccess',
+                                       'getUsersNotification',
+                                       'handleDisabledChange',
+                                       'handlePlatformRoleUpdate',
+                                       'handleAddUser',
+                                       'handleCreateUser',
+                                       'handleUpdateUser',
+                                       'updateUserSuccess',
+                                       'createUserSuccess',
+                                       'deleteUserSuccess'
+                                       );
+}
diff --git a/skyquake/plugins/user_management/src/dashboard/userMgmtSource.js b/skyquake/plugins/user_management/src/dashboard/userMgmtSource.js
new file mode 100644 (file)
index 0000000..2f922a9
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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) {
+              $.ajax({
+                  url: `/user?api_server=${API_SERVER}`,
+                  type: 'PUT',
+                  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 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;
+}
diff --git a/skyquake/plugins/user_management/src/dashboard/userMgmtStore.js b/skyquake/plugins/user_management/src/dashboard/userMgmtStore.js
new file mode 100644 (file)
index 0000000..19952fb
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * 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'] = 'system';
+        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.isReadOnly = true;
+        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,
+            isReadOnly: true
+        }, ActiveUser);
+        this.setState(state)
+    }
+    editUser(isEdit) {
+        this.setState({
+            isReadOnly: isEdit
+        })
+    }
+    handleCloseUserPanel() {
+        this.setState({
+            userOpen: false,
+            isEdit: false,
+            isReadOnly: true
+        })
+    }
+    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 = 'system';
+        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,
+                                activeIndex: null,
+                                isReadOnly: false
+                            }
+        ))
+    }
+    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,
+            isEdit: true,
+            isReadOnly: true
+        })
+    }
+    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,
+            isReadOnly: true,
+            activeIndex: users.length - 1
+        };
+        _.merge(newState, this.resetPassword())
+        this.setState(newState);
+    }
+}
diff --git a/skyquake/plugins/user_management/src/main.js b/skyquake/plugins/user_management/src/main.js
new file mode 100644 (file)
index 0000000..5dc626f
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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);
+
+
diff --git a/skyquake/plugins/user_management/webpack.production.config.js b/skyquake/plugins/user_management/webpack.production.config.js
new file mode 100644 (file)
index 0000000..49ad631
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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;