diff --git a/apps/dbagent/migrations/0000_init.sql b/apps/dbagent/migrations/0000_init.sql index b6cf89ba..4986f39a 100644 --- a/apps/dbagent/migrations/0000_init.sql +++ b/apps/dbagent/migrations/0000_init.sql @@ -1,46 +1,65 @@ +CREATE TYPE "public"."notification_level" AS ENUM('info', 'warning', 'alert');--> statement-breakpoint CREATE TYPE "public"."schedule_status" AS ENUM('disabled', 'scheduled', 'running');--> statement-breakpoint -CREATE TABLE "assoc_cluster_connections" ( +CREATE TABLE "aws_cluster_connections" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "cluster_id" uuid, - "connection_id" uuid + "cluster_id" uuid NOT NULL, + "connection_id" uuid NOT NULL ); --> statement-breakpoint -CREATE TABLE "clusters" ( +CREATE TABLE "aws_clusters" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "cluster_identifier" text NOT NULL, - "integration" text NOT NULL, - "data" jsonb NOT NULL, "region" text DEFAULT 'us-east-1' NOT NULL, - CONSTRAINT "instances_integration_identifier_unique" UNIQUE("cluster_identifier","integration") + "data" jsonb NOT NULL, + CONSTRAINT "uq_aws_clusters_integration_identifier" UNIQUE("cluster_identifier") +); +--> statement-breakpoint +CREATE TABLE "connection_info" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "connection_id" uuid NOT NULL, + "type" text NOT NULL, + "data" jsonb NOT NULL, + CONSTRAINT "uq_connections_info" UNIQUE("connection_id","type") ); --> statement-breakpoint CREATE TABLE "connections" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "project_id" uuid NOT NULL, "name" text NOT NULL, "is_default" boolean DEFAULT false NOT NULL, - "connstring" text NOT NULL, - "params" jsonb, - CONSTRAINT "connections_name_unique" UNIQUE("name"), - CONSTRAINT "connections_connstring_unique" UNIQUE("connstring") + "connection_string" text NOT NULL, + CONSTRAINT "uq_connections_name" UNIQUE("project_id","name"), + CONSTRAINT "uq_connections_connection_string" UNIQUE("project_id","connection_string") ); --> statement-breakpoint -CREATE TABLE "dbinfo" ( +CREATE TABLE "integrations" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "connection_id" uuid, - "module" text, - "data" jsonb, - CONSTRAINT "dbinfo_module_unique" UNIQUE("connection_id","module") + "project_id" uuid NOT NULL, + "name" text NOT NULL, + "data" jsonb NOT NULL, + CONSTRAINT "uq_integrations_name" UNIQUE("project_id","name") ); --> statement-breakpoint -CREATE TABLE "integrations" ( +CREATE TABLE "projects" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "name" text NOT NULL, + "owner_id" text NOT NULL, + CONSTRAINT "uq_projects_name" UNIQUE("owner_id","name") +); +--> statement-breakpoint +CREATE TABLE "schedule_runs" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "name" text, - "data" jsonb, - CONSTRAINT "integrations_name_unique" UNIQUE("name") + "schedule_id" uuid NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "result" text NOT NULL, + "summary" text, + "notification_level" "notification_level" DEFAULT 'info' NOT NULL, + "messages" jsonb NOT NULL ); --> statement-breakpoint CREATE TABLE "schedules" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "project_id" uuid NOT NULL, "connection_id" uuid NOT NULL, "playbook" varchar(255) NOT NULL, "schedule_type" varchar(255) NOT NULL, @@ -48,16 +67,21 @@ CREATE TABLE "schedules" ( "additional_instructions" text, "min_interval" integer, "max_interval" integer, - "enabled" boolean NOT NULL, + "enabled" boolean DEFAULT true NOT NULL, "last_run" timestamp, "next_run" timestamp, "status" "schedule_status" DEFAULT 'disabled' NOT NULL, "failures" integer DEFAULT 0, + "keep_history" integer DEFAULT 300 NOT NULL, "model" text DEFAULT 'openai-gpt-4o' NOT NULL ); --> statement-breakpoint -ALTER TABLE "assoc_cluster_connections" ADD CONSTRAINT "assoc_instance_connections_instance_id_fkey" FOREIGN KEY ("cluster_id") REFERENCES "public"."clusters"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "assoc_cluster_connections" ADD CONSTRAINT "assoc_instance_connections_connection_id_fkey" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "clusters" ADD CONSTRAINT "instances_integration_fkey" FOREIGN KEY ("integration") REFERENCES "public"."integrations"("name") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "dbinfo" ADD CONSTRAINT "dbinfo_connid_fkey" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "schedules" ADD CONSTRAINT "schedules_connection_id_fkey" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file +ALTER TABLE "aws_cluster_connections" ADD CONSTRAINT "fk_aws_cluster_connections_cluster" FOREIGN KEY ("cluster_id") REFERENCES "public"."aws_clusters"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "aws_cluster_connections" ADD CONSTRAINT "fk_aws_cluster_connections_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "connection_info" ADD CONSTRAINT "fk_connections_info_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "connections" ADD CONSTRAINT "fk_connections_project" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "integrations" ADD CONSTRAINT "fk_integrations_project" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "schedule_runs" ADD CONSTRAINT "fk_schedule_runs_schedule" FOREIGN KEY ("schedule_id") REFERENCES "public"."schedules"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "schedules" ADD CONSTRAINT "fk_schedules_project" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "schedules" ADD CONSTRAINT "fk_schedules_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "idx_schedule_runs_created_at" ON "schedule_runs" USING btree ("schedule_id","created_at"); \ No newline at end of file diff --git a/apps/dbagent/migrations/0001_lumpy_black_tarantula.sql b/apps/dbagent/migrations/0001_lumpy_black_tarantula.sql deleted file mode 100644 index 10501544..00000000 --- a/apps/dbagent/migrations/0001_lumpy_black_tarantula.sql +++ /dev/null @@ -1,14 +0,0 @@ -CREATE TYPE "public"."notification_level" AS ENUM('info', 'warning', 'alert');--> statement-breakpoint -CREATE TABLE "schedule_runs" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "schedule_id" uuid NOT NULL, - "created_at" timestamp DEFAULT now(), - "result" text NOT NULL, - "summary" text, - "notification_level" "notification_level" DEFAULT 'info' NOT NULL, - "messages" jsonb NOT NULL -); ---> statement-breakpoint -ALTER TABLE "schedules" ADD COLUMN "keep_history" integer DEFAULT 300;--> statement-breakpoint -ALTER TABLE "schedule_runs" ADD CONSTRAINT "schedule_runs_schedule_id_fkey" FOREIGN KEY ("schedule_id") REFERENCES "public"."schedules"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -CREATE INDEX "schedule_runs_created_at_idx" ON "schedule_runs" USING btree ("schedule_id","created_at"); \ No newline at end of file diff --git a/apps/dbagent/migrations/0002_lazy_galactus.sql b/apps/dbagent/migrations/0002_lazy_galactus.sql deleted file mode 100644 index e17ea159..00000000 --- a/apps/dbagent/migrations/0002_lazy_galactus.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "schedules" ALTER COLUMN "keep_history" SET NOT NULL; \ No newline at end of file diff --git a/apps/dbagent/migrations/0003_optimal_gargoyle.sql b/apps/dbagent/migrations/0003_optimal_gargoyle.sql deleted file mode 100644 index dfbd3778..00000000 --- a/apps/dbagent/migrations/0003_optimal_gargoyle.sql +++ /dev/null @@ -1,165 +0,0 @@ -ALTER TABLE - "clusters" RENAME TO "aws_clusters"; - ---> statement-breakpoint -ALTER TABLE - "dbinfo" RENAME TO "connection_info"; - ---> statement-breakpoint -ALTER TABLE - "connections" RENAME COLUMN "connstring" TO "connection_string"; - ---> statement-breakpoint -ALTER TABLE - "connection_info" RENAME COLUMN "module" TO "type"; - ---> statement-breakpoint -ALTER TABLE - "aws_clusters" DROP CONSTRAINT "instances_integration_identifier_unique"; - ---> statement-breakpoint -ALTER TABLE - "connections" DROP CONSTRAINT "connections_name_unique"; - ---> statement-breakpoint -ALTER TABLE - "connections" DROP CONSTRAINT "connections_connstring_unique"; - ---> statement-breakpoint -ALTER TABLE - "connection_info" DROP CONSTRAINT "dbinfo_module_unique"; - -ALTER TABLE - "integrations" RENAME CONSTRAINT "integrations_name_unique" TO "uq_integrations_name"; - ---> statement-breakpoint -ALTER TABLE - "assoc_cluster_connections" DROP CONSTRAINT "assoc_instance_connections_instance_id_fkey"; - ---> statement-breakpoint -ALTER TABLE - "aws_clusters" DROP CONSTRAINT "instances_integration_fkey"; - ---> statement-breakpoint -ALTER TABLE - "connection_info" DROP CONSTRAINT "dbinfo_connid_fkey"; - ---> statement-breakpoint -ALTER TABLE - "schedule_runs" DROP CONSTRAINT "schedule_runs_schedule_id_fkey"; - ---> statement-breakpoint -ALTER TABLE - "schedules" DROP CONSTRAINT "schedules_connection_id_fkey"; - ---> statement-breakpoint -DROP INDEX "schedule_runs_created_at_idx"; - ---> statement-breakpoint -ALTER TABLE - "connection_info" -ALTER COLUMN - "connection_id" -SET - NOT NULL; - ---> statement-breakpoint -ALTER TABLE - "connection_info" -ALTER COLUMN - "data" -SET - NOT NULL; - ---> statement-breakpoint -ALTER TABLE - "integrations" -ALTER COLUMN - "name" -SET - NOT NULL; - ---> statement-breakpoint -ALTER TABLE - "integrations" -ALTER COLUMN - "data" -SET - NOT NULL; - ---> statement-breakpoint -ALTER TABLE - "schedule_runs" -ALTER COLUMN - "created_at" -SET - NOT NULL; - ---> statement-breakpoint -ALTER TABLE - "schedules" -ALTER COLUMN - "enabled" -SET - DEFAULT true; - ---> statement-breakpoint -ALTER TABLE - "assoc_cluster_connections" -ADD - CONSTRAINT "assoc_instance_connections_instance_id_fkey" FOREIGN KEY ("cluster_id") REFERENCES "public"."aws_clusters"("id") ON DELETE no action ON UPDATE no action; - ---> statement-breakpoint -ALTER TABLE - "aws_clusters" -ADD - CONSTRAINT "fk_aws_clusters_integration_name" FOREIGN KEY ("integration") REFERENCES "public"."integrations"("name") ON DELETE no action ON UPDATE no action; - ---> statement-breakpoint -ALTER TABLE - "connection_info" -ADD - CONSTRAINT "fk_connections_info_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action; - ---> statement-breakpoint -ALTER TABLE - "schedule_runs" -ADD - CONSTRAINT "fk_schedule_runs_schedule" FOREIGN KEY ("schedule_id") REFERENCES "public"."schedules"("id") ON DELETE no action ON UPDATE no action; - ---> statement-breakpoint -ALTER TABLE - "schedules" -ADD - CONSTRAINT "fk_schedules_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action; - ---> statement-breakpoint -CREATE INDEX "idx_schedule_runs_created_at" ON "schedule_runs" USING btree ("schedule_id", "created_at"); - ---> statement-breakpoint -ALTER TABLE - "connections" DROP COLUMN "params"; - ---> statement-breakpoint -ALTER TABLE - "aws_clusters" -ADD - CONSTRAINT "uq_aws_clusters_integration_identifier" UNIQUE("cluster_identifier", "integration"); - ---> statement-breakpoint -ALTER TABLE - "connections" -ADD - CONSTRAINT "uq_connections_name" UNIQUE("name"); - ---> statement-breakpoint -ALTER TABLE - "connections" -ADD - CONSTRAINT "uq_connections_connection_string" UNIQUE("connection_string"); - ---> statement-breakpoint -ALTER TABLE - "connection_info" -ADD - CONSTRAINT "uq_connections_info" UNIQUE("connection_id", "type"); \ No newline at end of file diff --git a/apps/dbagent/migrations/0004_worthless_thor.sql b/apps/dbagent/migrations/0004_worthless_thor.sql deleted file mode 100644 index 22e70ef7..00000000 --- a/apps/dbagent/migrations/0004_worthless_thor.sql +++ /dev/null @@ -1,12 +0,0 @@ -ALTER TABLE "assoc_cluster_connections" RENAME TO "aws_cluster_connections";--> statement-breakpoint -ALTER TABLE "aws_clusters" DROP CONSTRAINT "uq_aws_clusters_integration_identifier";--> statement-breakpoint -ALTER TABLE "aws_cluster_connections" DROP CONSTRAINT "assoc_instance_connections_instance_id_fkey"; ---> statement-breakpoint -ALTER TABLE "aws_cluster_connections" DROP CONSTRAINT "assoc_instance_connections_connection_id_fkey"; ---> statement-breakpoint -ALTER TABLE "aws_clusters" DROP CONSTRAINT "fk_aws_clusters_integration_name"; ---> statement-breakpoint -ALTER TABLE "aws_cluster_connections" ADD CONSTRAINT "fk_aws_cluster_connections_cluster" FOREIGN KEY ("cluster_id") REFERENCES "public"."aws_clusters"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "aws_cluster_connections" ADD CONSTRAINT "fk_aws_cluster_connections_connection" FOREIGN KEY ("connection_id") REFERENCES "public"."connections"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "aws_clusters" DROP COLUMN "integration";--> statement-breakpoint -ALTER TABLE "aws_clusters" ADD CONSTRAINT "uq_aws_clusters_integration_identifier" UNIQUE("cluster_identifier"); \ No newline at end of file diff --git a/apps/dbagent/migrations/meta/0000_snapshot.json b/apps/dbagent/migrations/meta/0000_snapshot.json index 5c5fccd9..0ce9679e 100644 --- a/apps/dbagent/migrations/meta/0000_snapshot.json +++ b/apps/dbagent/migrations/meta/0000_snapshot.json @@ -1,11 +1,11 @@ { - "id": "8a69bb6c-0c56-4acc-ba84-f708a2f48a51", + "id": "46570abf-9adc-4929-88fc-4aef7de485f8", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { - "public.assoc_cluster_connections": { - "name": "assoc_cluster_connections", + "public.aws_cluster_connections": { + "name": "aws_cluster_connections", "schema": "", "columns": { "id": { @@ -19,29 +19,29 @@ "name": "cluster_id", "type": "uuid", "primaryKey": false, - "notNull": false + "notNull": true }, "connection_id": { "name": "connection_id", "type": "uuid", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, "foreignKeys": { - "assoc_instance_connections_instance_id_fkey": { - "name": "assoc_instance_connections_instance_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "clusters", + "fk_aws_cluster_connections_cluster": { + "name": "fk_aws_cluster_connections_cluster", + "tableFrom": "aws_cluster_connections", + "tableTo": "aws_clusters", "columnsFrom": ["cluster_id"], "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" }, - "assoc_instance_connections_connection_id_fkey": { - "name": "assoc_instance_connections_connection_id_fkey", - "tableFrom": "assoc_cluster_connections", + "fk_aws_cluster_connections_connection": { + "name": "fk_aws_cluster_connections_connection", + "tableFrom": "aws_cluster_connections", "tableTo": "connections", "columnsFrom": ["connection_id"], "columnsTo": ["id"], @@ -55,8 +55,8 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.clusters": { - "name": "clusters", + "public.aws_clusters": { + "name": "aws_clusters", "schema": "", "columns": { "id": { @@ -72,44 +72,82 @@ "primaryKey": false, "notNull": true }, - "integration": { - "name": "integration", + "region": { + "name": "region", "type": "text", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "'us-east-1'" }, "data": { "name": "data", "type": "jsonb", "primaryKey": false, "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "uq_aws_clusters_integration_identifier": { + "name": "uq_aws_clusters_integration_identifier", + "nullsNotDistinct": false, + "columns": ["cluster_identifier"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.connection_info": { + "name": "connection_info", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" }, - "region": { - "name": "region", + "connection_id": { + "name": "connection_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", "type": "text", "primaryKey": false, - "notNull": true, - "default": "'us-east-1'" + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true } }, "indexes": {}, "foreignKeys": { - "instances_integration_fkey": { - "name": "instances_integration_fkey", - "tableFrom": "clusters", - "tableTo": "integrations", - "columnsFrom": ["integration"], - "columnsTo": ["name"], + "fk_connections_info_connection": { + "name": "fk_connections_info_connection", + "tableFrom": "connection_info", + "tableTo": "connections", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" } }, "compositePrimaryKeys": {}, "uniqueConstraints": { - "instances_integration_identifier_unique": { - "name": "instances_integration_identifier_unique", + "uq_connections_info": { + "name": "uq_connections_info", "nullsNotDistinct": false, - "columns": ["cluster_identifier", "integration"] + "columns": ["connection_id", "type"] } }, "policies": {}, @@ -127,6 +165,12 @@ "notNull": true, "default": "gen_random_uuid()" }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, "name": { "name": "name", "type": "text", @@ -140,40 +184,44 @@ "notNull": true, "default": false }, - "connstring": { - "name": "connstring", + "connection_string": { + "name": "connection_string", "type": "text", "primaryKey": false, "notNull": true - }, - "params": { - "name": "params", - "type": "jsonb", - "primaryKey": false, - "notNull": false } }, "indexes": {}, - "foreignKeys": {}, + "foreignKeys": { + "fk_connections_project": { + "name": "fk_connections_project", + "tableFrom": "connections", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, "compositePrimaryKeys": {}, "uniqueConstraints": { - "connections_name_unique": { - "name": "connections_name_unique", + "uq_connections_name": { + "name": "uq_connections_name", "nullsNotDistinct": false, - "columns": ["name"] + "columns": ["project_id", "name"] }, - "connections_connstring_unique": { - "name": "connections_connstring_unique", + "uq_connections_connection_string": { + "name": "uq_connections_connection_string", "nullsNotDistinct": false, - "columns": ["connstring"] + "columns": ["project_id", "connection_string"] } }, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false }, - "public.dbinfo": { - "name": "dbinfo", + "public.integrations": { + "name": "integrations", "schema": "", "columns": { "id": { @@ -183,32 +231,32 @@ "notNull": true, "default": "gen_random_uuid()" }, - "connection_id": { - "name": "connection_id", + "project_id": { + "name": "project_id", "type": "uuid", "primaryKey": false, - "notNull": false + "notNull": true }, - "module": { - "name": "module", + "name": { + "name": "name", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true }, "data": { "name": "data", "type": "jsonb", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, "foreignKeys": { - "dbinfo_connid_fkey": { - "name": "dbinfo_connid_fkey", - "tableFrom": "dbinfo", - "tableTo": "connections", - "columnsFrom": ["connection_id"], + "fk_integrations_project": { + "name": "fk_integrations_project", + "tableFrom": "integrations", + "tableTo": "projects", + "columnsFrom": ["project_id"], "columnsTo": ["id"], "onDelete": "no action", "onUpdate": "no action" @@ -216,18 +264,18 @@ }, "compositePrimaryKeys": {}, "uniqueConstraints": { - "dbinfo_module_unique": { - "name": "dbinfo_module_unique", + "uq_integrations_name": { + "name": "uq_integrations_name", "nullsNotDistinct": false, - "columns": ["connection_id", "module"] + "columns": ["project_id", "name"] } }, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false }, - "public.integrations": { - "name": "integrations", + "public.projects": { + "name": "projects", "schema": "", "columns": { "id": { @@ -241,29 +289,120 @@ "name": "name", "type": "text", "primaryKey": false, - "notNull": false + "notNull": true }, - "data": { - "name": "data", - "type": "jsonb", + "owner_id": { + "name": "owner_id", + "type": "text", "primaryKey": false, - "notNull": false + "notNull": true } }, "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": { - "integrations_name_unique": { - "name": "integrations_name_unique", + "uq_projects_name": { + "name": "uq_projects_name", "nullsNotDistinct": false, - "columns": ["name"] + "columns": ["owner_id", "name"] } }, "policies": {}, "checkConstraints": {}, "isRLSEnabled": false }, + "public.schedule_runs": { + "name": "schedule_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "schedule_id": { + "name": "schedule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "result": { + "name": "result", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notification_level": { + "name": "notification_level", + "type": "notification_level", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'info'" + }, + "messages": { + "name": "messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "idx_schedule_runs_created_at": { + "name": "idx_schedule_runs_created_at", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "fk_schedule_runs_schedule": { + "name": "fk_schedule_runs_schedule", + "tableFrom": "schedule_runs", + "tableTo": "schedules", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, "public.schedules": { "name": "schedules", "schema": "", @@ -275,6 +414,12 @@ "notNull": true, "default": "gen_random_uuid()" }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, "connection_id": { "name": "connection_id", "type": "uuid", @@ -321,7 +466,8 @@ "name": "enabled", "type": "boolean", "primaryKey": false, - "notNull": true + "notNull": true, + "default": true }, "last_run": { "name": "last_run", @@ -350,6 +496,13 @@ "notNull": false, "default": 0 }, + "keep_history": { + "name": "keep_history", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 300 + }, "model": { "name": "model", "type": "text", @@ -360,8 +513,17 @@ }, "indexes": {}, "foreignKeys": { - "schedules_connection_id_fkey": { - "name": "schedules_connection_id_fkey", + "fk_schedules_project": { + "name": "fk_schedules_project", + "tableFrom": "schedules", + "tableTo": "projects", + "columnsFrom": ["project_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "fk_schedules_connection": { + "name": "fk_schedules_connection", "tableFrom": "schedules", "tableTo": "connections", "columnsFrom": ["connection_id"], @@ -378,6 +540,11 @@ } }, "enums": { + "public.notification_level": { + "name": "notification_level", + "schema": "public", + "values": ["info", "warning", "alert"] + }, "public.schedule_status": { "name": "schedule_status", "schema": "public", diff --git a/apps/dbagent/migrations/meta/0001_snapshot.json b/apps/dbagent/migrations/meta/0001_snapshot.json deleted file mode 100644 index 24639aa9..00000000 --- a/apps/dbagent/migrations/meta/0001_snapshot.json +++ /dev/null @@ -1,500 +0,0 @@ -{ - "id": "58d029f6-2a5a-478d-bd5b-624372925bd0", - "prevId": "8a69bb6c-0c56-4acc-ba84-f708a2f48a51", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.assoc_cluster_connections": { - "name": "assoc_cluster_connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_id": { - "name": "cluster_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "assoc_instance_connections_instance_id_fkey": { - "name": "assoc_instance_connections_instance_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "clusters", - "columnsFrom": ["cluster_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "assoc_instance_connections_connection_id_fkey": { - "name": "assoc_instance_connections_connection_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.clusters": { - "name": "clusters", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_identifier": { - "name": "cluster_identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "integration": { - "name": "integration", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'us-east-1'" - } - }, - "indexes": {}, - "foreignKeys": { - "instances_integration_fkey": { - "name": "instances_integration_fkey", - "tableFrom": "clusters", - "tableTo": "integrations", - "columnsFrom": ["integration"], - "columnsTo": ["name"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "instances_integration_identifier_unique": { - "name": "instances_integration_identifier_unique", - "nullsNotDistinct": false, - "columns": ["cluster_identifier", "integration"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connections": { - "name": "connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "connstring": { - "name": "connstring", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "params": { - "name": "params", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "connections_name_unique": { - "name": "connections_name_unique", - "nullsNotDistinct": false, - "columns": ["name"] - }, - "connections_connstring_unique": { - "name": "connections_connstring_unique", - "nullsNotDistinct": false, - "columns": ["connstring"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dbinfo": { - "name": "dbinfo", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "module": { - "name": "module", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "dbinfo_connid_fkey": { - "name": "dbinfo_connid_fkey", - "tableFrom": "dbinfo", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "dbinfo_module_unique": { - "name": "dbinfo_module_unique", - "nullsNotDistinct": false, - "columns": ["connection_id", "module"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.integrations": { - "name": "integrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "integrations_name_unique": { - "name": "integrations_name_unique", - "nullsNotDistinct": false, - "columns": ["name"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedule_runs": { - "name": "schedule_runs", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "schedule_id": { - "name": "schedule_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "notification_level": { - "name": "notification_level", - "type": "notification_level", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'info'" - }, - "messages": { - "name": "messages", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "schedule_runs_created_at_idx": { - "name": "schedule_runs_created_at_idx", - "columns": [ - { - "expression": "schedule_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "schedule_runs_schedule_id_fkey": { - "name": "schedule_runs_schedule_id_fkey", - "tableFrom": "schedule_runs", - "tableTo": "schedules", - "columnsFrom": ["schedule_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedules": { - "name": "schedules", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "playbook": { - "name": "playbook", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "schedule_type": { - "name": "schedule_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "cron_expression": { - "name": "cron_expression", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "additional_instructions": { - "name": "additional_instructions", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "min_interval": { - "name": "min_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "max_interval": { - "name": "max_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "last_run": { - "name": "last_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "next_run": { - "name": "next_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "schedule_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'disabled'" - }, - "failures": { - "name": "failures", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "keep_history": { - "name": "keep_history", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 300 - }, - "model": { - "name": "model", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'openai-gpt-4o'" - } - }, - "indexes": {}, - "foreignKeys": { - "schedules_connection_id_fkey": { - "name": "schedules_connection_id_fkey", - "tableFrom": "schedules", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.notification_level": { - "name": "notification_level", - "schema": "public", - "values": ["info", "warning", "alert"] - }, - "public.schedule_status": { - "name": "schedule_status", - "schema": "public", - "values": ["disabled", "scheduled", "running"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/apps/dbagent/migrations/meta/0002_snapshot.json b/apps/dbagent/migrations/meta/0002_snapshot.json deleted file mode 100644 index bab65339..00000000 --- a/apps/dbagent/migrations/meta/0002_snapshot.json +++ /dev/null @@ -1,500 +0,0 @@ -{ - "id": "3118fcc8-7d5c-4790-bd35-65b2242ee0d5", - "prevId": "58d029f6-2a5a-478d-bd5b-624372925bd0", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.assoc_cluster_connections": { - "name": "assoc_cluster_connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_id": { - "name": "cluster_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "assoc_instance_connections_instance_id_fkey": { - "name": "assoc_instance_connections_instance_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "clusters", - "columnsFrom": ["cluster_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "assoc_instance_connections_connection_id_fkey": { - "name": "assoc_instance_connections_connection_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.clusters": { - "name": "clusters", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_identifier": { - "name": "cluster_identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "integration": { - "name": "integration", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'us-east-1'" - } - }, - "indexes": {}, - "foreignKeys": { - "instances_integration_fkey": { - "name": "instances_integration_fkey", - "tableFrom": "clusters", - "tableTo": "integrations", - "columnsFrom": ["integration"], - "columnsTo": ["name"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "instances_integration_identifier_unique": { - "name": "instances_integration_identifier_unique", - "nullsNotDistinct": false, - "columns": ["cluster_identifier", "integration"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connections": { - "name": "connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "connstring": { - "name": "connstring", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "params": { - "name": "params", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "connections_name_unique": { - "name": "connections_name_unique", - "nullsNotDistinct": false, - "columns": ["name"] - }, - "connections_connstring_unique": { - "name": "connections_connstring_unique", - "nullsNotDistinct": false, - "columns": ["connstring"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dbinfo": { - "name": "dbinfo", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "module": { - "name": "module", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "dbinfo_connid_fkey": { - "name": "dbinfo_connid_fkey", - "tableFrom": "dbinfo", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "dbinfo_module_unique": { - "name": "dbinfo_module_unique", - "nullsNotDistinct": false, - "columns": ["connection_id", "module"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.integrations": { - "name": "integrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "integrations_name_unique": { - "name": "integrations_name_unique", - "nullsNotDistinct": false, - "columns": ["name"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedule_runs": { - "name": "schedule_runs", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "schedule_id": { - "name": "schedule_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "notification_level": { - "name": "notification_level", - "type": "notification_level", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'info'" - }, - "messages": { - "name": "messages", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "schedule_runs_created_at_idx": { - "name": "schedule_runs_created_at_idx", - "columns": [ - { - "expression": "schedule_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "schedule_runs_schedule_id_fkey": { - "name": "schedule_runs_schedule_id_fkey", - "tableFrom": "schedule_runs", - "tableTo": "schedules", - "columnsFrom": ["schedule_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedules": { - "name": "schedules", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "playbook": { - "name": "playbook", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "schedule_type": { - "name": "schedule_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "cron_expression": { - "name": "cron_expression", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "additional_instructions": { - "name": "additional_instructions", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "min_interval": { - "name": "min_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "max_interval": { - "name": "max_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "last_run": { - "name": "last_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "next_run": { - "name": "next_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "schedule_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'disabled'" - }, - "failures": { - "name": "failures", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "keep_history": { - "name": "keep_history", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 300 - }, - "model": { - "name": "model", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'openai-gpt-4o'" - } - }, - "indexes": {}, - "foreignKeys": { - "schedules_connection_id_fkey": { - "name": "schedules_connection_id_fkey", - "tableFrom": "schedules", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.notification_level": { - "name": "notification_level", - "schema": "public", - "values": ["info", "warning", "alert"] - }, - "public.schedule_status": { - "name": "schedule_status", - "schema": "public", - "values": ["disabled", "scheduled", "running"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/apps/dbagent/migrations/meta/0003_snapshot.json b/apps/dbagent/migrations/meta/0003_snapshot.json deleted file mode 100644 index 560ac087..00000000 --- a/apps/dbagent/migrations/meta/0003_snapshot.json +++ /dev/null @@ -1,495 +0,0 @@ -{ - "id": "2c78ac6e-edd6-4241-b358-150c77b257c5", - "prevId": "3118fcc8-7d5c-4790-bd35-65b2242ee0d5", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.assoc_cluster_connections": { - "name": "assoc_cluster_connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_id": { - "name": "cluster_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "assoc_instance_connections_instance_id_fkey": { - "name": "assoc_instance_connections_instance_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "aws_clusters", - "columnsFrom": ["cluster_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "assoc_instance_connections_connection_id_fkey": { - "name": "assoc_instance_connections_connection_id_fkey", - "tableFrom": "assoc_cluster_connections", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.aws_clusters": { - "name": "aws_clusters", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_identifier": { - "name": "cluster_identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "integration": { - "name": "integration", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'us-east-1'" - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "fk_aws_clusters_integration_name": { - "name": "fk_aws_clusters_integration_name", - "tableFrom": "aws_clusters", - "tableTo": "integrations", - "columnsFrom": ["integration"], - "columnsTo": ["name"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_aws_clusters_integration_identifier": { - "name": "uq_aws_clusters_integration_identifier", - "nullsNotDistinct": false, - "columns": ["cluster_identifier", "integration"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connection_info": { - "name": "connection_info", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "fk_connections_info_connection": { - "name": "fk_connections_info_connection", - "tableFrom": "connection_info", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_connections_info": { - "name": "uq_connections_info", - "nullsNotDistinct": false, - "columns": ["connection_id", "type"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connections": { - "name": "connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "connection_string": { - "name": "connection_string", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_connections_name": { - "name": "uq_connections_name", - "nullsNotDistinct": false, - "columns": ["name"] - }, - "uq_connections_connection_string": { - "name": "uq_connections_connection_string", - "nullsNotDistinct": false, - "columns": ["connection_string"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.integrations": { - "name": "integrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_integrations_name": { - "name": "uq_integrations_name", - "nullsNotDistinct": false, - "columns": ["name"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedule_runs": { - "name": "schedule_runs", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "schedule_id": { - "name": "schedule_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "notification_level": { - "name": "notification_level", - "type": "notification_level", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'info'" - }, - "messages": { - "name": "messages", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_schedule_runs_created_at": { - "name": "idx_schedule_runs_created_at", - "columns": [ - { - "expression": "schedule_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "fk_schedule_runs_schedule": { - "name": "fk_schedule_runs_schedule", - "tableFrom": "schedule_runs", - "tableTo": "schedules", - "columnsFrom": ["schedule_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedules": { - "name": "schedules", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "playbook": { - "name": "playbook", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "schedule_type": { - "name": "schedule_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "cron_expression": { - "name": "cron_expression", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "additional_instructions": { - "name": "additional_instructions", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "min_interval": { - "name": "min_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "max_interval": { - "name": "max_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "last_run": { - "name": "last_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "next_run": { - "name": "next_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "schedule_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'disabled'" - }, - "failures": { - "name": "failures", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "keep_history": { - "name": "keep_history", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 300 - }, - "model": { - "name": "model", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'openai-gpt-4o'" - } - }, - "indexes": {}, - "foreignKeys": { - "fk_schedules_connection": { - "name": "fk_schedules_connection", - "tableFrom": "schedules", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.notification_level": { - "name": "notification_level", - "schema": "public", - "values": ["info", "warning", "alert"] - }, - "public.schedule_status": { - "name": "schedule_status", - "schema": "public", - "values": ["disabled", "scheduled", "running"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/apps/dbagent/migrations/meta/0004_snapshot.json b/apps/dbagent/migrations/meta/0004_snapshot.json deleted file mode 100644 index a6529efa..00000000 --- a/apps/dbagent/migrations/meta/0004_snapshot.json +++ /dev/null @@ -1,479 +0,0 @@ -{ - "id": "b2cd2fdf-8020-4e54-a5ef-61499c647177", - "prevId": "2c78ac6e-edd6-4241-b358-150c77b257c5", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.aws_cluster_connections": { - "name": "aws_cluster_connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_id": { - "name": "cluster_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "fk_aws_cluster_connections_cluster": { - "name": "fk_aws_cluster_connections_cluster", - "tableFrom": "aws_cluster_connections", - "tableTo": "aws_clusters", - "columnsFrom": ["cluster_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - }, - "fk_aws_cluster_connections_connection": { - "name": "fk_aws_cluster_connections_connection", - "tableFrom": "aws_cluster_connections", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.aws_clusters": { - "name": "aws_clusters", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "cluster_identifier": { - "name": "cluster_identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "region": { - "name": "region", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'us-east-1'" - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_aws_clusters_integration_identifier": { - "name": "uq_aws_clusters_integration_identifier", - "nullsNotDistinct": false, - "columns": ["cluster_identifier"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connection_info": { - "name": "connection_info", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "fk_connections_info_connection": { - "name": "fk_connections_info_connection", - "tableFrom": "connection_info", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_connections_info": { - "name": "uq_connections_info", - "nullsNotDistinct": false, - "columns": ["connection_id", "type"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.connections": { - "name": "connections", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_default": { - "name": "is_default", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "connection_string": { - "name": "connection_string", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_connections_name": { - "name": "uq_connections_name", - "nullsNotDistinct": false, - "columns": ["name"] - }, - "uq_connections_connection_string": { - "name": "uq_connections_connection_string", - "nullsNotDistinct": false, - "columns": ["connection_string"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.integrations": { - "name": "integrations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "uq_integrations_name": { - "name": "uq_integrations_name", - "nullsNotDistinct": false, - "columns": ["name"] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedule_runs": { - "name": "schedule_runs", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "schedule_id": { - "name": "schedule_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "result": { - "name": "result", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "summary": { - "name": "summary", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "notification_level": { - "name": "notification_level", - "type": "notification_level", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'info'" - }, - "messages": { - "name": "messages", - "type": "jsonb", - "primaryKey": false, - "notNull": true - } - }, - "indexes": { - "idx_schedule_runs_created_at": { - "name": "idx_schedule_runs_created_at", - "columns": [ - { - "expression": "schedule_id", - "isExpression": false, - "asc": true, - "nulls": "last" - }, - { - "expression": "created_at", - "isExpression": false, - "asc": true, - "nulls": "last" - } - ], - "isUnique": false, - "concurrently": false, - "method": "btree", - "with": {} - } - }, - "foreignKeys": { - "fk_schedule_runs_schedule": { - "name": "fk_schedule_runs_schedule", - "tableFrom": "schedule_runs", - "tableTo": "schedules", - "columnsFrom": ["schedule_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.schedules": { - "name": "schedules", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "connection_id": { - "name": "connection_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "playbook": { - "name": "playbook", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "schedule_type": { - "name": "schedule_type", - "type": "varchar(255)", - "primaryKey": false, - "notNull": true - }, - "cron_expression": { - "name": "cron_expression", - "type": "varchar(255)", - "primaryKey": false, - "notNull": false - }, - "additional_instructions": { - "name": "additional_instructions", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "min_interval": { - "name": "min_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "max_interval": { - "name": "max_interval", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "last_run": { - "name": "last_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "next_run": { - "name": "next_run", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "status": { - "name": "status", - "type": "schedule_status", - "typeSchema": "public", - "primaryKey": false, - "notNull": true, - "default": "'disabled'" - }, - "failures": { - "name": "failures", - "type": "integer", - "primaryKey": false, - "notNull": false, - "default": 0 - }, - "keep_history": { - "name": "keep_history", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 300 - }, - "model": { - "name": "model", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "'openai-gpt-4o'" - } - }, - "indexes": {}, - "foreignKeys": { - "fk_schedules_connection": { - "name": "fk_schedules_connection", - "tableFrom": "schedules", - "tableTo": "connections", - "columnsFrom": ["connection_id"], - "columnsTo": ["id"], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": { - "public.notification_level": { - "name": "notification_level", - "schema": "public", - "values": ["info", "warning", "alert"] - }, - "public.schedule_status": { - "name": "schedule_status", - "schema": "public", - "values": ["disabled", "scheduled", "running"] - } - }, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} diff --git a/apps/dbagent/migrations/meta/_journal.json b/apps/dbagent/migrations/meta/_journal.json index a7a34ef7..9c634b0c 100644 --- a/apps/dbagent/migrations/meta/_journal.json +++ b/apps/dbagent/migrations/meta/_journal.json @@ -5,37 +5,9 @@ { "idx": 0, "version": "7", - "when": 1740555777405, + "when": 1741087439916, "tag": "0000_init", "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1740839458915, - "tag": "0001_lumpy_black_tarantula", - "breakpoints": true - }, - { - "idx": 2, - "version": "7", - "when": 1740840546323, - "tag": "0002_lazy_galactus", - "breakpoints": true - }, - { - "idx": 3, - "version": "7", - "when": 1741082366512, - "tag": "0003_optimal_gargoyle", - "breakpoints": true - }, - { - "idx": 4, - "version": "7", - "when": 1741086420350, - "tag": "0004_worthless_thor", - "breakpoints": true } ] } diff --git a/apps/dbagent/next.config.ts b/apps/dbagent/next.config.ts index de6a6a5e..e380106b 100644 --- a/apps/dbagent/next.config.ts +++ b/apps/dbagent/next.config.ts @@ -7,7 +7,7 @@ const nextConfig: NextConfig = { return [ { source: '/', - destination: '/start', + destination: '/projects', permanent: false } ]; @@ -16,4 +16,5 @@ const nextConfig: NextConfig = { return []; } }; -module.exports = nextConfig; + +export default nextConfig; diff --git a/apps/dbagent/package.json b/apps/dbagent/package.json index 5e7bee03..6897dfe5 100644 --- a/apps/dbagent/package.json +++ b/apps/dbagent/package.json @@ -74,5 +74,6 @@ "engines": { "node": "22.x", "pnpm": "10.x" - } + }, + "packageManager": "pnpm@10.5.2" } diff --git a/apps/dbagent/src/app/(main)/layout.tsx b/apps/dbagent/src/app/(main)/layout.tsx index 04350668..6e08a61f 100644 --- a/apps/dbagent/src/app/(main)/layout.tsx +++ b/apps/dbagent/src/app/(main)/layout.tsx @@ -1,23 +1,13 @@ -'use server'; -import { getCompletedTaskPercentage } from '~/components/onboarding/actions'; import { BelowHeaderBar, HeaderBar } from '~/components/ui/header-bar'; -import { SideNav } from '~/components/ui/side-nav'; export default async function Layout({ children }: { children: React.ReactNode }) { - const onboardingComplete = await getCompletedTaskPercentage(); - return ( <>
- -
- -
{children}
-
-
+ {children} ); } diff --git a/apps/dbagent/src/app/(main)/chats/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/chats/page.tsx similarity index 52% rename from apps/dbagent/src/app/(main)/chats/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/chats/page.tsx index 7b13e1ce..b06106e8 100644 --- a/apps/dbagent/src/app/(main)/chats/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/chats/page.tsx @@ -1,15 +1,6 @@ -'use server'; - import { actionGetScheduleRun } from '~/components/chats/actions'; import { ChatsUI } from '~/components/chats/chats-ui'; import { listConnections } from '~/lib/db/connections'; -import { ScheduleRun } from '~/lib/db/runs'; -import { Schedule } from '~/lib/db/schedules'; - -async function getConnections() { - const connections = await listConnections(); - return connections; -} interface SearchParams { runId?: string; @@ -17,17 +8,9 @@ interface SearchParams { export default async function Page({ searchParams }: { searchParams: Promise }) { const { runId } = await searchParams; - const connections = await getConnections(); - console.log('runId', runId); - let scheduleRun: { schedule: Schedule; run: ScheduleRun } | undefined; - if (runId) { - try { - scheduleRun = await actionGetScheduleRun(runId); - } catch (error) { - console.error('Error getting schedule run', error); - } - } + const connections = await listConnections(); + const scheduleRun = await actionGetScheduleRun(runId); return (
diff --git a/apps/dbagent/src/app/(main)/projects/[project]/layout.tsx b/apps/dbagent/src/app/(main)/projects/[project]/layout.tsx new file mode 100644 index 00000000..fbdf5d10 --- /dev/null +++ b/apps/dbagent/src/app/(main)/projects/[project]/layout.tsx @@ -0,0 +1,25 @@ +import { getCompletedTaskPercentage } from '~/components/onboarding/actions'; +import { SideNav } from '~/components/ui/side-nav'; + +type LayoutParams = { + project: string; +}; + +export default async function Layout({ + children, + params +}: { + children: React.ReactNode; + params: Promise; +}) { + const { project } = await params; + + const onboardingComplete = await getCompletedTaskPercentage(); + + return ( +
+ +
{children}
+
+ ); +} diff --git a/apps/dbagent/src/app/(main)/monitoring/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/page.tsx similarity index 76% rename from apps/dbagent/src/app/(main)/monitoring/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/monitoring/page.tsx index c4b63f53..72b11eae 100644 --- a/apps/dbagent/src/app/(main)/monitoring/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/page.tsx @@ -1,13 +1,8 @@ import { MonitoringScheduleTable } from '~/components/monitoring/schedules-table'; import { listConnections } from '~/lib/db/connections'; -async function getConnections() { - const connections = await listConnections(); - return connections; -} - export default async function Page() { - const connections = await getConnections(); + const connections = await listConnections(); return (
diff --git a/apps/dbagent/src/app/(main)/monitoring/runs/[scheduleId]/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/runs/[schedule]/page.tsx similarity index 85% rename from apps/dbagent/src/app/(main)/monitoring/runs/[scheduleId]/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/monitoring/runs/[schedule]/page.tsx index 6c3ccd01..7dd093f8 100644 --- a/apps/dbagent/src/app/(main)/monitoring/runs/[scheduleId]/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/runs/[schedule]/page.tsx @@ -2,11 +2,11 @@ import { ScheduleRunsTable } from '~/components/monitoring/schedule-runs-table'; import { getSchedule } from '~/lib/db/schedules'; interface PageParams { - scheduleId: string; + schedule: string; } export default async function Page({ params }: { params: Promise }) { - const { scheduleId } = await params; + const { schedule: scheduleId } = await params; const schedule = await getSchedule(scheduleId); return ( diff --git a/apps/dbagent/src/app/(main)/monitoring/schedule/[id]/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/schedule/[schedule]/page.tsx similarity index 68% rename from apps/dbagent/src/app/(main)/monitoring/schedule/[id]/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/monitoring/schedule/[schedule]/page.tsx index 13ece3be..161d6435 100644 --- a/apps/dbagent/src/app/(main)/monitoring/schedule/[id]/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/monitoring/schedule/[schedule]/page.tsx @@ -3,26 +3,27 @@ import { actionListPlaybooks } from '~/components/monitoring/actions'; import { ScheduleForm } from '~/components/monitoring/schedule-form'; interface PageParams { - id: string; - connection?: string; + project: string; + schedule: string; } export default async function Page({ params }: { params: Promise }) { + const { project, schedule } = await params; + const playbooks = await actionListPlaybooks(); const connections = await actionListConnections(); - const { id, connection } = await params; return (
- {id === 'add' ? ( - + {schedule === 'add' ? ( + ) : ( )}
diff --git a/apps/dbagent/src/app/(main)/playbooks/[name]/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/playbooks/[playbook]/page.tsx similarity index 57% rename from apps/dbagent/src/app/(main)/playbooks/[name]/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/playbooks/[playbook]/page.tsx index 45b02225..1ad04c04 100644 --- a/apps/dbagent/src/app/(main)/playbooks/[name]/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/playbooks/[playbook]/page.tsx @@ -2,8 +2,13 @@ import { notFound } from 'next/navigation'; import { PlaybookView } from '~/components/playbooks/playbook-view'; import { getPlaybookDetails } from '~/lib/tools/playbooks'; -export default function PlaybookPage({ params }: { params: { name: string } }) { - const playbook = getPlaybookDetails(params.name); +type PageParams = { + playbook: string; +}; + +export default async function PlaybookPage({ params }: { params: Promise }) { + const { playbook: playbookName } = await params; + const playbook = getPlaybookDetails(playbookName); if (!playbook) { notFound(); diff --git a/apps/dbagent/src/app/(main)/playbooks/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/playbooks/page.tsx similarity index 100% rename from apps/dbagent/src/app/(main)/playbooks/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/playbooks/page.tsx diff --git a/apps/dbagent/src/app/(main)/start/cloud/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/cloud/page.tsx similarity index 59% rename from apps/dbagent/src/app/(main)/start/cloud/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/cloud/page.tsx index 975ecc15..97a1756d 100644 --- a/apps/dbagent/src/app/(main)/start/cloud/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/start/cloud/page.tsx @@ -1,18 +1,18 @@ -'use server'; import { AWSIntegration } from '~/components/aws-integration/aws-integration'; import { listConnections } from '~/lib/db/connections'; -async function getConnections() { +type PageParams = { + project: string; +}; + +export default async function Page({ params }: { params: Promise }) { const connections = await listConnections(); - return connections; -} + const { project } = await params; -export default async function Page() { - const connections = await getConnections(); return (

Cloud Management Integration

- +
); } diff --git a/apps/dbagent/src/app/(main)/start/collect/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/collect/page.tsx similarity index 97% rename from apps/dbagent/src/app/(main)/start/collect/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/collect/page.tsx index e109031d..2b75605c 100644 --- a/apps/dbagent/src/app/(main)/start/collect/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/start/collect/page.tsx @@ -1,4 +1,3 @@ -'use server'; import { CollectInfo } from '~/components/collect/collect'; import { listConnections } from '~/lib/db/connections'; diff --git a/apps/dbagent/src/app/(main)/projects/[project]/start/connect/add/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/connect/add/page.tsx new file mode 100644 index 00000000..edbd601b --- /dev/null +++ b/apps/dbagent/src/app/(main)/projects/[project]/start/connect/add/page.tsx @@ -0,0 +1,15 @@ +import { ConnectionForm } from '~/components/connections/connection-form'; + +type PageParams = { + project: string; +}; + +export default async function Page({ params }: { params: Promise }) { + const { project } = await params; + + return ( +
+ +
+ ); +} diff --git a/apps/dbagent/src/app/(main)/start/connect/edit/[id]/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/connect/edit/[connection]/page.tsx similarity index 57% rename from apps/dbagent/src/app/(main)/start/connect/edit/[id]/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/connect/edit/[connection]/page.tsx index ce9d30f7..c57c3a86 100644 --- a/apps/dbagent/src/app/(main)/start/connect/edit/[id]/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/start/connect/edit/[connection]/page.tsx @@ -1,11 +1,17 @@ import { ConnectionForm } from '~/components/connections/connection-form'; -export default async function EditConnection({ params }: { params: Promise<{ id: string }> }) { - const { id } = await params; +type PageParams = { + project: string; + connection: string; +}; + +export default async function EditConnection({ params }: { params: Promise }) { + const { project, connection } = await params; + return (

Edit Connection

- +
); } diff --git a/apps/dbagent/src/app/(main)/start/connect/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/connect/page.tsx similarity index 100% rename from apps/dbagent/src/app/(main)/start/connect/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/connect/page.tsx diff --git a/apps/dbagent/src/app/(main)/start/notifications/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/notifications/page.tsx similarity index 54% rename from apps/dbagent/src/app/(main)/start/notifications/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/notifications/page.tsx index 52118d7b..6b0a7cc5 100644 --- a/apps/dbagent/src/app/(main)/start/notifications/page.tsx +++ b/apps/dbagent/src/app/(main)/projects/[project]/start/notifications/page.tsx @@ -1,12 +1,16 @@ -'use server'; - import { SlackIntegration } from '~/components/slack-integration/slack-integration'; -export default async function Page() { +type PageParams = { + project: string; +}; + +export default async function Page({ params }: { params: Promise }) { + const { project } = await params; + return (

Collect info about your database

- +
); } diff --git a/apps/dbagent/src/app/(main)/start/page.tsx b/apps/dbagent/src/app/(main)/projects/[project]/start/page.tsx similarity index 100% rename from apps/dbagent/src/app/(main)/start/page.tsx rename to apps/dbagent/src/app/(main)/projects/[project]/start/page.tsx diff --git a/apps/dbagent/src/app/(main)/projects/page.tsx b/apps/dbagent/src/app/(main)/projects/page.tsx new file mode 100644 index 00000000..5a550a67 --- /dev/null +++ b/apps/dbagent/src/app/(main)/projects/page.tsx @@ -0,0 +1,8 @@ +import { ProjectsList } from '~/components/projects/project-list'; +import { listProjects } from '~/lib/db/projects'; + +export default async function ProjectsPage() { + const result = await listProjects(); + + return ; +} diff --git a/apps/dbagent/src/app/(main)/start/connect/add/page.tsx b/apps/dbagent/src/app/(main)/start/connect/add/page.tsx deleted file mode 100644 index 70837466..00000000 --- a/apps/dbagent/src/app/(main)/start/connect/add/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { ConnectionForm } from '~/components/connections/connection-form'; - -export default function Page() { - return ( -
- -
- ); -} diff --git a/apps/dbagent/src/app/signin/page.tsx b/apps/dbagent/src/app/signin/page.tsx index 882455d1..f5b25589 100644 --- a/apps/dbagent/src/app/signin/page.tsx +++ b/apps/dbagent/src/app/signin/page.tsx @@ -1,15 +1,15 @@ 'use client'; import { signIn, useSession } from 'next-auth/react'; -import { useRouter } from 'next/navigation'; -import { useEffect } from 'react'; +import { useRouter, useSearchParams } from 'next/navigation'; +import { Suspense, useEffect } from 'react'; -export default function Page() { +function SignIn() { const session = useSession(); const router = useRouter(); + const searchParams = useSearchParams(); - const params = new URLSearchParams(window.location.search); - const callbackUrl = params.get('callbackUrl'); + const callbackUrl = searchParams.get('callbackUrl'); useEffect(() => { if (session.status === 'unauthenticated') { @@ -25,3 +25,11 @@ export default function Page() { return null; } + +export default function SignInPage() { + return ( + + + + ); +} diff --git a/apps/dbagent/src/auth.ts b/apps/dbagent/src/auth.ts index 0c1baf01..016f5096 100644 --- a/apps/dbagent/src/auth.ts +++ b/apps/dbagent/src/auth.ts @@ -23,7 +23,7 @@ function getProviders() { id: 'default', name: 'Local auth', async authorize() { - return { name: 'User', email: 'user@localhost' }; + return { id: 'local', name: 'User', email: 'user@localhost' }; } }) ]; @@ -39,6 +39,33 @@ const { handlers, signIn, signOut, auth } = NextAuth({ strategy: 'jwt' }, callbacks: { + async jwt({ token, account, user }) { + // Initial sign-in + if (account && user) { + return { + accessToken: account.access_token, + refreshToken: account.refresh_token, + expiresAt: Date.now() + (account.expires_in ?? 100) * 1000, + user + }; + } + + return token; + }, + async session({ session, token }) { + // @ts-expect-error Types don't match + session.user = token.user; + // @ts-expect-error Types don't match + session.token = { + accessToken: token.accessToken, + expiresAt: token.expiresAt, + refreshToken: token.refreshToken + }; + // @ts-expect-error Types don't match + session.error = token.error; + + return session; + }, authorized: async ({ auth }) => { // Logged in users are authenticated, otherwise redirect to login page return !!auth; diff --git a/apps/dbagent/src/components/aws-integration/actions.ts b/apps/dbagent/src/components/aws-integration/actions.ts index 1f76afa7..470653ec 100644 --- a/apps/dbagent/src/components/aws-integration/actions.ts +++ b/apps/dbagent/src/components/aws-integration/actions.ts @@ -9,11 +9,12 @@ import { RDSClusterDetailedInfo, RDSClusterInfo } from '~/lib/aws/rds'; -import { associateClusterConnection, saveCluster } from '~/lib/db/clusters'; -import { DbConnection } from '~/lib/db/connections'; +import { associateClusterConnection, saveCluster } from '~/lib/db/aws-clusters'; +import { Connection } from '~/lib/db/connections'; import { AwsIntegration, getIntegration, saveIntegration } from '~/lib/db/integrations'; export async function fetchRDSClusters( + projectId: string, accessKeyId: string, secretAccessKey: string, region: string @@ -25,7 +26,6 @@ export async function fetchRDSClusters( const instances = await listRDSInstances(client); // Add standalone instances as "clusters" with single instance const standaloneInstances = instances.filter((instance) => !instance.dbClusterIdentifier); - console.log('standaloneInstances', standaloneInstances); const standaloneAsClusters: RDSClusterInfo[] = standaloneInstances.map((instance) => ({ identifier: instance.identifier, engine: instance.engine, @@ -40,7 +40,7 @@ export async function fetchRDSClusters( })); clusters.push(...standaloneAsClusters); - await saveIntegration('aws', { accessKeyId, secretAccessKey, region }); + await saveIntegration(projectId, 'aws', { accessKeyId, secretAccessKey, region }); return { success: true, message: 'RDS instances fetched successfully', data: clusters }; } catch (error) { console.error('Error fetching RDS instances:', error); @@ -96,7 +96,7 @@ export async function getAWSIntegration(): Promise<{ success: boolean; message: export async function saveClusterDetails( clusterIdentifier: string, region: string, - connection: DbConnection + connection: Connection ): Promise<{ success: boolean; message: string }> { const aws = await getIntegration('aws'); if (!aws) { diff --git a/apps/dbagent/src/components/aws-integration/aws-integration.tsx b/apps/dbagent/src/components/aws-integration/aws-integration.tsx index 785f929f..27e590dd 100644 --- a/apps/dbagent/src/components/aws-integration/aws-integration.tsx +++ b/apps/dbagent/src/components/aws-integration/aws-integration.tsx @@ -19,7 +19,7 @@ import { import { Loader2 } from 'lucide-react'; import { useEffect, useState } from 'react'; import { RDSClusterDetailedInfo, RDSClusterInfo } from '~/lib/aws/rds'; -import { DbConnection } from '~/lib/db/connections'; +import { Connection } from '~/lib/db/connections'; import { fetchRDSClusterDetails, fetchRDSClusters, getAWSIntegration } from './actions'; import { DatabaseConnectionSelector } from './db-instance-connector'; import { RDSClusterCard } from './rds-instance-card'; @@ -36,7 +36,7 @@ const regions = [ 'ap-northeast-1' ]; -export function AWSIntegration({ connections }: { connections: DbConnection[] }) { +export function AWSIntegration({ projectId, connections }: { projectId: string; connections: Connection[] }) { const [accessKeyId, setAccessKeyId] = useState(''); const [secretAccessKey, setSecretAccessKey] = useState(''); const [region, setRegion] = useState(''); @@ -61,7 +61,7 @@ export function AWSIntegration({ connections }: { connections: DbConnection[] }) e.preventDefault(); setIsLoading(true); try { - const response = await fetchRDSClusters(accessKeyId, secretAccessKey, region); + const response = await fetchRDSClusters(projectId, accessKeyId, secretAccessKey, region); if (response.success) { if (response.data.length === 0) { toast('No RDS clusters found in the selected region'); diff --git a/apps/dbagent/src/components/aws-integration/db-instance-connector.tsx b/apps/dbagent/src/components/aws-integration/db-instance-connector.tsx index d86627c8..7b6fcb29 100644 --- a/apps/dbagent/src/components/aws-integration/db-instance-connector.tsx +++ b/apps/dbagent/src/components/aws-integration/db-instance-connector.tsx @@ -1,13 +1,13 @@ 'use client'; import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast } from '@internal/components'; import { useState } from 'react'; -import { DbConnection } from '~/lib/db/connections'; +import { Connection } from '~/lib/db/connections'; import { saveClusterDetails } from './actions'; interface DatabaseConnectionSelectorProps { clusterIdentifier: string; region: string; - connections: DbConnection[]; + connections: Connection[]; } export function DatabaseConnectionSelector({ @@ -16,7 +16,7 @@ export function DatabaseConnectionSelector({ connections }: DatabaseConnectionSelectorProps) { const defaultConnection = connections.find((c) => c.isDefault); - const [selectedConnection, setSelectedConnection] = useState(defaultConnection); + const [selectedConnection, setSelectedConnection] = useState(defaultConnection); const handleAssociate = async () => { if (!selectedConnection) { diff --git a/apps/dbagent/src/components/chats/actions.ts b/apps/dbagent/src/components/chats/actions.ts index dcf8ba71..a26ef206 100644 --- a/apps/dbagent/src/components/chats/actions.ts +++ b/apps/dbagent/src/components/chats/actions.ts @@ -1,10 +1,16 @@ 'use server'; -import { getScheduleRun, ScheduleRun } from '~/lib/db/runs'; -import { getSchedule, Schedule } from '~/lib/db/schedules'; +import { getScheduleRun } from '~/lib/db/schedule-runs'; +import { getSchedule } from '~/lib/db/schedules'; -export async function actionGetScheduleRun(runId: string): Promise<{ schedule: Schedule; run: ScheduleRun }> { - const run = await getScheduleRun(runId); - const schedule = await getSchedule(run.scheduleId); - return { schedule, run }; +export async function actionGetScheduleRun(runId?: string) { + if (!runId) return null; + + try { + const run = await getScheduleRun(runId); + const schedule = await getSchedule(run.scheduleId); + return { schedule, run }; + } catch (error) { + return null; + } } diff --git a/apps/dbagent/src/components/chats/chats-ui.tsx b/apps/dbagent/src/components/chats/chats-ui.tsx index d47483d5..0452a7c1 100644 --- a/apps/dbagent/src/components/chats/chats-ui.tsx +++ b/apps/dbagent/src/components/chats/chats-ui.tsx @@ -17,8 +17,8 @@ import { Bot, Clock, Lightbulb, Send, User, Wrench } from 'lucide-react'; import { useSearchParams } from 'next/navigation'; import { Suspense, useEffect, useRef, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import { DbConnection } from '~/lib/db/connections'; -import { ScheduleRun } from '~/lib/db/runs'; +import { Connection } from '~/lib/db/connections'; +import { ScheduleRun } from '~/lib/db/schedule-runs'; import { Schedule } from '~/lib/db/schedules'; import { ChatSidebar } from './chat-sidebar'; import { ConnectionSelector } from './conn-selector'; @@ -29,8 +29,8 @@ export function ChatsUI({ connections, scheduleRun }: { - connections: DbConnection[]; - scheduleRun?: { schedule: Schedule; run: ScheduleRun }; + connections: Connection[]; + scheduleRun?: { schedule: Schedule; run: ScheduleRun } | null; }) { return ( Loading...
}> @@ -43,8 +43,8 @@ function ChatsUIContent({ connections, scheduleRun }: { - connections: DbConnection[]; - scheduleRun?: { schedule: Schedule; run: ScheduleRun }; + connections: Connection[]; + scheduleRun?: { schedule: Schedule; run: ScheduleRun } | null; }) { const searchParams = useSearchParams(); const [selectedChatId, setSelectedChatId] = useState(null); diff --git a/apps/dbagent/src/components/chats/conn-selector.tsx b/apps/dbagent/src/components/chats/conn-selector.tsx index 3ba399f8..61503267 100644 --- a/apps/dbagent/src/components/chats/conn-selector.tsx +++ b/apps/dbagent/src/components/chats/conn-selector.tsx @@ -1,24 +1,24 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@internal/components'; import * as React from 'react'; -import { DbConnection } from '~/lib/db/connections'; +import { Connection } from '~/lib/db/connections'; export function ConnectionSelector({ connections, onSelect, connectionId }: { - connections: DbConnection[]; + connections: Connection[]; onSelect: (connectionId: string) => void; connectionId?: string; }) { - let defaultConnection: DbConnection | undefined; + let defaultConnection: Connection | undefined; if (connectionId) { defaultConnection = connections.find((c) => c.id === connectionId); } else { defaultConnection = connections.find((c) => c.isDefault); } - const [selectedConnection, setSelectedConnection] = React.useState(defaultConnection); + const [selectedConnection, setSelectedConnection] = React.useState(defaultConnection); return ( - {errors.connstring &&

{errors.connstring.message}

} + {errors.connectionString &&

{errors.connectionString.message}

}
{id && !showDeleteConfirm && ( @@ -120,7 +126,7 @@ export function ConnectionForm({ id }: ConnectionFormProps) { )} -
diff --git a/apps/dbagent/src/components/monitoring/actions.ts b/apps/dbagent/src/components/monitoring/actions.ts index f662151c..0905cf30 100644 --- a/apps/dbagent/src/components/monitoring/actions.ts +++ b/apps/dbagent/src/components/monitoring/actions.ts @@ -2,7 +2,7 @@ import { openai } from '@ai-sdk/openai'; import { generateText } from 'ai'; -import { getScheduleRuns, ScheduleRun } from '~/lib/db/runs'; +import { getScheduleRuns, ScheduleRun } from '~/lib/db/schedule-runs'; import { deleteSchedule, getSchedule, diff --git a/apps/dbagent/src/components/monitoring/schedule-form.tsx b/apps/dbagent/src/components/monitoring/schedule-form.tsx index a930d966..92e9781b 100644 --- a/apps/dbagent/src/components/monitoring/schedule-form.tsx +++ b/apps/dbagent/src/components/monitoring/schedule-form.tsx @@ -29,7 +29,7 @@ import Link from 'next/link'; import { useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useState } from 'react'; import * as z from 'zod'; -import { DbConnection } from '~/lib/db/connections'; +import { Connection } from '~/lib/db/connections'; import { Schedule } from '~/lib/db/schedules'; import { ModelSelector } from '../chats/model-selector'; import { actionCreateSchedule, actionDeleteSchedule, actionGetSchedule, actionUpdateSchedule } from './actions'; @@ -58,12 +58,12 @@ type ScheduleFormEditParams = }; type ScheduleFormParams = { + projectId: string; playbooks: string[]; - connections: DbConnection[]; - connection?: string; + connections: Connection[]; } & ScheduleFormEditParams; -export function ScheduleForm({ isEditMode, scheduleId, playbooks, connections }: ScheduleFormParams) { +export function ScheduleForm({ projectId, isEditMode, scheduleId, playbooks, connections }: ScheduleFormParams) { const router = useRouter(); const searchParams = useSearchParams(); const [showCronModal, setShowCronModal] = useState(false); @@ -107,6 +107,7 @@ export function ScheduleForm({ isEditMode, scheduleId, playbooks, connections }: const onSubmit = async (data: z.infer) => { const schedule: Omit = { + projectId, connectionId: connections.find((c) => c.name === data.connection)?.id.toString() || '', model: data.model, playbook: data.playbook, @@ -125,14 +126,14 @@ export function ScheduleForm({ isEditMode, scheduleId, playbooks, connections }: await actionCreateSchedule(schedule); } console.log(data); - router.push('/monitoring'); + router.push(`/projects/${projectId}/monitoring`); }; const handleDelete = async () => { if (!scheduleId) return; await actionDeleteSchedule(scheduleId); - router.push('/monitoring'); + router.push(`/projects/${projectId}/monitoring`); }; return ( @@ -345,7 +346,7 @@ export function ScheduleForm({ isEditMode, scheduleId, playbooks, connections }: )} )} - + diff --git a/apps/dbagent/src/components/monitoring/schedule-runs-table.tsx b/apps/dbagent/src/components/monitoring/schedule-runs-table.tsx index d4081166..257f82a9 100644 --- a/apps/dbagent/src/components/monitoring/schedule-runs-table.tsx +++ b/apps/dbagent/src/components/monitoring/schedule-runs-table.tsx @@ -31,9 +31,10 @@ import { PlayCircle } from 'lucide-react'; import Link from 'next/link'; +import { useParams } from 'next/navigation'; import { useEffect, useState } from 'react'; import ReactMarkdown from 'react-markdown'; -import { ScheduleRun } from '~/lib/db/runs'; +import { ScheduleRun } from '~/lib/db/schedule-runs'; import { Schedule } from '~/lib/db/schedules'; import { actionGetScheduleRuns } from './actions'; @@ -41,6 +42,7 @@ export function ScheduleRunsTable({ schedule }: { schedule: Schedule }) { const [isLoading, setIsLoading] = useState(true); const [runs, setRuns] = useState([]); const [expandedRows, setExpandedRows] = useState>({}); + const { project } = useParams<{ project: string }>(); useEffect(() => { const fetchRuns = async () => { @@ -208,7 +210,7 @@ export function ScheduleRunsTable({ schedule }: { schedule: Schedule }) { - + - + @@ -128,7 +130,7 @@ export function MonitoringScheduleTable({ connections }: { connections: DbConnec - + @@ -172,12 +174,12 @@ export function MonitoringScheduleTable({ connections }: { connections: DbConnec
- + - + diff --git a/apps/dbagent/src/components/onboarding/actions.ts b/apps/dbagent/src/components/onboarding/actions.ts index f43fdb50..64075495 100644 --- a/apps/dbagent/src/components/onboarding/actions.ts +++ b/apps/dbagent/src/components/onboarding/actions.ts @@ -1,8 +1,8 @@ 'use server'; -import { getClusters } from '~/lib/db/clusters'; +import { getClusters } from '~/lib/db/aws-clusters'; +import { getConnectionInfo } from '~/lib/db/connection-info'; import { getDefaultConnection } from '~/lib/db/connections'; -import { getDbInfo } from '~/lib/db/dbinfo'; import { getIntegration } from '~/lib/db/integrations'; // Server action to get completed tasks @@ -14,7 +14,7 @@ export async function getCompletedTasks(): Promise { } completedTasks.push('connect'); - const tables = await getDbInfo(connection.id, 'tables'); + const tables = await getConnectionInfo(connection.id, 'tables'); if (tables) { completedTasks.push('collect'); } diff --git a/apps/dbagent/src/components/onboarding/onboarding.tsx b/apps/dbagent/src/components/onboarding/onboarding.tsx index f0bc9937..028a6e48 100644 --- a/apps/dbagent/src/components/onboarding/onboarding.tsx +++ b/apps/dbagent/src/components/onboarding/onboarding.tsx @@ -3,7 +3,7 @@ import { Button } from '@internal/components'; import confetti from 'canvas-confetti'; import { Activity, Check, Database, GitBranch, Server } from 'lucide-react'; -import { useRouter } from 'next/navigation'; +import { useParams, useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { getCompletedTasks } from './actions'; import { OnboardingProgress } from './onboarding-progress'; @@ -43,6 +43,7 @@ export const onboardingTasks = [ export function Onboarding() { const router = useRouter(); const [completedTasks, setCompletedTasks] = useState([]); + const { project } = useParams<{ project: string }>(); useEffect(() => { getCompletedTasks() @@ -68,7 +69,7 @@ export function Onboarding() { }, []); const handleTaskAction = async (navigateTo: string) => { - router.push(navigateTo); + router.push(`/projects/${project}/${navigateTo}`); }; return ( @@ -113,8 +114,10 @@ export function Onboarding() {

- - +
diff --git a/apps/dbagent/src/components/playbooks/playbook-view.tsx b/apps/dbagent/src/components/playbooks/playbook-view.tsx index ba113394..98a813d8 100644 --- a/apps/dbagent/src/components/playbooks/playbook-view.tsx +++ b/apps/dbagent/src/components/playbooks/playbook-view.tsx @@ -3,9 +3,12 @@ import { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@internal/components'; import { ArrowLeft, Clock, PlayCircle } from 'lucide-react'; import Link from 'next/link'; +import { useParams } from 'next/navigation'; import { Playbook } from '~/lib/tools/playbooks'; export function PlaybookView({ playbook }: { playbook: Playbook }) { + const { project } = useParams<{ project: string }>(); + return (
@@ -27,13 +30,13 @@ export function PlaybookView({ playbook }: { playbook: Playbook }) {
{playbook.content}
- + - + @@ -76,7 +77,7 @@ export function PlaybooksTable() { variant="outline" size="icon" title="Run playbook" - onClick={() => router.push(`/chats?playbook=${playbook.name}`)} + onClick={() => router.push(`/projects/${project}/chats?playbook=${playbook.name}`)} > @@ -84,7 +85,9 @@ export function PlaybooksTable() { variant="outline" size="icon" title="Schedule playbook" - onClick={() => router.push(`/monitoring/schedule/add?playbook=${playbook.name}`)} + onClick={() => + router.push(`/projects/${project}/monitoring/schedule/add?playbook=${playbook.name}`) + } > diff --git a/apps/dbagent/src/components/projects/project-list.tsx b/apps/dbagent/src/components/projects/project-list.tsx new file mode 100644 index 00000000..863fba43 --- /dev/null +++ b/apps/dbagent/src/components/projects/project-list.tsx @@ -0,0 +1,324 @@ +'use client'; + +import { + Button, + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, + Input, + Label, + Popover, + PopoverContent, + PopoverTrigger, + Skeleton, + toast +} from '@internal/components'; +import { Database, MoreVertical, PlusCircle } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { Suspense, useState } from 'react'; +import { createProject, deleteProject, Project, updateProject } from '~/lib/db/projects'; + +interface ProjectListProps { + projects: Project[]; +} + +function CreateProjectButton() { + const [projectName, setProjectName] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!projectName.trim()) return; + + setIsLoading(true); + + const result = await createProject({ name: projectName }); + if (result.success) { + router.push(`/projects/${result.id}/start`); + } else { + toast.error(result.error); + } + + setIsLoading(false); + }; + + return ( + + + + + +
+
+
+ + setProjectName(e.target.value)} + required + className="border-primary/20 focus-visible:ring-primary/30" + /> +
+
+
+ +
+ +
+
+ ); +} + +export function ProjectsList({ projects }: ProjectListProps) { + return ( +
+ {projects.length === 0 ? ( + + ) : ( +
+
+
+

Database Projects

+

Manage your postgres database projects

+
+ +
+ + +
+ )} +
+ ); +} + +function ProjectListView({ projects }: ProjectListProps) { + return ( + + {[1, 2, 3].map((i) => ( + + + + + + + + + + + + + + ))} +
+ } + > +
+ {projects.map((project) => ( + + ))} +
+ + ); +} + +function ProjectCard({ project }: { project: Project }) { + const router = useRouter(); + const [showRenameModal, setShowRenameModal] = useState(false); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [newProjectName, setNewProjectName] = useState(''); + + const handleRename = async () => { + if (newProjectName.trim() !== '') { + const result = await updateProject(project.id, { name: newProjectName }); + if (result.success) { + toast.success('Project renamed successfully'); + router.refresh(); + } else { + toast.error(result.error); + } + setShowRenameModal(false); + } + }; + + const handleDelete = async () => { + const result = await deleteProject({ id: project.id }); + if (result.success) { + toast.success('Project deleted successfully'); + router.refresh(); + } else { + toast.error(result.error); + } + setShowDeleteModal(false); + }; + + return ( + <> + { + router.push(`/projects/${project.id}/start`); + }} + > +
+
+ + {project.name} +
+ + { + e.stopPropagation(); + }} + > + + + + { + e.stopPropagation(); + setShowRenameModal(true); + }} + > + Rename + + { + e.stopPropagation(); + setShowDeleteModal(true); + }} + > + Delete + + + +
+
+ + setShowRenameModal(open)}> + + + Rename Project + + setNewProjectName(e.target.value)} + placeholder="Enter new project name" + /> + + + + + + + + setShowDeleteModal(open)}> + + + Delete Project + + Are you sure you want to delete this project? + + + + + + + + ); +} + +function CreateProjectOnboarding() { + const router = useRouter(); + + const [projectName, setProjectName] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!projectName.trim()) return; + + setIsLoading(true); + + const result = await createProject({ name: projectName }); + if (result.success) { + router.push(`/projects/${result.id}/start`); + } else { + toast.error(result.error); + } + + setIsLoading(false); + }; + + return ( +
+
+ {[...Array(20)].map((_, i) => ( +
+ ))} +
+ + +
+ +
+
+ + setProjectName(e.target.value)} + required + className="border-primary/20 focus-visible:ring-primary/30" + /> +
+
+
+ + + + +
+
+ ); +} diff --git a/apps/dbagent/src/components/slack-integration/actions.ts b/apps/dbagent/src/components/slack-integration/actions.ts index 70b77458..0b51c122 100644 --- a/apps/dbagent/src/components/slack-integration/actions.ts +++ b/apps/dbagent/src/components/slack-integration/actions.ts @@ -2,7 +2,10 @@ import { getIntegration, saveIntegration, SlackIntegration } from '~/lib/db/integrations'; -export async function saveWebhookUrl(webhookUrl: string): Promise<{ success: boolean; message: string }> { +export async function saveWebhookUrl( + projectId: string, + webhookUrl: string +): Promise<{ success: boolean; message: string }> { // TODO: Implement actual saving logic here // This is a placeholder for demonstration purposes const success = webhookUrl && webhookUrl.startsWith('https://hooks.slack.com/'); @@ -13,7 +16,7 @@ export async function saveWebhookUrl(webhookUrl: string): Promise<{ success: boo } try { - await saveIntegration('slack', { webhookUrl }); + await saveIntegration(projectId, 'slack', { webhookUrl }); } catch (error) { console.error('Failed to save webhook URL:', error); return { success: false, message: `Failed to save webhook URL.` }; diff --git a/apps/dbagent/src/components/slack-integration/slack-integration.tsx b/apps/dbagent/src/components/slack-integration/slack-integration.tsx index 8683c503..244e4a8f 100644 --- a/apps/dbagent/src/components/slack-integration/slack-integration.tsx +++ b/apps/dbagent/src/components/slack-integration/slack-integration.tsx @@ -20,7 +20,7 @@ import Link from 'next/link'; import { useEffect, useState } from 'react'; import { getWebhookUrl, saveWebhookUrl } from './actions'; -export function SlackIntegration() { +export function SlackIntegration({ projectId }: { projectId: string }) { const [isLoading, setIsLoading] = useState(true); const { @@ -53,7 +53,7 @@ export function SlackIntegration() { const onSubmit = async (data: { webhookUrl: string }) => { try { - const response = await saveWebhookUrl(data.webhookUrl); + const response = await saveWebhookUrl(projectId, data.webhookUrl); if (response.success) { toast('Slack webhook URL saved successfully'); } else { diff --git a/apps/dbagent/src/components/ui/aws-rds-icon.tsx b/apps/dbagent/src/components/ui/aws-rds-icon.tsx new file mode 100644 index 00000000..d8395785 --- /dev/null +++ b/apps/dbagent/src/components/ui/aws-rds-icon.tsx @@ -0,0 +1,20 @@ +export const RDSIcon = ({ className }: { className?: string }) => ( + + + + + + + + + + + + + + +); diff --git a/apps/dbagent/src/components/ui/azure-icon.tsx b/apps/dbagent/src/components/ui/azure-icon.tsx new file mode 100644 index 00000000..ed34c588 --- /dev/null +++ b/apps/dbagent/src/components/ui/azure-icon.tsx @@ -0,0 +1,40 @@ +export const AzureIcon = ({ className }: { className?: string }) => ( + + + + + + + + + + + + + + + + + + +); diff --git a/apps/dbagent/src/components/ui/google-cloud-sql-icon.tsx b/apps/dbagent/src/components/ui/google-cloud-sql-icon.tsx new file mode 100644 index 00000000..10cf5fb9 --- /dev/null +++ b/apps/dbagent/src/components/ui/google-cloud-sql-icon.tsx @@ -0,0 +1,15 @@ +export const GoogleCloudSQLIcon = ({ className }: { className?: string }) => ( + + + + + + + + + + +); diff --git a/apps/dbagent/src/components/ui/header-bar.tsx b/apps/dbagent/src/components/ui/header-bar.tsx index a0530a5c..68bb73a6 100644 --- a/apps/dbagent/src/components/ui/header-bar.tsx +++ b/apps/dbagent/src/components/ui/header-bar.tsx @@ -5,7 +5,6 @@ import { Avatar, AvatarImage, AvatarInitials, - Button, DropdownMenu, DropdownMenuContent, DropdownMenuGroup, @@ -13,7 +12,6 @@ import { DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, - MakiLogoSymbol, useIsMobile } from '@internal/components'; import { useSession } from 'next-auth/react'; @@ -40,7 +38,6 @@ export const HeaderBar = ({ children }: PropsWithChildren<{ user?: User }>) => { @@ -63,7 +54,7 @@ export const HeaderBar = ({ children }: PropsWithChildren<{ user?: User }>) => { }; export const BelowHeaderBar = ({ children }: PropsWithChildren) => { - return
{children}
; + return
{children}
; }; function UserAvatar({ user }: { user?: User }) { diff --git a/apps/dbagent/src/components/ui/postgres-icon.tsx b/apps/dbagent/src/components/ui/postgres-icon.tsx new file mode 100644 index 00000000..ac700dc4 --- /dev/null +++ b/apps/dbagent/src/components/ui/postgres-icon.tsx @@ -0,0 +1,11 @@ +export const PostgresIcon = ({ className }: { className?: string }) => ( + + + + +); diff --git a/apps/dbagent/src/components/ui/side-nav.tsx b/apps/dbagent/src/components/ui/side-nav.tsx index 8faefb46..cfd7ad13 100644 --- a/apps/dbagent/src/components/ui/side-nav.tsx +++ b/apps/dbagent/src/components/ui/side-nav.tsx @@ -1,6 +1,6 @@ 'use client'; -import { cn, Input } from '@internal/components'; +import { cn } from '@internal/components'; import { ActivityIcon, AlarmClock, @@ -17,10 +17,11 @@ import { useEffect, useState } from 'react'; interface SideNavProps { className?: string; + projectId: string; onboardingComplete: number; } -export function SideNav({ className, onboardingComplete }: SideNavProps) { +export function SideNav({ className, projectId, onboardingComplete }: SideNavProps) { const pathname = usePathname(); const [onboardingCompleteState, setOnboardingComplete] = useState(onboardingComplete); @@ -41,15 +42,14 @@ export function SideNav({ className, onboardingComplete }: SideNavProps) { }; }, []); - console.log('onboardingComplete', onboardingCompleteState); + const basePath = `/projects/${projectId}`; return (
-