From 04916aa9d6fb96dea1ea9dfbf47e7b9151a286c6 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Mon, 22 Feb 2021 17:41:28 +0100 Subject: [PATCH 1/5] WIP: rework AMQP commands --- src/ic/ic-action.js | 180 ++++++++++++++++++++++++++++++++++++- src/ic/ic-store.js | 31 ++++++- src/ic/ics-data-manager.js | 69 ++++++++++++-- src/ic/ics.js | 28 +++--- src/scenario/scenario.js | 74 +++------------ 5 files changed, 291 insertions(+), 91 deletions(-) diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index b0333b8..b187c5e 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -17,6 +17,7 @@ import React from 'react'; import { Button, DropdownButton, Dropdown, InputGroup, FormControl } from 'react-bootstrap'; +import AppDispatcher from "../common/app-dispatcher"; class ICAction extends React.Component { constructor(props) { @@ -47,9 +48,178 @@ class ICAction extends React.Component { }; } } + return null } + runAction(action, when) { + + console.log("configs", this.props.configs) + console.log("selectedConfigs", this.props.selectedConfigs) + console.log("ics", this.props.ics) + console.log("selectedICs", this.props.selectedICs) + console.log("action", action) + console.log("when", when) + + if (action.data.action === 'none') { + console.warn("No command selected. Nothing was sent."); + return; + } + + if (!this.props.hasConfigs){ + let newAction = {}; + newAction["action"] = action.data.action + newAction["when"] = when + + for (let index of this.props.selectedICs) { + let ic = this.props.ics[index]; + let icID = ic.id; + + /* VILLAScontroller protocol + see: https://villas.fein-aachen.org/doc/controller-protocol.html + + RESET SHUTDOWN + { + "action": "reset/shutdown/stop/pause/resume" + "when": "1234567" + } + + DELETE + { + "action": "delete" + "parameters":{ + "uuid": "uuid-of-the-manager-for-this-IC" + } + "when": "1234567" + } + + CREATE is not possible within ICAction (see add IC) + */ + + if (newAction.action === "delete"){ + // prepare parameters for delete incl. correct IC id + newAction["parameters"] = {}; + newAction.parameters["uuid"] = ic.id; + icID = ic.manager; // send delete action to manager of IC + } + + AppDispatcher.dispatch({ + type: 'ics/start-action', + icid: ic.id, + action: newAction, + result: null, + token: this.props.token + }); + + } // end for loop over selected ICs + } else { + + /*VILLAScontoller protocol + see: https://villas.fein-aachen.org/doc/controller-protocol.html + * + * STOP PAUSE RESUME + { + "action": "reset/shutdown/stop/pause/resume" + "when": "1234567" + } + * + * START + { + "action": "start" + "when": 1234567 + "parameters": { + Start parameters for this IC as configured in the component config + } + "model": { + "type": "url" + "url": "https://villas.k8s.eonerc.rwth-aachen.de/api/v2/files/{fileID}" where fileID is the model file configured in the component config + "token": "asessiontoken" + } + "results":{ + "type": "url" + "url" : "https://villas.k8s.eonerc.rwth-aachen.de/api/v2/results/{resultID}/file" where resultID is the ID of the result created for this run + "token": "asessiontoken" + } + } + * + * + * */ + + + let newActions = []; + for (let config of this.props.selectedConfigs) { + let newAction = {} + newAction["action"] = action.data.action + newAction["when"] = when + + // get IC for component config + let ic = null; + for (let component of this.props.ics) { + if (component.id === config.icID) { + ic = component; + } + } + + if (ic == null) { + continue; + } + + // the following is not required by the protocol; it is an internal help + newAction["icid"] = ic.id + + if (newAction.action === 'start') { + newAction["parameters"] = config.startParameters; + newAction["model"] = {} + + if (config.fileIDs.length > 0){ + newAction.model["type"] = "url" + newAction.model["token"] = this.props.token + // TODO do not default to the first file of the config + newAction.model["url"] = "/files/" + config.fileIDs[0].toString() + } + + newAction["results"] = {} + newAction.results["type"] = "url" + newAction.results["token"] = this.props.token + newAction.results["url"] = "/results/RESULTID/file" // RESULTID serves as placeholder and is replaced later + + } + + // add the new action + newActions.push(newAction); + console.log("New actions in loop", newAction, newActions) + + } // end for loop over selected configs + + + let newResult = {} + newResult["result"] = {} + if (action.data.action === 'start') { + + let configSnapshots = []; + // create config snapshots in case action is start + for (let config of this.props.selectedConfigs) { + let index = this.props.configs.indexOf(config) + configSnapshots.push(this.props.snapshotConfig(index)); + } + + // create new result for new run + newResult.result["description"] = "Placeholder for description" + newResult.result["scenarioID"] = this.props.selectedConfigs[0].scenarioID + newResult.result["configSnapshots"] = configSnapshots + } + + + console.log("Dispatching actions for configs", newActions, newResult) + AppDispatcher.dispatch({ + type: 'ics/start-action', + action: newActions, + result: newResult, + token: this.props.token + }); + } + } + setAction = id => { // search action for (let action of this.props.actions) { @@ -65,7 +235,13 @@ class ICAction extends React.Component { render() { - let sendCommandDisabled = this.props.runDisabled || this.state.selectedAction == null || this.state.selectedAction.id === "-1" + let sendCommandDisabled = false; + if (!this.props.hasConfigs && this.props.selectedICs.length === 0 || this.state.selectedAction == null || this.state.selectedAction.id === "-1"){ + sendCommandDisabled = true; + } + if (this.props.hasConfigs && this.props.selectedConfigs.length === 0|| this.state.selectedAction == null || this.state.selectedAction.id === "-1"){ + sendCommandDisabled = true; + } let time = this.state.time.getFullYear().pad(4) + '-' + this.state.time.getMonth().pad(2) + '-' + @@ -98,7 +274,7 @@ class ICAction extends React.Component { + onClick={() => this.runAction(this.state.selectedAction, this.state.time)}>Run Select time for synced command execution ; diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index 7cf314a..c6d0810 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -66,16 +66,41 @@ class InfrastructureComponentStore extends ArrayStore { return state; case 'ics/start-action': - if (!Array.isArray(action.data)) - action.data = [ action.data ] + if (!Array.isArray(action.action)) + action.action = [ action.action ] - ICsDataManager.doActions(action.ic, action.data, action.token); + ICsDataManager.doActions(action.icid, action.action, action.token, action.result); return state; case 'ics/action-error': console.log(action.error); return state; + case 'ics/action-result-added': + + for (let a of action.actions){ + let icid = Object.assign({}, a.icid) + + if (a.results !== undefined && a.results != null){ + // adapt URL for newly created result ID + a.results.url = a.results.url.replace("RESULTID", action.data.result.id); + a.results.url = ICsDataManager.makeURL(a.results.url); + a.results.url = window.location.host + a.results.url; + } + if (a.model !== undefined && a.model != null) { + // adapt URL for model file + a.model.url = ICsDataManager.makeURL(a.model.url); + a.model.url = window.location.host + a.model.url; + } + delete a.icid + ICsDataManager.doActions(icid, [a], action.token) + } + return state; + + case 'ics/action-result-add-error': + console.log(action.error); + return state + case 'ics/get-status': ICsDataManager.getStatus(action.url, action.token, action.ic); return super.reduce(state, action); diff --git a/src/ic/ics-data-manager.js b/src/ic/ics-data-manager.js index 02d480f..a6a625d 100644 --- a/src/ic/ics-data-manager.js +++ b/src/ic/ics-data-manager.js @@ -24,24 +24,79 @@ class IcsDataManager extends RestDataManager { super('ic', '/ic'); } - doActions(ic, actions, token = null) { + doActions(icid, actions, token = null, result=null) { for (let action of actions) { if (action.when) // Send timestamp as Unix Timestamp action.when = Math.round(action.when.getTime() / 1000); } - RestAPI.post(this.makeURL(this.url + '/' + ic.id + '/action'), actions, token).then(response => { + if (icid !== undefined && icid != null) { + + console.log("doActions, icid:", icid) + // sending action to a specific IC via IC list + + RestAPI.post(this.makeURL(this.url + '/' + icid + '/action'), actions, token).then(response => { AppDispatcher.dispatch({ - type: 'ics/action-started', - data: response + type: 'ics/action-started', + data: response }); - }).catch(error => { + }).catch(error => { AppDispatcher.dispatch({ - type: 'ics/action-error', + type: 'ics/action-error', + error + }); + }); + } else { + // sending the same action to multiple ICs via scenario controls + + // distinguish between "start" action and any other + + if (actions[0].action !== "start"){ + for (let a of actions){ + console.log("doActions, a.icid:", a.icid) + icid = JSON.parse(JSON.stringify(a.icid)) + delete a.icid + console.log("doActions, icid:", icid) + // sending action to a specific IC via IC list + + RestAPI.post(this.makeURL(this.url + '/' + icid + '/action'), [a], token).then(response => { + AppDispatcher.dispatch({ + type: 'ics/action-started', + data: response + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ics/action-error', + error + }); + }); + + } + } else{ + // for start actions procedure is different + // first a result needs to be created, then the start actions can be sent + + RestAPI.post(this.makeURL( '/results'), result, token).then(response => { + AppDispatcher.dispatch({ + type: 'ics/action-result-added', + data: response, + actions: actions, + token: token, + }); + }).catch(error => { + AppDispatcher.dispatch({ + type: 'ics/action-result-add-error', error + }); }); - }); + + + } + + + + } } getStatus(url,token,ic){ diff --git a/src/ic/ics.js b/src/ic/ics.js index de10aaa..9c1f2db 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -240,18 +240,7 @@ class InfrastructureComponents extends Component { this.setState({ selectedICs: selectedICs }); } - runAction(action, when) { - for (let index of this.state.selectedICs) { - action.when = when; - AppDispatcher.dispatch({ - type: 'ics/start-action', - ic: this.state.ics[index], - data: action.data, - token: this.state.sessionToken, - }); - } - } static isICOutdated(component) { if (!component.stateUpdateAt) @@ -420,19 +409,19 @@ class InfrastructureComponents extends Component { modifier={(stateUpdateAt, component) => this.stateUpdateModifier(stateUpdateAt, component)} /> - {this.state.currentUser.role === "Admin" && editable ? + {this.state.currentUser.role === "Admin" ? !this.isExternalIC(index)} exportButton - deleteButton + deleteButton = {(index) => !this.isExternalIC(index)} onEdit={index => this.setState({editModal: true, modalIC: ics[index], modalIndex: index})} onExport={index => this.exportIC(index)} onDelete={index => this.setState({deleteModal: true, modalIC: ics[index], modalIndex: index})} /> : this.exportIC(index)} /> @@ -496,12 +485,15 @@ class InfrastructureComponents extends Component { {this.state.currentUser.role === "Admin" && this.state.numberOfExternalICs > 0 ?
this.runAction(action, when)} + hasConfigs = {false} + ics={this.state.ics} + selectedICs={this.state.selectedICs} + token={this.state.sessionToken} actions={[ {id: '-1', title: 'Action', data: {action: 'none'}}, {id: '0', title: 'Reset', data: {action: 'reset'}}, {id: '1', title: 'Shutdown', data: {action: 'shutdown'}}, + {id: '2', title: 'Delete', data: {action: 'delete'}} ]} />
diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index 791e79f..cacb2db 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -302,6 +302,7 @@ class Scenario extends React.Component { } copyConfig(index) { + console.log("index", index, "copyConfig: ", this.state.configs[index]) let config = JSON.parse(JSON.stringify(this.state.configs[index])); let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10)))); @@ -394,60 +395,6 @@ class Scenario extends React.Component { } - runAction(action, when) { - if (action.data.action === 'none') { - console.warn("No command selected. Nothing was sent."); - return; - } - - let configs = []; - for (let index of this.state.selectedConfigs) { - // get IC for component config - let ic = null; - for (let component of this.state.ics) { - if (component.id === this.state.configs[index].icID) { - ic = component; - } - } - - if (ic == null) { - continue; - } - - if (action.data.action === 'start') { - configs.push(this.copyConfig(index)); - action.data.parameters = this.state.configs[index].startParameters; - } - - action.data.when = when; - - console.log("Sending action: ", action.data) - - AppDispatcher.dispatch({ - type: 'ics/start-action', - ic: ic, - data: action.data, - token: this.state.sessionToken - }); - } - - if (configs.length !== 0) { //create result (only if command was 'start') - let componentConfigs = {}; - componentConfigs["configs"] = configs; - let data = {}; - data["Description"] = "Run " + this.state.scenario.name; // default description, to be change by user later - data["ResultFileIDs"] = []; - data["scenarioID"] = this.state.scenario.id; - data["ConfigSnapshots"] = JSON.stringify(componentConfigs, null, 2); - AppDispatcher.dispatch({ - type: 'results/start-add', - data, - token: this.state.sessionToken, - }) - } - - }; - getICName(icID) { for (let ic of this.state.ics) { if (ic.id === icID) { @@ -710,7 +657,7 @@ class Scenario extends React.Component { } openResultConfigSnaphots(result) { - if (!result.configSnapshots || result.configSnapshots == "") { + if (result.configSnapshots === null || result.configSnapshots === undefined) { this.setState({ modalResultConfigs: {"configs": []}, modalResultConfigsIndex: result.id, @@ -881,7 +828,8 @@ class Scenario extends React.Component { this.usesExternalIC(index)} + // checkboxDisabled={(index) => this.usesExternalIC(index)} + checkboxDistabled={false} onChecked={(index, event) => this.onConfigChecked(index, event)} width='30' /> @@ -925,11 +873,15 @@ class Scenario extends React.Component { />
- {this.state.ExternalICInUse ? ( + {/*{this.state.ExternalICInUse ? (*/}
this.runAction(action, when)} + hasConfigs={true} + ics={this.state.ics} + configs={this.state.configs} + selectedConfigs = {this.state.selectedConfigs} + snapshotConfig = {(index) => this.copyConfig(index)} + token = {this.state.sessionToken} actions={[ { id: '-1', title: 'Action', data: { action: 'none' } }, { id: '0', title: 'Start', data: { action: 'start' } }, @@ -938,8 +890,8 @@ class Scenario extends React.Component { { id: '3', title: 'Resume', data: { action: 'resume' } } ]} />
- ) : (
) - } + {/*) : (
)*/} + {/*}*/} < div style={{ clear: 'both' }} /> From 035e1defc78f04a9d44ee054f95022c06abfaa52 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 23 Feb 2021 11:38:15 +0100 Subject: [PATCH 2/5] IC actions start, stop, pause, resume working with correct params - start parameters of component config added to start action #285 - auto-creation of result and url for start action working #286 - model defaults to first file of component config for now #286 --- src/ic/ic-action.js | 13 +++---------- src/ic/ic-store.js | 6 ++---- src/ic/ics-data-manager.js | 33 ++++++++++++++++++++------------- src/scenario/scenario.js | 9 ++++----- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index b187c5e..33fe9a8 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -54,13 +54,6 @@ class ICAction extends React.Component { runAction(action, when) { - console.log("configs", this.props.configs) - console.log("selectedConfigs", this.props.selectedConfigs) - console.log("ics", this.props.ics) - console.log("selectedICs", this.props.selectedICs) - console.log("action", action) - console.log("when", when) - if (action.data.action === 'none') { console.warn("No command selected. Nothing was sent."); return; @@ -169,9 +162,10 @@ class ICAction extends React.Component { if (newAction.action === 'start') { newAction["parameters"] = config.startParameters; - newAction["model"] = {} + if (config.fileIDs.length > 0){ + newAction["model"] = {} newAction.model["type"] = "url" newAction.model["token"] = this.props.token // TODO do not default to the first file of the config @@ -187,7 +181,6 @@ class ICAction extends React.Component { // add the new action newActions.push(newAction); - console.log("New actions in loop", newAction, newActions) } // end for loop over selected configs @@ -204,7 +197,7 @@ class ICAction extends React.Component { } // create new result for new run - newResult.result["description"] = "Placeholder for description" + newResult.result["description"] = "Start at " + when; newResult.result["scenarioID"] = this.props.selectedConfigs[0].scenarioID newResult.result["configSnapshots"] = configSnapshots } diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index c6d0810..d2e00de 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -79,7 +79,6 @@ class InfrastructureComponentStore extends ArrayStore { case 'ics/action-result-added': for (let a of action.actions){ - let icid = Object.assign({}, a.icid) if (a.results !== undefined && a.results != null){ // adapt URL for newly created result ID @@ -87,13 +86,12 @@ class InfrastructureComponentStore extends ArrayStore { a.results.url = ICsDataManager.makeURL(a.results.url); a.results.url = window.location.host + a.results.url; } - if (a.model !== undefined && a.model != null) { + if (a.model !== undefined && a.model != null && JSON.stringify(a.model) !== JSON.stringify({})) { // adapt URL for model file a.model.url = ICsDataManager.makeURL(a.model.url); a.model.url = window.location.host + a.model.url; } - delete a.icid - ICsDataManager.doActions(icid, [a], action.token) + ICsDataManager.doActions(a.icid, [a], action.token) } return state; diff --git a/src/ic/ics-data-manager.js b/src/ic/ics-data-manager.js index a6a625d..a2382fc 100644 --- a/src/ic/ics-data-manager.js +++ b/src/ic/ics-data-manager.js @@ -25,15 +25,16 @@ class IcsDataManager extends RestDataManager { } doActions(icid, actions, token = null, result=null) { - for (let action of actions) { - if (action.when) - // Send timestamp as Unix Timestamp - action.when = Math.round(action.when.getTime() / 1000); - } - if (icid !== undefined && icid != null) { - console.log("doActions, icid:", icid) + if (icid !== undefined && icid != null && JSON.stringify(icid) !== JSON.stringify({})) { + + for (let action of actions) { + if (action.when) { + // Send timestamp as Unix Timestamp + action.when = Math.round(action.when.getTime() / 1000); + } + } // sending action to a specific IC via IC list RestAPI.post(this.makeURL(this.url + '/' + icid + '/action'), actions, token).then(response => { @@ -54,13 +55,14 @@ class IcsDataManager extends RestDataManager { if (actions[0].action !== "start"){ for (let a of actions){ - console.log("doActions, a.icid:", a.icid) - icid = JSON.parse(JSON.stringify(a.icid)) - delete a.icid - console.log("doActions, icid:", icid) - // sending action to a specific IC via IC list - RestAPI.post(this.makeURL(this.url + '/' + icid + '/action'), [a], token).then(response => { + // sending action to a specific IC via IC list + if (a.when) { + // Send timestamp as Unix Timestamp + a.when = Math.round(a.when.getTime() / 1000); + } + + RestAPI.post(this.makeURL(this.url + '/' + a.icid + '/action'), [a], token).then(response => { AppDispatcher.dispatch({ type: 'ics/action-started', data: response @@ -84,6 +86,11 @@ class IcsDataManager extends RestDataManager { actions: actions, token: token, }); + + AppDispatcher.dispatch({ + type: "results/added", + data: response.result, + }); }).catch(error => { AppDispatcher.dispatch({ type: 'ics/action-result-add-error', diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index cacb2db..ab65b82 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -302,7 +302,6 @@ class Scenario extends React.Component { } copyConfig(index) { - console.log("index", index, "copyConfig: ", this.state.configs[index]) let config = JSON.parse(JSON.stringify(this.state.configs[index])); let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10)))); @@ -665,7 +664,7 @@ class Scenario extends React.Component { }); } else { this.setState({ - modalResultConfigs: JSON.parse(result.configSnapshots), + modalResultConfigs: result.configSnapshots, modalResultConfigsIndex: result.id, resultConfigsModal: true }); @@ -873,7 +872,7 @@ class Scenario extends React.Component { /> - {/*{this.state.ExternalICInUse ? (*/} + {this.state.ExternalICInUse ? (
- {/*) : (
)*/} - {/*}*/} + ) : (
) + } < div style={{ clear: 'both' }} /> From e4b77b38c1d6826c0ce02637813c077ba8117630 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 23 Feb 2021 11:41:37 +0100 Subject: [PATCH 3/5] re-enable checkbox deactivation if IC is not managed externally (was turned off for testing) --- src/scenario/scenario.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scenario/scenario.js b/src/scenario/scenario.js index ab65b82..1f8dee2 100644 --- a/src/scenario/scenario.js +++ b/src/scenario/scenario.js @@ -827,8 +827,7 @@ class Scenario extends React.Component { this.usesExternalIC(index)} - checkboxDistabled={false} + checkboxDisabled={(index) => this.usesExternalIC(index)} onChecked={(index, event) => this.onConfigChecked(index, event)} width='30' /> From ac944a5beda0529b81745189074a72d52e93851c Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 23 Feb 2021 13:35:24 +0100 Subject: [PATCH 4/5] IC actions for delete, shutdown, reset are working; add notification for actions --- .../data-managers/notifications-factory.js | 8 +++++++ src/ic/ic-action.js | 21 ++++++++++++++++--- src/ic/ic-store.js | 4 ++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/common/data-managers/notifications-factory.js b/src/common/data-managers/notifications-factory.js index ece1e8b..a032db0 100644 --- a/src/common/data-managers/notifications-factory.js +++ b/src/common/data-managers/notifications-factory.js @@ -138,6 +138,14 @@ class NotificationsFactory { }; } + static ACTION_INFO() { + return { + title: 'Action successfully requested', + level: 'info' + }; + } + + } export default NotificationsFactory; diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index 33fe9a8..c2e4455 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -18,6 +18,8 @@ import React from 'react'; import { Button, DropdownButton, Dropdown, InputGroup, FormControl } from 'react-bootstrap'; import AppDispatcher from "../common/app-dispatcher"; +import NotificationsFactory from "../common/data-managers/notifications-factory"; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; class ICAction extends React.Component { constructor(props) { @@ -92,13 +94,26 @@ class ICAction extends React.Component { if (newAction.action === "delete"){ // prepare parameters for delete incl. correct IC id newAction["parameters"] = {}; - newAction.parameters["uuid"] = ic.id; - icID = ic.manager; // send delete action to manager of IC + newAction.parameters["uuid"] = ic.uuid; + // get the ID of the manager IC + let managerIC = null; + for (let i of this.props.ics){ + if (i.uuid === ic.manager){ + managerIC = i; + } + } + if (managerIC == null){ + console.log("DELETE action", newAction); + NotificationsDataManager.addNotification(NotificationsFactory.DELETE_ERROR("Could not find manager IC with UUID " + ic.manager)); + continue; + } + + icID = managerIC.id; // send delete action to manager of IC } AppDispatcher.dispatch({ type: 'ics/start-action', - icid: ic.id, + icid: icID, action: newAction, result: null, token: this.props.token diff --git a/src/ic/ic-store.js b/src/ic/ic-store.js index d2e00de..39b1c8c 100644 --- a/src/ic/ic-store.js +++ b/src/ic/ic-store.js @@ -72,6 +72,10 @@ class InfrastructureComponentStore extends ArrayStore { ICsDataManager.doActions(action.icid, action.action, action.token, action.result); return state; + case 'ics/action-started': + NotificationsDataManager.addNotification(NotificationsFactory.ACTION_INFO()); + return state; + case 'ics/action-error': console.log(action.error); return state; From 939a168ce3e0a72ff50b340746efad3a8682eb25 Mon Sep 17 00:00:00 2001 From: Sonja Happ Date: Tue, 23 Feb 2021 15:57:50 +0100 Subject: [PATCH 5/5] enable create action via add IC button for new externally managed IC --- src/ic/ic-action.js | 1 - src/ic/ics.js | 36 +++++++++++++++++++++++++++++++----- src/ic/new-ic.js | 2 +- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/ic/ic-action.js b/src/ic/ic-action.js index c2e4455..02d3a63 100644 --- a/src/ic/ic-action.js +++ b/src/ic/ic-action.js @@ -103,7 +103,6 @@ class ICAction extends React.Component { } } if (managerIC == null){ - console.log("DELETE action", newAction); NotificationsDataManager.addNotification(NotificationsFactory.DELETE_ERROR("Could not find manager IC with UUID " + ic.manager)); continue; } diff --git a/src/ic/ics.js b/src/ic/ics.js index 9c1f2db..95d224f 100644 --- a/src/ic/ics.js +++ b/src/ic/ics.js @@ -36,6 +36,8 @@ import ICDialog from './ic-dialog'; import ICAction from './ic-action'; import DeleteDialog from '../common/dialogs/delete-dialog'; +import NotificationsDataManager from "../common/data-managers/notifications-data-manager"; +import NotificationsFactory from "../common/data-managers/notifications-factory"; class InfrastructureComponents extends Component { static getStores() { @@ -149,11 +151,35 @@ class InfrastructureComponents extends Component { this.setState({ newModal : false }); if (data) { - AppDispatcher.dispatch({ - type: 'ics/start-add', - data, - token: this.state.sessionToken, - }); + if (!data.managedexternally) { + AppDispatcher.dispatch({ + type: 'ics/start-add', + data, + token: this.state.sessionToken, + }); + } else { + // externally managed IC: dispatch create action to selected manager + let newAction = {}; + newAction["action"] = "create"; + newAction["parameters"] = data; + newAction["when"] = new Date() + + // find the manager IC + let managerIC = this.state.ics.find(ic => ic.uuid === data.manager) + if (managerIC === null || managerIC === undefined){ + NotificationsDataManager.addNotification(NotificationsFactory.ADD_ERROR("Could not find manager IC with UUID " + data.manager)); + return; + } + + AppDispatcher.dispatch({ + type: 'ics/start-action', + icid: managerIC.id, + action: newAction, + result: null, + token: this.state.sessionToken + }); + + } } } diff --git a/src/ic/new-ic.js b/src/ic/new-ic.js index 2e81887..39aeebd 100644 --- a/src/ic/new-ic.js +++ b/src/ic/new-ic.js @@ -170,7 +170,7 @@ class NewICDialog extends React.Component { {this.props.managers.length > 0 ? <> - An externally managed component is created and managed by an IC manager via AMQP} > + An externally managed component is created and managed by an IC manager via AMQP} > this.handleChange(e)}>