ADD: added react-router and updated structure of app

This commit is contained in:
Henry Winkel
2023-11-03 12:35:43 +01:00
parent f926604c7f
commit 3e95bc2633
29 changed files with 950 additions and 798 deletions

14
webapp/jsconfig.json Normal file
View File

@@ -0,0 +1,14 @@
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES2020",
"jsx": "react",
"strictNullChecks": true,
"strictFunctionTypes": true
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

1131
webapp/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,10 +11,10 @@
"milsymbol": "^2.2.0",
"react": "^18.2.0",
"react-bootstrap": "^2.9.0",
"react-container-dimensions": "^1.4.1",
"react-dom": "^18.2.0",
"react-hook-form": "^7.46.2",
"react-leaflet": "^4.2.1",
"react-router-dom": "^6.18.0",
"react-scripts": "^5.0.1",
"react-use-websocket": "^4.3.1",
"sass": "^1.66.1",

View File

@@ -1,235 +1,36 @@
// App.js
import React, { Component } from "react";
import "./App.css";
// import { connect, sendMsg } from "./components/api/index";
import Header from './components/Header';
import Controls from "./components/control/controls";
// import ChatHistory from "./components/ChatHistory/ChatHistory.jsx";
import OpenSeaMap from "./components/OpenSeaMap/OpenSeaMap";
import Header from "./components/Header/index"
import SimControl from './components/SimControl'
import {w3cwebsocket as W3CWebSocket} from "websocket"
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Gateway from "./components/Gateway";
import Database from "./components/Database";
import Scenarios from "./components/Scenarios";
import Settings from "./components/Settings";
export const defaultLocale = "en-US";
const config = {
// apiUrl: process.env.REACT_APP_WEBAPP_WS_URL,
apiUrl: "192.168.3.13",
apiProt: 30747
}
// const config = {
// // apiUrl: process.env.REACT_APP_WEBAPP_WS_URL,
// apiUrl: "localhost",
// apiProt: 9999
// }
const client = new W3CWebSocket("ws://"+config.apiUrl+":"+config.apiProt+"/");
class App extends Component {
state = {
Entities: [],
EntityOnFocus: undefined,
PositionClicked: undefined
}
componentDidMount() {
console.log(config.apiUrl);
client.onopen = () => {
console.log("Websocket Client for Map Connected");
};
client.onmessage = (message) => {
const dataFromServer = JSON.parse(message.data);
// console.log('reply: ', dataFromServer);
if(dataFromServer.Data === "COP")
{
if(dataFromServer.Entities === undefined)
{
dataFromServer.Entities = [];
}
// console.log(this.state.EntityOnFocus);
let tmp = new Array(); ;
if(this.state.Entities !== undefined && this.state.Entities.length !== 0){
if(dataFromServer.Entities.length > 0)
{
dataFromServer.Entities.forEach((elementFromWS, indexWS) => {
if (this.isStored(elementFromWS.id) !== true)
{
tmp.push(elementFromWS);
}
this.state.Entities.forEach((elementStored, indexStore) => {
if(elementFromWS.id === elementStored.id)
{
// console.log(elementStored);
if(elementStored.onFocus !==true | elementStored.onFocus === undefined)
{
tmp.push(elementFromWS);
}else
{
tmp.push(elementStored);
}
}else{
// console.log(elementFromWS);
// tmp.push(elementFromWS);
}
});
});
}
}else{
tmp = dataFromServer.Entities;
}
// console.log(tmp);
this.setState((state) => ({
// Entities: structuredClone(dataFromServer.Entities)
Entities: structuredClone(tmp)
})
)
}
}
/// interval for updates
setInterval(() => {
this.updateEntities();
}, 2000);
}
isStored(id) {
var found = false;
this.state.Entities.forEach((elementStored, indexStore) => {
if (id === elementStored.id)
{
found = true;
}
});
return found;
}
updateEntities()
{
var msg =
{
Type: "Request",
Data: "COP"
}
client.send(JSON.stringify(msg));
}
getEntityFromID(Entities, SelectedEntity)
{
// console.log(Entities);
}
setEntityOnFocus(Entity)
{
if(Entity == undefined)
{
this.resetEntityOnFocus();
return;
}
this.getEntityFromID(this.state.Entities,Entity)
console.log(Entity);
this.setState({
EntityOnFocus: Entity
});
this.state.Entities.forEach((element, index) => {
// console.log(element);
if(element.id === Entity.EntityID)
{
var tmpList = structuredClone(this.state.Entities);
tmpList[index].onFocus = true;
if(Entity.NewPos !== undefined)
{
tmpList[index].Position = Entity.NewPos
}
this.setState({
Entities: structuredClone(tmpList)
});
if(Entity.dragged !== undefined)
{
if(Entity.dragged === true)
{
tmpList[index].dragged = true;
}
}
console.log(tmpList[index]);
}
});
}
resetEntityOnFocus()
{
if(this.state.EntityOnFocus !== undefined)
{
this.state.Entities.map((element ,index) => {
if(element.id === this.state.EntityOnFocus.EntityID)
{
this.state.Entities[index].onFocus = false;
}
})
console.log(this.state.Entities)
this.setState({
EntityOnFocus: undefined
})
}
}
setFocusPosition(props)
{
// console.log(Entity);
this.setState({
PositionClicked: props
});
}
Functions = {
updateEntities: this.updateEntities.bind(this),
resetEntityOnFocus: this.resetEntityOnFocus.bind(this)
}
render() {
const {name} = this.state;
const App = () => {
return (
<div className="App">
<Header />
<div className="Content">
<><Header />
<BrowserRouter>
<Routes>
<Route path="/" element={<SimControl />} />
<Route path="/scenarios" element={<Scenarios />} />
<Route path="/database" element={<Database />} />
<Route path="/gateway" element={<Gateway />} />
<Route path="/settings" element={<Settings />} />
<Controls Functions= {this.Functions} Client= {client} Entities= {this.state.Entities} updateEntities = {this.updateEntities} EntityOnFocus = {this.state.EntityOnFocus} PositionClicked = {this.state.PositionClicked} />
<OpenSeaMap Entities= {this.state.Entities} Client= {client} updateEntities = {this.updateEntities} setEntityOnFocus = {this.setEntityOnFocus.bind(this)} setFocusPosition = {this.setFocusPosition.bind(this)}/>
</div>
</div>
</Routes>
</BrowserRouter></>
);
}
}
export default App;

View File

@@ -0,0 +1,12 @@
import React from "react";
function Database()
{
return(
<p>Database</p>
);
}
export default Database;

View File

@@ -0,0 +1,3 @@
import Database from "./Database.jsx";
export default Database;

View File

@@ -0,0 +1,12 @@
import React from "react";
function Gateway()
{
return(
<p>Gateway</p>
);
}
export default Gateway;

View File

@@ -0,0 +1,3 @@
import Gateway from "./Gateway.jsx";
export default Gateway;

View File

@@ -1,10 +1,38 @@
import React from "react";
import Container from 'react-bootstrap/Container';
import Nav from 'react-bootstrap/Nav';
import Navbar from 'react-bootstrap/Navbar';
import "./header.scss";
import 'bootstrap/dist/css/bootstrap.min.css';
function Header() {
return(
<Navbar expand="lg" bg="secondary">
<Container fluid >
<Navbar.Brand href="/"><h2>Cloud Simulator</h2></Navbar.Brand>
<Navbar.Toggle aria-controls="navbarScroll" />
<Navbar.Collapse id="navbarScroll">
<Nav
className="me-auto my-2 my-lg-0"
style={{ maxHeight: '100px' }}
navbarScroll
>
<Nav.Link href="scenarios">Scenarios</Nav.Link>
<Nav.Link href="database">Database</Nav.Link>
<Nav.Link href="gateway">Gateway</Nav.Link>
<Nav.Link href="settings">Settings</Nav.Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
);
}
const Header = () => (
<div className="header">
<font className="caption">Cloud Simulator</font>
</div>
);
export default Header;

View File

@@ -0,0 +1,12 @@
import React from "react";
function Scenarios()
{
return(
<p>Scenarios</p>
);
}
export default Scenarios;

View File

@@ -0,0 +1,3 @@
import Scenarios from "./Scenarios.jsx";
export default Scenarios;

View File

@@ -0,0 +1,12 @@
import React from "react";
function Settings()
{
return(
<p>Settings</p>
);
}
export default Settings;

View File

@@ -0,0 +1,3 @@
import Settings from "./Settings.jsx";
export default Settings;

View File

@@ -0,0 +1,220 @@
import React, { Component } from "react";
import {w3cwebsocket as W3CWebSocket} from "websocket"
// import Header from './components/Header';
import Controls from "./components/control/controls";
import OpenSeaMap from "./components/OpenSeaMap/OpenSeaMap";
const config = {
// apiUrl: process.env.REACT_APP_WEBAPP_WS_URL,
apiUrl: "192.168.3.13",
apiProt: 30747
}
const client = new W3CWebSocket("ws://"+config.apiUrl+":"+config.apiProt+"/");
class SimControl extends Component {
state = {
Entities: [],
EntityOnFocus: undefined,
PositionClicked: undefined
}
componentDidMount() {
console.log(config.apiUrl);
client.onopen = () => {
console.log("Websocket Client for Map Connected");
};
client.onmessage = (message) => {
const dataFromServer = JSON.parse(message.data);
// console.log('reply: ', dataFromServer);
if(dataFromServer.Data === "COP")
{
if(dataFromServer.Entities === undefined)
{
dataFromServer.Entities = [];
}
// console.log(this.state.EntityOnFocus);
let tmp = new Array(); ;
if(this.state.Entities !== undefined && this.state.Entities.length !== 0){
if(dataFromServer.Entities.length > 0)
{
dataFromServer.Entities.forEach((elementFromWS, indexWS) => {
if (this.isStored(elementFromWS.id) !== true)
{
tmp.push(elementFromWS);
}
this.state.Entities.forEach((elementStored, indexStore) => {
if(elementFromWS.id === elementStored.id)
{
// console.log(elementStored);
if(elementStored.onFocus !==true | elementStored.onFocus === undefined)
{
tmp.push(elementFromWS);
}else
{
tmp.push(elementStored);
}
}else{
// console.log(elementFromWS);
// tmp.push(elementFromWS);
}
});
});
}
}else{
tmp = dataFromServer.Entities;
}
// console.log(tmp);
this.setState((state) => ({
// Entities: structuredClone(dataFromServer.Entities)
Entities: structuredClone(tmp)
})
)
}
}
/// interval for updates
setInterval(() => {
this.updateEntities();
}, 2000);
}
isStored(id) {
var found = false;
this.state.Entities.forEach((elementStored, indexStore) => {
if (id === elementStored.id)
{
found = true;
}
});
return found;
}
updateEntities()
{
var msg =
{
Type: "Request",
Data: "COP"
}
client.send(JSON.stringify(msg));
}
getEntityFromID(Entities, SelectedEntity)
{
// console.log(Entities);
}
setEntityOnFocus(Entity)
{
if(Entity === undefined)
{
this.resetEntityOnFocus();
return;
}
this.getEntityFromID(this.state.Entities,Entity)
console.log(Entity);
this.setState({
EntityOnFocus: Entity
});
this.state.Entities.forEach((element, index) => {
// console.log(element);
if(element.id === Entity.EntityID)
{
var tmpList = structuredClone(this.state.Entities);
tmpList[index].onFocus = true;
if(Entity.NewPos !== undefined)
{
tmpList[index].Position = Entity.NewPos
}
this.setState({
Entities: structuredClone(tmpList)
});
if(Entity.dragged !== undefined)
{
if(Entity.dragged === true)
{
tmpList[index].dragged = true;
}
}
console.log(tmpList[index]);
}
});
}
resetEntityOnFocus()
{
if(this.state.EntityOnFocus !== undefined)
{
this.state.Entities.map((element ,index) => {
if(element.id === this.state.EntityOnFocus.EntityID)
{
this.state.Entities[index].onFocus = false;
}
})
console.log(this.state.Entities)
this.setState({
EntityOnFocus: undefined
})
}
}
setFocusPosition(props)
{
// console.log(Entity);
this.setState({
PositionClicked: props
});
}
Functions = {
updateEntities: this.updateEntities.bind(this),
resetEntityOnFocus: this.resetEntityOnFocus.bind(this)
}
render() {
const {name} = this.state;
return (
<div className="App">
<div className="Content">
<Controls Functions= {this.Functions} Client= {client} Entities= {this.state.Entities} updateEntities = {this.updateEntities} EntityOnFocus = {this.state.EntityOnFocus} PositionClicked = {this.state.PositionClicked} />
<OpenSeaMap Entities= {this.state.Entities} Client= {client} updateEntities = {this.updateEntities} setEntityOnFocus = {this.setEntityOnFocus.bind(this)} setFocusPosition = {this.setFocusPosition.bind(this)}/>
</div>
</div>
);
}
}
export default SimControl;

View File

@@ -5,7 +5,7 @@ import { MapContainer, TileLayer,Marker, Popup, Tooltip,useMapEvents,contextmenu
import { friend,Hostile, iconShip,createIcon } from "./icon";
import "./OpenSeaMap.scss";
import {w3cwebsocket as W3CWebSocket} from "websocket";
import ContainerDimensions from 'react-container-dimensions';
// import ContainerDimensions from 'react-container-dimensions';
import {} from "leaflet-contextmenu";

View File

@@ -4,7 +4,7 @@ import { useForm, SubmitHandler } from "react-hook-form"
import Form from 'react-bootstrap/Form';
import FloatingLabel from 'react-bootstrap/FloatingLabel';
import InputGroup from 'react-bootstrap/InputGroup';
import round from "../Utils";
import round from "../../../Utils";
import 'bootstrap/dist/css/bootstrap.min.css';

View File

@@ -1,6 +1,6 @@
import React from 'react';
import './tracklist.scss'
import round from '../../Utils';
import round from '../../../../Utils';

View File

@@ -3,23 +3,10 @@ import './controls.css'
// import { sendMsg } from '../api';
import Tracklist from './Tracklist'
import EntityControl from './EntityControl';
import round from '../Utils';
import round from '../../../Utils';
// import {w3cwebsocket as W3CWebSocket} from "websocket"
// const config = {
// // apiUrl: process.env.REACT_APP_WEBAPP_WS_URL,
// apiUrl: "192.168.3.13",
// apiProt: 30747
// }
// const client = new W3CWebSocket("ws://"+config.apiUrl+":"+config.apiProt+"/");
// const round = (n, dp) => {
// const h = +('1'.padEnd(dp + 1, '0')) // 10 or 100 or 1000 or etc
// return Math.round(n * h) / h
// }
class Controls extends React.Component
{
@@ -30,16 +17,8 @@ state = {
componentDidMount()
{
// client.onopen = () => {
// console.log(" Control Websocket Client Connected");
// };
// client.onmessage = (message) => {
// const dataFromServer = JSON.parse(message.data);
// console.log('reply', dataFromServer);
// }
if (this.props.Entities == undefined)
if (this.props.Entities === undefined)
{
this.props.Entities = new Array();
}

View File

@@ -0,0 +1,3 @@
import SimControl from "./SimControl.jsx";
export default SimControl;