ADD: added react-router and updated structure of app
This commit is contained in:
14
webapp/jsconfig.json
Normal file
14
webapp/jsconfig.json
Normal 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
1131
webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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 App = () => {
|
||||
return (
|
||||
<><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 />} />
|
||||
|
||||
</Routes>
|
||||
</BrowserRouter></>
|
||||
);
|
||||
}
|
||||
|
||||
// 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;
|
||||
return (
|
||||
<div className="App">
|
||||
<Header />
|
||||
<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 App;
|
||||
|
||||
12
webapp/src/components/Database/Database.jsx
Normal file
12
webapp/src/components/Database/Database.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
|
||||
function Database()
|
||||
{
|
||||
return(
|
||||
<p>Database</p>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default Database;
|
||||
3
webapp/src/components/Database/index.js
Normal file
3
webapp/src/components/Database/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Database from "./Database.jsx";
|
||||
|
||||
export default Database;
|
||||
12
webapp/src/components/Gateway/Gateway.jsx
Normal file
12
webapp/src/components/Gateway/Gateway.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
|
||||
function Gateway()
|
||||
{
|
||||
return(
|
||||
<p>Gateway</p>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default Gateway;
|
||||
3
webapp/src/components/Gateway/index.js
Normal file
3
webapp/src/components/Gateway/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Gateway from "./Gateway.jsx";
|
||||
|
||||
export default Gateway;
|
||||
@@ -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;
|
||||
|
||||
12
webapp/src/components/Scenarios/Scenarios.jsx
Normal file
12
webapp/src/components/Scenarios/Scenarios.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
|
||||
function Scenarios()
|
||||
{
|
||||
return(
|
||||
<p>Scenarios</p>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default Scenarios;
|
||||
3
webapp/src/components/Scenarios/index.js
Normal file
3
webapp/src/components/Scenarios/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Scenarios from "./Scenarios.jsx";
|
||||
|
||||
export default Scenarios;
|
||||
12
webapp/src/components/Settings/Settings.jsx
Normal file
12
webapp/src/components/Settings/Settings.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
|
||||
function Settings()
|
||||
{
|
||||
return(
|
||||
<p>Settings</p>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
export default Settings;
|
||||
3
webapp/src/components/Settings/index.js
Normal file
3
webapp/src/components/Settings/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import Settings from "./Settings.jsx";
|
||||
|
||||
export default Settings;
|
||||
220
webapp/src/components/SimControl/SimControl.jsx
Normal file
220
webapp/src/components/SimControl/SimControl.jsx
Normal 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;
|
||||
0
webapp/src/components/SimControl/SimControl.scss
Normal file
0
webapp/src/components/SimControl/SimControl.scss
Normal 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";
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import './tracklist.scss'
|
||||
import round from '../../Utils';
|
||||
import round from '../../../../Utils';
|
||||
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
3
webapp/src/components/SimControl/index.js
Normal file
3
webapp/src/components/SimControl/index.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import SimControl from "./SimControl.jsx";
|
||||
|
||||
export default SimControl;
|
||||
Reference in New Issue
Block a user