Platform Role Assignments take 2
[osm/UI.git] / skyquake / plugins / user_management / src / dashboard / dashboard.jsx
1 /*
2  * STANDARD_RIFT_IO_COPYRIGHT
3  */
4
5 import React from 'react';
6 import ReactDOM from 'react-dom';
7 import AppHeader from 'widgets/header/header.jsx';
8 import UserManagementStore from './userMgmtStore.js';
9 import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
10 import 'style/layout.scss';
11 import './userMgmt.scss';
12 import {Panel, PanelWrapper} from 'widgets/panel/panel';
13
14
15 import TextInput from 'widgets/form_controls/textInput.jsx';
16 import Input from 'widgets/form_controls/input.jsx';
17 import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
18 import SelectOption from 'widgets/form_controls/selectOption.jsx';
19 import 'widgets/form_controls/formControls.scss';
20 import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
21 import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
22
23 class UserManagementDashboard extends React.Component {
24     constructor(props) {
25         super(props);
26         this.Store = this.props.flux.stores.hasOwnProperty('UserManagementStore') ? this.props.flux.stores.UserManagementStore : this.props.flux.createStore(UserManagementStore);
27        this.state = this.Store.getState();
28        this.actions = this.state.actions;
29
30     }
31     componentDidUpdate() {
32         let self = this;
33         ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
34         setTimeout(function() {
35             let element = self[`user-ref-${self.state.activeIndex}`]
36             element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
37         })
38     }
39     componentWillMount() {
40         this.Store.listen(this.updateState);
41         this.Store.getUsers();
42     }
43     componentWillUnmount() {
44         this.Store.unlisten(this.updateState);
45     }
46     updateState = (state) => {
47         this.setState(state);
48     }
49     updateInput = (key, e) => {
50         let property = key;
51         this.actions.handleUpdateInput({
52             [property]:e.target.value
53         })
54     }
55     disabledChange = (e) => {
56         this.actions.handleDisabledChange(e.target.checked);
57     }
58     platformChange = (platformRole, e) => {
59         this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
60     }
61     addProjectRole = (e) => {
62         this.actions.handleAddProjectItem();
63     }
64     removeProjectRole = (i, e) => {
65         this.actions.handleRemoveProjectItem(i);
66     }
67     updateProjectRole = (i, e) => {
68         this.actions.handleUpdateProjectRole(i, e)
69     }
70     addUser = () => {
71         this.actions.handleAddUser();
72     }
73     viewUser = (un, index) => {
74         this.actions.viewUser(un, index);
75     }
76     editUser = () => {
77         this.actions.editUser(false);
78     }
79     cancelEditUser = () => {
80         this.actions.editUser(true)
81     }
82     closePanel = () => {
83         this.actions.handleCloseUserPanel();
84     }
85     // updateUser = (e) => {
86     //     e.preventDefault();
87     //     e.stopPropagation();
88
89     //     this.Store.updateUser();
90     // }
91     deleteUser = (e) => {
92         e.preventDefault();
93         e.stopPropagation();
94         this.Store.deleteUser({
95                 'user-name': this.state['user-name'],
96                 'user-domain': this.state['user-domain']
97             });
98     }
99     createUser = (e) => {
100         e.preventDefault();
101         e.stopPropagation();
102         if(this.state['new-password'] != this.state['confirm-password']) {
103             this.props.actions.showNotification('Passwords do not match')
104         } else {
105             this.Store.createUser({
106                 'user-name': this.state['user-name'],
107                 'user-domain': this.state['user-domain'],
108                 'password': this.state['new-password']
109                 // 'confirm-password': this.state['confirm-password']
110             });
111         }
112     }
113     updateUser = (e) => {
114         let self = this;
115         e.preventDefault();
116         e.stopPropagation();
117         let validatedPasswords = validatePasswordFields(this.state);
118         if(validatedPasswords) {
119             this.Store.updateUser(_.merge({
120                             'user-name': this.state['user-name'],
121                             'user-domain': this.state['user-domain'],
122                             'password': this.state['new-password']
123                         }));
124         }
125         function validatePasswordFields(state) {
126             let oldOne = state['old-password'];
127             let newOne = state['new-password'];
128             let confirmOne = state['confirm-password'];
129             if(true) {
130                 if(oldOne == newOne) {
131                     self.props.actions.showNotification('Your new password must not match your old one');
132                     return false;
133                 }
134                 if(newOne != confirmOne) {
135                     self.props.actions.showNotification('Passwords do not match');
136                     return false;
137                 }
138                 return {
139                     // 'old-password': oldOne,
140                     'new-password': newOne,
141                     'confirm-password': confirmOne
142                 }
143             } else {
144                 return {};
145             }
146         }
147     }
148      evaluateSubmit = (e) => {
149         if (e.keyCode == 13) {
150             if (this.props.isEdit) {
151                 this.updateUser(e);
152             } else {
153                 this.createUser(e);
154             }
155             e.preventDefault();
156             e.stopPropagation();
157         }
158     }
159     onTransitionEnd = (e) => {
160         this.actions.handleHideColumns(e);
161         console.log('transition end')
162     }
163     disableChange = (e) => {
164         let value = e.target.value;
165         value = value.toUpperCase();
166         if (value=="TRUE") {
167             value = true;
168         } else {
169             value = false;
170         }
171         console.log(value)
172     }
173     render() {
174         let self = this;
175         let html;
176         let props = this.props;
177         let state = this.state;
178         let passwordSectionHTML = null;
179         let formButtonsHTML = (
180             <ButtonGroup className="buttonGroup">
181                 <Button label="EDIT" type="submit" onClick={this.editUser} />
182             </ButtonGroup>
183         );
184         if(!this.state.isReadOnly) {
185             passwordSectionHTML = ( this.state.isEdit ?
186                                         (
187                                             <FormSection title="PASSWORD CHANGE">
188                                                 <Input label="NEW PASSWORD" type="password" value={state['new-password']}  onChange={this.updateInput.bind(null, 'new-password')}/>
189                                                 <Input label="REPEAT NEW PASSWORD" type="password"  value={state['confirm-password']}  onChange={this.updateInput.bind(null, 'confirm-password')}/>
190                                             </FormSection>
191                                         ) :
192                                         (
193                                             <FormSection title="CREATE PASSWORD">
194                                                 <Input label="CREATE PASSWORD" type="password" value={state.newPassword}  onChange={this.updateInput.bind(null, 'new-password')}/>
195                                                 <Input label="REPEAT PASSWORD" type="password"  value={state.repeatNewPassword}  onChange={this.updateInput.bind(null, 'confirm-password')}/>
196                                             </FormSection>
197                                         )
198                                     );
199             formButtonsHTML = (
200                                 state.isEdit ?
201                                 (
202                                     <ButtonGroup className="buttonGroup">
203                                         <Button label="Update" type="submit" onClick={this.updateUser} />
204                                         <Button label="Delete" onClick={this.deleteUser} />
205                                         <Button label="Cancel" onClick={this.cancelEditUser} />
206                                     </ButtonGroup>
207                                 )
208                                 : (
209                                     <ButtonGroup className="buttonGroup">
210                                         <Button label="Create" type="submit" onClick={this.createUser}  />
211                                     </ButtonGroup>
212                                 )
213                             )
214         }
215
216         html = (
217             <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'flexDirection': 'row'}} >
218                 <PanelWrapper ref={(div) => { this.UserList = div}} className={`column userList expanded ${this.state.userOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
219                     <Panel title="User List" style={{marginBottom: 0}} no-corners>
220                         <div className="tableRow tableRow--header">
221                             <div className="userName">
222                                 Username
223                             </div>
224                             <div>
225                                 Domain
226                             </div>
227                         </div>
228                         {state.users && state.users.map((u, k) => {
229                             let platformRoles = [];
230                             for(let role in u.platformRoles) {
231                                 platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
232                             }
233                             return (
234                                 <div ref={(el) => this[`user-ref-${k}`] = el} className={`tableRow tableRow--data ${((self.state.activeIndex == k) && self.state.userOpen) ? 'tableRow--data-active' : ''}`} key={k}>
235                                     <div
236                                         className={`userName userName-header ${((self.state.activeIndex == k) && self.state.userOpen) ? 'activeUser' : ''}`}
237                                         onClick={self.viewUser.bind(null, u, k)}>
238                                         {u['user-name']}
239                                     </div>
240                                     <div>
241                                         {u['user-domain']}
242                                     </div>
243
244
245                                 </div>
246                             )
247                         })}
248                     </Panel>
249                     <ButtonGroup  className="buttonGroup" style={{margin: '0 0.5rem 0.5rem', background: '#ddd', paddingBottom: '0.5rem'}}>
250                         <Button label="Add User" onClick={this.addUser} />
251                     </ButtonGroup>
252                 </PanelWrapper>
253                 <PanelWrapper onKeyUp={this.evaluateSubmit}
254                     className={`userAdmin column`}>
255                     <Panel
256                         title={state.isEdit ? state['user-name'] : 'Create User'}
257                         style={{marginBottom: 0}}
258                         hasCloseButton={this.closePanel}
259                         no-corners>
260                         <FormSection title="USER INFO">
261                         {
262                             this.state.isEdit ?
263                                 null
264                                 : <Input  readonly={state.isReadOnly}  label="Username" value={state['user-name']} onChange={this.updateInput.bind(null, 'user-name')} />
265                         }
266                             <Input readonly={true} label="Domain" value={state['user-domain']}  onChange={this.updateInput.bind(null, 'user-domain')}></Input>
267
268                             <Input type="radiogroup" readonly={state.isReadOnly} label="Disabled" value={state.disabled} options={[{value: true, label: 'YES'}, {value: false, label: 'NO'}]}  onChange={this.disableChange} />
269                         </FormSection>
270                         <FormSection title="PLATFORM ROLES" style={{display:'none'}}>
271                             <Input label="Super Admin" onChange={this.platformChange.bind(null, 'super_admin')} checked={state.platformRoles.super_admin} type="checkbox" />
272                             <Input label="Platform Admin" onChange={this.platformChange.bind(null, 'platform_admin')}  checked={state.platformRoles.platform_admin} type="checkbox" />
273                             <Input label="Platform Oper" onChange={this.platformChange.bind(null, 'platform_oper')}  checked={state.platformRoles.platform_oper} type="checkbox" />
274                         </FormSection>
275                         <FormSection title="PROJECT ROLES" style={{display:'none'}}>
276                             <InputCollection
277                                 inital={true}
278                                 type='select'
279                                 readonly={state.isReadOnly}
280                                 options={state.projectRolesOptions}
281                                 collection={state.projectRoles}
282                                 onChange={this.updateProjectRole}
283                                 AddItemFn={this.addProjectRole}
284                                 RemoveItemFn={this.removeProjectRole}
285                                 />
286                         </FormSection>
287                         {passwordSectionHTML}
288
289                     </Panel>
290                         {formButtonsHTML}
291
292                 </PanelWrapper>
293
294
295             </PanelWrapper>
296         );
297         return html;
298     }
299 }
300 // onClick={this.Store.update.bind(null, Account)}
301 UserManagementDashboard.contextTypes = {
302     router: React.PropTypes.object
303 };
304
305 UserManagementDashboard.defaultProps = {
306     userList: [],
307     selectedUser: {}
308 }
309
310 export default SkyquakeComponent(UserManagementDashboard);
311
312
313 function isElementInView(el) {
314     var rect = el && el.getBoundingClientRect() || {};
315
316     return (
317         rect.top >= 0 &&
318         rect.left >= 0 &&
319         rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
320         rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
321     );
322 }
323
324
325 // isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
326
327 class isDisabled extends React.Component {
328     constructor(props) {
329         super(props);
330     }
331     render() {
332         let props = this.props;
333         return (<div/>)
334     }
335 }
336
337 /**
338  * AddItemFn:
339  */
340 class InputCollection extends React.Component {
341     constructor(props) {
342         super(props);
343         this.collection = props.collection;
344     }
345     buildTextInput(onChange, v, i) {
346         return (
347             <Input
348                 readonly={this.props.readonly}
349                 style={{flex: '1 1'}}
350                 key={i}
351                 value={v}
352                 onChange= {onChange.bind(null, i)}
353             />
354         )
355     }
356     buildSelectOption(initial, options, onChange, v, i) {
357         return (
358             <SelectOption
359                 readonly={this.props.readonly}
360                 key={`${i}-${v.replace(' ', '_')}`}
361                 intial={initial}
362                 defaultValue={v}
363                 options={options}
364                 onChange={onChange.bind(null, i)}
365             />
366         );
367     }
368     showInput() {
369
370     }
371     render() {
372         const props = this.props;
373         let inputType;
374         let className = "InputCollection";
375         if (props.className) {
376             className = `${className} ${props.className}`;
377         }
378         if (props.type == 'select') {
379             inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
380         } else {
381             inputType = this.buildTextInput.bind(this, props.onChange)
382         }
383         let html = (
384             <div className="InputCollection-wrapper">
385                 {props.collection.map((v,i) => {
386                     return (
387                         <div key={i} className={className} >
388                             {inputType(v, i)}
389                             {
390                                 props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
391                         </div>
392                     )
393                 })}
394                 { props.readonly ? null : <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>}
395             </div>
396         );
397         return html;
398     }
399 }
400
401 InputCollection.defaultProps = {
402     input: Input,
403     collection: [],
404     onChange: function(i, e) {
405         console.log(`
406                         Updating with: ${e.target.value}
407                         At index of: ${i}
408                     `)
409     },
410     AddItemFn: function(e) {
411         console.log(`Adding a new item to collection`)
412     },
413     RemoveItemFn: function(i, e) {
414         console.log(`Removing item from collection at index of: ${i}`)
415     }
416 }
417
418 class FormSection extends React.Component {
419     render() {
420         let className = 'FormSection ' + this.props.className;
421         let html = (
422             <div
423                 style={this.props.style}
424                 className={className}
425             >
426                 <div className="FormSection-title">
427                     {this.props.title}
428                 </div>
429                 <div className="FormSection-body">
430                     {this.props.children}
431                 </div>
432             </div>
433         );
434         return html;
435     }
436 }
437
438 FormSection.defaultProps = {
439     className: ''
440 }