Project management bug fixes. Platform Role assignment init
authorLaurence Maultsby <laurence.maultsby@riftio.com>
Tue, 21 Mar 2017 18:56:10 +0000 (14:56 -0400)
committerLaurence Maultsby <laurence.maultsby@riftio.com>
Tue, 21 Mar 2017 18:56:10 +0000 (14:56 -0400)
Signed-off-by: Laurence Maultsby <laurence.maultsby@riftio.com>
skyquake/plugins/project_management/src/dashboard/dashboard.jsx
skyquake/plugins/project_management/src/dashboard/projectMgmt.scss
skyquake/plugins/project_management/src/dashboard/projectMgmtStore.js
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.jsx [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementActions.js [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementSource.js [new file with mode: 0644]
skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementStore.js [new file with mode: 0644]

index cabad1e..4cbb1ef 100644 (file)
@@ -95,24 +95,13 @@ class ProjectManagementDashboard extends React.Component {
         e.preventDefault();
         e.stopPropagation();
         let projectUsers = self.state.projectUsers;
-        let cleanUsers = [];
-        //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 {
-                cleanUsers.push(u);
-            }
-           })
-        })
+        let cleanUsers = this.cleanUsers(projectUsers);
+
         this.Store.createProject({
             'name': self.state['name'],
             'description': self.state.description,
             'project-config' : {
-                'user': projectUsers
+                'user': cleanUsers
             }
         });
     }
@@ -121,20 +110,7 @@ class ProjectManagementDashboard extends React.Component {
         e.preventDefault();
         e.stopPropagation();
         let projectUsers = self.state.projectUsers;
-        let cleanUsers = [];
-        //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']))) {
-            if(!r || ((r.role || r['keys']) && (!r.role || !r['keys']))) {
-                // projectUsers.splice(i, 1);
-            } else {
-                cleanUsers.push(u);
-            }
-           })
-        })
+        let cleanUsers = this.cleanUsers(projectUsers);
 
         this.Store.updateProject(_.merge({
             'name': self.state['name'],
@@ -143,6 +119,24 @@ class ProjectManagementDashboard extends React.Component {
                 'user': cleanUsers
             }
         }));
+    }
+    cleanUsers(projectUsers) {
+        let cleanUsers = [];
+        //Remove null values from role
+        projectUsers.map((u) => {
+            let cleanRoles = [];
+           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.role || ( !r || ((r.role || r['keys']) && (!r.role || !r['keys'])))) {
+            } else {
+                    cleanRoles.push(r)
+            }
+           });
+           u.role = cleanRoles;
+           cleanUsers.push(u);
+        });
+        return cleanUsers;
     }
      evaluateSubmit = (e) => {
         if (e.keyCode == 13) {
@@ -299,7 +293,7 @@ class ProjectManagementDashboard extends React.Component {
                         }
                             <Input readonly={state.isReadOnly} type="textarea" label="Description" value={state['description']}  onChange={this.updateInput.bind(null, 'description')}></Input>
                         </FormSection>
-                        <FormSection title="USER ROLES">
+                        <FormSection title="USER ROLES"  className="userTable">
 
                         <table>
                             <thead>
@@ -333,7 +327,7 @@ class ProjectManagementDashboard extends React.Component {
                                         </td>
                                         {
                                             state.roles.map((r,j) => {
-                                                return <td key={j}><Input type="checkbox" onChange={self.toggleUserRoleInProject.bind(self, i, j)} checked={(userRoles.indexOf(r) > -1)} /></td>
+                                                return <td key={j}><Input readonly={state.isReadOnly} type="checkbox" onChange={self.toggleUserRoleInProject.bind(self, i, j)} value={(userRoles.indexOf(r) > -1)} checked={(userRoles.indexOf(r) > -1)} /></td>
                                             })
                                         }
                                     </tr>
@@ -343,76 +337,6 @@ class ProjectManagementDashboard extends React.Component {
                             </tbody>
                         </table>
 
-
-                        { false ?
-                            <div>
-                                <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>
-                                        )
-                                    })
-                                }
-                                </div>
-                                 : null
-                             }
                             {
                                 !state.isReadOnly ?
                                     <div className="tableRow tableRow--header">
index dc8fcce..0d76a29 100644 (file)
         }
 
     table {
+        font-size: 0.8rem;
         thead {
             border-bottom:1px solid #d3d3d3;
             td{
             }
         }
     }
+    .userTable {
+        .FormSection-body {
+            max-width: 652px;
+            overflow-x: scroll;
+        }
+    }
 }
 
 
index 857e9a7..d7d76b8 100644 (file)
@@ -15,8 +15,8 @@ export default class ProjectManagementStore {
         this.projectUsers = [];
         this.selectedUser = null;
         this.selectedRole = null;
-        this.roles = ['rw-rbac-platform:super-admin', 'operator_role'
-        // 'some_other_role', 'yet_another_role', 'operator_role', 'some_other_role', 'yet_another_role'
+        this.roles = ['rw-rbac-platform:platform-admin', 'rw-rbac-platform:platform-oper', 'rw-rbac-platform:super-admin'
+        // ,'some_other_role', 'yet_another_role', 'operator_role', 'some_other_role', 'yet_another_role'
         ];
         this.users = [];
         this.activeIndex = null;
diff --git a/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.jsx b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.jsx
new file mode 100644 (file)
index 0000000..49efb82
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import ProjectManagementStore from './platformRoleManagementStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import './platformRoleManagement.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 PlatformRoleManagement 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);
+    }
+    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;
+        let selectedUsers = [];
+        //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)
+        })
+    }
+    toggleUserRoleInProject = (userIndex, roleIndex, e) => {
+        this.actions.handleToggleUserRoleInProject({
+            userIndex,
+            roleIndex,
+            checked: JSON.parse(e.currentTarget.checked)
+        })
+    }
+    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>
+        );
+        let projectUsers = [];
+        self.state.projectUsers.map((u) => {
+            projectUsers.push(u['user-name']);
+        });
+
+        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 ${false ? 'projectList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
+                <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="USER ROLES">
+
+                        <table>
+                            <thead>
+                                <tr>
+                                    {!state.isReadOnly ? <td></td> : null}
+                                    <td>User Name</td>
+                                    {
+                                        state.roles.map((r,i) => {
+                                            return <td key={i}>{r}</td>
+                                        })
+                                    }
+                                </tr>
+                            </thead>
+                            <tbody>
+                                {
+                            state.projectUsers.map((u,i)=> {
+                                let userRoles = u.role.map((r) => {
+                                    return r.role;
+                                })
+                                return (
+                                    <tr key={i}>
+                                        {!state.isReadOnly ? <td><span
+                                                                    className="removeInput"
+                                                                    onClick={self.removeUserFromProject.bind(self, u)}
+                                                                >
+                                                                    <img src={imgRemove} />
+
+                                                                </span></td> : null}
+                                        <td>
+                                            {u['user-name']}
+                                        </td>
+                                        {
+                                            state.roles.map((r,j) => {
+                                                return <td key={j}><Input type="checkbox" onChange={self.toggleUserRoleInProject.bind(self, i, j)} checked={(userRoles.indexOf(r) > -1)} /></td>
+                                            })
+                                        }
+                                    </tr>
+                                )
+                            })
+                        }
+                            </tbody>
+                        </table>
+
+
+                        { false ?
+                            <div>
+                                <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>
+                                        )
+                                    })
+                                }
+                                </div>
+                                 : null
+                             }
+                            {
+                                !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.filter((u) => {
+                                                        return projectUsers.indexOf(u['user-name']) == -1
+                                                    }).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)}
+PlatformRoleManagement.contextTypes = {
+    router: React.PropTypes.object
+};
+
+PlatformRoleManagement.defaultProps = {
+    projectList: [],
+    selectedProject: {}
+}
+
+export default SkyquakeComponent(PlatformRoleManagement);
+
+
+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/user_management/src/platformRoleManagement/platformRoleManagement.scss b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagement.scss
new file mode 100644 (file)
index 0000000..dc8fcce
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * 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;
+        }
+
+    table {
+        thead {
+            border-bottom:1px solid #d3d3d3;
+            td{
+                font-weight:bold;
+            }
+        }
+        td{
+            padding:0.25rem 0.5rem;
+            vertical-align: middle;
+            .checkbox {
+                -ms-flex-pack:center;
+                    justify-content:center;
+            }
+        }
+    }
+}
+
+
+
+.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;
+        -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/user_management/src/platformRoleManagement/platformRoleManagementActions.js b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementActions.js
new file mode 100644 (file)
index 0000000..5f2b1ea
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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',
+                                       'handleToggleUserRoleInProject',
+                                       'addRoleToUserInProject',
+                                       'handleRemoveRoleFromUserInProject',
+                                       'updateProjectSuccess',
+                                       'createProjectSuccess',
+                                       'deleteProjectSuccess'
+                                       );
+}
diff --git a/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementSource.js b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementSource.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/user_management/src/platformRoleManagement/platformRoleManagementStore.js b/skyquake/plugins/user_management/src/platformRoleManagement/platformRoleManagementStore.js
new file mode 100644 (file)
index 0000000..87eeb61
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import PlatformRoleManagementActions from './platformRoleManagementActions.js';
+import PlatformRoleManagementSource from './platformRoleManagementSource.js';
+import _ from 'lodash';
+export default class PlatformRoleManagementStore {
+    constructor() {
+        this.actions = PlatformRoleManagementActions(this.alt);
+        this.bindActions(this.actions);
+        this.registerAsync(PlatformRoleManagementSource);
+        this.projects = [];
+        this['name'] = '';
+        this['description'] = 'Some Description';
+        this.projectUsers = [];
+        this.selectedUser = null;
+        this.selectedRole = null;
+        this.roles = ['super_admin', 'operator_role'
+        // 'some_other_role', 'yet_another_role', 'operator_role', 'some_other_role', 'yet_another_role'
+        ];
+        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, selectedUser: null})
+    }
+    handleToggleUserRoleInProject(data) {
+        let self = this;
+        let {userIndex, roleIndex, checked} = data;
+        let projectUsers = this.projectUsers;
+        let selectedRole = self.roles[roleIndex];
+        if(checked) {
+            projectUsers[userIndex].role.push({
+                role: self.roles[roleIndex],
+                keys: self.roles[roleIndex]
+            })
+        } else {
+            let role = projectUsers[userIndex].role;
+            let roleIndex = _.findIndex(role, {role:selectedRole, keys: selectedRole})
+            projectUsers[userIndex].role.splice(roleIndex, 1)
+        }
+       self.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);
+    }
+}