From fdeab76fe6ace38f23ffbda72e193de1dc14142f Mon Sep 17 00:00:00 2001 From: irismarie Date: Wed, 27 May 2020 15:16:41 +0200 Subject: [PATCH 1/6] [WIP] add user functionality for each scenario --- src/scenario/scenario-store.js | 35 +++++++++++++++++++++- src/scenario/scenario.js | 40 +++++++++++++++++++++++++- src/scenario/scenarios-data-manager.js | 14 +++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 777475c..75c77ee 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -19,4 +19,37 @@ import ScenariosDataManager from './scenarios-data-manager'; import ArrayStore from '../common/array-store'; -export default new ArrayStore('scenarios', ScenariosDataManager); +//export default new ArrayStore('scenarios', ScenariosDataManager); + +class ScenarioStore extends ArrayStore { + constructor() { + super('scenarios', ScenariosDataManager); + } + + getInitialState() { + return { + state: super.getInitialState(), + users: null + }; + } + + getUsers(token, id) { + ScenariosDataManager.getUsers(token, id); + } + + reduce(state, action) { + switch (action.type) { + case 'scenarios/users': + state.users = action.users; + return state; + case 'scenarios/users-error': + return state; + + default: + return super.reduce(state, action); + } + } + +} + +export default new ScenarioStore(); \ No newline at end of file diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 005b859..11c2739 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -21,6 +21,7 @@ import { Button } from 'react-bootstrap'; import FileSaver from 'file-saver'; import ScenarioStore from './scenario-store'; +//import ScenariosDataManager from './scenarios-data-manager'; import ICStore from '../ic/ic-store'; import DashboardStore from '../dashboard/dashboard-store'; import ConfigStore from '../componentconfig/config-store'; @@ -43,6 +44,10 @@ import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; class Scenario extends React.Component { + constructor(props) { + super(props); + this.getUsers = true; + } static getStores() { return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore]; @@ -51,7 +56,7 @@ class Scenario extends React.Component { static calculateState(prevState, props) { // get selected scenario const sessionToken = LoginStore.getState().token; - + const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10)); if (scenario == null) { AppDispatcher.dispatch({ @@ -60,6 +65,21 @@ class Scenario extends React.Component { token: sessionToken }); } + let users = null; + let sc = ScenarioStore.getState().users; + /* + if (sc) { + users = sc.users; + if (users == null && this.getUsers ) { + ScenarioStore.getUsers(sessionToken, props.match.params.scenario); + this.getUsers = false; + } + } + */ + + + + // ScenariosDataManager.getUsers(sessionToken, props.match.params.scenario); // obtain all dashboards of a scenario let dashboards = DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10)); @@ -85,6 +105,7 @@ class Scenario extends React.Component { return { scenario, + users, sessionToken, configs, dashboards, @@ -111,6 +132,9 @@ class Scenario extends React.Component { } componentDidMount() { + // get users of scenario + ScenarioStore.getUsers(this.state.sessionToken, this.state.scenario.id); + //load selected scenario AppDispatcher.dispatch({ type: 'scenarios/start-load', @@ -140,6 +164,9 @@ class Scenario extends React.Component { } componentDidUpdate(prevProps, prevState) { +// if (this.state.users) { +// this.getUsers = false; +// } if (this.state.dashboards.length > prevState.dashboards.length) { if (this.addWidgets) { // add widgets // this can only be true after dashboard import, so there is only one dashboard @@ -461,6 +488,17 @@ class Scenario extends React.Component { return

{this.state.scenario.name}

+

Users

+ + + + this.setState({ deleteUserModal: true, modalUserData: this.state.users[index], modalUserIndex: index })} + /> +
{/*Component Configurations table*/}

Component Configurations

diff --git a/src/scenario/scenarios-data-manager.js b/src/scenario/scenarios-data-manager.js index ec4a442..b5e48fe 100644 --- a/src/scenario/scenarios-data-manager.js +++ b/src/scenario/scenarios-data-manager.js @@ -24,6 +24,20 @@ class ScenariosDataManager extends RestDataManager { super('scenario', '/scenarios'); } + getUsers(token, id) { + RestAPI.get(this.makeURL('/scenarios/' + id + '/users/'), token).then(response => { + AppDispatcher.dispatch({ + type: 'scenarios/users', + users: response.users + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'scenarios/users-error', + error: error + }) + }) + } + getComponentConfigs(token, id) { RestAPI.get(this.makeURL('/scenarios/' + id + '/configs'), token).then(response => { AppDispatcher.dispatch({ From 93ca536f40c0805f002f353519650361347e5457 Mon Sep 17 00:00:00 2001 From: irismarie Date: Thu, 28 May 2020 12:09:46 +0200 Subject: [PATCH 2/6] moved action handling to LoginStore as it's derived directly from ReduceStore --- src/scenario/scenario-store.js | 25 +------------------------ src/scenario/scenario.js | 22 ++-------------------- src/user/login-store.js | 9 ++++++++- 3 files changed, 11 insertions(+), 45 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 75c77ee..be89e90 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -19,37 +19,14 @@ import ScenariosDataManager from './scenarios-data-manager'; import ArrayStore from '../common/array-store'; -//export default new ArrayStore('scenarios', ScenariosDataManager); - class ScenarioStore extends ArrayStore { constructor() { - super('scenarios', ScenariosDataManager); - } - - getInitialState() { - return { - state: super.getInitialState(), - users: null - }; + super('scenarios', ScenariosDataManager); } getUsers(token, id) { ScenariosDataManager.getUsers(token, id); } - - reduce(state, action) { - switch (action.type) { - case 'scenarios/users': - state.users = action.users; - return state; - case 'scenarios/users-error': - return state; - - default: - return super.reduce(state, action); - } - } - } export default new ScenarioStore(); \ No newline at end of file diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 11c2739..b8e3f5a 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -43,11 +43,8 @@ import EditSignalMapping from "../signal/edit-signal-mapping"; import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; + class Scenario extends React.Component { - constructor(props) { - super(props); - this.getUsers = true; - } static getStores() { return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore]; @@ -65,22 +62,8 @@ class Scenario extends React.Component { token: sessionToken }); } - let users = null; - let sc = ScenarioStore.getState().users; - /* - if (sc) { - users = sc.users; - if (users == null && this.getUsers ) { - ScenarioStore.getUsers(sessionToken, props.match.params.scenario); - this.getUsers = false; - } - } - */ - - - // ScenariosDataManager.getUsers(sessionToken, props.match.params.scenario); - + let users = LoginStore.getState().scenarioUsers; // obtain all dashboards of a scenario let dashboards = DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10)); @@ -132,7 +115,6 @@ class Scenario extends React.Component { } componentDidMount() { - // get users of scenario ScenarioStore.getUsers(this.state.sessionToken, this.state.scenario.id); //load selected scenario diff --git a/src/user/login-store.js b/src/user/login-store.js index 0b461e2..c5718db 100644 --- a/src/user/login-store.js +++ b/src/user/login-store.js @@ -30,7 +30,8 @@ class LoginStore extends ReduceStore { return { currentUser: null, token: null, - loginMessage: null + loginMessage: null, + scenarioUsers: null }; } @@ -76,7 +77,13 @@ class LoginStore extends ReduceStore { // If it was an error and hasn't been handled, the credentials must have been wrong. state = Object.assign({}, state, { loginMessage: 'Wrong credentials! Please try again.' }); } + return state; + case 'scenarios/users': + state.scenarioUsers = action.users; + return state; + + case 'scenarios/users-error': return state; default: From b7ee4bb35c794a82d63c33ad4707e6f1753547ad Mon Sep 17 00:00:00 2001 From: irismarie Date: Sun, 31 May 2020 13:51:43 +0200 Subject: [PATCH 3/6] [WIP] delete user --- src/scenario/scenario-store.js | 4 ++ src/scenario/scenario.js | 51 ++++++++++++++++++++++++-- src/scenario/scenarios-data-manager.js | 7 ++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 7ca1c17..1f08ffb 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -29,6 +29,10 @@ class ScenarioStore extends ArrayStore{ ScenariosDataManager.getUsers(token, id); } + deleteUser(token, id, username) { + ScenariosDataManager.deleteUser(token, id, username); + } + reduce(state, action) { switch (action.type) { diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 33a1722..2828767 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -17,7 +17,7 @@ import React from 'react'; import { Container } from 'flux/utils'; -import { Button } from 'react-bootstrap'; +import { Button, DropdownButton, Dropdown } from 'react-bootstrap'; import FileSaver from 'file-saver'; import ScenarioStore from './scenario-store'; @@ -42,12 +42,14 @@ import EditConfigDialog from "../componentconfig/edit-config"; import EditSignalMapping from "../signal/edit-signal-mapping"; import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; +import UsersStore from '../user/users-store'; + class Scenario extends React.Component { static getStores() { - return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore]; + return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore, UsersStore]; } static calculateState(prevState, props) { @@ -64,6 +66,12 @@ class Scenario extends React.Component { } let users = LoginStore.getState().scenarioUsers; + let allUsers = UsersStore.getState(); + let allUserNames = []; + allUsers.forEach((user) => { + allUserNames.push(user.username); + }); + // obtain all dashboards of a scenario let dashboards = DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10)); @@ -80,6 +88,8 @@ class Scenario extends React.Component { return { scenario, users, + allUsers, + allUserNames, sessionToken, configs, dashboards, @@ -101,6 +111,9 @@ class Scenario extends React.Component { deleteDashboardModal: false, importDashboardModal: false, modalDashboardData: {}, + + addUserModal: false, + deleteUserName: '', } } @@ -119,8 +132,22 @@ class Scenario extends React.Component { type: 'ics/start-load', token: this.state.sessionToken }); + + // load users + AppDispatcher.dispatch({ + type: 'users/start-load', + token: this.state.sessionToken + }); } + // add User to Scenario + addUser() { + + } + + closeDeleteUserModal() { + ScenarioStore.deleteUser(this.state.sessionToken, this.state.scenario.id, this.state.deleteUserName); + } /* ############################################## * Component Configuration modification methods @@ -418,6 +445,8 @@ class Scenario extends React.Component { return

{this.state.scenario.name}

+ + {/*Scenario Users table*/}

Users

@@ -426,10 +455,26 @@ class Scenario extends React.Component { title='' width='200' deleteButton - onDelete={(index) => this.setState({ deleteUserModal: true, modalUserData: this.state.users[index], modalUserIndex: index })} + onDelete={(index) => this.setState({ deleteUserModal: true, deleteUserName: this.state.users[index].username, modalUserIndex: index })} />
+
+ this.addUser()} + // style={buttonStyle}> User + > + {this.state.allUserNames.map((opt,i) => ( + + {opt} + + ))} + +
+ + this.closeDeleteUserModal(c)} /> + {/*Component Configurations table*/}

Component Configurations

diff --git a/src/scenario/scenarios-data-manager.js b/src/scenario/scenarios-data-manager.js index 756816a..9854901 100644 --- a/src/scenario/scenarios-data-manager.js +++ b/src/scenario/scenarios-data-manager.js @@ -41,6 +41,13 @@ class ScenariosDataManager extends RestDataManager { }) } + deleteUser(token, id, username) { + RestAPI.delete(this.requestURL('remove/update', 'user', 'username='+username), token).then(response => { + + }) + //super.remove(user, token, "scenarioID="+id); + } + onScenariosLoad(data, token){ if (!Array.isArray(data)) { From 0fe5bdcc58b1fc072f29b0b1315f6d2e4c9e94bd Mon Sep 17 00:00:00 2001 From: irismarie Date: Wed, 3 Jun 2020 10:38:43 +0200 Subject: [PATCH 4/6] add/remove user to/from scenario (only admin) --- src/scenario/scenario-store.js | 54 +++++++++++++++++++++++++- src/scenario/scenario.js | 15 ++++--- src/scenario/scenarios-data-manager.js | 42 ++++++++++++++++---- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 1f08ffb..9cfc16b 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -25,14 +25,59 @@ class ScenarioStore extends ArrayStore{ super('scenarios', ScenariosDataManager); } + // calls to VILLASweb backend getUsers(token, id) { ScenariosDataManager.getUsers(token, id); } + addUser(token, id, username) { + ScenariosDataManager.addUser(token, id, username); + } + deleteUser(token, id, username) { ScenariosDataManager.deleteUser(token, id, username); } + /* store functions, called when calls to backend have returned */ + // save users after they are loaded ('getUsers' call) + saveUsers(state, action) { + let scenarioID = action.scenarioID; + state.forEach((element, index, array) => { + if (element.id === scenarioID) { + array[index]["users"] = action.users; + this.__emitChange(); + return state; + } + }) + } + + // save new user after it was added to scenario ('addUser' call) + saveUser(state, action) { + let scenarioID = action.scenarioID; + state.forEach((element, index, array) => { + if (element.id === scenarioID) { + array[index]["users"].push(action.user); + this.__emitChange(); + return state; + } + }) + } + + // remove user from ScenarioStore + removeUser(state, action) { + let scenarioID = action.scenarioID; + state.forEach((element, index, array) => { + if (element.id === scenarioID) { + const userindex = array[index]["users"].indexOf(action.user); + if (index > -1) { + array[index]["users"].splice(userindex, 1); + } + this.__emitChange(); + return state; + } + }) + } + reduce(state, action) { switch (action.type) { @@ -66,7 +111,14 @@ class ScenarioStore extends ArrayStore{ return super.reduce(state, action); } -// case 'scenarios/users/start-load': + case 'scenarios/users': + return this.saveUsers(state, action); + + case 'scenarios/user-added': + return this.saveUser(state, action); + + case 'scenarios/user-deleted': + return this.removeUser(state, action); default: return super.reduce(state, action); diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 2828767..706b0c2 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -56,6 +56,7 @@ class Scenario extends React.Component { // get selected scenario const sessionToken = LoginStore.getState().token; + let users = null; const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10)); if (scenario == null) { AppDispatcher.dispatch({ @@ -64,8 +65,10 @@ class Scenario extends React.Component { token: sessionToken }); } + else { + users = scenario.users; + } - let users = LoginStore.getState().scenarioUsers; let allUsers = UsersStore.getState(); let allUserNames = []; allUsers.forEach((user) => { @@ -114,6 +117,7 @@ class Scenario extends React.Component { addUserModal: false, deleteUserName: '', + deleteUserModal: false, } } @@ -141,11 +145,13 @@ class Scenario extends React.Component { } // add User to Scenario - addUser() { - + addUser(userindex) { + let username = this.state.allUserNames[userindex]; + ScenarioStore.addUser(this.state.sessionToken, this.state.scenario.id, username); } closeDeleteUserModal() { + this.setState({deleteUserModal: false}); ScenarioStore.deleteUser(this.state.sessionToken, this.state.scenario.id, this.state.deleteUserName); } @@ -462,8 +468,7 @@ class Scenario extends React.Component {
this.addUser()} - // style={buttonStyle}> User + onSelect={(index) => this.addUser(index)} > {this.state.allUserNames.map((opt,i) => ( diff --git a/src/scenario/scenarios-data-manager.js b/src/scenario/scenarios-data-manager.js index 9854901..bfa3422 100644 --- a/src/scenario/scenarios-data-manager.js +++ b/src/scenario/scenarios-data-manager.js @@ -24,14 +24,31 @@ class ScenariosDataManager extends RestDataManager { constructor() { super('scenario', '/scenarios'); - this.onLoad = this.onScenariosLoad + this.onLoad = this.onScenariosLoad } getUsers(token, id) { RestAPI.get(this.makeURL('/scenarios/' + id + '/users/'), token).then(response => { AppDispatcher.dispatch({ type: 'scenarios/users', - users: response.users + users: response.users, + scenarioID: id + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'scenarios/users-error', + error: error + }) + }) + } + + addUser(token, id, username) { + let path = id + '/user'; + RestAPI.put(this.requestURL('load/add', path, '?username=' + username), null, token).then(response => { + AppDispatcher.dispatch({ + type: 'scenarios/user-added', + user: response.user, + scenarioID: id }); }).catch(error => { AppDispatcher.dispatch({ @@ -42,19 +59,28 @@ class ScenariosDataManager extends RestDataManager { } deleteUser(token, id, username) { - RestAPI.delete(this.requestURL('remove/update', 'user', 'username='+username), token).then(response => { - + let path = id + '/user'; + RestAPI.delete(this.makeURL(this.url + '/' + path + '?username=' + username), token).then(response => { + AppDispatcher.dispatch({ + type: 'scenarios/user-deleted', + user: response.user, + scenarioID: id + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'scenarios/users-error', + error: error + }) }) - //super.remove(user, token, "scenarioID="+id); } - onScenariosLoad(data, token){ + onScenariosLoad(data, token) { if (!Array.isArray(data)) { data = [data]; } - for (let scenario of data){ + for (let scenario of data) { AppDispatcher.dispatch({ type: 'configs/start-load', token: token, @@ -70,7 +96,7 @@ class ScenariosDataManager extends RestDataManager { AppDispatcher.dispatch({ type: 'files/start-load', token: token, - param: '?scenarioID='+scenario.id, + param: '?scenarioID=' + scenario.id, }); } } From da74f199f721c953dee42ab64e004d293ddaf06d Mon Sep 17 00:00:00 2001 From: irismarie Date: Fri, 19 Jun 2020 15:30:50 +0200 Subject: [PATCH 5/6] input user to add in text field --- src/scenario/scenario-store.js | 11 +-- src/scenario/scenario.js | 131 ++++++++++++++------------------- 2 files changed, 63 insertions(+), 79 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 9cfc16b..92edbdd 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -39,8 +39,9 @@ class ScenarioStore extends ArrayStore{ } /* store functions, called when calls to backend have returned */ + // save users after they are loaded ('getUsers' call) - saveUsers(state, action) { + storeUsers(state, action) { let scenarioID = action.scenarioID; state.forEach((element, index, array) => { if (element.id === scenarioID) { @@ -52,7 +53,7 @@ class ScenarioStore extends ArrayStore{ } // save new user after it was added to scenario ('addUser' call) - saveUser(state, action) { + storeUser(state, action) { let scenarioID = action.scenarioID; state.forEach((element, index, array) => { if (element.id === scenarioID) { @@ -71,8 +72,8 @@ class ScenarioStore extends ArrayStore{ const userindex = array[index]["users"].indexOf(action.user); if (index > -1) { array[index]["users"].splice(userindex, 1); + this.__emitChange(); } - this.__emitChange(); return state; } }) @@ -112,10 +113,10 @@ class ScenarioStore extends ArrayStore{ } case 'scenarios/users': - return this.saveUsers(state, action); + return this.storeUsers(state, action); case 'scenarios/user-added': - return this.saveUser(state, action); + return this.storeUser(state, action); case 'scenarios/user-deleted': return this.removeUser(state, action); diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 706b0c2..4053023 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -17,11 +17,11 @@ import React from 'react'; import { Container } from 'flux/utils'; -import { Button, DropdownButton, Dropdown } from 'react-bootstrap'; +import { Button, InputGroup, FormControl } from 'react-bootstrap'; + import FileSaver from 'file-saver'; import ScenarioStore from './scenario-store'; -//import ScenariosDataManager from './scenarios-data-manager'; import ICStore from '../ic/ic-store'; import DashboardStore from '../dashboard/dashboard-store'; import ConfigStore from '../componentconfig/config-store'; @@ -42,21 +42,18 @@ import EditConfigDialog from "../componentconfig/edit-config"; import EditSignalMapping from "../signal/edit-signal-mapping"; import FileStore from "../file/file-store" import WidgetStore from "../widget/widget-store"; -import UsersStore from '../user/users-store'; class Scenario extends React.Component { static getStores() { - return [ ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore, UsersStore]; + return [ScenarioStore, ConfigStore, DashboardStore, ICStore, LoginStore, SignalStore, FileStore, WidgetStore]; } static calculateState(prevState, props) { // get selected scenario const sessionToken = LoginStore.getState().token; - - let users = null; const scenario = ScenarioStore.getState().find(s => s.id === parseInt(props.match.params.scenario, 10)); if (scenario == null) { AppDispatcher.dispatch({ @@ -65,15 +62,6 @@ class Scenario extends React.Component { token: sessionToken }); } - else { - users = scenario.users; - } - - let allUsers = UsersStore.getState(); - let allUserNames = []; - allUsers.forEach((user) => { - allUserNames.push(user.username); - }); // obtain all dashboards of a scenario let dashboards = DashboardStore.getState().filter(dashb => dashb.scenarioID === parseInt(props.match.params.scenario, 10)); @@ -87,12 +75,8 @@ class Scenario extends React.Component { let signals = SignalStore.getState(); - return { scenario, - users, - allUsers, - allUserNames, sessionToken, configs, dashboards, @@ -115,7 +99,6 @@ class Scenario extends React.Component { importDashboardModal: false, modalDashboardData: {}, - addUserModal: false, deleteUserName: '', deleteUserModal: false, } @@ -136,22 +119,18 @@ class Scenario extends React.Component { type: 'ics/start-load', token: this.state.sessionToken }); - - // load users - AppDispatcher.dispatch({ - type: 'users/start-load', - token: this.state.sessionToken - }); } - // add User to Scenario - addUser(userindex) { - let username = this.state.allUserNames[userindex]; - ScenarioStore.addUser(this.state.sessionToken, this.state.scenario.id, username); + /* ############################################## + * User modification methods + ############################################## */ + + addUser() { + ScenarioStore.addUser(this.state.sessionToken, this.state.scenario.id, this.userToAdd); } closeDeleteUserModal() { - this.setState({deleteUserModal: false}); + this.setState({ deleteUserModal: false }); ScenarioStore.deleteUser(this.state.sessionToken, this.state.scenario.id, this.state.deleteUserName); } @@ -159,7 +138,7 @@ class Scenario extends React.Component { * Component Configuration modification methods ############################################## */ - addConfig(){ + addConfig() { const config = { scenarioID: this.state.scenario.id, name: 'New Component Configuration', @@ -175,8 +154,8 @@ class Scenario extends React.Component { } - closeEditConfigModal(data){ - this.setState({ editConfigModal : false }); + closeEditConfigModal(data) { + this.setState({ editConfigModal: false }); if (data) { AppDispatcher.dispatch({ @@ -201,7 +180,7 @@ class Scenario extends React.Component { }); } - importConfig(data){ + importConfig(data) { this.setState({ importConfigModal: false }); if (data == null) { @@ -303,7 +282,7 @@ class Scenario extends React.Component { getICName(icID) { for (let ic of this.state.ics) { if (ic.id === icID) { - return ic.name || ic.uuid; + return ic.name || ic.uuid; } } } @@ -313,7 +292,7 @@ class Scenario extends React.Component { ############################################## */ closeNewDashboardModal(data) { - this.setState({ newDashboardModal : false }); + this.setState({ newDashboardModal: false }); if (data) { let newDashboard = data; // add default grid value and scenarioID @@ -328,7 +307,7 @@ class Scenario extends React.Component { } } - closeDeleteDashboardModal(confirmDelete){ + closeDeleteDashboardModal(confirmDelete) { this.setState({ deleteDashboardModal: false }); if (confirmDelete === false) { @@ -379,9 +358,9 @@ class Scenario extends React.Component { * Signal modification methods ############################################## */ - closeDeleteSignalModal(data){ + closeDeleteSignalModal(data) { // data contains the signal to be deleted - if (data){ + if (data) { AppDispatcher.dispatch({ type: 'signals/start-remove', @@ -392,7 +371,7 @@ class Scenario extends React.Component { } } - closeNewSignalModal(data){ + closeNewSignalModal(data) { //data contains the new signal incl. configID and direction if (data) { AppDispatcher.dispatch({ @@ -403,17 +382,17 @@ class Scenario extends React.Component { } } - closeEditSignalsModal(data, direction){ + closeEditSignalsModal(data, direction) { - if( direction === "in") { - this.setState({editInputSignalsModal: false}); - } else if( direction === "out"){ - this.setState({editOutputSignalsModal: false}); + if (direction === "in") { + this.setState({ editInputSignalsModal: false }); + } else if (direction === "out") { + this.setState({ editOutputSignalsModal: false }); } else { return; // no valid direction } - if (data){ + if (data) { //data is an array of signals for (let sig of data) { //dispatch changes to signals @@ -431,7 +410,7 @@ class Scenario extends React.Component { * File modification methods ############################################## */ - getFileName(id){ + getFileName(id) { for (let file of this.state.files) { if (file.id === id) { return file.name; @@ -454,38 +433,42 @@ class Scenario extends React.Component { {/*Scenario Users table*/}

Users

-
- - - this.setState({ deleteUserModal: true, deleteUserName: this.state.users[index].username, modalUserIndex: index })} +
+
+ + + this.setState({ deleteUserModal: true, deleteUserName: this.state.scenario.users[index].username, modalUserIndex: index })} /> -
+ -
- this.addUser(index)} - > - {this.state.allUserNames.map((opt,i) => ( - - {opt} - - ))} - + + this.userToAdd = e.target.value} + /> + + + +
this.closeDeleteUserModal(c)} /> + {/*Component Configurations table*/}

Component Configurations

this.onConfigChecked(index, event)} width='30' /> - this.getFileName(selectedFileID)}/> + this.getFileName(selectedFileID)} /> + ]} />
@@ -557,7 +540,7 @@ class Scenario extends React.Component { onDelete={(data) => this.closeDeleteSignalModal(data)} direction="Input" signals={this.state.signals} - configID={this.state.modalConfigData.id}/> + configID={this.state.modalConfigData.id} /> {/*Dashboard table*/}

Dashboards

@@ -581,10 +564,10 @@ class Scenario extends React.Component {
- this.closeNewDashboardModal(data)}/> - this.closeImportDashboardModal(data)} /> + this.closeNewDashboardModal(data)} /> + this.closeImportDashboardModal(data)} /> - this.closeDeleteDashboardModal(e)}/> + this.closeDeleteDashboardModal(e)} />
; From 781f83afd37d76b16a0ddeed78a557a89a4970e0 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 23 Jun 2020 16:43:52 +0200 Subject: [PATCH 6/6] Work on user add/remove from scenarios: use async dispatches instead of function calls; list of users updates now after adding/removing a user, a notification is shown upon error #220 --- src/scenario/scenario-store.js | 76 +++++++++-------------- src/scenario/scenario.js | 85 ++++++++++++++++---------- src/scenario/scenarios-data-manager.js | 18 +++--- src/user/login-store.js | 7 --- 4 files changed, 90 insertions(+), 96 deletions(-) diff --git a/src/scenario/scenario-store.js b/src/scenario/scenario-store.js index 92edbdd..8164229 100644 --- a/src/scenario/scenario-store.js +++ b/src/scenario/scenario-store.js @@ -18,6 +18,7 @@ import ScenariosDataManager from './scenarios-data-manager'; import ArrayStore from '../common/array-store'; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; class ScenarioStore extends ArrayStore{ @@ -25,58 +26,18 @@ class ScenarioStore extends ArrayStore{ super('scenarios', ScenariosDataManager); } - // calls to VILLASweb backend - getUsers(token, id) { - ScenariosDataManager.getUsers(token, id); - } - - addUser(token, id, username) { - ScenariosDataManager.addUser(token, id, username); - } - - deleteUser(token, id, username) { - ScenariosDataManager.deleteUser(token, id, username); - } - - /* store functions, called when calls to backend have returned */ - + // store function, called when calls to backend have returned // save users after they are loaded ('getUsers' call) storeUsers(state, action) { let scenarioID = action.scenarioID; state.forEach((element, index, array) => { if (element.id === scenarioID) { array[index]["users"] = action.users; - this.__emitChange(); - return state; } }) - } + this.__emitChange(); + return state; - // save new user after it was added to scenario ('addUser' call) - storeUser(state, action) { - let scenarioID = action.scenarioID; - state.forEach((element, index, array) => { - if (element.id === scenarioID) { - array[index]["users"].push(action.user); - this.__emitChange(); - return state; - } - }) - } - - // remove user from ScenarioStore - removeUser(state, action) { - let scenarioID = action.scenarioID; - state.forEach((element, index, array) => { - if (element.id === scenarioID) { - const userindex = array[index]["users"].indexOf(action.user); - if (index > -1) { - array[index]["users"].splice(userindex, 1); - this.__emitChange(); - } - return state; - } - }) } reduce(state, action) { @@ -112,14 +73,33 @@ class ScenarioStore extends ArrayStore{ return super.reduce(state, action); } - case 'scenarios/users': + case 'scenarios/start-load-users': + this.dataManager.getUsers(action.token, action.data); + return super.reduce(state, action); + + case 'scenarios/users-loaded': return this.storeUsers(state, action); - case 'scenarios/user-added': - return this.storeUser(state, action); + case 'scenarios/add-user': + this.dataManager.addUser(action.token, action.data, action.username); + return super.reduce(state, action); - case 'scenarios/user-deleted': - return this.removeUser(state, action); + case 'scenarios/remove-user': + this.dataManager.deleteUser(action.token, action.data, action.username) + return super.reduce(state, action); + + case 'scenarios/users-error': + if (action.error && !action.error.handled && action.error.response) { + + const SCENARIO_USERS_ERROR_NOTIFICATION = { + title: 'Failed to modify scenario users ', + message: action.error.response.body.message, + level: 'error' + }; + NotificationsDataManager.addNotification(SCENARIO_USERS_ERROR_NOTIFICATION); + + } + return super.reduce(state, action); default: return super.reduce(state, action); diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 5a51cad..8d3495e 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -108,7 +108,6 @@ class Scenario extends React.Component { } componentDidMount() { - ScenarioStore.getUsers(this.state.sessionToken, this.state.scenario.id); //load selected scenario AppDispatcher.dispatch({ @@ -117,6 +116,13 @@ class Scenario extends React.Component { token: this.state.sessionToken }); + + AppDispatcher.dispatch({ + type: 'scenarios/start-load-users', + data: this.state.scenario.id, + token: this.state.sessionToken + }); + // load ICs to enable that component configs and dashboards work with them AppDispatcher.dispatch({ type: 'ics/start-load', @@ -129,12 +135,23 @@ class Scenario extends React.Component { ############################################## */ addUser() { - ScenarioStore.addUser(this.state.sessionToken, this.state.scenario.id, this.userToAdd); + AppDispatcher.dispatch({ + type: 'scenarios/add-user', + data: this.state.scenario.id, + username: this.userToAdd, + token: this.state.sessionToken + }); } closeDeleteUserModal() { this.setState({ deleteUserModal: false }); - ScenarioStore.deleteUser(this.state.sessionToken, this.state.scenario.id, this.state.deleteUserName); + + AppDispatcher.dispatch({ + type: 'scenarios/remove-user', + data: this.state.scenario.id, + username: this.state.deleteUserName, + token: this.state.sessionToken + }); } /* ############################################## @@ -404,36 +421,6 @@ class Scenario extends React.Component { return

{this.state.scenario.name}

- {/*Scenario Users table*/} -

Users

-
-
- - - this.setState({ deleteUserModal: true, deleteUserName: this.state.scenario.users[index].username, modalUserIndex: index })} - /> -
- - - this.userToAdd = e.target.value} - /> - - - -
-
- - this.closeDeleteUserModal(c)} /> {/*Component Configurations table*/} @@ -544,6 +531,38 @@ class Scenario extends React.Component { this.closeDeleteDashboardModal(e)} /> + {/*Scenario Users table*/} +

Users sharing this scenario

+
+ + + + this.setState({ deleteUserModal: true, deleteUserName: this.state.scenario.users[index].username, modalUserIndex: index })} + /> +
+ + + this.userToAdd = e.target.value} + /> + + + +

+
+ + this.closeDeleteUserModal(c)} /> + +
; } } diff --git a/src/scenario/scenarios-data-manager.js b/src/scenario/scenarios-data-manager.js index bfa3422..bd89f31 100644 --- a/src/scenario/scenarios-data-manager.js +++ b/src/scenario/scenarios-data-manager.js @@ -28,9 +28,9 @@ class ScenariosDataManager extends RestDataManager { } getUsers(token, id) { - RestAPI.get(this.makeURL('/scenarios/' + id + '/users/'), token).then(response => { + RestAPI.get(this.makeURL('/scenarios/' + id + '/users'), token).then(response => { AppDispatcher.dispatch({ - type: 'scenarios/users', + type: 'scenarios/users-loaded', users: response.users, scenarioID: id }); @@ -46,10 +46,11 @@ class ScenariosDataManager extends RestDataManager { let path = id + '/user'; RestAPI.put(this.requestURL('load/add', path, '?username=' + username), null, token).then(response => { AppDispatcher.dispatch({ - type: 'scenarios/user-added', - user: response.user, - scenarioID: id + type: 'scenarios/start-load-users', + data: id, + token: token }); + }).catch(error => { AppDispatcher.dispatch({ type: 'scenarios/users-error', @@ -62,10 +63,11 @@ class ScenariosDataManager extends RestDataManager { let path = id + '/user'; RestAPI.delete(this.makeURL(this.url + '/' + path + '?username=' + username), token).then(response => { AppDispatcher.dispatch({ - type: 'scenarios/user-deleted', - user: response.user, - scenarioID: id + type: 'scenarios/start-load-users', + data: id, + token: token }); + }).catch(error => { AppDispatcher.dispatch({ type: 'scenarios/users-error', diff --git a/src/user/login-store.js b/src/user/login-store.js index c5718db..47e603d 100644 --- a/src/user/login-store.js +++ b/src/user/login-store.js @@ -79,13 +79,6 @@ class LoginStore extends ReduceStore { } return state; - case 'scenarios/users': - state.scenarioUsers = action.users; - return state; - - case 'scenarios/users-error': - return state; - default: return state; }