From 6240c7b2d3c72ca688f6ad340776ecac411e8a99 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Fri, 24 Jan 2025 17:49:15 -0500 Subject: [PATCH 01/16] Add data validation for commands --- backend/data/data_models.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/data/data_models.py b/backend/data/data_models.py index 68adddb..f7f2a86 100644 --- a/backend/data/data_models.py +++ b/backend/data/data_models.py @@ -33,8 +33,14 @@ def validate_params_format(self): The format of the comma seperated values is "data1,data2" so no spaces between data and the commas. """ # TODO: (Member) Implement this method - return self - + if (self.params == None and self.format == None): + return self + elif (self.params == None or self.format == None): + raise(ValueError) + elif (len(self.params.split(",")) == len(self.format.split(","))): + return self + else: + raise(ValueError) class Command(BaseSQLModel, table=True): """ From c463b13bda9092a96fa667213aed44dcad07eff7 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 12:24:01 -0500 Subject: [PATCH 02/16] implement create command --- backend/api/endpoints/command.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/api/endpoints/command.py b/backend/api/endpoints/command.py index 583ea5a..1ad8e52 100644 --- a/backend/api/endpoints/command.py +++ b/backend/api/endpoints/command.py @@ -22,8 +22,8 @@ def get_commands(db: Session = Depends(get_db)): items = db.exec(query).all() return {"data": items} - -@command_router.post("/", response_model=CommandSingleResponse) +#, response_model=CommandSingleResponse +@command_router.post("/") def create_command(payload: CommandRequest): """ Creates an item with the given payload in the database and returns this payload after pulling it from the database @@ -32,7 +32,23 @@ def create_command(payload: CommandRequest): @return returns a json object with field of "data" under which there is the payload now pulled from the database """ # TODO:(Member) Implement this endpoint - + + # Find number of commands in database + db = get_db() + query = select(Command) + items = db.exec(query).all() + num_commands = len(items) + + command = Command ( + id=num_commands + 1, + command_type=payload.command_type, # Replace with appropriate maincommand.id + params=payload.params, # Replace with appropriate parameters + ) + + db.add(command) + + return {"data": command} + @command_router.delete("/{id}", response_model=CommandListResponse) From dcd195bfb28c4830116d8243f30a250b93976e2e Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 14:10:34 -0500 Subject: [PATCH 03/16] implement delete command --- backend/api/endpoints/command.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/backend/api/endpoints/command.py b/backend/api/endpoints/command.py index 1ad8e52..4c02267 100644 --- a/backend/api/endpoints/command.py +++ b/backend/api/endpoints/command.py @@ -22,9 +22,8 @@ def get_commands(db: Session = Depends(get_db)): items = db.exec(query).all() return {"data": items} -#, response_model=CommandSingleResponse -@command_router.post("/") -def create_command(payload: CommandRequest): +@command_router.post("/", response_model=CommandSingleResponse) +def create_command(payload: CommandRequest, db: Session = Depends(get_db)): """ Creates an item with the given payload in the database and returns this payload after pulling it from the database @@ -34,25 +33,25 @@ def create_command(payload: CommandRequest): # TODO:(Member) Implement this endpoint # Find number of commands in database - db = get_db() query = select(Command) items = db.exec(query).all() num_commands = len(items) command = Command ( - id=num_commands + 1, - command_type=payload.command_type, # Replace with appropriate maincommand.id - params=payload.params, # Replace with appropriate parameters + id=1+num_commands, + command_type=payload.command_type, + params=payload.params, ) db.add(command) + db.commit() + db.refresh(command) return {"data": command} - @command_router.delete("/{id}", response_model=CommandListResponse) -def delete_command(id: int): +def delete_command(id: int, db: Session = Depends(get_db)): """ Deletes the item with the given id if it exists. Otherwise raises a 404 error. @@ -60,3 +59,14 @@ def delete_command(id: int): @return returns the list of commands after deleting the item """ # TODO:(Member) Implement this endpoint + try: + query = select(Command).where(Command.id == id) + command = db.exec(query).one() + db.delete(command) + db.commit() + + query2 = select(Command).where(Command.id != id) + items = db.exec(query2).all() + return {"data": items} + except: + raise HTTPException(status_code=404, detail="Item does not exist") \ No newline at end of file From bde659e65cec9e67ff934382c5696ae245d03527 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 15:13:29 -0500 Subject: [PATCH 04/16] add logger middleware --- backend/api/middlewares/logger_middleware.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/backend/api/middlewares/logger_middleware.py b/backend/api/middlewares/logger_middleware.py index 44daa5d..6aaf8ba 100644 --- a/backend/api/middlewares/logger_middleware.py +++ b/backend/api/middlewares/logger_middleware.py @@ -3,6 +3,12 @@ from fastapi import Request, Response from starlette.middleware.base import BaseHTTPMiddleware +from ...utils.logging import logger + +import time +import json +from datetime import datetime + class LoggerMiddleware(BaseHTTPMiddleware): async def dispatch( @@ -18,5 +24,14 @@ async def dispatch( @return Response from endpoint """ # TODO:(Member) Finish implementing this method + logger.info(f'{request.method} {request.url.path}') + #logger.info(f"Request Parameters: {request.path_params}") + current_datetime = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + logger.info(f"Datetime of request: {current_datetime}") + + start = time.perf_counter() response = await call_next(request) + duration = time.perf_counter() - start + logger.info(f"Duration: {duration} seconds") + return response From dafe1d43c6b02a68b1798ca017d700d9a5c64206 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 15:29:10 -0500 Subject: [PATCH 05/16] finish onboarding for backend --- test/backend/test_api.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/backend/test_api.py b/test/backend/test_api.py index c859834..3b9546e 100644 --- a/test/backend/test_api.py +++ b/test/backend/test_api.py @@ -3,6 +3,8 @@ from backend.data.enums import CommandStatus from backend.utils.time import to_unix_time +from datetime import datetime + def test_get_commands(fastapi_test_client: TestClient, commands_json): with fastapi_test_client as client: @@ -24,8 +26,10 @@ def test_create_command(fastapi_test_client: TestClient): assert result.get("status") == CommandStatus.PENDING.value assert result.get("params") == "123456789" # TODO: Figure out a better way to check the times - assert result.get("created_on") - assert result.get("updated_on") + created_on_dt = datetime.fromisoformat(result.get("created_on")) + updated_on_dt = datetime.fromisoformat(result.get("updated_on")) + assert isinstance(created_on_dt, datetime) + assert isinstance(updated_on_dt, datetime) def test_delete_command_fail(fastapi_test_client: TestClient): with fastapi_test_client as client: From cb2bfe615e9537806bb8cf8732cb9b18bd2919ba Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 18:04:17 -0500 Subject: [PATCH 06/16] implement delete command --- frontend/src/display/command_api.ts | 10 ++++++++++ frontend/src/display/table.tsx | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/frontend/src/display/command_api.ts b/frontend/src/display/command_api.ts index f5ce725..3a9eb24 100644 --- a/frontend/src/display/command_api.ts +++ b/frontend/src/display/command_api.ts @@ -20,3 +20,13 @@ export const getCommands = async (): Promise => { * @param id: command to delete * @returns Promise: list of commands after the command with the given id was deleted */ + +export const deleteCommand = async(id: number): Promise => { + try { + const { data } = await axios.delete(`${API_URL}/commands/${id}`) + return data; + } catch (error) { + console.error(error) + throw error + } +} diff --git a/frontend/src/display/table.tsx b/frontend/src/display/table.tsx index 9f95a77..2fee949 100644 --- a/frontend/src/display/table.tsx +++ b/frontend/src/display/table.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from "react" import { CommandResponse } from "../data/response" -import { getCommands } from "./command_api" +import { getCommands, deleteCommand } from "./command_api" import CommandRow from "./row" const CommandTable = () => { @@ -19,7 +19,12 @@ const CommandTable = () => { return () => { // TODO: (Member) Handle delete logic here // You will need to create a function in `command_api.ts` before you can finish this part. + const deleteCommandFn = async () => { + const data = await deleteCommand(id); + setCommands(data.data) + } + deleteCommandFn(); } } From 957b4cc784d9484ef3f16af67ef22b4aebfc890b Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 19:10:18 -0500 Subject: [PATCH 07/16] implement create command --- frontend/src/data/request.ts | 4 +-- frontend/src/input/command_input.tsx | 47 ++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/frontend/src/data/request.ts b/frontend/src/data/request.ts index d069f36..8ff9f61 100644 --- a/frontend/src/data/request.ts +++ b/frontend/src/data/request.ts @@ -1,6 +1,6 @@ export interface CommandRequest { - name: string + command_type: number, params: string | null - format: string | null + //format: string | null } diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 2cdbb5e..c79dbd2 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -1,26 +1,55 @@ import "./command_input.css" +import { useState, useEffect } from "react" +import { MainCommandResponse } from "../data/response" +import { createCommand, getMainCommands } from "./input_api" + const CommandInput = () => { // TODO: (Member) Setup state and useEffect calls here + const [commandType, setCommandType] = useState("1") + const [params, setParams] = useState("") + const [mainCommands, setMainCommands] = useState([]) + + + useEffect(() => { + const setMainCommandsFn = async () => { + const data = await getMainCommands() + setMainCommands(data.data) + } + + setMainCommandsFn(); + }, []) + + + const handleSubmit = (e: React.FormEvent) => { + // TODO:(Member) Submit to your post endpoint + e.preventDefault(); + const reqBody = { + command_type: +commandType, + params: params, + }; + + //console.log('Req body:', reqBody); + + const createCommandFn = async () => { + await createCommand(reqBody); + } - const handleSubmit = () => { - // TODO:(Member) Submit to your post endpoint + createCommandFn(); } return ( <> -
+
- setCommandType(e.target.value)}>{/* TODO: (Member) Display the list of commands based on the get commands request*/} + {mainCommands.map(cmd => ())}
- {/* TODO: (Member) Add input handling here if the selected command has a param input*/} - + setParams(e.target.value)}/> {/* TODO: (Member) Add input handling here if the selected command has a param input*/} +
From 2fa2963f3d63e2774aaf9e083dd7fe735b13c9ca Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 25 Jan 2025 21:09:39 -0500 Subject: [PATCH 08/16] fix create command --- frontend/src/input/command_input.tsx | 77 ++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 11 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index c79dbd2..686032a 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -6,53 +6,108 @@ import { createCommand, getMainCommands } from "./input_api" const CommandInput = () => { // TODO: (Member) Setup state and useEffect calls here - const [commandType, setCommandType] = useState("1") - const [params, setParams] = useState("") const [mainCommands, setMainCommands] = useState([]) - + const [commandType, setCommandType] = useState(null) + const [params, setParams] = useState<{[key: string] : string}>({}) useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() setMainCommands(data.data) - } + setCommandType(data.data[0]) + + const parameters = commandType?.params?.split(",") || [] + let paramsObject : { [key: string]: string } = {} + for(const param of parameters) { + paramsObject[param] = "" + } + setParams(paramsObject); + } setMainCommandsFn(); }, []) const handleSubmit = (e: React.FormEvent) => { - // TODO:(Member) Submit to your post endpoint + // TODO:(Member) Submit to your post endpoint e.preventDefault(); + + //check if parameters are valid + const allParams = commandType?.params?.split(",") || []; + const paramsList = [] + for (const param of allParams) { + if (!params[param]) { + alert("Parameter missing") + return; + } + paramsList.push(params[param]) + } + + const reqBody = { - command_type: +commandType, - params: params, + command_type: commandType?.id || 0, + params: paramsList.join(",") }; //console.log('Req body:', reqBody); + const createCommandFn = async () => { await createCommand(reqBody); + window.location.reload(); } - createCommandFn(); } + /* + setParams(e.target.value)}/> + {// Use parameters of command type to output input boxes} + { .params.map(param => ({cmd.name}))} + */ + //console.log(`Command: `, commandType) + //console.log(`Parameters: `, params) + + const changeCommandType = (e: any) => { + setCommandType(mainCommands.find(cmd => cmd.id == +e.target.value) || null) + const parameters = commandType?.params?.split(",") || [] + let paramsObject : { [key: string]: string } = {} + for(const param of parameters) { + paramsObject[param] = "" + } + setParams(paramsObject); + } + + const changeParam = (e: any) => { + const param = e.target.id + const value = e.target.value + + setParams(prevParams => ({ + ...prevParams, + [param]: value, + })); + } + return ( <>
- {mainCommands.map(cmd => ())}
- setParams(e.target.value)}/> {/* TODO: (Member) Add input handling here if the selected command has a param input*/} + + {/* TODO: (Member) Add input handling here if the selected command has a param input*/} + {commandType && + commandType.params?.split(",").map((param) => ())}
- + ) } From 1ff2486a0887d27eb554738bdef04a66923948e8 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 1 Feb 2025 16:04:11 -0500 Subject: [PATCH 09/16] make requested changes --- backend/api/endpoints/command.py | 9 +++------ backend/api/middlewares/logger_middleware.py | 2 +- backend/data/data_models.py | 12 ++++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/backend/api/endpoints/command.py b/backend/api/endpoints/command.py index 4c02267..85c385d 100644 --- a/backend/api/endpoints/command.py +++ b/backend/api/endpoints/command.py @@ -35,10 +35,8 @@ def create_command(payload: CommandRequest, db: Session = Depends(get_db)): # Find number of commands in database query = select(Command) items = db.exec(query).all() - num_commands = len(items) command = Command ( - id=1+num_commands, command_type=payload.command_type, params=payload.params, ) @@ -59,14 +57,13 @@ def delete_command(id: int, db: Session = Depends(get_db)): @return returns the list of commands after deleting the item """ # TODO:(Member) Implement this endpoint - try: - query = select(Command).where(Command.id == id) - command = db.exec(query).one() + command = db.get(Command, id) + if command: db.delete(command) db.commit() query2 = select(Command).where(Command.id != id) items = db.exec(query2).all() return {"data": items} - except: + else: raise HTTPException(status_code=404, detail="Item does not exist") \ No newline at end of file diff --git a/backend/api/middlewares/logger_middleware.py b/backend/api/middlewares/logger_middleware.py index 6aaf8ba..d658882 100644 --- a/backend/api/middlewares/logger_middleware.py +++ b/backend/api/middlewares/logger_middleware.py @@ -3,7 +3,7 @@ from fastapi import Request, Response from starlette.middleware.base import BaseHTTPMiddleware -from ...utils.logging import logger +from backend.utils.logging import logger import time import json diff --git a/backend/data/data_models.py b/backend/data/data_models.py index f7f2a86..82fb7df 100644 --- a/backend/data/data_models.py +++ b/backend/data/data_models.py @@ -33,18 +33,18 @@ def validate_params_format(self): The format of the comma seperated values is "data1,data2" so no spaces between data and the commas. """ # TODO: (Member) Implement this method - if (self.params == None and self.format == None): + if self.params is None and self.format is None: return self - elif (self.params == None or self.format == None): - raise(ValueError) - elif (len(self.params.split(",")) == len(self.format.split(","))): + elif self.params is None or self.format is None: + raise ValueError() + elif len(self.params.split(",")) == len(self.format.split(",")): return self else: - raise(ValueError) + raise ValueError() class Command(BaseSQLModel, table=True): """ - An instance of a MainCommand. + An instance off a MainCommand. This table holds the data related to actual commands sent from the ground station up to the OBC. """ From db6bb393acdbb99d61cac715ea75be852020e7cd Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sat, 1 Feb 2025 19:28:42 -0500 Subject: [PATCH 10/16] complete new changes for backend --- backend/api/endpoints/command.py | 21 +++++++++----------- backend/api/middlewares/logger_middleware.py | 7 +++---- backend/data/data_models.py | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/backend/api/endpoints/command.py b/backend/api/endpoints/command.py index 85c385d..19ca249 100644 --- a/backend/api/endpoints/command.py +++ b/backend/api/endpoints/command.py @@ -36,10 +36,7 @@ def create_command(payload: CommandRequest, db: Session = Depends(get_db)): query = select(Command) items = db.exec(query).all() - command = Command ( - command_type=payload.command_type, - params=payload.params, - ) + command = Command (**dict(payload)) db.add(command) db.commit() @@ -58,12 +55,12 @@ def delete_command(id: int, db: Session = Depends(get_db)): """ # TODO:(Member) Implement this endpoint command = db.get(Command, id) - if command: - db.delete(command) - db.commit() + if command is None: + raise HTTPException(status_code=404, detail="Item does not exist") + + db.delete(command) + db.commit() - query2 = select(Command).where(Command.id != id) - items = db.exec(query2).all() - return {"data": items} - else: - raise HTTPException(status_code=404, detail="Item does not exist") \ No newline at end of file + query2 = select(Command).where(Command.id != id) + items = db.exec(query2).all() + return {"data": items} diff --git a/backend/api/middlewares/logger_middleware.py b/backend/api/middlewares/logger_middleware.py index d658882..596680d 100644 --- a/backend/api/middlewares/logger_middleware.py +++ b/backend/api/middlewares/logger_middleware.py @@ -5,8 +5,7 @@ from backend.utils.logging import logger -import time -import json +from time import perf_counter from datetime import datetime @@ -29,9 +28,9 @@ async def dispatch( current_datetime = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") logger.info(f"Datetime of request: {current_datetime}") - start = time.perf_counter() + start = perf_counter() response = await call_next(request) - duration = time.perf_counter() - start + duration = perf_counter() - start logger.info(f"Duration: {duration} seconds") return response diff --git a/backend/data/data_models.py b/backend/data/data_models.py index 82fb7df..342901c 100644 --- a/backend/data/data_models.py +++ b/backend/data/data_models.py @@ -36,11 +36,11 @@ def validate_params_format(self): if self.params is None and self.format is None: return self elif self.params is None or self.format is None: - raise ValueError() + raise ValueError("Parameters do not match required format") elif len(self.params.split(",")) == len(self.format.split(",")): return self else: - raise ValueError() + raise ValueError("Parameters do not match required format") class Command(BaseSQLModel, table=True): """ From 2822edb31ade53655a6f41cadcc20c9807996e94 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sun, 2 Feb 2025 18:49:52 -0500 Subject: [PATCH 11/16] complete new changes for frontend --- frontend/src/input/command_input.tsx | 64 +++++++++++++--------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 686032a..a3ed75f 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -7,40 +7,43 @@ import { createCommand, getMainCommands } from "./input_api" const CommandInput = () => { // TODO: (Member) Setup state and useEffect calls here const [mainCommands, setMainCommands] = useState([]) - const [commandType, setCommandType] = useState(null) - const [params, setParams] = useState<{[key: string] : string}>({}) + const [commandType, setCommandType] = useState({id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0}) + const [params, setParams] = useState>(new Map()); useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() + if(!data.data) { + alert("Error occured. Please try again later.") + } setMainCommands(data.data) - setCommandType(data.data[0]) - const parameters = commandType?.params?.split(",") || [] - let paramsObject : { [key: string]: string } = {} + const parameters = data.data[0].params?.split(",") || [] + let paramsObject : Map = new Map() + for(const param of parameters) { - paramsObject[param] = "" + paramsObject.set(param, "") } setParams(paramsObject); } setMainCommandsFn(); }, []) - + const handleSubmit = (e: React.FormEvent) => { // TODO:(Member) Submit to your post endpoint e.preventDefault(); - //check if parameters are valid + //Check if parameters are valid const allParams = commandType?.params?.split(",") || []; const paramsList = [] for (const param of allParams) { - if (!params[param]) { + if (!params.get(param)) { alert("Parameter missing") return; } - paramsList.push(params[param]) + paramsList.push(params.get(param)) } @@ -49,8 +52,6 @@ const CommandInput = () => { params: paramsList.join(",") }; - //console.log('Req body:', reqBody); - const createCommandFn = async () => { await createCommand(reqBody); @@ -59,32 +60,26 @@ const CommandInput = () => { createCommandFn(); } - /* - setParams(e.target.value)}/> - {// Use parameters of command type to output input boxes} - { .params.map(param => ({cmd.name}))} - */ - //console.log(`Command: `, commandType) - //console.log(`Parameters: `, params) - - const changeCommandType = (e: any) => { - setCommandType(mainCommands.find(cmd => cmd.id == +e.target.value) || null) - const parameters = commandType?.params?.split(",") || [] - let paramsObject : { [key: string]: string } = {} + const changeCommandType = (e: React.ChangeEvent) => { + const type : MainCommandResponse = mainCommands.find(cmd => cmd.id == +e.target.value) || {id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0} + setCommandType(type) + const parameters = type?.params?.split(",") || [] + let paramsObject : Map = new Map() for(const param of parameters) { - paramsObject[param] = "" + paramsObject.set(param, "") } - setParams(paramsObject); + setParams(paramsObject) } - const changeParam = (e: any) => { + const changeParam = (e: React.ChangeEvent) => { const param = e.target.id const value = e.target.value - setParams(prevParams => ({ - ...prevParams, - [param]: value, - })); + setParams(prevParams => { + const newParams = new Map(prevParams); + newParams.set(param, value); + return newParams; + }) } return ( @@ -95,7 +90,7 @@ const CommandInput = () => { {/* TODO: (Member) Display the list of commands based on the get commands request*/} @@ -103,7 +98,8 @@ const CommandInput = () => { {/* TODO: (Member) Add input handling here if the selected command has a param input*/} {commandType && - commandType.params?.split(",").map((param) => ())} + commandType.params?.split(",").map((param) => ())} + @@ -111,4 +107,4 @@ const CommandInput = () => { ) } -export default CommandInput; +export default CommandInput; \ No newline at end of file From cc0b376730d64971b9b151ef5eae55436533162b Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Sun, 2 Feb 2025 18:49:52 -0500 Subject: [PATCH 12/16] complete new changes for frontend --- frontend/src/input/command_input.tsx | 75 +++++++++++++++------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 686032a..e077e31 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -7,40 +7,50 @@ import { createCommand, getMainCommands } from "./input_api" const CommandInput = () => { // TODO: (Member) Setup state and useEffect calls here const [mainCommands, setMainCommands] = useState([]) - const [commandType, setCommandType] = useState(null) - const [params, setParams] = useState<{[key: string] : string}>({}) + const [commandType, setCommandType] = useState({id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0}) + const [params, setParams] = useState>(new Map()); useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() + if(!data.data) { + alert("Error occured. Please try again later.") + } setMainCommands(data.data) - setCommandType(data.data[0]) - const parameters = commandType?.params?.split(",") || [] - let paramsObject : { [key: string]: string } = {} + const parameters = data.data[0].params?.split(",") || [] + let paramsObject : Map = new Map() + for(const param of parameters) { - paramsObject[param] = "" + paramsObject.set(param, "") } setParams(paramsObject); } setMainCommandsFn(); }, []) - + const handleSubmit = (e: React.FormEvent) => { // TODO:(Member) Submit to your post endpoint e.preventDefault(); - //check if parameters are valid + //Check if parameters are valid const allParams = commandType?.params?.split(",") || []; const paramsList = [] + + let sendAlert = false + const missingParams = [] for (const param of allParams) { - if (!params[param]) { - alert("Parameter missing") - return; + if (!params.get(param)) { + sendAlert = true + missingParams.push(param) } - paramsList.push(params[param]) + paramsList.push(params.get(param)) + } + if(sendAlert) { + alert(`Parameters missing: ${missingParams.join(", ")}`) + return; } @@ -49,8 +59,6 @@ const CommandInput = () => { params: paramsList.join(",") }; - //console.log('Req body:', reqBody); - const createCommandFn = async () => { await createCommand(reqBody); @@ -59,32 +67,26 @@ const CommandInput = () => { createCommandFn(); } - /* - setParams(e.target.value)}/> - {// Use parameters of command type to output input boxes} - { .params.map(param => ({cmd.name}))} - */ - //console.log(`Command: `, commandType) - //console.log(`Parameters: `, params) - - const changeCommandType = (e: any) => { - setCommandType(mainCommands.find(cmd => cmd.id == +e.target.value) || null) - const parameters = commandType?.params?.split(",") || [] - let paramsObject : { [key: string]: string } = {} + const changeCommandType = (e: React.ChangeEvent) => { + const type : MainCommandResponse = mainCommands.find(cmd => cmd.id == +e.target.value) || {id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0} + setCommandType(type) + const parameters = type?.params?.split(",") || [] + let paramsObject : Map = new Map() for(const param of parameters) { - paramsObject[param] = "" + paramsObject.set(param, "") } - setParams(paramsObject); + setParams(paramsObject) } - const changeParam = (e: any) => { + const changeParam = (e: React.ChangeEvent) => { const param = e.target.id const value = e.target.value - setParams(prevParams => ({ - ...prevParams, - [param]: value, - })); + setParams(prevParams => { + const newParams = new Map(prevParams); + newParams.set(param, value); + return newParams; + }) } return ( @@ -95,7 +97,7 @@ const CommandInput = () => { {/* TODO: (Member) Display the list of commands based on the get commands request*/} @@ -103,7 +105,8 @@ const CommandInput = () => { {/* TODO: (Member) Add input handling here if the selected command has a param input*/} {commandType && - commandType.params?.split(",").map((param) => ())} + commandType.params?.split(",").map((param) => ())} + @@ -111,4 +114,4 @@ const CommandInput = () => { ) } -export default CommandInput; +export default CommandInput; \ No newline at end of file From fe95383703a3519cac6c92a3bf054bbc3348d519 Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Mon, 3 Feb 2025 13:19:53 -0500 Subject: [PATCH 13/16] finish frontend changes --- frontend/src/input/command_input.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index e077e31..8834323 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -13,8 +13,9 @@ const CommandInput = () => { useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() - if(!data.data) { + if(data.data.length == 0) { alert("Error occured. Please try again later.") + return } setMainCommands(data.data) setCommandType(data.data[0]) @@ -39,16 +40,14 @@ const CommandInput = () => { const allParams = commandType?.params?.split(",") || []; const paramsList = [] - let sendAlert = false const missingParams = [] for (const param of allParams) { if (!params.get(param)) { - sendAlert = true missingParams.push(param) } paramsList.push(params.get(param)) } - if(sendAlert) { + if(missingParams.length != 0) { alert(`Parameters missing: ${missingParams.join(", ")}`) return; } From 4a5fc2129f739dd94a04c0a4daa51659fc8e62fa Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Mon, 3 Feb 2025 13:20:03 -0500 Subject: [PATCH 14/16] finish frontend changes --- frontend/src/input/command_input.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 8834323..3752ddd 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -7,14 +7,14 @@ import { createCommand, getMainCommands } from "./input_api" const CommandInput = () => { // TODO: (Member) Setup state and useEffect calls here const [mainCommands, setMainCommands] = useState([]) - const [commandType, setCommandType] = useState({id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0}) + const [commandType, setCommandType] = useState(null) const [params, setParams] = useState>(new Map()); useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() if(data.data.length == 0) { - alert("Error occured. Please try again later.") + alert("Error occurred. Please try again later.") return } setMainCommands(data.data) @@ -67,9 +67,13 @@ const CommandInput = () => { } const changeCommandType = (e: React.ChangeEvent) => { - const type : MainCommandResponse = mainCommands.find(cmd => cmd.id == +e.target.value) || {id: 0, name: "", params: null, format: null, data_size: 0, total_size: 0} - setCommandType(type) - const parameters = type?.params?.split(",") || [] + const cmdType = mainCommands.find(cmd => cmd.id == +e.target.value) || null + if(!cmdType) { + alert("Error occurred. Please try again later.") + return + } + setCommandType(cmdType) + const parameters = cmdType?.params?.split(",") || [] let paramsObject : Map = new Map() for(const param of parameters) { paramsObject.set(param, "") @@ -96,7 +100,7 @@ const CommandInput = () => { {/* TODO: (Member) Display the list of commands based on the get commands request*/} From 54c6b5fee108e9b29068ea9cf94f25d6071ad26e Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Mon, 3 Feb 2025 13:41:26 -0500 Subject: [PATCH 15/16] minor change --- frontend/src/input/command_input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 3752ddd..11cc2ae 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -67,7 +67,7 @@ const CommandInput = () => { } const changeCommandType = (e: React.ChangeEvent) => { - const cmdType = mainCommands.find(cmd => cmd.id == +e.target.value) || null + const cmdType = mainCommands.find(cmd => cmd.id == +e.target.value) if(!cmdType) { alert("Error occurred. Please try again later.") return From b8fae6410b638cba9c10900cf7231486832562bf Mon Sep 17 00:00:00 2001 From: Jiatao Geng Date: Mon, 3 Feb 2025 20:08:45 -0500 Subject: [PATCH 16/16] make requested changes --- frontend/src/input/command_input.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/input/command_input.tsx b/frontend/src/input/command_input.tsx index 11cc2ae..f19f467 100644 --- a/frontend/src/input/command_input.tsx +++ b/frontend/src/input/command_input.tsx @@ -13,7 +13,7 @@ const CommandInput = () => { useEffect(() => { const setMainCommandsFn = async () => { const data = await getMainCommands() - if(data.data.length == 0) { + if(data.data.length === 0) { alert("Error occurred. Please try again later.") return } @@ -47,7 +47,7 @@ const CommandInput = () => { } paramsList.push(params.get(param)) } - if(missingParams.length != 0) { + if(missingParams.length !== 0) { alert(`Parameters missing: ${missingParams.join(", ")}`) return; } @@ -67,7 +67,7 @@ const CommandInput = () => { } const changeCommandType = (e: React.ChangeEvent) => { - const cmdType = mainCommands.find(cmd => cmd.id == +e.target.value) + const cmdType = mainCommands.find(cmd => cmd.id === +e.target.value) if(!cmdType) { alert("Error occurred. Please try again later.") return