diff --git a/client/src/components/Components.d.ts b/client/src/components/Components.d.ts new file mode 100644 index 000000000..a2fe9e389 --- /dev/null +++ b/client/src/components/Components.d.ts @@ -0,0 +1,61 @@ +import * as React from 'react'; +import * as Entities from '../utils/entities'; +import { ComponentCard } from './ComponentCard'; +import { DataUpload } from './DataUpload'; + +interface TypeMap { + props: {}; + Component: React.FC; +}; + +/** + * ComponentCard + */ + +interface IComponentCardProps { + /** + * The id of the component. + */ + componentId: string; + /** + * The id of the rocket or the rocket object. + */ + rocket: Entities.IRocketPopulated | Entities.IRocketPopulated; + /** + * event handler for when the component delete button is clicked. + */ + onDelete: () => void; + /** + * event handler for when the component edit button is clicked. + */ + updateComponent: () => void; + /** + * event handler for when the data config button is clicked. + */ + onDataConfigClick: (id: string) => void; +} + +export type ComponentCardTypeMap = TypeMap & { + props: IComponentCardProps; + Component: ComponentCard; +}; + +/** + * DataUpload + */ + +interface IDataUploadProps { + /** + * Controls whether the dialog is open or not. + */ + isOpen: boolean; + /** + * event handler for when the dialog is closed. + */ + onClose: () => void; +} + +export type DataUploadTypeMap = TypeMap & { + props: IDataUploadProps; + Component: DataUpload; +}; \ No newline at end of file diff --git a/client/src/components/DataUpload.tsx b/client/src/components/DataUpload.tsx index 91d4c391d..3a956df1c 100644 --- a/client/src/components/DataUpload.tsx +++ b/client/src/components/DataUpload.tsx @@ -1,6 +1,6 @@ +import React, { useState, forwardRef, useEffect } from 'react'; import { Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, Slide, Stack, Tooltip, Typography } from "@mui/material"; import { useActiveMission } from "../utils/ActiveMissionContext"; -import React, { useState, forwardRef, useEffect } from 'react'; import { TransitionProps } from "@mui/material/transitions"; import FileUpload from "react-material-file-upload"; @@ -12,7 +12,8 @@ interface IDataUploadProps { } -const MissionConfig: React.FC = (props: IDataUploadProps) => { + +const DataUpload: React.FC = (props: IDataUploadProps) => { const { isOpen, onClose } = props; const [files, setFiles] = useState([]); @@ -70,4 +71,4 @@ const MissionConfig: React.FC = (props: IDataUploadProps) => { ); } -export default MissionConfig; \ No newline at end of file +export default DataUpload; diff --git a/client/src/components/RocketSimDailog.tsx b/client/src/components/RocketSimDailog.tsx new file mode 100644 index 000000000..f45cc55dc --- /dev/null +++ b/client/src/components/RocketSimDailog.tsx @@ -0,0 +1,145 @@ +import React, { useState, useEffect } from 'react'; +import { IRocketSimModel } from '../utils/entities'; +import api from '../services/api'; +import { Alert, Button, Collapse, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, InputAdornment, Stack, TextField, Typography } from '@mui/material'; +import { Close } from '@mui/icons-material'; + +interface IRocketSimModalProps { + isOpen: boolean; + onClose: () => void; + id?: string; +} + +const RocketSimDialog: React.FC = (props: IRocketSimModalProps) => { + const { isOpen, onClose, id } = props; + + const [alert, setAlert] = useState(false); + const [alertMessage, setAlertMessage] = useState(''); + const [success, setSuccess] = useState(false); + // RocketSimModel Properties + const [dryMass, setDryMass] = useState(null); + const [wetMass, setWetMass] = useState(null); + const [name, setName] = useState(null); + const [centerOfGravity, setCenterOfGravity] = useState(null); + const [centerOfPressure, setCenterOfPressure] = useState(null); + const [rocketLength, setRocketLength] = useState(null); + const [fuselageDiameter, setFuselageDiameter] = useState(null); + const [fuselageLength, setFuselageLength] = useState(null); + + const rocketSimProperties = [ + { label: "Name", value: name, setter: setName, type: 'none' }, + { label: "Dry Mass", value: dryMass, setter: setDryMass, type: 'numeric', units: 'kg' }, + { label: "Wet Mass", value: wetMass, setter: setWetMass, type: 'numeric', units: 'kg' }, + { label: "Center of Gravity", value: centerOfGravity, setter: setCenterOfGravity, type: 'numeric', units: 'ft' }, + { label: "Center of Pressure", value: centerOfPressure, setter: setCenterOfPressure, type: 'numeric', units: 'ft' }, + { label: "Rocket Length", value: rocketLength, setter: setRocketLength, type: 'numeric', units: 'ft' }, + { label: "Fuselage Length", value: fuselageLength, setter: setFuselageLength, type: 'numeric', units: 'ft' }, + { label: "Fuselage Diameter", value: fuselageDiameter, setter: setFuselageDiameter, type: 'numeric', units: 'Inches' }, + ]; + + const handleSave = async () => { + const payload: IRocketSimModel = { + Name: name!, + DryMass: dryMass!, + WetMass: wetMass!, + CenterOfGravity: centerOfGravity!, + CenterOfPressure: centerOfPressure!, + RocketLength: rocketLength!, + FuselageDiameter: fuselageDiameter!, + FuselageLength: fuselageLength!, + }; + + if (id) { + // update rocketSim + setSuccess(!(await api.updateRocketSim(id, payload)).error.error); + } else { + // create rocketSim + setSuccess(!(await api.createRocketSim(payload)).error.error); + } + console.log(success) + setAlertMessage(success ? 'RocketSim updated successfully' : 'RocketSim failed to update. Fill in all fields'); + setAlert(!success); + if (success) { + onClose(); + } + }; + + const handleClose = () => { + onClose(); + }; + + const handleChange = (e: any, setState: Function) => { + setState(e.target.value as string); + }; + + useEffect(() => { + async function fetchRocketSim() { + if (id) { + // fetch rocketSim + const response = await api.getRocketSim(id); + const rocketSim = response.data as IRocketSimModel; + + setName(rocketSim.Name); + setDryMass(rocketSim.DryMass); + setWetMass(rocketSim.WetMass); + setCenterOfGravity(rocketSim.CenterOfGravity); + setCenterOfPressure(rocketSim.CenterOfPressure); + setRocketLength(rocketSim.RocketLength); + setFuselageDiameter(rocketSim.FuselageDiameter); + setFuselageLength(rocketSim.FuselageLength); + } + } + fetchRocketSim(); + }, [id]); + + return ( + + + Rocket Sim Input + + + + { + setAlert(false); + }} + > + + + } + sx={{ mb: 2 }} + > + {alertMessage} + + + + {rocketSimProperties.map((property, index) => ( + handleChange(e, property.setter)} + required + variant="outlined" + InputProps={{ + endAdornment: {property.units} + }} + /> + ))} + + + + + + + + ); +} + +export default RocketSimDialog; \ No newline at end of file diff --git a/client/src/services/api.ts b/client/src/services/api.ts index d088b44a3..96ea398df 100644 --- a/client/src/services/api.ts +++ b/client/src/services/api.ts @@ -6,7 +6,8 @@ import { IRocket, IComponentPopulated, IComponent, - IMission + IMission, + IRocketSimModel } from '../utils/entities'; const api = axios.create({ @@ -34,7 +35,9 @@ interface IApiResponse { IMission | IMission[] | IMissionPopulated[] | - IMissionPopulated; + IMissionPopulated | + IRocketSimModel | + IRocketSimModel[]; error: IError; } @@ -757,6 +760,158 @@ async function deleteDataConfig(id: string, componentId: string): Promise { + let response: AxiosResponse; + let data: IApiResponse = { + data: [] as IRocketPopulated[], + error: {} as IError + } as IApiResponse; + + try { + response = await api.get('/rocketSim'); + data = { + data: response.data.results + ? response.data.results + : response.data.result as IRocketPopulated[], + error: handleError(response) + }; + } catch (e) { + const err = e as AxiosError; + data.error.error = true; + data.error.message = `Error getting all rockets. Full error: \n${err.message}`; + } + + return data; +} + +/** + * @param id Id of a rocketSim + * @returns The rocketSim + */ +async function getRocketSim(id: string): Promise { + let response: AxiosResponse; + let data: IApiResponse = { + data: {} as IRocketSimModel, + error: {} as IError + } as IApiResponse; + + try { + response = await api.get(`/rocketSim/${id}`); + data = { + data: response.data.result + ? response.data.result as IRocketSimModel + : response.data.results as IRocketSimModel, + error: handleError(response) + }; + } catch (e) { + const err = e as AxiosError; + data.error.error = true; + data.error.message = `Error getting rocketSim by id with ${id}. Full error: \n${err.message}`; + } + + return data; +} + +/** + * @param payload The rocket to create type IRocketSimModel + * @returns The created rocketSim + * + * @description Creates a rocketSim + */ +async function createRocketSim(payload: IRocketSimModel): Promise { + let response: AxiosResponse; + let data: IApiResponse = { + data: {} as IRocket, + error: {} as IError + } as IApiResponse; + + try { + response = await api.post('/rocketSim', payload); + data = { + data: response.data.result + ? response.data.result + : response.data.results as IRocketSimModel, + error: handleError(response) + }; + } catch (e) { + const err = e as AxiosError; + data.error.error = true; + data.error.message = `Error creating new rocketSim. Full error:\n${err.message}`; + } + + return data; +} + +/** + * @param id Id of a rocket + * @param payload The rocket to update type IRocket + * @returns The updated rocket + */ +async function updateRocketSim(id: string, payload: IRocketSimModel): Promise { + let response: AxiosResponse; + let data: IApiResponse = { + data: {} as IRocketSimModel, + error: {} as IError + } as IApiResponse; + + try { + response = await api.patch(`/rocketSim/${id}`, payload); + data = { + data: response.data.result + ? response.data.result as IRocketSimModel + : response.data.results as IRocketSimModel, + error: handleError(response) + }; + } catch(e) { + const err = e as AxiosError; + data.error.error = true; + data.error.message = `Error updating the rocketSim with the id ${id}. Full error:\n${err.message}`; + } + + return data; +} +/** + * @param id Id of a rocket + * @returns The deleted rocket + * + * @description Deletes a rocket + */ +async function deleteRocketSim(id: string): Promise { + let response: AxiosResponse; + let data: IApiResponse = { + data: {} as IRocketSimModel, + error: {} as IError + } as IApiResponse; + + try { + response = await api.delete(`/rocketSim/${id}`); + data = { + data: response.data.result + ? response.data.result + : response.data.results as IRocketSimModel, + error: handleError(response) + }; + } catch(e) { + const err = e as AxiosError; + data.error.error = true; + data.error.message = `Error deleting rocketSim with the id ${id}. Full error:\n${err.message}`; + } + + return data; +} + // eslint-disable-next-line import/no-anonymous-default-export export default { getRockets, @@ -778,5 +933,10 @@ export default { getDataConfig, createDataConfig, updateDataConfig, - deleteDataConfig + deleteDataConfig, + getRocketSims, + getRocketSim, + createRocketSim, + updateRocketSim, + deleteRocketSim }; \ No newline at end of file diff --git a/client/src/utils/entities.ts b/client/src/utils/entities.ts index 859d71843..62ee765a8 100644 --- a/client/src/utils/entities.ts +++ b/client/src/utils/entities.ts @@ -112,4 +112,50 @@ export interface IFieldData { ParentFieldGroupName: string; TelemetryId: Buffer; Data: IDataPoint[]; -} \ No newline at end of file +} + +/* ------- Skilldev ------ */ + +enum NoseConeShape { + Elliptical = "Elliptical", + Conical = "Conical", + Parabolic = "Parabolic", + PowerSeries = "PowerSeries" +}; + +interface IAeroDimensions { + NoseCone: { + Length: number; + Diameter: number; + TipRadius: number; + Shape: NoseConeShape; + }, + BoatTail: { + Length: number; + ForeDiameter: number; + AftDiameter: number; + }, + Fins: { + Count: number; + Span: number; + RootChord: number; + TipChord: number; + Sweep: number; + Thickness: number; + } +} + +export interface IRocketSimModel { + _id?: string; + Name: string; + DryMass: number; + WetMass: number; + CenterOfGravity: number; + CenterOfPressure: number; + RocketLength: number; + FuselageLength: number; + FuselageDiameter: number; + AeroDimensions?: IAeroDimensions; +}; + +/* ------- Skilldev ------ */ \ No newline at end of file diff --git a/client/src/views/rocket-details-view.tsx b/client/src/views/rocket-details-view.tsx index 4e6932b48..068641509 100644 --- a/client/src/views/rocket-details-view.tsx +++ b/client/src/views/rocket-details-view.tsx @@ -22,6 +22,8 @@ import MissionConfig from '../components/MissionConfig'; import api from '../services/api'; import _ from 'lodash'; import { IRocketPopulated } from '../utils/entities'; +import RocketSimulationTab from './tabs/simulation-tab'; +import RocketSimDialog from '../components/RocketSimDailog'; interface TabPanelProps { children?: React.ReactNode; @@ -76,12 +78,14 @@ export default function RocketDetailsView(props: RocketDetailsProps) { // Popup state const [componentModalOpen, setComponentModalOpen] = useState(false); + const [isSimulationDialogOpen, setIsSimulationDialogOpen] = useState(false); const [isRocketPopUpOpen, setIsRocketPopUpOpen] = useState(false); const [isMissionConfigOpen, setIsMissionConfigOpen] = useState(false); const [rocketData, setRocketData] = useState({} as IRocketPopulated); const [selectedMission, setSelectedMission] = useState(''); const [isMissionActive, setIsMissionActive] = useState(false); + const [updateSims, setUpdateSims] = useState(false); const handleSelectedMission = (mission: string) => { setSelectedMission(mission); @@ -173,6 +177,7 @@ export default function RocketDetailsView(props: RocketDetailsProps) { + {value===1 && ( @@ -190,6 +195,11 @@ export default function RocketDetailsView(props: RocketDetailsProps) { Mission )} + {value===3 && ( + + )} + + + @@ -243,6 +256,13 @@ export default function RocketDetailsView(props: RocketDetailsProps) { onSave={()=> refresh} onClose={() => setComponentModalOpen(false)} /> + { + setIsSimulationDialogOpen(false); + setUpdateSims(true); + }} + />
diff --git a/client/src/views/tabs/simulation-tab.tsx b/client/src/views/tabs/simulation-tab.tsx new file mode 100644 index 000000000..ecbd7d37f --- /dev/null +++ b/client/src/views/tabs/simulation-tab.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useState } from 'react'; +import LoadingButton from '@mui/material/Button'; +import { Button } from '@mui/material'; +import api from '../../services/api' +import { IRocketSimModel } from '../../utils/entities'; + + + +const RocketSimulationTab: React.FC = () => { + // state + const [data, setData] = useState([{Name: 'None'}]); + useEffect(() => { + const fetchData = async () => { + const result = await api.getRocketSims(); + const d = result.data as IRocketSimModel[]; + setData(d); + } + fetchData(); + + }, []); + + return ( + <> + {data.map((sim: IRocketSimModel) => () => ( + <> + {sim.Name} + + ))} + + ); +}; + +export default RocketSimulationTab; \ No newline at end of file diff --git a/documentation/assets/entity-design-pattern.png b/documentation/assets/entity-design-pattern.png new file mode 100644 index 000000000..5472adbca Binary files /dev/null and b/documentation/assets/entity-design-pattern.png differ diff --git a/documentation/developer-guide.md b/documentation/developer-guide.md index 8ab28e5f6..e17d29e31 100644 --- a/documentation/developer-guide.md +++ b/documentation/developer-guide.md @@ -6,6 +6,7 @@ Please see the [installation guide](installation.md#developer-installation) for ## Resources - [Git Tutorial](https://www.figma.com/proto/LAxam3HVit5yoHmCxu2xa2/Git?page-id=0%3A1&type=design&node-id=1-796&viewport=554%2C653%2C0.24&t=YB0SXZsT8TWyvT93-1&scaling=min-zoom&starting-point-node-id=1%3A19&mode=design) - UVic Rocketry Git reference guide - [Software Process](https://docs.google.com/presentation/d/1gkJjfWnc6jsr0PQ29cYPVdIOYFZum4SubFt4X8ovL-o/edit#slide=id.g146cc2337ed_0_4) - UVic Rocketry Software Process guidelines +- [Ground Support](https://www.figma.com/proto/FmNk8xeKIUDAEmA377DV3l/Rocketry-Software?page-id=0%3A1&type=design&node-id=2085-5509&viewport=-1610%2C-611%2C0.11&t=cZkbvCD7xCJrTlDc-1&scaling=min-zoom&starting-point-node-id=2085%3A5509&show-proto-sidebar=1&mode=design) - Presentation on high level overview ## Standards ### Code Style @@ -86,17 +87,167 @@ const Component: React.FC = (props: IProps) => { export default Component; ``` There should be an accompanying documentation file in the `documentation/components` folder with the same name as the component. This file should contain a description of the component and how to use it. Use this template: [Example Component Document](./components/exampleComponentDocumentation.md). + +Once your component is finished add it to the `index.d.ts` file in the `components` folder. This will allow you to import the component from the `components` folder without having to specify the file name. For example: + +```tsx +import { ExampleComponent, IExampleProps } from '../components'; +``` +rather than +```tsx +import { ExampleComponent } from '../components/exampleComponent'; +``` + + ### How to Make a View -### How to access the API +Create a new file in the `views` folder with the name of the view in kebab-case. The file is named in `kebab-case` and the extension should be `.tsx` as we are using TypeScript. Use the following template to create a view: +```tsx +import React, { useEffect } from 'react'; +import { Grid } from '@material-ui/core'; +import { Header } from '../../components'; +interface IProps { + // props +} + +const View: React.FC = (props: IProps) => { + const { } = props; + // state + const [data, setData] = useState(null); + // or + const useSocketContext = () => useContext(Context); + + // render + return ( + + + +
+ + + // View content goes here + + + ); +}; +``` + +### How to access the API Frontend + +The helper file api.ts is give typesafety and security to ground supports api from the frontend. The file is located in `src/services/api.ts`. To learn more about the API please see the [API Documentation](./api.md). + +```tsx +// Import the entity + verb you specifically want to access +import { ... } from "../utils/api.ts"; +// If you GETTing a value from the api you also most likely need the populated version of the entity +import { ...Populated } from "../utils/api.ts"; +``` + +`Example` +getting a rocket from the API updating a value in the rocket and then sending it back to the API. + +```tsx +import { IRocketPopulated } from "../utils/"; +import { getRocket, updateRocket } from "../services/api.ts"; +import { useState, useEffect } from "react"; + +const [rocketData, setRocketData] = useState(null); + +async retrieveRocket = () => { + const rocketResponse = await getRocket(1); + const rocketData = rocketResponse.data as IRocketPopulated; + return rocketData; +} + +// Retrieve the rocket data called when the component is mounted +useEffect(() => { + const rocketData = await retrieveRocket(); + setRocketData(rocketData); +}, []); + +// Update the rocket data +setRocketData({ + ...rocketData, + name: "New Rocket Name" +}); + +const success = await updateRocket(1, rocketData).error.status === 200; +``` + + +### How to access context + +We have two contexts that are currently being used. The first is the `SocketContext` which is used to access the socket. The second is the `activeMissionContext` which is used to access the rocket and mission data of an active flight. To access the context use the following template: + +```tsx + +``` +### How to access the Socket ## Server Backend +For the server there are three main things that need to be created. The first is an **entity** which is the object that is stored in the database. The second is a **controller** which is the logic that is used to interact with the entity. The third is a **route** which is the endpoint that is used to access the controller. + +

+ +

+ ### How to create an Entity ```tsx +import mongoose, { Document, Schema, Types } from "mongoose"; + +export interface IEntity { + // entity properties + Name: string; +}; + +export interface IEntityModel extends IEntity, Document { }; + +export const EntitySchema = new Schema( + { + // entity properties + Name: { + type: String, + required: true, + validator: (value: string) => { + // validation logic + } + }, + }, + { + versionKey: false, + timestamps: true + } +); + +export const Entity = mongoose.model("Entity", EntitySchema); +``` + +### How to create a Controller +For basic CRUD operations we will just be using the Generic controller. This controller is located in `src/controllers/Generic.ts`. +### How to create a Route +```tsx +import express from "express"; +import controller from "../controllers/Generic"; +import Entity from "../models/Entity"; + +const router = express.Router(); + +router.get("/", controller.getAll(Entity)); +router.get("/:id", controller.getById(Entity)); +router.post("/", controller.create(Entity)); +router.patch("/:id", controller.update(Entity)); +router.delete("/:id", controller.remove(Entity)); +export default router; ``` -## Telemetry Backend \ No newline at end of file +## Telemetry Backend diff --git a/services/server/src/models/RocketSimModel.ts b/services/server/src/models/RocketSimModel.ts new file mode 100644 index 000000000..e6da34d1f --- /dev/null +++ b/services/server/src/models/RocketSimModel.ts @@ -0,0 +1,174 @@ +import mongoose, { Document, Schema, Types } from "mongoose"; + +export interface IRocketSimModel { + Name: string; + DryMass: number; + WetMass: number; + CenterOfGravity: number; + CenterOfPressure: number; + RocketLength: number; + FuselageLength: number; + FuselageDiameter: number; + AeroDimensions?: IAeroDimensions; +}; + +enum NoseConeShape { + Elliptical = "Elliptical", + Conical = "Conical", + Parabolic = "Parabolic", + PowerSeries = "PowerSeries" +}; + +interface IAeroDimensions { + NoseCone: { + Length: number; + Diameter: number; + TipRadius: number; + Shape: NoseConeShape; + }, + BoatTail: { + Length: number; + ForeDiameter: number; + AftDiameter: number; + }, + Fins: { + Count: number; + Span: number; + RootChord: number; + TipChord: number; + Sweep: number; + Thickness: number; + } +} + +const AeroDimensions: Schema = new Schema( + { + NoseCone: { + Length: { + type: Number, + required: true + }, + Diameter: { + type: Number, + required: true + }, + TipRadius: { + type: Number, + required: true + }, + Shape: { + type: String, + enum: Object.values(NoseConeShape), + required: true + } + }, + BoatTail: { + Length: { + type: Number, + required: true + }, + ForeDiameter: { + type: Number, + required: true + }, + AftDiameter: { + type: Number, + required: true + } + }, + Fins: { + Count: { + type: Number, + required: true + }, + Span: { + type: Number, + required: true + }, + RootChord: { + type: Number, + required: true + }, + TipChord: { + type: Number, + required: true + }, + Sweep: { + type: Number, + required: true + }, + Thickness: { + type: Number, + required: true + } + } + }, + { + versionKey: false, + timestamps: true + } +); + +export interface IRocketSimModelModel extends IRocketSimModel, Document { }; + +export const RocketSimModelSchema = new Schema( + { + Name: { + type: String, + required: true + }, + DryMass: { + type: Number, + required: true, + validator: (mass: number) => { + return mass > 0 && !isNaN(mass); + } + }, + WetMass: { + type: Number, + required: true, + validator: (mass: number) => { + return mass > 0 && !isNaN(mass); + } + }, + FuselageLength: { + type: Number, + required: true, + validator: (length: number) => { + return length > 0 && !isNaN(length); + } + }, + FuselageDiameter: { + type: Number, + required: true, + validator: (diameter: number) => { + return diameter > 0 && !isNaN(diameter); + } + }, + RocketLength: { + type: Number, + required: true, + validator: (length: number) => { + return length > 0 && !isNaN(length); + } + }, + CenterOfGravity: { + type: Number, + required: true + }, + CenterOfPressure: { + type: Number, + required: true + }, + AeroDimensions: { + type: AeroDimensions, + required: false + } + }, + { + versionKey: false, + timestamps: true + } +); + +export const RocketSimModel = mongoose.model("RocketSimModel", RocketSimModelSchema); \ No newline at end of file diff --git a/services/server/src/routes/RocketSimRoute.ts b/services/server/src/routes/RocketSimRoute.ts new file mode 100644 index 000000000..cb5fe5e19 --- /dev/null +++ b/services/server/src/routes/RocketSimRoute.ts @@ -0,0 +1,22 @@ +import express from 'express'; +import controller from '../controllers/Generic'; +import { RocketSimModel } from '../models/RocketSimModel'; + +const router = express.Router(); + +// GET all data config +router.get('/', controller.getAll(RocketSimModel)); + +// GET single data config +router.get('/:id', controller.get(RocketSimModel)); + +// POST new data config +router.post('/', controller.create(RocketSimModel)); + +// UPDATE a data config +router.patch('/:id', controller.update(RocketSimModel)); + +// DELETE a data config +router.delete('/:id', controller.deleteOne(RocketSimModel)); + +export = router; \ No newline at end of file diff --git a/services/server/src/server.ts b/services/server/src/server.ts index 33282953c..a85ca27d8 100644 --- a/services/server/src/server.ts +++ b/services/server/src/server.ts @@ -8,6 +8,7 @@ import RocketRoute from './routes/RocketRoute'; import ComponentRoute from './routes/ComponentRoute'; import MissionRoute from './routes/MissionRoute'; import DataConfigRoute from './routes/DataConfigRoute'; +import RocketSimRoute from './routes/RocketSimRoute'; const router = express(); @@ -58,6 +59,7 @@ const StartServer = () => { router.use('/component', ComponentRoute); router.use('/dataConfig', DataConfigRoute); router.use('/mission', MissionRoute); + router.use('/rocketSim', RocketSimRoute); /** Healthcheck */ router.get('/ping', (req, res, next) => res.status(200).json({ ping: 'pong' }));