Canvas: Generate graph state out of dodo-app config
Restructure code, create shared config lib.
Change-Id: I2cf06d35c486d4557484daf8618a2c215316fa7e
diff --git a/apps/canvas/config/src/graph.ts b/apps/canvas/config/src/graph.ts
new file mode 100644
index 0000000..e8741f9
--- /dev/null
+++ b/apps/canvas/config/src/graph.ts
@@ -0,0 +1,320 @@
+import { z } from "zod";
+import { Node } from "@xyflow/react";
+import { Domain, ServiceType, VolumeType } from "./types.js";
+
+export const serviceAnalyzisSchema = z.object({
+ name: z.string(),
+ location: z.string(),
+ configVars: z.array(
+ z.object({
+ name: z.string(),
+ category: z.enum(["CommandLineFlag", "EnvironmentVariable"]),
+ type: z.optional(z.enum(["String", "Number", "Boolean"])),
+ semanticType: z.optional(
+ z.enum([
+ "EXPANDED_ENV_VAR",
+ "PORT",
+ "FILESYSTEM_PATH",
+ "DATABASE_URL",
+ "SQLITE_PATH",
+ "POSTGRES_URL",
+ "POSTGRES_PASSWORD",
+ "POSTGRES_USER",
+ "POSTGRES_DB",
+ "POSTGRES_PORT",
+ "POSTGRES_HOST",
+ "POSTGRES_SSL",
+ "MONGO_URL",
+ "MONGO_PASSWORD",
+ "MONGO_USER",
+ "MONGO_DB",
+ "MONGO_PORT",
+ "MONGO_HOST",
+ "MONGO_SSL",
+ ]),
+ ),
+ }),
+ ),
+});
+
+export type BoundEnvVar =
+ | {
+ id: string;
+ source: string | null;
+ }
+ | {
+ id: string;
+ source: string | null;
+ name: string;
+ isEditting: boolean;
+ }
+ | {
+ id: string;
+ source: string | null;
+ name: string;
+ alias: string;
+ isEditting: boolean;
+ }
+ | {
+ id: string;
+ source: string | null;
+ portId: string;
+ name: string;
+ alias: string;
+ isEditting: boolean;
+ };
+
+export type EnvVar = {
+ name: string;
+ value: string;
+};
+
+export type InitData = {
+ label: string;
+ envVars: BoundEnvVar[];
+ ports: Port[];
+};
+
+export type NodeData = InitData & {
+ activeField?: string | undefined;
+ state?: string | null;
+};
+
+export type PortConnectedTo = {
+ serviceId: string;
+ portId: string;
+};
+
+export type NetworkData = NodeData & {
+ domain: string;
+};
+
+export type NetworkNode = Node<NetworkData> & {
+ type: "network";
+};
+
+export type GatewayHttpsData = NodeData & {
+ readonly?: boolean;
+ network?: string;
+ subdomain?: string;
+ https?: PortConnectedTo;
+ auth?: {
+ enabled: boolean;
+ groups: string[];
+ noAuthPathPatterns: string[];
+ };
+};
+
+export type GatewayHttpsNode = Node<GatewayHttpsData> & {
+ type: "gateway-https";
+};
+
+export type GatewayTCPData = NodeData & {
+ readonly?: boolean;
+ network?: string;
+ subdomain?: string;
+ exposed: PortConnectedTo[];
+ selected?: {
+ serviceId?: string;
+ portId?: string;
+ };
+};
+
+export type GatewayTCPNode = Node<GatewayTCPData> & {
+ type: "gateway-tcp";
+};
+
+export type Port = {
+ id: string;
+ name: string;
+ value: number;
+};
+
+export type ServiceData = NodeData & {
+ type: ServiceType;
+ repository?:
+ | {
+ id: number;
+ repoNodeId: string;
+ }
+ | {
+ id: number;
+ repoNodeId: string;
+ branch: string;
+ }
+ | {
+ id: number;
+ repoNodeId: string;
+ branch: string;
+ rootDir: string;
+ };
+ env: string[];
+ volume: string[];
+ preBuildCommands: string;
+ isChoosingPortToConnect: boolean;
+ dev?:
+ | {
+ enabled: false;
+ expose?: Domain;
+ }
+ | {
+ enabled: true;
+ expose?: Domain;
+ codeServerNodeId: string;
+ sshNodeId: string;
+ };
+ info?: z.infer<typeof serviceAnalyzisSchema>;
+};
+
+export type ServiceNode = Node<ServiceData> & {
+ type: "app";
+};
+
+export type VolumeData = NodeData & {
+ type: VolumeType;
+ size: string;
+ attachedTo: string[];
+};
+
+export type VolumeNode = Node<VolumeData> & {
+ type: "volume";
+};
+
+export type PostgreSQLData = NodeData & {
+ volumeId: string;
+};
+
+export type PostgreSQLNode = Node<PostgreSQLData> & {
+ type: "postgresql";
+};
+
+export type MongoDBData = NodeData & {
+ volumeId: string;
+};
+
+export type MongoDBNode = Node<MongoDBData> & {
+ type: "mongodb";
+};
+
+export type GithubData = NodeData & {
+ repository?: {
+ id: number;
+ sshURL: string;
+ fullName: string;
+ };
+};
+
+export type GithubNode = Node<GithubData> & {
+ type: "github";
+};
+
+export type NANode = Node<NodeData> & {
+ type: undefined;
+};
+
+export type AppNode =
+ | NetworkNode
+ | GatewayHttpsNode
+ | GatewayTCPNode
+ | ServiceNode
+ | VolumeNode
+ | PostgreSQLNode
+ | MongoDBNode
+ | GithubNode
+ | NANode;
+
+export type NodeType = Exclude<Pick<AppNode, "type">["type"], undefined>;
+
+export const networkSchema = z.object({
+ name: z.string().min(1),
+ domain: z.string().min(1),
+ hasAuth: z.boolean(),
+});
+
+export type Network = z.infer<typeof networkSchema>;
+
+export 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 serviceInfoSchema = z.object({
+ name: z.string(),
+ workers: z.array(
+ z.object({
+ id: z.string(),
+ commit: z.optional(
+ z.object({
+ hash: z.string(),
+ message: z.string(),
+ }),
+ ),
+ commands: z.optional(
+ z.array(
+ z.object({
+ command: z.string(),
+ state: z.string(),
+ }),
+ ),
+ ),
+ }),
+ ),
+});
+
+export const envSchema = z.object({
+ managerAddr: z.optional(z.string().min(1)),
+ instanceId: z.optional(z.string().min(1)),
+ deployKeyPublic: z.optional(z.nullable(z.string().min(1))),
+ networks: z.array(networkSchema).default([]),
+ integrations: z.object({
+ github: z.boolean(),
+ }),
+ services: z.array(serviceInfoSchema),
+ user: z.object({
+ id: z.string(),
+ username: z.string(),
+ }),
+ access: z.array(accessSchema),
+});
+
+export type ServiceInfo = z.infer<typeof serviceInfoSchema>;
+export type Env = z.infer<typeof envSchema>;