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