mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Added redux slice for infrastructure page. Changed its components into functional components. Moved some common components and functions into /common and /utils accordingly
Signed-off-by: Andrii Podriez <andrey5577990@gmail.com>
This commit is contained in:
parent
45bac93f1d
commit
d46155a0db
23 changed files with 1619 additions and 16 deletions
19
src/app.js
19
src/app.js
|
@ -29,21 +29,20 @@ import Home from './common/home';
|
|||
import Header from './common/header';
|
||||
import Menu from './common/menu';
|
||||
|
||||
import InfrastructureComponents from './ic/ics';
|
||||
import InfrastructureComponent from './ic/ic';
|
||||
import InfrastructureComponent from './pages/infrastructure/ic';
|
||||
import Dashboard from './dashboard/dashboard';
|
||||
import Scenarios from './scenario/scenarios';
|
||||
import Scenario from './scenario/scenario';
|
||||
import Users from './user/users';
|
||||
import User from './user/user';
|
||||
import APIBrowser from './common/api-browser';
|
||||
import LoginStore from './user/login-store'
|
||||
|
||||
|
||||
import './styles/app.css';
|
||||
import './styles/login.css';
|
||||
import branding from './branding/branding';
|
||||
|
||||
|
||||
import Infrastructure from './pages/infrastructure/infrastructure'
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
|
@ -53,10 +52,6 @@ class App extends React.Component {
|
|||
this.state = {}
|
||||
}
|
||||
|
||||
static getStores() {
|
||||
return [LoginStore]
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
NotificationsDataManager.setSystem(this.refs.notificationSystem);
|
||||
|
||||
|
@ -126,8 +121,12 @@ class App extends React.Component {
|
|||
</>
|
||||
: '' }
|
||||
{ currentUser.role === "Admin" || pages.infrastructure ? <>
|
||||
<Route exact path="/infrastructure" component={InfrastructureComponents} />
|
||||
<Route path="/infrastructure/:ic" component={InfrastructureComponent} />
|
||||
<Route exact path="/infrastructure">
|
||||
<Infrastructure />
|
||||
</Route>
|
||||
<Route path="/infrastructure/:ic">
|
||||
<InfrastructureComponent />
|
||||
</Route>
|
||||
</>
|
||||
: '' }
|
||||
{ pages.account ? <Route path="/account" component={User} /> : '' }
|
||||
|
|
48
src/common/confirm-command.js
Normal file
48
src/common/confirm-command.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* 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, Modal} from 'react-bootstrap';
|
||||
|
||||
class ConfirmCommand extends React.Component {
|
||||
onModalKeyPress = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
|
||||
this.props.onClose(false);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Modal keyboard show={this.props.show} onHide={() => this.props.onClose(false)} onKeyPress={this.onModalKeyPress}>
|
||||
<Modal.Header>
|
||||
<Modal.Title>Confirm {this.props.command}</Modal.Title>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
Are you sure you want to {this.props.command} <strong>'{this.props.name}'</strong>?
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button onClick={() => this.props.onClose(true)}>Cancel</Button>
|
||||
<Button onClick={() => this.props.onClose(false)}>Confirm</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>;
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfirmCommand;
|
23
src/common/rawDataTable.js
Normal file
23
src/common/rawDataTable.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import { isJSON } from "../utils/isJson";
|
||||
import ReactJson from "react-json-view";
|
||||
|
||||
const RawDataTable = (props) => {
|
||||
if(props.rawData !== null && isJSON(props.rawData)){
|
||||
return (
|
||||
<ReactJson
|
||||
src={props.rawData}
|
||||
name={false}
|
||||
displayDataTypes={false}
|
||||
displayObjectSize={false}
|
||||
enableClipboard={false}
|
||||
collapsed={1}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div>No valid JSON raw data available.</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default RawDataTable;
|
20
src/localStorage.js
Normal file
20
src/localStorage.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* 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/>.
|
||||
******************************************************************************/
|
||||
|
||||
//authentication
|
||||
export const sessionToken = localStorage.getItem("token");
|
||||
export const currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
225
src/pages/infrastructure/ic-category-table.js
Normal file
225
src/pages/infrastructure/ic-category-table.js
Normal file
|
@ -0,0 +1,225 @@
|
|||
/**
|
||||
* 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 { useSelector, useDispatch } from "react-redux";
|
||||
|
||||
import {Table, ButtonColumn, CheckboxColumn, DataColumn, LabelColumn, LinkColumn } from '../../common/table';
|
||||
import { Badge } from 'react-bootstrap';
|
||||
import FileSaver from 'file-saver';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment'
|
||||
import IconToggleButton from "../../common/buttons/icon-toggle-button";
|
||||
|
||||
import { checkICsByCategory } from "../../store/icSlice";
|
||||
import { useState } from "react";
|
||||
|
||||
import { stateLabelStyle } from "./styles";
|
||||
|
||||
//a Table of IC components of specific category from props.category
|
||||
//titled with props.title
|
||||
const ICCategoryTable = (props) => {
|
||||
|
||||
const ics = useSelector(state => state.infrastructure.ICsArray);
|
||||
|
||||
let currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
||||
|
||||
const checkedICs = useSelector(state => state.infrastructure.checkedICsArray);
|
||||
|
||||
const [isGenericDisplayed, setIsGenericDisplayed] = useState(false)
|
||||
|
||||
const exportIC = (index) => {
|
||||
// filter properties
|
||||
let ic = Object.assign({}, ics[index]);
|
||||
delete ic.id;
|
||||
|
||||
// show save dialog
|
||||
const blob = new Blob([JSON.stringify(ic, null, 2)], { type: 'application/json' });
|
||||
FileSaver.saveAs(blob, 'ic-' + (_.get(ic, 'name') || 'undefined') + '.json');
|
||||
}
|
||||
|
||||
const modifyUptimeColumn = (uptime, component) => {
|
||||
if (uptime >= 0) {
|
||||
let momentDurationFormatSetup = require("moment-duration-format");
|
||||
momentDurationFormatSetup(moment)
|
||||
|
||||
let timeString = moment.duration(uptime, "seconds").humanize();
|
||||
return <span>{timeString}</span>
|
||||
}
|
||||
else {
|
||||
return <Badge bg="secondary">unknown</Badge>
|
||||
}
|
||||
}
|
||||
|
||||
const stateUpdateModifier = (updatedAt, component) => {
|
||||
let dateFormat = 'ddd, DD MMM YYYY HH:mm:ss ZZ';
|
||||
let dateTime = moment(updatedAt, dateFormat);
|
||||
return dateTime.fromNow()
|
||||
}
|
||||
|
||||
const statePrio = (state) => {
|
||||
switch (state) {
|
||||
case 'running':
|
||||
case 'starting':
|
||||
return 1;
|
||||
case 'paused':
|
||||
case 'pausing':
|
||||
case 'resuming':
|
||||
return 2;
|
||||
case 'idle':
|
||||
return 3;
|
||||
case 'shutdown':
|
||||
return 4;
|
||||
case 'error':
|
||||
return 10;
|
||||
default:
|
||||
return 99;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//if category of the table is manager we need to filter the generic-typed ics
|
||||
//according to the state of IconToggleButton
|
||||
let tableData = [];
|
||||
|
||||
if(props.category == "manager"){
|
||||
tableData = ics.filter(ic=> (ic.category == props.category) && (isGenericDisplayed ** (ic.type == "generic")))
|
||||
}else{
|
||||
tableData = ics.filter(ic=> ic.category == props.category)
|
||||
}
|
||||
|
||||
tableData.sort((a, b) => {
|
||||
if (a.state !== b.state) {
|
||||
return statePrio(a.state) > statePrio(b.state);
|
||||
}
|
||||
else if (a.name !== b.name) {
|
||||
return a.name < b.name;
|
||||
}
|
||||
else {
|
||||
return a.stateUpdatedAt < b.stateUpdatedAt;
|
||||
}
|
||||
})
|
||||
|
||||
const isLocalIC = (index, ics) => {
|
||||
let ic = ics[index]
|
||||
return !ic.managedexternally
|
||||
}
|
||||
|
||||
const checkAllICs = (ics, title) => {
|
||||
//TODO
|
||||
}
|
||||
|
||||
const isICchecked = (ic) => {
|
||||
//TODO
|
||||
return false
|
||||
}
|
||||
|
||||
const areAllChecked = (title) => {
|
||||
//TODO
|
||||
return false
|
||||
}
|
||||
|
||||
const onICChecked = (ic, event) => {
|
||||
//TODO
|
||||
}
|
||||
|
||||
return (<div>
|
||||
<h2>
|
||||
{props.title}
|
||||
{ props.category == "manager" ?
|
||||
<span className='icon-button'>
|
||||
<IconToggleButton
|
||||
childKey={0}
|
||||
index={1}
|
||||
onChange={() => setIsGenericDisplayed(!isGenericDisplayed)}
|
||||
checked={isGenericDisplayed}
|
||||
checkedIcon='eye'
|
||||
uncheckedIcon='eye-slash'
|
||||
tooltipChecked='click to hide generic managers'
|
||||
tooltipUnchecked='click to show generic managers'
|
||||
/>
|
||||
</span>:<></>
|
||||
}
|
||||
</h2>
|
||||
<Table data={tableData}>
|
||||
<CheckboxColumn
|
||||
enableCheckAll
|
||||
onCheckAll={() => checkAllICs(ics, props.title)}
|
||||
allChecked={areAllChecked(props.title)}
|
||||
checkboxDisabled={(index) => isLocalIC(index, ics) === true}
|
||||
checked={(ic) => isICchecked(ic)}
|
||||
onChecked={(ic, event) => onICChecked(ic, event)}
|
||||
width='30'
|
||||
/>
|
||||
{currentUser.role === "Admin" ?
|
||||
<DataColumn
|
||||
title='ID'
|
||||
dataKey='id'
|
||||
/>
|
||||
: <></>
|
||||
}
|
||||
<LinkColumn
|
||||
title='Name'
|
||||
dataKeys={['name']}
|
||||
link='/infrastructure/'
|
||||
linkKey='id'
|
||||
/>
|
||||
<LabelColumn
|
||||
title='State'
|
||||
labelKey='state'
|
||||
labelStyle={(state, component) => stateLabelStyle(state, component)}
|
||||
/>
|
||||
<DataColumn
|
||||
title='Type'
|
||||
dataKeys={['type']}
|
||||
/>
|
||||
<DataColumn
|
||||
title='Uptime'
|
||||
dataKey='uptime'
|
||||
modifier={(uptime, component) => modifyUptimeColumn(uptime, component)}
|
||||
/>
|
||||
<DataColumn
|
||||
title='Last Update'
|
||||
dataKey='stateUpdateAt'
|
||||
modifier={(uptime, component) => stateUpdateModifier(uptime, component)}
|
||||
/>
|
||||
|
||||
{currentUser.role === "Admin" ?
|
||||
<ButtonColumn
|
||||
width='150'
|
||||
align='right'
|
||||
editButton
|
||||
showEditButton ={(index) => isLocalIC(index, ics)}
|
||||
exportButton
|
||||
deleteButton
|
||||
showDeleteButton = {null}
|
||||
onEdit={index => {}}
|
||||
onExport={index => exportIC(index)}
|
||||
onDelete={index => {}}
|
||||
/>
|
||||
:
|
||||
<ButtonColumn
|
||||
width='50'
|
||||
exportButton
|
||||
onExport={(index) => exportIC(index)}
|
||||
/>
|
||||
}
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ICCategoryTable;
|
75
src/pages/infrastructure/ic-pages/default-ic-page.js
Normal file
75
src/pages/infrastructure/ic-pages/default-ic-page.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import {Col, Row} from "react-bootstrap";
|
||||
import IconButton from '../../../common/buttons/icon-button';
|
||||
import ManagedICsTable from "./managed-ics-table";
|
||||
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { loadICbyId } from '../../../store/icSlice';
|
||||
import { sessionToken, currentUser } from '../../../localStorage';
|
||||
import { loadConfig } from '../../../store/configSlice';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {refresh, rawDataTable} from "../ic"
|
||||
|
||||
import ICParamsTable from '../ic-params-table';
|
||||
import RawDataTable from '../../../common/rawDataTable';
|
||||
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
|
||||
const DefaultICPage = (props) => {
|
||||
const ic = props.ic;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const refresh = () => {
|
||||
dispatch(loadICbyId({token: sessionToken, id: ic.id}));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
}, []);
|
||||
|
||||
return (<div className='section'>
|
||||
<h1>{ic.name}
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Refresh'
|
||||
onClick={() => refresh(ic, sessionToken)}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default DefaultICPage;
|
88
src/pages/infrastructure/ic-pages/default-manager-page.js
Normal file
88
src/pages/infrastructure/ic-pages/default-manager-page.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* 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, { useEffect, useState } from 'react';
|
||||
import {Col, Row} from "react-bootstrap";
|
||||
import IconButton from '../../../common/buttons/icon-button';
|
||||
import ManagedICsTable from "./managed-ics-table";
|
||||
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { loadICbyId } from '../../../store/icSlice';
|
||||
import { sessionToken, currentUser } from '../../../localStorage';
|
||||
import { loadConfig } from '../../../store/configSlice';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {refresh, rawDataTable} from "../ic"
|
||||
|
||||
import ICParamsTable from '../ic-params-table';
|
||||
import RawDataTable from '../../../common/rawDataTable';
|
||||
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
|
||||
const DefaultManagerPage = (props) => {
|
||||
const ic = props.ic;
|
||||
|
||||
const ics = useSelector((state) => state.infrastructure.ICsArray);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const managedICs = ics.filter(managedIC => managedIC.category !== "manager" && managedIC.manager === ic.uuid);
|
||||
const [jobName, setJobName] = useState(null);
|
||||
|
||||
const refresh = () => {
|
||||
dispatch(loadICbyId({token: sessionToken, id: ic.id}));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
}, []);
|
||||
|
||||
return (<div className='section'>
|
||||
<h1>{props.ic.name}
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<ManagedICsTable
|
||||
managedICs={managedICs}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<hr />
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>)
|
||||
|
||||
}
|
||||
|
||||
export default DefaultManagerPage;
|
120
src/pages/infrastructure/ic-pages/gateway-villas-node.js
Normal file
120
src/pages/infrastructure/ic-pages/gateway-villas-node.js
Normal file
|
@ -0,0 +1,120 @@
|
|||
import { useState } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
import ICParamsTable from "../ic-params-table";
|
||||
import RawDataTable from '../../../common/rawDataTable';
|
||||
|
||||
import { restartIC, shutdownIC, loadICbyId } from "../../../store/icSlice";
|
||||
import { sessionToken, currentUser } from "../../../localStorage";
|
||||
import { buttonStyle, iconStyle } from "../styles";
|
||||
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import {Button, Col, Container, Row} from "react-bootstrap";
|
||||
import ConfirmCommand from "../../../common/confirm-command";
|
||||
|
||||
const GatewayVillasNode = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ic = props.ic;
|
||||
|
||||
const [command, setCommand] = useState("");
|
||||
const [isCommandConfirmed, setIsCommandConfirmed] = useState(false);
|
||||
|
||||
const sendControlCommand = () => {
|
||||
switch(command){
|
||||
case "restart":
|
||||
dispatch(restartIC({apiurl: ic.apiurl}))
|
||||
case "shutdown":
|
||||
dispatch(shutdownIC({apiurl: ic.apiurl}))
|
||||
default:
|
||||
console.log("Command not found");
|
||||
}
|
||||
}
|
||||
|
||||
const confirmCommand = (canceled) => {
|
||||
if(!canceled){
|
||||
sendControlCommand();
|
||||
}
|
||||
|
||||
setIsCommandConfirmed(false);
|
||||
setCommand("");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h1>{ic.name}
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => dispatch(loadICbyId({id: ic.id, token: sessionToken}))}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
{currentUser.role === "Admin" ?
|
||||
<div>
|
||||
<h4>Controls</h4>
|
||||
<div className='solid-button'>
|
||||
<Button
|
||||
variant='secondary'
|
||||
style={{ margin: '5px' }}
|
||||
size='lg'
|
||||
onClick={() => {
|
||||
setIsCommandConfirmed(true);
|
||||
setIsCommandConfirmed('restart');
|
||||
}}>
|
||||
Restart
|
||||
</Button>
|
||||
<Button
|
||||
variant='secondary'
|
||||
style={{ margin: '5px' }}
|
||||
size='lg'
|
||||
onClick={() => {
|
||||
setIsCommandConfirmed(true);
|
||||
setIsCommandConfirmed('shutdown');
|
||||
}}>
|
||||
Shutdown
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
: <div />
|
||||
}
|
||||
<ConfirmCommand
|
||||
show={isCommandConfirmed}
|
||||
command={command}
|
||||
name={ic.name}
|
||||
onClose={c => confirmCommand(c)}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<hr/>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<h4>Raw Config</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw != null ? ic.statusupdateraw.config : null}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<h4>Raw Statistics</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw != null ? ic.statusupdateraw.statistics: null}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default GatewayVillasNode;
|
170
src/pages/infrastructure/ic-pages/kubernetes-ic-page.js
Normal file
170
src/pages/infrastructure/ic-pages/kubernetes-ic-page.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* 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 { useState, useEffect } from "react";
|
||||
import { Col, Row, Container, Table } from "react-bootstrap";
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import ManagedICsTable from "./managed-ics-table";
|
||||
import FileSaver from 'file-saver';
|
||||
import RawDataTable from "../../../common/rawDataTable";
|
||||
import { downloadGraph } from "../../../utils/icUtils";
|
||||
import { sessionToken, currentUser } from "../../../localStorage";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { loadAllICs, loadICbyId } from "../../../store/icSlice";
|
||||
|
||||
import ICParamsTable from "../ic-params-table";
|
||||
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
|
||||
const KubernetesICPage = (props) => {
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ic = props.ic;
|
||||
|
||||
const ics = useSelector((state) => state.infrastructure.ICsArray);
|
||||
const config = useSelector((state) => state.config.config);
|
||||
//const managedICs = ics.filter(managedIC => managedIC.category !== "manager" && managedIC.manager === ic.uuid);
|
||||
|
||||
let namespace = null;
|
||||
let jobName = null;
|
||||
let podNames = [];
|
||||
let clusterName = null;
|
||||
let rancherURL = null;
|
||||
|
||||
let managerIC = ics.find(manager => manager.uuid === ic.manager);
|
||||
|
||||
// Take k8s cluster details from managers status update
|
||||
if (managerIC != null) {
|
||||
let managerProps = managerIC.statusupdateraw.properties;
|
||||
|
||||
if (managerProps != null) {
|
||||
rancherURL = managerProps.rancher_url;
|
||||
clusterName = managerProps.cluster_name;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to backend config
|
||||
if (config != null && config.kubernetes != null) {
|
||||
let k8s = config.kubernetes;
|
||||
if (k8s != null) {
|
||||
if (rancherURL == null) {
|
||||
rancherURL = k8s.rancher_url
|
||||
}
|
||||
|
||||
if (clusterName == null) {
|
||||
clusterName = k8s.cluster_name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rancherURL != null && clusterName != null) {
|
||||
if (ic.statusupdateraw != null) {
|
||||
let icProps = ic.statusupdateraw.properties
|
||||
if (icProps != null && icProps.namespace != null) {
|
||||
namespace = icProps.namespace;
|
||||
jobName = icProps.job_name;
|
||||
|
||||
if (icProps.pod_names != null) {
|
||||
podNames = icProps.pod_names;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let rancherTableRows = []
|
||||
|
||||
if (rancherURL != null && clusterName != null) {
|
||||
let baseURL = rancherURL + "/dashboard/c/" + clusterName + "/explorer";
|
||||
|
||||
if (namespace != null) {
|
||||
if (jobName != null) {
|
||||
let url = baseURL + "/batch.job/" + namespace + "/" + jobName;
|
||||
|
||||
rancherTableRows.push(<tr>
|
||||
<td>Job</td>
|
||||
<td>{namespace}</td>
|
||||
<td><a href={url}>{jobName}</a></td>
|
||||
</tr>)
|
||||
}
|
||||
|
||||
for (const podName of podNames) {
|
||||
let url = baseURL + "/pod/" + namespace + "/" + podName;
|
||||
|
||||
rancherTableRows.push(<tr>
|
||||
<td>Pod</td>
|
||||
<td>{namespace}</td>
|
||||
<td><a href={url}>{podName}</a></td>
|
||||
</tr>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
dispatch(loadICbyId({token: sessionToken, id: ic.id}));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h1>{ic.name}
|
||||
<span className='icon-button'>
|
||||
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<div>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<h4>Resources</h4>
|
||||
<Table striped size="sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kind</th>
|
||||
<th>Namespace</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rancherTableRows}
|
||||
</tbody>
|
||||
</Table>
|
||||
</Col>
|
||||
</Row>
|
||||
<hr/>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default KubernetesICPage;
|
59
src/pages/infrastructure/ic-pages/managed-ics-table.js
Normal file
59
src/pages/infrastructure/ic-pages/managed-ics-table.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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 { Table, LabelColumn, LinkColumn, DataColumn } from '../../../common/table';
|
||||
import { stateLabelStyle } from "../styles";
|
||||
|
||||
|
||||
class ManagedICsTable extends React.Component {
|
||||
|
||||
render() {
|
||||
|
||||
return (<div>
|
||||
<h3>Managed ICs:</h3>
|
||||
<Table data={this.props.managedICs}>
|
||||
{this.props.currentUser.role === "Admin" ?
|
||||
<DataColumn
|
||||
title='ID'
|
||||
dataKey='id'
|
||||
/>
|
||||
: <></>
|
||||
}
|
||||
<LinkColumn
|
||||
title='Name'
|
||||
dataKeys={['name']}
|
||||
link='/infrastructure/'
|
||||
linkKey='id'
|
||||
/>
|
||||
<LabelColumn
|
||||
title='State'
|
||||
labelKey='state'
|
||||
labelStyle={(state, component) => stateLabelStyle(state, component)}
|
||||
/>
|
||||
<DataColumn
|
||||
title='Type'
|
||||
dataKeys={['type']}
|
||||
/>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ManagedICsTable;
|
99
src/pages/infrastructure/ic-pages/manager-villas-node.js
Normal file
99
src/pages/infrastructure/ic-pages/manager-villas-node.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* 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 { useState, useEffect } from "react";
|
||||
import { Col, Row } from "react-bootstrap";
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import ManagedICsTable from "./managed-ics-table";
|
||||
import FileSaver from 'file-saver';
|
||||
import RawDataTable from "../../../common/rawDataTable";
|
||||
import { downloadGraph } from "../../../utils/icUtils";
|
||||
import { sessionToken, currentUser } from "../../../localStorage";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { loadAllICs, loadICbyId } from "../../../store/icSlice";
|
||||
|
||||
import ICParamsTable from "../ic-params-table";
|
||||
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
|
||||
const ManagerVillasNode = (props) => {
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ic = props.ic;
|
||||
|
||||
const ics = useSelector((state) => state.infrastructure.ICsArray);
|
||||
const managedICs = ics.filter(managedIC => managedIC.category !== "manager" && managedIC.manager === ic.uuid);
|
||||
const graphURL = ic.apiurl !== "" ? ic.apiurl + "/graph.svg" : "";
|
||||
|
||||
const refresh = () => {
|
||||
dispatch(loadICbyId({token: sessionToken, id: ic.id}));
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h1>{ic.name}
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<ManagedICsTable
|
||||
managedICs={managedICs}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<hr />
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<div className='section-buttons-group-right'>
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip='Download Graph'
|
||||
onClick={() => downloadGraph(graphURL)}
|
||||
icon='download'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</div>
|
||||
<h4>Graph</h4>
|
||||
<div>
|
||||
<img alt={"Graph image download failed and/or incorrect image API URL"} src={graphURL} />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default ManagerVillasNode;
|
81
src/pages/infrastructure/ic-pages/manager-villas-relay.js
Normal file
81
src/pages/infrastructure/ic-pages/manager-villas-relay.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* 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 { useState, useEffect } from "react";
|
||||
import { Col, Row, Container } from "react-bootstrap";
|
||||
import IconButton from "../../../common/buttons/icon-button";
|
||||
import ManagedICsTable from "./managed-ics-table";
|
||||
import RawDataTable from "../../../common/rawDataTable";
|
||||
import { sessionToken, currentUser } from "../../../localStorage";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { loadAllICs, loadICbyId } from "../../../store/icSlice";
|
||||
|
||||
import ICParamsTable from "../ic-params-table";
|
||||
|
||||
import { iconStyle, buttonStyle } from "../styles";
|
||||
|
||||
const ManagerVillasRelay = (props) => {
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ic = props.ic;
|
||||
|
||||
const ics = useSelector((state) => state.infrastructure.ICsArray);
|
||||
const managedICs = ics.filter(managedIC => managedIC.category !== "manager" && managedIC.manager === ic.uuid);
|
||||
|
||||
const refresh = () => {
|
||||
dispatch(loadICbyId({token: sessionToken, id: ic.id}));
|
||||
}
|
||||
|
||||
return (<div className='section'>
|
||||
|
||||
<h1>{ic.name}
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={2}
|
||||
tooltip='Refresh'
|
||||
onClick={() => refresh()}
|
||||
icon='sync-alt'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Properties</h4>
|
||||
<ICParamsTable ic={ic}/>
|
||||
</Col>
|
||||
<Col>
|
||||
<ManagedICsTable
|
||||
managedICs={managedICs}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<h4>Raw Status</h4>
|
||||
<RawDataTable rawData={ic.statusupdateraw}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default ManagerVillasRelay;
|
74
src/pages/infrastructure/ic-params-table.js
Normal file
74
src/pages/infrastructure/ic-params-table.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
import { Table, } from 'react-bootstrap';
|
||||
import moment from 'moment';
|
||||
import { isJSON } from '../../utils/isJson';
|
||||
import ReactJson from 'react-json-view';
|
||||
|
||||
const ICParamsTable = (props) => {
|
||||
const ic = props.ic;
|
||||
|
||||
return(
|
||||
<Table striped size="sm">
|
||||
<thead>
|
||||
<tr><th>Property</th><th>Value</th></tr>
|
||||
</thead>
|
||||
<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>
|
||||
{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>
|
||||
)
|
||||
}
|
||||
|
||||
export default ICParamsTable;
|
63
src/pages/infrastructure/ic.js
Normal file
63
src/pages/infrastructure/ic.js
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* 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 { useEffect, useRef } from "react";
|
||||
import { sessionToken, currentUser } from "../../localStorage";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { loadAllICs, loadICbyId } from "../../store/icSlice";
|
||||
import { loadConfig } from "../../store/configSlice";
|
||||
|
||||
import DefaultManagerPage from "./ic-pages/default-manager-page";
|
||||
import GatewayVillasNode from "./ic-pages/gateway-villas-node";
|
||||
import ManagerVillasNode from "./ic-pages/manager-villas-node";
|
||||
import ManagerVillasRelay from "./ic-pages/manager-villas-relay";
|
||||
import KubernetesICPage from "./ic-pages/kubernetes-ic-page";
|
||||
import DefaultICPage from "./ic-pages/default-ic-page";
|
||||
|
||||
const InfrastructureComponent = (props) => {
|
||||
const params = useParams();
|
||||
const id = params.ic;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ic = useSelector(state => state.infrastructure.currentIC);
|
||||
const isICLoading = useSelector(state => state.infrastructure.isCurrentICLoading);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(loadAllICs({token: sessionToken}));
|
||||
dispatch(loadICbyId({token: sessionToken, id: id}));
|
||||
dispatch(loadConfig({token: sessionToken}));
|
||||
}, []);
|
||||
|
||||
if(ic == null || ic === undefined){
|
||||
return <div>Loading...</div>
|
||||
} else if(ic.category ==="gateway" && ic.type === "villas-node"){
|
||||
return <GatewayVillasNode ic={ic}/>
|
||||
} else if(ic.category ==="manager" && ic.type === "villas-node"){
|
||||
return <ManagerVillasNode ic={ic}/>
|
||||
} else if(ic.category ==="manager" && ic.type === "villas-relay"){
|
||||
return <ManagerVillasRelay ic={ic}/>
|
||||
} else if(ic.category ==="manager") {
|
||||
return <DefaultManagerPage ic={ic} />
|
||||
} else if(ic.category === "simulator" && ic.type === "kubernetes"){
|
||||
return <KubernetesICPage ic={ic}/>
|
||||
} else {
|
||||
return <DefaultICPage ic={ic} />
|
||||
}
|
||||
}
|
||||
|
||||
export default InfrastructureComponent;
|
140
src/pages/infrastructure/infrastructure.js
Normal file
140
src/pages/infrastructure/infrastructure.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* 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 { useEffect, useState } from "react"
|
||||
import { useDispatch } from "react-redux";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Badge } from 'react-bootstrap';
|
||||
|
||||
import { loadAllICs, loadICbyId } from "../../store/icSlice";
|
||||
import { set } from "lodash";
|
||||
|
||||
import IconButton from "../../common/buttons/icon-button";
|
||||
|
||||
import ICCategoryTable from "./ic-category-table";
|
||||
|
||||
import { sessionToken, currentUser } from "../../localStorage";
|
||||
|
||||
const Infrastructure = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const ICsArray = useSelector(state => state.infrastructure.ICsArray);
|
||||
|
||||
//track status of the modals
|
||||
const [isEditModalOpened, setIsEditModalOpened] = useState(false);
|
||||
const [isNewModalOpened, setIsNewModalOpened] = useState(false);
|
||||
const [isImportModalOpened, setIsImportModalOpened] = useState(false);
|
||||
const [isDeleteModalOpened, setIsDeleteModalOpened] = useState(false);
|
||||
const [isICModalOpened, setIsICModalOpened] = useState(false);
|
||||
|
||||
const [checkedICs, setCheckedICs] = useState([]);
|
||||
|
||||
const currentUser = JSON.parse(localStorage.getItem("currentUser"));
|
||||
|
||||
useEffect(() => {
|
||||
//load array of ics and start a timer for periodic refresh
|
||||
dispatch(loadAllICs({token: sessionToken}));
|
||||
let timer = window.setInterval(() => refresh(), 10000);
|
||||
|
||||
return () => {
|
||||
window.clearInterval(timer);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const refresh = () => {
|
||||
//if none of the modals are currently opened, we reload ics array
|
||||
if(!(isEditModalOpened || isDeleteModalOpened || isICModalOpened)){
|
||||
dispatch(loadAllICs({token: sessionToken}));
|
||||
}
|
||||
}
|
||||
|
||||
const buttonStyle = {
|
||||
marginLeft: '10px',
|
||||
}
|
||||
|
||||
const iconStyle = {
|
||||
height: '30px',
|
||||
width: '30px'
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='section'>
|
||||
<h1>Infrastructure
|
||||
{//TODO
|
||||
/* {currentUser.role === "Admin" ?
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Add Infrastructure Component'
|
||||
onClick={() => setIsNewModalOpened(true)}
|
||||
icon='plus'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Import Infrastructure Component'
|
||||
onClick={() => setIsImportModalOpened(true)}
|
||||
icon='upload'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
:
|
||||
<span />
|
||||
} */}
|
||||
</h1>
|
||||
|
||||
<ICCategoryTable
|
||||
title={"IC Managers"}
|
||||
category={"manager"}
|
||||
/>
|
||||
|
||||
<ICCategoryTable
|
||||
title={"Simulators"}
|
||||
category={"simulator"}
|
||||
/>
|
||||
|
||||
<ICCategoryTable
|
||||
title={"Gateways"}
|
||||
category={"gateway"}
|
||||
/>
|
||||
|
||||
<ICCategoryTable
|
||||
title={"Services"}
|
||||
category={"service"}
|
||||
/>
|
||||
|
||||
<ICCategoryTable
|
||||
title={"Equipment"}
|
||||
category={"equipment"}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
{//TODO
|
||||
/* <NewICDialog show={this.state.newModal} onClose={data => this.closeNewModal(data)} managers={this.state.managers} />
|
||||
<EditICDialog show={this.state.editModal} onClose={data => this.closeEditModal(data)} ic={this.state.modalIC} />
|
||||
<ImportICDialog show={this.state.importModal} onClose={data => this.closeImportModal(data)} />
|
||||
<DeleteDialog title="infrastructure-component" name={this.state.modalIC.name || 'Unknown'} show={this.state.deleteModal} onClose={(e) => this.closeDeleteModal(e)} /> */}
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Infrastructure;
|
58
src/pages/infrastructure/styles.js
Normal file
58
src/pages/infrastructure/styles.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { isICOutdated } from "../../utils/icUtils";
|
||||
|
||||
export const buttonStyle = {
|
||||
marginLeft: '5px',
|
||||
}
|
||||
|
||||
export const iconStyle = {
|
||||
height: '25px',
|
||||
width: '25px'
|
||||
}
|
||||
|
||||
//outputs a corresponding style for a LabelColumn Component
|
||||
export const stateLabelStyle = (state, component) => {
|
||||
let style = [];
|
||||
|
||||
switch (state) {
|
||||
case 'error':
|
||||
style[0] = 'danger';
|
||||
break;
|
||||
case 'idle':
|
||||
style[0] = 'primary';
|
||||
break;
|
||||
case 'starting':
|
||||
style[0] = 'info';
|
||||
break;
|
||||
case 'running':
|
||||
style[0] = 'success';
|
||||
break;
|
||||
case 'pausing':
|
||||
style[0] = 'info';
|
||||
break;
|
||||
case 'paused':
|
||||
style[0] = 'info';
|
||||
break;
|
||||
case 'resuming':
|
||||
style[0] = 'warning';
|
||||
break;
|
||||
case 'stopping':
|
||||
style[0] = 'warning';
|
||||
break;
|
||||
case 'resetting':
|
||||
style[0] = 'warning';
|
||||
break;
|
||||
case 'shuttingdown':
|
||||
style[0] = 'warning';
|
||||
break;
|
||||
case 'shutdown':
|
||||
style[0] = 'warning';
|
||||
break;
|
||||
|
||||
default:
|
||||
style[0] = 'secondary';
|
||||
}
|
||||
|
||||
style[1] = isICOutdated(component) && state !== 'shutdown' ? 'badge-outdated' : ''
|
||||
|
||||
return style;
|
||||
}
|
54
src/store/configSlice.js
Normal file
54
src/store/configSlice.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* 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 {createSlice, createAsyncThunk} from '@reduxjs/toolkit'
|
||||
import RestAPI from '../common/api/rest-api';
|
||||
|
||||
const configSlice = createSlice({
|
||||
name: 'config',
|
||||
initialState: {
|
||||
config: {},
|
||||
isLoading: false
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(loadConfig.pending, (state, action) => {
|
||||
state.isLoading = true
|
||||
})
|
||||
.addCase(loadConfig.fulfilled, (state, action) => {
|
||||
state.isLoading = false
|
||||
state.config = action.payload;
|
||||
console.log("fetched config", action.payload)
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
//loads all ICs and saves them in the store
|
||||
export const loadConfig = createAsyncThunk(
|
||||
'config/loadConfig',
|
||||
async (data) => {
|
||||
try {
|
||||
const res = await RestAPI.get("/api/v2/config", null);
|
||||
console.log("response:", res)
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.log("Error loading config", error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default configSlice.reducer;
|
131
src/store/icSlice.js
Normal file
131
src/store/icSlice.js
Normal file
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* 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 {createSlice, createAsyncThunk} from '@reduxjs/toolkit'
|
||||
import RestAPI from '../common/api/rest-api';
|
||||
|
||||
import { sessionToken } from '../localStorage';
|
||||
|
||||
const icSlice = createSlice({
|
||||
name: 'infrastructure',
|
||||
initialState: {
|
||||
ICsArray: [],
|
||||
checkedICsArray: [],
|
||||
isLoading: false,
|
||||
currentIC: {},
|
||||
isCurrentICLoading: false
|
||||
|
||||
},
|
||||
reducers: {
|
||||
checkICsByCategory: (state, args) => {
|
||||
const category = args.payload;
|
||||
|
||||
for(const ic in state.ICsArray){
|
||||
if (ic.category == category) state.checkedICsArray.push(ic)
|
||||
}
|
||||
}
|
||||
},
|
||||
extraReducers: builder => {
|
||||
builder
|
||||
.addCase(loadAllICs.pending, (state, action) => {
|
||||
state.isLoading = true
|
||||
})
|
||||
.addCase(loadAllICs.fulfilled, (state, action) => {
|
||||
state.ICsArray = action.payload;
|
||||
console.log("fetched ICs")
|
||||
})
|
||||
.addCase(loadICbyId.pending, (state, action) => {
|
||||
state.isCurrentICLoading = true
|
||||
})
|
||||
.addCase(loadICbyId.fulfilled, (state, action) => {
|
||||
state.isCurrentICLoading = false
|
||||
state.currentIC = action.payload;
|
||||
console.log("fetched IC", state.currentIC.name)
|
||||
})
|
||||
//TODO
|
||||
// .addCase(restartIC.fullfilled, (state, action) => {
|
||||
// console.log("restart fullfilled")
|
||||
// //loadAllICs({token: sessionToken})
|
||||
// })
|
||||
// .addCase(shutdownIC.fullfilled, (state, action) => {
|
||||
// console.log("shutdown fullfilled")
|
||||
// //loadAllICs({token: sessionToken})
|
||||
// })
|
||||
}
|
||||
});
|
||||
|
||||
//loads all ICs and saves them in the store
|
||||
export const loadAllICs = createAsyncThunk(
|
||||
'infrastructure/loadAllICs',
|
||||
async (data) => {
|
||||
try {
|
||||
const res = await RestAPI.get('/api/v2/ic', data.token);
|
||||
return res.ics;
|
||||
} catch (error) {
|
||||
console.log("Error loading ICs data: ", error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
//loads one IC by its id
|
||||
export const loadICbyId = createAsyncThunk(
|
||||
'infrastructure/loadICbyId',
|
||||
async (data) => {
|
||||
try {
|
||||
const res = await RestAPI.get('/api/v2/ic/' + data.id, data.token);
|
||||
return res.ic;
|
||||
} catch (error) {
|
||||
console.log("Error loading IC (id=" + data.id + ") : ", error);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
//TODO
|
||||
|
||||
//restarts ICs
|
||||
export const restartIC = createAsyncThunk(
|
||||
'infrastructure/restartIC',
|
||||
async (data) => {
|
||||
try {
|
||||
const url = data.apiurl + '/restart'
|
||||
const res = await RestAPI.post(data.apiurl, null);
|
||||
console.log(res)
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.log("Error restarting IC: ", error);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
//restarts ICs
|
||||
export const shutdownIC = createAsyncThunk(
|
||||
'infrastructure/shutdownIC',
|
||||
async (data) => {
|
||||
try {
|
||||
const url = data.apiurl + '/shutdown'
|
||||
const res = await RestAPI.post(data.apiurl, null);
|
||||
console.log(res)
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.log("Error shutting IC down: ", error);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export const {checkICsByCategory} = icSlice.actions;
|
||||
|
||||
export default icSlice.reducer;
|
|
@ -15,12 +15,17 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import { configureStore } from "@reduxjs/toolkit"
|
||||
import userReducer from './userSlice'
|
||||
import { configureStore } from "@reduxjs/toolkit";
|
||||
|
||||
import userReducer from './userSlice';
|
||||
import icReducer from './icSlice';
|
||||
import configReducer from './configSlice'
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer
|
||||
user: userReducer,
|
||||
infrastructure: icReducer,
|
||||
config: configReducer
|
||||
},
|
||||
devTools: true
|
||||
})
|
|
@ -21,8 +21,12 @@ import RestAPI from '../common/api/rest-api';
|
|||
import ICDataDataManager from '../ic/ic-data-data-manager';
|
||||
|
||||
const userSlice = createSlice({
|
||||
name: 'login',
|
||||
initialState: {currentUser: null, currentToken: null, isLoading: false, loginMessage: ''},
|
||||
name: 'user',
|
||||
initialState: {
|
||||
currentUser: null,
|
||||
currentToken: null,
|
||||
isLoading: false,
|
||||
loginMessage: ''},
|
||||
extraReducers: (builder) => {
|
||||
builder
|
||||
.addCase(login.pending, (state, action) => {
|
||||
|
@ -62,7 +66,6 @@ export const login = createAsyncThunk(
|
|||
async (userData, thunkAPI) => {
|
||||
try {
|
||||
const res = await RestAPI.post('/api/v2/authenticate/internal', userData)
|
||||
|
||||
return {user: res.user, token: res.token}
|
||||
} catch(error) {
|
||||
console.log('Error while trying to log in: ', error)
|
||||
|
|
42
src/styles/login.css
Normal file
42
src/styles/login.css
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/>.
|
||||
******************************************************************************/
|
||||
|
||||
.login-parent {
|
||||
display: flex;
|
||||
max-width: 800px;
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.login-welcome {
|
||||
float: right;
|
||||
max-width: 400px;
|
||||
padding: 15px 20px;
|
||||
border-radius: var(--borderradius) 0px 0px var(--borderradius);
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 9px 18px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.login-container {
|
||||
float: left;
|
||||
max-width: 400px;
|
||||
border-radius: 0px var(--borderradius) var(--borderradius) 0px;
|
||||
padding: 15px 20px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
||||
0 9px 18px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
13
src/utils/icUtils.js
Normal file
13
src/utils/icUtils.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export const isICOutdated = (component) => {
|
||||
if (!component.stateUpdateAt)
|
||||
return true;
|
||||
|
||||
const fiveMinutes = 5 * 60 * 1000;
|
||||
|
||||
return Date.now() - new Date(component.stateUpdateAt) > fiveMinutes;
|
||||
}
|
||||
|
||||
export const downloadGraph = async (url) => {
|
||||
let blob = await fetch(url).then(r => r.blob())
|
||||
FileSaver.saveAs(blob, this.props.ic.name + ".svg");
|
||||
}
|
13
src/utils/isJson.js
Normal file
13
src/utils/isJson.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export const isJSON = (data) => {
|
||||
if (data === undefined || data === null) {
|
||||
return false;
|
||||
}
|
||||
let str = JSON.stringify(data);
|
||||
try {
|
||||
JSON.parse(str)
|
||||
}
|
||||
catch (ex) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
Loading…
Add table
Reference in a new issue