diff --git a/cdk/api_gateway/api_documentation/.openapi-generator/FILES b/cdk/api_gateway/api_documentation/.openapi-generator/FILES index 70dc6d58..7461813c 100644 --- a/cdk/api_gateway/api_documentation/.openapi-generator/FILES +++ b/cdk/api_gateway/api_documentation/.openapi-generator/FILES @@ -1,4 +1,3 @@ -.openapi-generator-ignore Apis/DefaultApi.md Models/EquipmentUsage.md Models/EquipmentUsageProperties.md diff --git a/cdk/api_gateway/api_documentation/Models/Printer3DInfo.md b/cdk/api_gateway/api_documentation/Models/Printer3DInfo.md index d74cdb0d..e179d9ed 100644 --- a/cdk/api_gateway/api_documentation/Models/Printer3DInfo.md +++ b/cdk/api_gateway/api_documentation/Models/Printer3DInfo.md @@ -6,10 +6,10 @@ | **printer\_name** | **String** | The name of the printer used. | [default to null] | | **print\_name** | **String** | A name for the printed object. | [default to null] | | **print\_duration** | **Integer** | The duration of a 3d print in minutes. | [default to null] | -| **print\_mass** | **Double** | The mass of an object. | [optional] [default to null] | -| **print\_mass\_estimate** | **Double** | The mass of an object. | [optional] [default to null] | +| **print\_mass** | **Double** | The actual mass of the print in grams. Use an empty string to specify an unknown mass. | [optional] [default to null] | +| **print\_mass\_estimate** | **Double** | The expected mass of the print in grams. | [optional] [default to null] | | **resin\_volume** | **Double** | The displacement volume (in mL) of an object. | [optional] [default to null] | -| **resin\_type** | **String** | | [optional] [default to null] | +| **resin\_type** | **String** | The type of resin used in the print. | [optional] [default to null] | | **print\_status** | **String** | An enum of strings of possible print statuses. | [default to null] | | **print\_notes** | **String** | Notes about the print. | [optional] [default to null] | diff --git a/cdk/api_gateway/api_documentation/documentation.yaml b/cdk/api_gateway/api_documentation/documentation.yaml index bd1fe65d..d7d4b868 100644 --- a/cdk/api_gateway/api_documentation/documentation.yaml +++ b/cdk/api_gateway/api_documentation/documentation.yaml @@ -15,7 +15,12 @@ info: overwriting as the primary (and secondary) identifiers are provided by request bodies and not generated internally. POST methods will specify "Fails on existing UserID" or "Fails on existing UserID and Timestamp" if it fails to case 1 or 2 - respectively. + respectively. Additionally, due to the want for consistency when storing and + retrieving data, ALL values passed in request bodies MUST be strings. In this + documentation, the expected data types will be listed to provide a reference + to infer the correct data types when parsing returned data. Any fields that can + have an empty value will declared what the string representation of that is + in its description. version: "1.0.0" servers: @@ -401,12 +406,6 @@ components: - "Complete" - "Incomplete" - mass: - description: The mass of an object. - type: number - format: double - minimum: 0 - displacement_volume: description: The displacement volume (in mL) of an object. type: number @@ -449,12 +448,21 @@ components: print_duration: $ref: '#/components/schemas/printDuration' print_mass: - $ref: '#/components/schemas/mass' + description: | + The actual mass of the print in grams. Use an empty string to specify an unknown mass. + type: number + format: double + minimum: 0 print_mass_estimate: - $ref: '#/components/schemas/mass' + description: | + The expected mass of the print in grams. + type: number + format: double + minimum: 0 resin_volume: $ref: '#/components/schemas/displacement_volume' resin_type: + description: The type of resin used in the print. type: string minLength: 1 print_status: @@ -474,6 +482,7 @@ components: anyOf: - required: - print_mass_estimate + - print_mass - required: - resin_volume - resin_type diff --git a/cdk/api_gateway/lambda_code/equipment_handler/equipment_handler.py b/cdk/api_gateway/lambda_code/equipment_handler/equipment_handler.py index a05834ae..b75667d5 100644 --- a/cdk/api_gateway/lambda_code/equipment_handler/equipment_handler.py +++ b/cdk/api_gateway/lambda_code/equipment_handler/equipment_handler.py @@ -197,10 +197,6 @@ def create_user_equipment_usage(self, data: dict): # Always force GSI_ATTRIBUTE_NAME key to have value of "1" data[GSI_ATTRIBUTE_NAME] = "1" - # Make sure "print_mass" field at least exists - if "print_mass" not in data: - data["print_mass"] = "" - # Actually try putting the item into the table try: self.equipment_table.put_item( @@ -437,7 +433,7 @@ def validateEquipmentRequestBody(self, data: dict): general_printer_3d_info_fields: list[str] = ["printer_name", "print_name", "print_duration", "print_status", "print_notes"] # Required fields specific to FDM 3D Printers - fdm_printer_3d_required_fields: list[str] = ["print_mass_estimate"] + general_printer_3d_info_fields + fdm_printer_3d_required_fields: list[str] = ["print_mass_estimate", "print_mass"] + general_printer_3d_info_fields # Required fields specific to SLA 3D Printers sla_printer_3d_required_fields: list[str] = ["resin_volume", "resin_type"] + general_printer_3d_info_fields diff --git a/cdk/api_gateway/tests/test_equipment_handler.py b/cdk/api_gateway/tests/test_equipment_handler.py index 4a6d5409..6caf7740 100644 --- a/cdk/api_gateway/tests/test_equipment_handler.py +++ b/cdk/api_gateway/tests/test_equipment_handler.py @@ -417,7 +417,8 @@ def test_post_valid_fdm_printer_equipment_log(self, get_equipment_handler): "print_duration": "5", "print_status": "In Progress", "print_notes": "", - "print_mass_estimate": "5" + "print_mass_estimate": "5", + "print_mass": "", } request_body: dict = generate_request_body( diff --git a/site/visitor-console/src/components/EditModal.tsx b/site/visitor-console/src/components/EditModal.tsx index 089b1333..31e3d753 100644 --- a/site/visitor-console/src/components/EditModal.tsx +++ b/site/visitor-console/src/components/EditModal.tsx @@ -1,34 +1,11 @@ import { useState, useEffect } from "react"; import { Modal, Button } from "react-bootstrap"; -interface EquipmentLog { - user_id: string; - timestamp: string; - location: string; - equipment_type: string; - equipment_history: string; - project_name: string; - project_type: string; - project_details?: string; - department?: string; - class_number?: string; - faculty_name?: string; - project_sponsor?: string; - organization_affiliation?: string; - printer_name?: string; - print_name?: string; - print_duration?: string; - print_mass?: string; - print_mass_estimate?: string; - resin_volume?: string; - resin_type?: string; - print_status?: string; - print_notes?: string; - intern?: string; - satisfaction?: string; - difficulties?: string; - issue_description?: string; -} +import { FDM_PRINTER_STRING, SLA_PRINTER_STRING } from "../library/constants"; + +import { EquipmentLog } from "../library/types"; + +import { is3DPrinter } from "../library/constants"; interface EditModalProps { show: boolean; @@ -41,24 +18,23 @@ const EditModal = ({ show, handleClose, log, handleSave }: EditModalProps) => { const [printStatus, setPrintStatus] = useState(""); const [printNotes, setPrintNotes] = useState(""); - const is3DPrinter = - log?.equipment_type === "FDM 3D Printer (Plastic)" || - log?.equipment_type === "SLA 3D Printer (Resin)"; - useEffect(() => { - if (log && is3DPrinter) { - setPrintStatus(log.print_status || ""); - setPrintNotes(log.print_notes || ""); + if (log && is3DPrinter(log?.equipment_type)) { + setPrintStatus(log?.printer_3d_info?.print_status || ""); + setPrintNotes(log?.printer_3d_info?.print_notes || ""); } - }, [log, is3DPrinter]); + }, [log]); const handleSaveClick = () => { if (log) { const updatedLog = { ...log, - ...(is3DPrinter && { - print_status: printStatus, - print_notes: printNotes, + ...(log.printer_3d_info && { + printer_3d_info: { + ...log.printer_3d_info, + print_status: printStatus, + print_notes: printNotes, + }, }), }; handleSave(updatedLog); @@ -75,13 +51,7 @@ const EditModal = ({ show, handleClose, log, handleSave }: EditModalProps) => { {log ? ( <> {Object.entries(log).map(([key, value]) => { - if ( - key === "print_status" || - key === "print_notes" || - key === "_ignore" || - value === undefined || - value === null - ) { + if (key === "_ignore" || value === undefined || value === null) { return null; } @@ -111,7 +81,7 @@ const EditModal = ({ show, handleClose, log, handleSave }: EditModalProps) => { })} {/* Editable fields only for 3D printers */} - {is3DPrinter && ( + {is3DPrinter(log.equipment_type) && ( <>
diff --git a/site/visitor-console/src/library/types.ts b/site/visitor-console/src/library/types.ts index 1889c87a..53c6a95e 100644 --- a/site/visitor-console/src/library/types.ts +++ b/site/visitor-console/src/library/types.ts @@ -39,3 +39,7 @@ export interface EquipmentSchema { difficulties?: string; issue_description?: string; } + +export interface EquipmentLog extends EquipmentSchema { + _ignore?: string; +} diff --git a/site/visitor-console/src/pages/EquipmentForm.tsx b/site/visitor-console/src/pages/EquipmentForm.tsx index a8339a83..6bf05ffd 100644 --- a/site/visitor-console/src/pages/EquipmentForm.tsx +++ b/site/visitor-console/src/pages/EquipmentForm.tsx @@ -44,6 +44,12 @@ const stageSchemas = [ then: yup.string().required(), otherwise: yup.string().notRequired(), }), + // Always default print mass to the unknown value as the print isn't finished + print_mass: yup.string().when("equipment_type", { + is: FDM_PRINTER_STRING, + then: yup.string().default(""), + otherwise: yup.string().notRequired(), + }), // Specifically require resin volume and type when using resin 3d printers resin_volume: yup.string().when("equipment_type", { diff --git a/site/visitor-console/src/pages/EquipmentUsage.tsx b/site/visitor-console/src/pages/EquipmentUsage.tsx index 88a82af1..0344ff31 100644 --- a/site/visitor-console/src/pages/EquipmentUsage.tsx +++ b/site/visitor-console/src/pages/EquipmentUsage.tsx @@ -5,11 +5,7 @@ import { withAuthenticator } from "@aws-amplify/ui-react"; import { Link } from "react-router-dom"; import EditModal from "../components/EditModal"; -import { EquipmentSchema } from "../library/types"; - -interface EquipmentLog extends EquipmentSchema { - _ignore?: string; -} +import { EquipmentLog } from "../library/types"; const EquipmentUsage = () => { const [searchUsername, setSearchUsername] = useState(""); @@ -39,7 +35,7 @@ const EquipmentUsage = () => { } const data = await response.json(); - console.log(data); + console.log(`Data received:\n${JSON.stringify(data, null, 2)}`); const logs = Array.isArray(data.equipment_logs) ? data.equipment_logs : []; @@ -65,7 +61,7 @@ const EquipmentUsage = () => { setSelectedLog(null); }; - const handleSave = (updatedLog: EquipmentLog) => { + const handleSave = async (updatedLog: EquipmentLog) => { setEquipmentLogs((prevLogs) => prevLogs.map((log) => log.timestamp === updatedLog.timestamp && @@ -74,6 +70,40 @@ const EquipmentUsage = () => { : log ) ); + + console.log(JSON.stringify(updatedLog, null, 2)); + + try { + const user_id = updatedLog.user_id; + delete updatedLog.user_id; + + const response = await fetch(`${api_endpoint}/equipment/${user_id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + "X-Api-Key": import.meta.env.VITE_BACKEND_KEY, + }, + body: JSON.stringify(updatedLog), + }); + + if (response.ok) { + const responseData = await response.json(); + console.log("Data successfully sent to the API:", responseData); + } else { + const errorText = await response.text(); + console.error( + "Failed to send data to the API:", + response.status, + errorText + ); + console.log("Failed to update the equipment log."); + } + } catch (error) { + console.error( + "An error occurred while updating the equipment log:", + error + ); + } }; const filteredLogs = equipmentLogs.filter((log) =>