mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
merge with master
This commit is contained in:
commit
d6f8213e38
9 changed files with 394 additions and 332 deletions
82
package-lock.json
generated
82
package-lock.json
generated
|
@ -4178,12 +4178,20 @@
|
|||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.1",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fsevents": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"chownr": {
|
||||
|
@ -7883,9 +7891,9 @@
|
|||
"integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ=="
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
||||
"integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg=="
|
||||
"version": "2.8.9",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
|
||||
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
|
||||
},
|
||||
"hpack.js": {
|
||||
"version": "2.1.6",
|
||||
|
@ -10608,9 +10616,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
|
||||
"version": "8.2.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.2.4.tgz",
|
||||
"integrity": "sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -14077,14 +14085,6 @@
|
|||
"react-display-name": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"react-grid-system": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-grid-system/-/react-grid-system-7.1.2.tgz",
|
||||
"integrity": "sha512-5XKVkevZWDITlpivmK8iQcmdfj7cuIzPlcejOmhRK9FGdNsFsRHXO2H7zaKfssJ2CymQXOTvU0ZN8TX9BPBr+g==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-immutable-proptypes": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz",
|
||||
|
@ -14122,39 +14122,6 @@
|
|||
"react-base16-styling": "^0.6.0",
|
||||
"react-lifecycles-compat": "^3.0.4",
|
||||
"react-textarea-autosize": "^8.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"fbemitter": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz",
|
||||
"integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==",
|
||||
"requires": {
|
||||
"fbjs": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fbjs": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.0.tgz",
|
||||
"integrity": "sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==",
|
||||
"requires": {
|
||||
"cross-fetch": "^3.0.4",
|
||||
"fbjs-css-vars": "^1.0.0",
|
||||
"loose-envify": "^1.0.0",
|
||||
"object-assign": "^4.1.0",
|
||||
"promise": "^7.1.1",
|
||||
"setimmediate": "^1.0.5",
|
||||
"ua-parser-js": "^0.7.18"
|
||||
}
|
||||
},
|
||||
"flux": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/flux/-/flux-4.0.1.tgz",
|
||||
"integrity": "sha512-emk4RCvJ8RzNP2lNpphKnG7r18q8elDYNAPx7xn+bDeOIo9FFfxEfIQ2y6YbQNmnsGD3nH1noxtLE64Puz1bRQ==",
|
||||
"requires": {
|
||||
"fbemitter": "^3.0.0",
|
||||
"fbjs": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
|
@ -14403,9 +14370,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
|
||||
"integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==",
|
||||
"version": "7.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.0.tgz",
|
||||
"integrity": "sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
|
@ -16226,11 +16193,6 @@
|
|||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
|
||||
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
|
||||
},
|
||||
"style-loader": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
|
||||
|
@ -16934,11 +16896,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz",
|
||||
|
@ -17872,8 +17829,7 @@
|
|||
},
|
||||
"ssri": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz",
|
||||
"integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==",
|
||||
"resolved": "",
|
||||
"requires": {
|
||||
"figgy-pudding": "^3.5.1"
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
"react-dnd-html5-backend": "^14.0.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-fullscreenable": "^2.5.1-0",
|
||||
"react-grid-system": "^7.1.2",
|
||||
"react-json-view": "^1.21.3",
|
||||
"react-notification-system": "^0.4.0",
|
||||
"react-rnd": "^10.2.4",
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import { Form, Col, Row, Button } from 'react-bootstrap';
|
||||
import _ from 'lodash';
|
||||
import { Form, Col, Row } from 'react-bootstrap';
|
||||
import Dialog from '../common/dialogs/dialog';
|
||||
import ParametersEditor from '../common/parameters-editor';
|
||||
|
||||
|
@ -36,15 +35,15 @@ class EditICDialog extends React.Component {
|
|||
type: '',
|
||||
category: '',
|
||||
managedexternally: false,
|
||||
startParameterSchema: {},
|
||||
properties: {}
|
||||
startparameterschema: {}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
onClose(canceled) {
|
||||
if (canceled === false) {
|
||||
if (this.valid) {
|
||||
let data = this.props.ic;
|
||||
let data = JSON.parse(JSON.stringify(this.props.ic));
|
||||
|
||||
if (this.state.name != null && this.state.name !== "" && this.state.name !== this.props.ic.name) {
|
||||
data.name = this.state.name;
|
||||
|
@ -69,12 +68,8 @@ class EditICDialog extends React.Component {
|
|||
data.category = this.state.category;
|
||||
}
|
||||
|
||||
if (this.state.startParameterSchema !== {}) {
|
||||
data.startParameterSchema = this.state.startParameterSchema;
|
||||
}
|
||||
|
||||
if (this.state.properties !== {}) {
|
||||
data.properties = this.state.properties;
|
||||
if (this.state.startparameterschema !== {}) {
|
||||
data.startparameterschema = this.state.startparameterschema;
|
||||
}
|
||||
|
||||
data.managedexternally = this.state.managedexternally;
|
||||
|
@ -98,11 +93,7 @@ class EditICDialog extends React.Component {
|
|||
}
|
||||
|
||||
handleStartParameterSchemaChange(data) {
|
||||
this.setState({ startParameterSchema: data });
|
||||
}
|
||||
|
||||
handlePropertiesChange(data) {
|
||||
this.setState({ properties: data });
|
||||
this.setState({ startparameterschema: data });
|
||||
}
|
||||
|
||||
resetState() {
|
||||
|
@ -115,8 +106,7 @@ class EditICDialog extends React.Component {
|
|||
description: this.props.ic.description,
|
||||
category: this.props.ic.category,
|
||||
managedexternally: false,
|
||||
startParameterSchema: this.props.ic.startParameterSchema,
|
||||
properties: this.props.ic.properties,
|
||||
startparameterschema: this.props.ic.startparameterschema,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -133,7 +123,7 @@ class EditICDialog extends React.Component {
|
|||
|
||||
reader.onload = event => {
|
||||
const params = JSON.parse(reader.result);
|
||||
this.setState({ startParameterSchema: params})
|
||||
this.setState({ startparameterschema: params})
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -224,19 +214,12 @@ class EditICDialog extends React.Component {
|
|||
</Col>
|
||||
</Row>
|
||||
<ParametersEditor
|
||||
content={this.state.startParameterSchema}
|
||||
disabled={false}
|
||||
content={this.state.startparameterschema}
|
||||
onChange={(data) => this.handleStartParameterSchemaChange(data)}
|
||||
disabled={false}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group controlId='properties'>
|
||||
<Form.Label column={false}>Properties</Form.Label>
|
||||
<ParametersEditor
|
||||
content={this.state.properties}
|
||||
disabled={true}
|
||||
onChange={(data) => this.handlePropertiesChange(data)}
|
||||
/>
|
||||
</Form.Group>
|
||||
|
||||
</Form>
|
||||
</Dialog>
|
||||
);
|
||||
|
|
42
src/ic/ic-pages/default-page.js
Normal file
42
src/ic/ic-pages/default-page.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import {Col, Container, Row} from "react-bootstrap";
|
||||
|
||||
class DefaultICPage extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className='section'>
|
||||
<h1>{this.props.ic.name} </h1>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{this.props.ICParamsTable(this.props.ic)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default DefaultICPage;
|
169
src/ic/ic-pages/gateway-villas-node.js
Normal file
169
src/ic/ic-pages/gateway-villas-node.js
Normal file
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import {Button, Col, Container, Row} from "react-bootstrap";
|
||||
import IconButton from "../../common/icon-button";
|
||||
import ConfirmCommand from "../confirm-command";
|
||||
import FileSaver from 'file-saver';
|
||||
import AppDispatcher from "../../common/app-dispatcher";
|
||||
|
||||
class GatewayVillasNode extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
confirmCommand: false,
|
||||
command: '',
|
||||
}
|
||||
}
|
||||
|
||||
async downloadGraph(url) {
|
||||
let blob = await fetch(url).then(r => r.blob())
|
||||
FileSaver.saveAs(blob, this.props.ic.name + ".svg");
|
||||
}
|
||||
|
||||
sendControlCommand() {
|
||||
if (this.state.command === "restart") {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/restart',
|
||||
url: this.props.ic.apiurl + "/restart",
|
||||
token: this.props.sessionToken,
|
||||
});
|
||||
} else if (this.state.command === "shutdown") {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/shutdown',
|
||||
url: this.props.ic.apiurl + "/shutdown",
|
||||
token: this.props.sessionToken,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
confirmCommand(canceled){
|
||||
if(!canceled){
|
||||
this.sendControlCommand();
|
||||
}
|
||||
|
||||
this.setState({confirmCommand: false, command: ''});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
let graphURL = ""
|
||||
if (this.props.ic.apiurl !== "") {
|
||||
graphURL = this.props.ic.apiurl + "/graph.svg"
|
||||
}
|
||||
|
||||
console.log("Villasnode Gateway: ", this.props.ic)
|
||||
|
||||
return (<div className='section'>
|
||||
|
||||
|
||||
<h1>{this.props.ic.name}
|
||||
<span className='icon-button'>
|
||||
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => this.props.refresh(this.props.ic, this.props.sessionToken)}
|
||||
icon='sync-alt'
|
||||
buttonStyle={this.props.buttonStyle}
|
||||
iconStyle={this.props.iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{this.props.ICParamsTable(this.props.ic)}
|
||||
</Col>
|
||||
<Col>
|
||||
<div className='section-buttons-group-right'>
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip='Download Graph'
|
||||
onClick={() => this.downloadGraph(graphURL)}
|
||||
icon='download'
|
||||
buttonStyle={this.props.buttonStyle}
|
||||
iconStyle={this.props.iconStyle}
|
||||
/>
|
||||
</div>
|
||||
<hr/>
|
||||
<b>Graph:</b>
|
||||
<div>
|
||||
<img alt={"Graph image download failed and/or incorrect image API URL"} src={graphURL} />
|
||||
</div>
|
||||
|
||||
{this.props.currentUser.role === "Admin" ?
|
||||
<div>
|
||||
<hr/>
|
||||
<b>Controls:</b>
|
||||
<div className='solid-button'>
|
||||
<Button
|
||||
variant='secondary'
|
||||
style={{ margin: '5px' }}
|
||||
size='lg'
|
||||
onClick={() => this.setState({ confirmCommand: true, command: 'restart' })}>
|
||||
Restart
|
||||
</Button>
|
||||
<Button
|
||||
variant='secondary'
|
||||
style={{ margin: '5px' }}
|
||||
size='lg'
|
||||
onClick={() => this.setState({ confirmCommand: true, command: 'shutdown' })}>
|
||||
Shutdown
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
: <div />
|
||||
}
|
||||
<ConfirmCommand
|
||||
show={this.state.confirmCommand}
|
||||
command={this.state.command}
|
||||
name={this.props.ic.name}
|
||||
onClose={c => this.confirmCommand(c)}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<b>Raw Status</b>
|
||||
{this.props.rawDataTable(this.props.ic.statusupdateraw)}
|
||||
</Col>
|
||||
<Col>
|
||||
<b>Raw Config</b>
|
||||
{this.props.rawDataTable(this.props.ic.statusupdateraw != null ? this.props.ic.statusupdateraw.config : null )}
|
||||
</Col>
|
||||
<Col>
|
||||
<b>Raw Statistics</b>
|
||||
{this.props.rawDataTable(this.props.ic.statusupdateraw != null ? this.props.ic.statusupdateraw.statistics : null)}
|
||||
</Col>
|
||||
<Col>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GatewayVillasNode;
|
62
src/ic/ic-pages/manager-villas-relay.js
Normal file
62
src/ic/ic-pages/manager-villas-relay.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* This file is part of VILLASweb.
|
||||
*
|
||||
* VILLASweb is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* VILLASweb is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import IconButton from "../../common/icon-button";
|
||||
import {Col, Container, Row} from "react-bootstrap";
|
||||
|
||||
class ManagerVillasRelay extends React.Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className='section'>
|
||||
|
||||
<h1>{this.props.ic.name}
|
||||
<span className='icon-button'>
|
||||
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => this.props.refresh(this.props.ic, this.props.sessionToken)}
|
||||
icon='sync-alt'
|
||||
buttonStyle={this.props.buttonStyle}
|
||||
iconStyle={this.props.iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{this.props.ICParamsTable(this.props.ic)}
|
||||
</Col>
|
||||
<Col>
|
||||
<b>Raw Status</b>
|
||||
{this.props.rawDataTable(this.props.ic.statusupdateraw)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ManagerVillasRelay;
|
321
src/ic/ic.js
321
src/ic/ic.js
|
@ -20,22 +20,18 @@ import ICstore from './ic-store';
|
|||
import ICdataStore from './ic-data-store'
|
||||
import { Container as FluxContainer } from 'flux/utils';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import { Container, Col, Row, Table, Button } from 'react-bootstrap';
|
||||
import { Table, } from 'react-bootstrap';
|
||||
import moment from 'moment';
|
||||
import ReactJson from 'react-json-view';
|
||||
import ConfirmCommand from './confirm-command';
|
||||
import IconButton from '../common/icon-button';
|
||||
import FileSaver from 'file-saver';
|
||||
|
||||
|
||||
import GatewayVillasNode from './ic-pages/gateway-villas-node'
|
||||
import ManagerVillasRelay from './ic-pages/manager-villas-relay'
|
||||
import DefaultICPage from './ic-pages/default-page'
|
||||
|
||||
class InfrastructureComponent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
confirmCommand: false,
|
||||
command: '',
|
||||
sessionToken: localStorage.getItem("token"),
|
||||
currentUser: JSON.parse(localStorage.getItem("currentUser")),
|
||||
};
|
||||
|
@ -61,21 +57,19 @@ class InfrastructureComponent extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
refresh() {
|
||||
static refresh(ic, token) {
|
||||
// get status of VILLASnode and VILLASrelay ICs
|
||||
if (this.state.ic.category === "gateway" && (this.state.ic.type === "villas-node" || this.state.ic.type === "villas-relay")
|
||||
&& this.state.ic.apiurl !== '' && this.state.ic.apiurl !== undefined && this.state.ic.apiurl !== null && !this.state.ic.managedexternally) {
|
||||
if (ic.apiurl !== '' && ic.apiurl !== undefined && ic.apiurl !== null && !ic.managedexternally) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/get-status',
|
||||
url: this.state.ic.apiurl,
|
||||
token: this.state.sessionToken,
|
||||
ic: this.state.ic
|
||||
url: ic.apiurl,
|
||||
token: token,
|
||||
ic: ic
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isJSON(data) {
|
||||
static isJSON(data) {
|
||||
if (data === undefined || data === null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -89,46 +83,61 @@ class InfrastructureComponent extends React.Component {
|
|||
return true
|
||||
}
|
||||
|
||||
async downloadGraph(url) {
|
||||
let blob = await fetch(url).then(r => r.blob())
|
||||
FileSaver.saveAs(blob, this.state.ic.name + ".svg");
|
||||
}
|
||||
|
||||
sendControlCommand() {
|
||||
if (this.state.command === "restart") {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/restart',
|
||||
url: this.state.ic.apiurl + "/restart",
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
} else if (this.state.command === "shutdown") {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'ics/shutdown',
|
||||
url: this.state.ic.apiurl + "/shutdown",
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
static rawDataTable(rawData){
|
||||
if(rawData !== null && InfrastructureComponent.isJSON(rawData)){
|
||||
return (
|
||||
<ReactJson
|
||||
src={rawData}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div>No valid JSON raw data available.</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
confirmCommand(canceled){
|
||||
if(!canceled){
|
||||
this.sendControlCommand();
|
||||
}
|
||||
|
||||
this.setState({confirmCommand: false, command: ''});
|
||||
static ICParamsTable(ic) {
|
||||
return (
|
||||
<Table striped size="sm">
|
||||
<tbody>
|
||||
<tr><td>Name</td><td>{ic.name}</td></tr>
|
||||
<tr><td>Description</td><td>{ic.description}</td></tr>
|
||||
<tr><td>UUID</td><td>{ic.uuid}</td></tr>
|
||||
<tr><td>State</td><td>{ic.state}</td></tr>
|
||||
<tr><td>Category</td><td>{ic.category}</td></tr>
|
||||
<tr><td>Type</td><td>{ic.type}</td></tr>
|
||||
<tr><td>Uptime</td><td>{moment.duration(ic.uptime, "seconds").humanize()}</td></tr>
|
||||
<tr><td>Location</td><td>{ic.location}</td></tr>
|
||||
<tr><td>Websocket URL</td><td>{ic.websocketurl}</td></tr>
|
||||
<tr><td>API URL</td><td>{ic.apiurl}</td></tr>
|
||||
<tr><td>Start parameter schema</td><td>
|
||||
{InfrastructureComponent.isJSON(ic.startparameterschema) ?
|
||||
<ReactJson
|
||||
src={ic.startparameterschema}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={0}
|
||||
/> : <div>No Start parameter schema JSON available.</div>}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
if (this.state.ic === undefined) {
|
||||
return <h1>Loading Infrastructure Component...</h1>;
|
||||
}
|
||||
|
||||
let graphURL = ""
|
||||
if (this.state.ic.apiurl !== "") {
|
||||
graphURL = this.state.ic.apiurl + "/graph.svg"
|
||||
}
|
||||
|
||||
const buttonStyle = {
|
||||
marginLeft: '5px',
|
||||
}
|
||||
|
@ -138,196 +147,36 @@ class InfrastructureComponent extends React.Component {
|
|||
width: '25px'
|
||||
}
|
||||
|
||||
return <div className='section'>
|
||||
<h1>{this.state.ic.name}</h1>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<Table striped size="sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>{this.state.ic.name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td>{this.state.ic.description}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UUID</td>
|
||||
<td>{this.state.ic.uuid}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>State</td>
|
||||
<td>{this.state.ic.state}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Category</td>
|
||||
<td>{this.state.ic.category}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Type</td>
|
||||
<td>{this.state.ic.type}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uptime</td>
|
||||
<td>{moment.duration(this.state.ic.uptime, "seconds").humanize()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Location</td>
|
||||
<td>{this.state.ic.location}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Websocket URL</td>
|
||||
<td>{this.state.ic.websocketurl}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>API URL</td>
|
||||
<td>{this.state.ic.apiurl}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start parameter schema</td>
|
||||
<td>
|
||||
{this.isJSON(this.state.ic.startparameterschema) ?
|
||||
<ReactJson
|
||||
src={this.state.ic.startparameterschema}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={0}
|
||||
/> : <div>No Start parameter schema JSON available.</div>}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</Table>
|
||||
</Col>
|
||||
<Col>
|
||||
{this.state.category ==="gateway" && this.state.ic.type === "villas-node" ?
|
||||
<>
|
||||
<div className='section-buttons-group-right'>
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip='Download Graph'
|
||||
onClick={() => this.downloadGraph(graphURL)}
|
||||
icon='download'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</div>
|
||||
<hr/>
|
||||
<b>Graph:</b>
|
||||
<div>
|
||||
<img alt={"Graph image download failed and/or incorrect image API URL"} src={graphURL} />
|
||||
</div>
|
||||
|
||||
{this.state.currentUser.role === "Admin" ?
|
||||
<div>
|
||||
<hr/>
|
||||
<b>Controls:</b>
|
||||
<div className='solid-button'>
|
||||
<Button variant='secondary' style={{ margin: '5px' }} size='lg'
|
||||
onClick={() => this.setState({ confirmCommand: true, command: 'restart' })}>Restart</Button>
|
||||
<Button variant='secondary' style={{ margin: '5px' }} size='lg' onClick={() => this.setState({
|
||||
confirmCommand: true,
|
||||
command: 'shutdown'
|
||||
})}>Shutdown</Button>
|
||||
</div>
|
||||
</div>
|
||||
: <div />
|
||||
}
|
||||
<ConfirmCommand
|
||||
show={this.state.confirmCommand}
|
||||
command={this.state.command}
|
||||
name={this.state.ic.name}
|
||||
onClose={c => this.confirmCommand(c)}
|
||||
/>
|
||||
</>
|
||||
: <div />}
|
||||
|
||||
{this.state.category ==="gateway" && this.state.ic.type === "villas-relay" ?
|
||||
<>
|
||||
<div className='section-buttons-group-right'>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Refresh'
|
||||
onClick={() => this.refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</div>
|
||||
<hr/>
|
||||
<b>Raw Status</b>
|
||||
{this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ?
|
||||
<ReactJson
|
||||
src={this.state.ic.statusupdateraw}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/> : <div>No valid JSON raw data available.</div>}
|
||||
</>
|
||||
:
|
||||
<div />}
|
||||
</Col>
|
||||
</Row>
|
||||
{this.state.category ==="gateway" && this.state.ic.type === "villas-node" ?
|
||||
<>
|
||||
<div className='section-buttons-group-right'>
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => this.refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</div>
|
||||
<Row>
|
||||
|
||||
<Col>
|
||||
<b>Raw Status</b>
|
||||
{this.state.ic.statusupdateraw !== null && this.isJSON(this.state.ic.statusupdateraw) ?
|
||||
<ReactJson
|
||||
src={this.state.ic.statusupdateraw}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/> : <div>No valid JSON raw data available.</div>}
|
||||
</Col>
|
||||
<Col>
|
||||
<b>Raw Config</b>
|
||||
{this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["config"]) ?
|
||||
<ReactJson
|
||||
src={this.state.ic.statusupdateraw["config"]}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/> : <div>No valid config JSON raw data available.</div>}
|
||||
</Col>
|
||||
<Col>
|
||||
<b>Raw Statistics</b>
|
||||
{this.state.ic.statusupdateraw && this.isJSON(this.state.ic.statusupdateraw["statistics"]) ?
|
||||
<ReactJson
|
||||
src={this.state.ic.statusupdateraw["statistics"]}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/> : <div>No valid statistics JSON raw data available.</div>}
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
</>: <div />}
|
||||
</Container>
|
||||
</div>;
|
||||
let page = <>IC page not defined</>
|
||||
if (this.state.ic.category ==="gateway" && this.state.ic.type === "villas-node") {
|
||||
page = <GatewayVillasNode
|
||||
ic = {this.state.ic}
|
||||
currentUser = {this.state.currentUser}
|
||||
sessionToken = {this.state.sessionToken}
|
||||
ICParamsTable = {(ic) => InfrastructureComponent.ICParamsTable(ic)}
|
||||
rawDataTable = {(rawData) => InfrastructureComponent.rawDataTable(rawData)}
|
||||
refresh = {(ic, token) => InfrastructureComponent.refresh(ic, token)}
|
||||
buttonStyle = {buttonStyle}
|
||||
iconStyle = {iconStyle}
|
||||
/>
|
||||
} else if (this.state.ic.category ==="manager" && this.state.ic.type === "villas-relay") {
|
||||
page = <ManagerVillasRelay
|
||||
ic = {this.state.ic}
|
||||
currentUser = {this.state.currentUser}
|
||||
sessionToken = {this.state.sessionToken}
|
||||
ICParamsTable = {(ic) => InfrastructureComponent.ICParamsTable(ic)}
|
||||
rawDataTable = {(rawData) => InfrastructureComponent.rawDataTable(rawData)}
|
||||
refresh = {(ic, token) => InfrastructureComponent.refresh(ic, token)}
|
||||
buttonStyle = {buttonStyle}
|
||||
iconStyle = {iconStyle}
|
||||
/>
|
||||
} else {
|
||||
page = <DefaultICPage
|
||||
ic = {this.state.ic}
|
||||
ICParamsTable = {(ic) => InfrastructureComponent.ICParamsTable(ic)}
|
||||
/>
|
||||
}
|
||||
return page
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ class InfrastructureComponents extends Component {
|
|||
refresh() {
|
||||
if (this.state.editModal || this.state.deleteModal || this.state.icModal){
|
||||
// do nothing since a dialog is open at the moment
|
||||
return
|
||||
}
|
||||
else {
|
||||
AppDispatcher.dispatch({
|
||||
|
|
|
@ -22,10 +22,11 @@ import AppDispatcher from '../common/app-dispatcher';
|
|||
import ScenarioStore from './scenario-store';
|
||||
import DashboardStore from '../dashboard/dashboard-store';
|
||||
import WidgetStore from "../widget/widget-store";
|
||||
import ConfigStore from '../componentconfig/config-store';
|
||||
import ComponentConfigStore from '../componentconfig/config-store';
|
||||
import SignalStore from '../signal/signal-store'
|
||||
import ResultStore from '../result/result-store'
|
||||
import FileStore from '../file/file-store'
|
||||
import LoginStore from '../user/login-store'
|
||||
import Table from '../common/table';
|
||||
import TableColumn from '../common/table-column';
|
||||
import NewScenarioDialog from './new-scenario';
|
||||
|
@ -38,7 +39,7 @@ import IconButton from '../common/icon-button';
|
|||
class Scenarios extends Component {
|
||||
|
||||
static getStores() {
|
||||
return [ScenarioStore, DashboardStore, WidgetStore, ConfigStore, SignalStore, ResultStore, FileStore];
|
||||
return [ScenarioStore, DashboardStore, WidgetStore, ComponentConfigStore, SignalStore, ResultStore, FileStore,LoginStore];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -49,7 +50,7 @@ class Scenarios extends Component {
|
|||
return {
|
||||
scenarios: ScenarioStore.getState(),
|
||||
dashboards: DashboardStore.getState(),
|
||||
configs: ConfigStore.getState(),
|
||||
configs: ComponentConfigStore.getState(),
|
||||
sessionToken: localStorage.getItem("token"),
|
||||
|
||||
newModal: false,
|
||||
|
|
Loading…
Add table
Reference in a new issue