Canvas: Rework Deployment/Gateways tab
Change-Id: I938262b9a6ba2af060531e7dcdf91ddd66721385
diff --git a/apps/canvas/back/prisma/migrations/20250517144829_access/migration.sql b/apps/canvas/back/prisma/migrations/20250517144829_access/migration.sql
new file mode 100644
index 0000000..0127521
--- /dev/null
+++ b/apps/canvas/back/prisma/migrations/20250517144829_access/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Project" ADD COLUMN "access" TEXT;
diff --git a/apps/canvas/back/prisma/schema.prisma b/apps/canvas/back/prisma/schema.prisma
index 09ddc69..68ff022 100644
--- a/apps/canvas/back/prisma/schema.prisma
+++ b/apps/canvas/back/prisma/schema.prisma
@@ -22,4 +22,5 @@
instanceId String?
deployKey String?
githubToken String?
+ access String?
}
\ No newline at end of file
diff --git a/apps/canvas/back/src/app_manager.ts b/apps/canvas/back/src/app_manager.ts
index 2f62ddd..803192c 100644
--- a/apps/canvas/back/src/app_manager.ts
+++ b/apps/canvas/back/src/app_manager.ts
@@ -1,9 +1,54 @@
import axios from "axios";
import { z } from "zod";
+const accessSchema = z.discriminatedUnion("type", [
+ z.object({
+ type: z.literal("https"),
+ name: z.string(),
+ address: z.string(),
+ }),
+ z.object({
+ type: z.literal("ssh"),
+ name: z.string(),
+ host: z.string(),
+ port: z.number(),
+ }),
+ z.object({
+ type: z.literal("tcp"),
+ name: z.string(),
+ host: z.string(),
+ port: z.number(),
+ }),
+ z.object({
+ type: z.literal("udp"),
+ name: z.string(),
+ host: z.string(),
+ port: z.number(),
+ }),
+ z.object({
+ type: z.literal("postgresql"),
+ name: z.string(),
+ host: z.string(),
+ port: z.number(),
+ database: z.string(),
+ username: z.string(),
+ password: z.string(),
+ }),
+ z.object({
+ type: z.literal("mongodb"),
+ name: z.string(),
+ host: z.string(),
+ port: z.number(),
+ database: z.string(),
+ username: z.string(),
+ password: z.string(),
+ }),
+]);
+
export const DeployResponseSchema = z.object({
id: z.string(),
deployKey: z.string(),
+ access: z.array(accessSchema),
});
export type DeployResponse = z.infer<typeof DeployResponseSchema>;
@@ -24,6 +69,7 @@
if (response.status !== 200) {
throw new Error(`Failed to deploy application: ${response.statusText}`);
}
+ console.log(response.data);
const result = DeployResponseSchema.safeParse(response.data);
if (!result.success) {
throw new Error(`Invalid deploy response format: ${result.error.message}`);
@@ -31,13 +77,20 @@
return result.data;
}
- async update(instanceId: string, config: unknown): Promise<boolean> {
+ async update(instanceId: string, config: unknown): Promise<DeployResponse> {
const response = await axios.request({
url: `${this.baseUrl}/api/dodo-app/${instanceId}`,
method: "put",
data: { config },
});
- return response.status === 200;
+ if (response.status !== 200) {
+ throw new Error(`Failed to update application: ${response.statusText}`);
+ }
+ const result = DeployResponseSchema.safeParse(response.data);
+ if (!result.success) {
+ throw new Error(`Invalid update response format: ${result.error.message}`);
+ }
+ return result.data;
}
async getStatus(instanceId: string): Promise<unknown> {
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index 6dede14..4dc942f 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -261,29 +261,25 @@
draft: null,
instanceId: deployResponse.id,
deployKey: deployResponse.deployKey,
+ access: JSON.stringify(deployResponse.access),
},
});
diff = { toAdd: extractGithubRepos(state) };
deployKey = deployResponse.deployKey;
} else {
- const success = await appManager.update(p.instanceId, req.body.config);
- if (success) {
- diff = calculateRepoDiff(extractGithubRepos(p.state), extractGithubRepos(state));
- deployKey = p.deployKey;
- await db.project.update({
- where: {
- id: projectId,
- },
- data: {
- state,
- draft: null,
- },
- });
- } else {
- resp.status(500);
- resp.write(JSON.stringify({ error: "Failed to update deployment" }));
- return;
- }
+ const deployResponse = await appManager.update(p.instanceId, req.body.config);
+ diff = calculateRepoDiff(extractGithubRepos(p.state), extractGithubRepos(state));
+ deployKey = p.deployKey;
+ await db.project.update({
+ where: {
+ id: projectId,
+ },
+ data: {
+ state,
+ draft: null,
+ access: JSON.stringify(deployResponse.access),
+ },
+ });
}
if (diff && p.githubToken && deployKey) {
const github = new GithubClient(p.githubToken);
@@ -388,6 +384,7 @@
data: {
instanceId: null,
deployKey: null,
+ access: null,
state: null,
draft: p.draft ?? p.state,
},
@@ -465,6 +462,7 @@
select: {
deployKey: true,
githubToken: true,
+ access: true,
},
});
if (!project) {
@@ -480,6 +478,7 @@
// TODO(gio): get from env or command line flags
managerAddr: "http://10.42.0.95:8081",
deployKey: project.deployKey,
+ access: JSON.parse(project.access ?? "[]"),
integrations: {
github: !!project.githubToken,
},
diff --git a/apps/canvas/back/start.sh b/apps/canvas/back/start.sh
new file mode 100755
index 0000000..23bc786
--- /dev/null
+++ b/apps/canvas/back/start.sh
@@ -0,0 +1 @@
+DODO_PORT_WEB=8080 DODO_PORT_API=8081 npm run start