Canvas: Add Reload button on Monitoring page

Change-Id: I593d9068870bcd5f0d43680af4a08d814a18a2a9
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index de18582..cfd8955 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -662,6 +662,27 @@
 	}
 };
 
+const handleReloadWorker: express.Handler = async (req, resp) => {
+	const projectId = Number(req.params["projectId"]);
+	const serviceName = req.params["serviceName"];
+	const workerId = req.params["workerId"];
+
+	const projectMonitor = projectMonitors.get(projectId);
+	if (!projectMonitor) {
+		resp.status(404).send({ error: "Project monitor not found" });
+		return;
+	}
+
+	try {
+		await projectMonitor.reloadWorker(serviceName, workerId);
+		resp.status(200).send({ message: "Worker reload initiated" });
+	} catch (error) {
+		console.error(`Failed to reload worker ${workerId} in service ${serviceName} for project ${projectId}:`, error);
+		const errorMessage = error instanceof Error ? error.message : "Unknown error";
+		resp.status(500).send({ error: `Failed to reload worker: ${errorMessage}` });
+	}
+};
+
 const auth = (req: express.Request, resp: express.Response, next: express.NextFunction) => {
 	const userId = req.get("x-forwarded-userid");
 	const username = req.get("x-forwarded-user");
@@ -750,11 +771,13 @@
 	projectRouter.get("/:projectId/repos/github", handleGithubRepos);
 	projectRouter.post("/:projectId/github-token", handleUpdateGithubToken);
 	projectRouter.get("/:projectId/env", handleEnv);
+	projectRouter.post("/:projectId/reload/:serviceName/:workerId", handleReloadWorker);
 	projectRouter.post("/:projectId/reload", handleReload);
 	projectRouter.get("/:projectId/logs/:service/:workerId", handleServiceLogs);
 	projectRouter.post("/:projectId/remove-deployment", handleRemoveDeployment);
 	projectRouter.get("/", handleProjectAll);
 	projectRouter.post("/", handleProjectCreate);
+
 	app.use("/api/project", projectRouter); // Mount the authenticated router
 
 	app.use("/", express.static("../front/dist"));
diff --git a/apps/canvas/back/src/project_monitor.ts b/apps/canvas/back/src/project_monitor.ts
index c0ea56c..b494854 100644
--- a/apps/canvas/back/src/project_monitor.ts
+++ b/apps/canvas/back/src/project_monitor.ts
@@ -75,6 +75,25 @@
 	hasLogs(): boolean {
 		return this.logs.size > 0;
 	}
+
+	async reloadWorker(workerId: string): Promise<void> {
+		const workerAddress = this.workers.get(workerId);
+		if (!workerAddress) {
+			throw new Error(`Worker ${workerId} not found in service ${this.serviceName}`);
+		}
+		try {
+			const response = await fetch(`${workerAddress}/update`, { method: "POST" });
+			if (!response.ok) {
+				throw new Error(
+					`Failed to trigger reload for worker ${workerId} at ${workerAddress}: ${response.statusText}`,
+				);
+			}
+			console.log(`Reload triggered for worker ${workerId} in service ${this.serviceName}`);
+		} catch (error) {
+			console.error(`Error reloading worker ${workerId} in service ${this.serviceName}:`, error);
+			throw error; // Re-throw to be caught by ProjectMonitor
+		}
+	}
 }
 
 export class ProjectMonitor {
@@ -131,4 +150,12 @@
 		}
 		return new Map();
 	}
+
+	async reloadWorker(serviceName: string, workerId: string): Promise<void> {
+		const serviceMonitor = this.serviceMonitors.get(serviceName);
+		if (!serviceMonitor) {
+			throw new Error(`Service ${serviceName} not found`);
+		}
+		await serviceMonitor.reloadWorker(workerId);
+	}
 }