From 3840a80f66ac919f319c4577b17bc46178a6fa29 Mon Sep 17 00:00:00 2001 From: samfreund Date: Wed, 14 Jan 2026 20:11:14 -0600 Subject: [PATCH 1/6] forceReload after OD models are modified --- .../settings/ObjectDetectionCard.vue | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue index db6e9d419e..7a32777d89 100644 --- a/photon-client/src/components/settings/ObjectDetectionCard.vue +++ b/photon-client/src/components/settings/ObjectDetectionCard.vue @@ -5,7 +5,7 @@ import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore"; import { type ObjectDetectionModelProperties } from "@/types/SettingTypes"; import PvDeleteModal from "@/components/common/pv-delete-modal.vue"; import { useTheme } from "vuetify"; -import { axiosPost } from "@/lib/PhotonUtils"; +import { axiosPost, forceReloadPage } from "@/lib/PhotonUtils"; const theme = useTheme(); const showImportDialog = ref(false); @@ -43,7 +43,7 @@ const handleImport = async () => { timeout: -1 }); - axiosPost("/objectdetection/import", "import an object detection model", formData, { + await axiosPost("/objectdetection/import", "import an object detection model", formData, { headers: { "Content-Type": "multipart/form-data" }, onUploadProgress: ({ progress }) => { const uploadPercentage = (progress || 0) * 100.0; @@ -70,12 +70,16 @@ const handleImport = async () => { importHeight.value = null; importWidth.value = null; importVersion.value = null; + + forceReloadPage(); }; const deleteModel = async (model: ObjectDetectionModelProperties) => { - axiosPost("/objectdetection/delete", "delete an object detection model", { + await axiosPost("/objectdetection/delete", "delete an object detection model", { modelPath: model.modelPath }); + + forceReloadPage(); }; const renameModel = async (model: ObjectDetectionModelProperties, newName: string) => { @@ -85,11 +89,13 @@ const renameModel = async (model: ObjectDetectionModelProperties, newName: strin timeout: -1 }); - axiosPost("/objectdetection/rename", "rename an object detection model", { + await axiosPost("/objectdetection/rename", "rename an object detection model", { modelPath: model.modelPath, newName: newName }); showRenameDialog.value.show = false; + + forceReloadPage(); }; // Filters out models that are not supported by the current backend, and returns a flattened list. @@ -115,19 +121,21 @@ const openExportIndividualModelPrompt = () => { }; const showNukeDialog = ref(false); -const nukeModels = () => { - axiosPost("/objectdetection/nuke", "clear and reset object detection models"); +const nukeModels = async () => { + await axiosPost("/objectdetection/nuke", "clear and reset object detection models"); + + forceReloadPage(); }; const showBulkImportDialog = ref(false); const importFile = ref(null); -const handleBulkImport = () => { +const handleBulkImport = async () => { if (importFile.value === null) return; const formData = new FormData(); formData.append("data", importFile.value); - axiosPost("/objectdetection/bulkimport", "import object detection models", formData, { + await axiosPost("/objectdetection/bulkimport", "import object detection models", formData, { headers: { "Content-Type": "multipart/form-data" }, onUploadProgress: ({ progress }) => { const uploadPercentage = (progress || 0) * 100.0; @@ -150,6 +158,8 @@ const handleBulkImport = () => { }); showImportDialog.value = false; importFile.value = null; + + forceReloadPage(); }; From 7eadc8cd06221529ff30267ad3728839b6d9cd7f Mon Sep 17 00:00:00 2001 From: samfreund Date: Wed, 14 Jan 2026 20:11:29 -0600 Subject: [PATCH 2/6] fix error in status check util --- photon-client/src/lib/PhotonUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/photon-client/src/lib/PhotonUtils.ts b/photon-client/src/lib/PhotonUtils.ts index 805f4731c2..04af8ba19d 100644 --- a/photon-client/src/lib/PhotonUtils.ts +++ b/photon-client/src/lib/PhotonUtils.ts @@ -22,7 +22,7 @@ export const statusCheck = async (timeout: number, ip?: string): Promise 0) { try { pollLimit--; - await axios.get(ip ? `http://${ip}/status` : "/status"); + await axios.get(ip ? `http://${ip}/api/status` : "/status"); return true; } catch { // Backend not ready yet, wait and retry From 74f16343ef2ac310bbdb3c7e6083adf5bb0e7848 Mon Sep 17 00:00:00 2001 From: samfreund Date: Wed, 14 Jan 2026 23:36:39 -0600 Subject: [PATCH 3/6] change rename to modify frontend value --- .../src/components/settings/ObjectDetectionCard.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue index 7a32777d89..721bca82cf 100644 --- a/photon-client/src/components/settings/ObjectDetectionCard.vue +++ b/photon-client/src/components/settings/ObjectDetectionCard.vue @@ -95,7 +95,11 @@ const renameModel = async (model: ObjectDetectionModelProperties, newName: strin }); showRenameDialog.value.show = false; - forceReloadPage(); + useSettingsStore().general.availableModels.forEach((m) => { + if (m.modelPath === model.modelPath) { + m.nickname = newName; + } + }); }; // Filters out models that are not supported by the current backend, and returns a flattened list. From 649c3e1624676454378b57291144778e8bb210f1 Mon Sep 17 00:00:00 2001 From: samfreund Date: Wed, 14 Jan 2026 23:48:18 -0600 Subject: [PATCH 4/6] change delete to modify frontend value --- photon-client/src/components/settings/ObjectDetectionCard.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue index 721bca82cf..5c81a202f1 100644 --- a/photon-client/src/components/settings/ObjectDetectionCard.vue +++ b/photon-client/src/components/settings/ObjectDetectionCard.vue @@ -79,7 +79,9 @@ const deleteModel = async (model: ObjectDetectionModelProperties) => { modelPath: model.modelPath }); - forceReloadPage(); + useSettingsStore().general.availableModels = useSettingsStore().general.availableModels.filter( + (m) => m.modelPath !== model.modelPath + ); }; const renameModel = async (model: ObjectDetectionModelProperties, newName: string) => { From e447595e055ea3afd7ac26aca6e48485d37f234e Mon Sep 17 00:00:00 2001 From: samfreund Date: Thu, 15 Jan 2026 00:06:09 -0600 Subject: [PATCH 5/6] final cleanup --- .../settings/ObjectDetectionCard.vue | 28 ++++++++----------- .../photonvision/server/RequestHandler.java | 18 ++++++++---- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue index 5c81a202f1..17c112c01e 100644 --- a/photon-client/src/components/settings/ObjectDetectionCard.vue +++ b/photon-client/src/components/settings/ObjectDetectionCard.vue @@ -5,7 +5,7 @@ import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore"; import { type ObjectDetectionModelProperties } from "@/types/SettingTypes"; import PvDeleteModal from "@/components/common/pv-delete-modal.vue"; import { useTheme } from "vuetify"; -import { axiosPost, forceReloadPage } from "@/lib/PhotonUtils"; +import { axiosPost } from "@/lib/PhotonUtils"; const theme = useTheme(); const showImportDialog = ref(false); @@ -26,7 +26,7 @@ const importWidth = ref(null); const importVersion = ref(null); // TODO gray out the button when model is uploading -const handleImport = async () => { +const handleImport = () => { if (importModelFile.value === null) return; const formData = new FormData(); @@ -43,7 +43,7 @@ const handleImport = async () => { timeout: -1 }); - await axiosPost("/objectdetection/import", "import an object detection model", formData, { + axiosPost("/objectdetection/import", "import an object detection model", formData, { headers: { "Content-Type": "multipart/form-data" }, onUploadProgress: ({ progress }) => { const uploadPercentage = (progress || 0) * 100.0; @@ -70,12 +70,10 @@ const handleImport = async () => { importHeight.value = null; importWidth.value = null; importVersion.value = null; - - forceReloadPage(); }; -const deleteModel = async (model: ObjectDetectionModelProperties) => { - await axiosPost("/objectdetection/delete", "delete an object detection model", { +const deleteModel = (model: ObjectDetectionModelProperties) => { + axiosPost("/objectdetection/delete", "delete an object detection model", { modelPath: model.modelPath }); @@ -84,14 +82,14 @@ const deleteModel = async (model: ObjectDetectionModelProperties) => { ); }; -const renameModel = async (model: ObjectDetectionModelProperties, newName: string) => { +const renameModel = (model: ObjectDetectionModelProperties, newName: string) => { useStateStore().showSnackbarMessage({ message: "Renaming Object Detection Model...", color: "secondary", timeout: -1 }); - await axiosPost("/objectdetection/rename", "rename an object detection model", { + axiosPost("/objectdetection/rename", "rename an object detection model", { modelPath: model.modelPath, newName: newName }); @@ -127,21 +125,19 @@ const openExportIndividualModelPrompt = () => { }; const showNukeDialog = ref(false); -const nukeModels = async () => { - await axiosPost("/objectdetection/nuke", "clear and reset object detection models"); - - forceReloadPage(); +const nukeModels = () => { + axiosPost("/objectdetection/nuke", "clear and reset object detection models"); }; const showBulkImportDialog = ref(false); const importFile = ref(null); -const handleBulkImport = async () => { +const handleBulkImport = () => { if (importFile.value === null) return; const formData = new FormData(); formData.append("data", importFile.value); - await axiosPost("/objectdetection/bulkimport", "import object detection models", formData, { + axiosPost("/objectdetection/bulkimport", "import object detection models", formData, { headers: { "Content-Type": "multipart/form-data" }, onUploadProgress: ({ progress }) => { const uploadPercentage = (progress || 0) * 100.0; @@ -164,8 +160,6 @@ const handleBulkImport = async () => { }); showImportDialog.value = false; importFile.value = null; - - forceReloadPage(); }; diff --git a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java index 350ec04bf6..6aebb966f3 100644 --- a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java +++ b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java @@ -852,6 +852,12 @@ public static void onBulkImportObjectDetectionModelRequest(Context ctx) { ctx.result("There was an error while saving the uploaded object detection models"); logger.error("There was an error while saving the uploaded object detection models"); } + + DataChangeService.getInstance() + .publishEvent( + new OutgoingUIEvent<>( + "fullsettings", + UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig()))); } private record DeleteObjectDetectionModelRequest(Path modelPath) {} @@ -903,12 +909,6 @@ public static void onDeleteObjectDetectionModelRequest(Context ctx) { ctx.result("Error deleting object detection model: " + e.getMessage()); logger.error("Error deleting object detection model", e); } - - DataChangeService.getInstance() - .publishEvent( - new OutgoingUIEvent<>( - "fullsettings", - UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig()))); } private record RenameObjectDetectionModelRequest(Path modelPath, String newName) {} @@ -970,6 +970,12 @@ public static void onNukeObjectDetectionModelsRequest(Context ctx) { ctx.result("Error clearing object detection models: " + e.getMessage()); logger.error("Error clearing object detection models", e); } + + DataChangeService.getInstance() + .publishEvent( + new OutgoingUIEvent<>( + "fullsettings", + UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig()))); } public static void onDeviceRestartRequest(Context ctx) { From f7e9c9aebd8fe99335d6ce1e284aceb914ac6bd2 Mon Sep 17 00:00:00 2001 From: samfreund Date: Thu, 15 Jan 2026 00:30:56 -0600 Subject: [PATCH 6/6] swap to backend --- .../src/components/settings/ObjectDetectionCard.vue | 10 ---------- .../java/org/photonvision/server/RequestHandler.java | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/photon-client/src/components/settings/ObjectDetectionCard.vue b/photon-client/src/components/settings/ObjectDetectionCard.vue index 17c112c01e..0aa8f00c83 100644 --- a/photon-client/src/components/settings/ObjectDetectionCard.vue +++ b/photon-client/src/components/settings/ObjectDetectionCard.vue @@ -76,10 +76,6 @@ const deleteModel = (model: ObjectDetectionModelProperties) => { axiosPost("/objectdetection/delete", "delete an object detection model", { modelPath: model.modelPath }); - - useSettingsStore().general.availableModels = useSettingsStore().general.availableModels.filter( - (m) => m.modelPath !== model.modelPath - ); }; const renameModel = (model: ObjectDetectionModelProperties, newName: string) => { @@ -94,12 +90,6 @@ const renameModel = (model: ObjectDetectionModelProperties, newName: string) => newName: newName }); showRenameDialog.value.show = false; - - useSettingsStore().general.availableModels.forEach((m) => { - if (m.modelPath === model.modelPath) { - m.nickname = newName; - } - }); }; // Filters out models that are not supported by the current backend, and returns a flattened list. diff --git a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java index 6aebb966f3..63ffd2ec3d 100644 --- a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java +++ b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java @@ -904,6 +904,12 @@ public static void onDeleteObjectDetectionModelRequest(Context ctx) { ctx.status(200).result("Successfully deleted object detection model"); + DataChangeService.getInstance() + .publishEvent( + new OutgoingUIEvent<>( + "fullsettings", + UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig()))); + } catch (Exception e) { ctx.status(500); ctx.result("Error deleting object detection model: " + e.getMessage()); @@ -951,6 +957,12 @@ public static void onRenameObjectDetectionModelRequest(Context ctx) { NeuralNetworkModelManager.getInstance().discoverModels(); ctx.status(200).result("Successfully renamed object detection model"); + + DataChangeService.getInstance() + .publishEvent( + new OutgoingUIEvent<>( + "fullsettings", + UIPhotonConfiguration.programStateToUi(ConfigManager.getInstance().getConfig()))); } catch (Exception e) { ctx.status(500); ctx.result("Error renaming object detection model: " + e.getMessage());