diff --git a/e2e-tests/fixtures/execute-sql-1.md b/e2e-tests/fixtures/execute-sql-1.md
new file mode 100644
index 0000000..82fa7ba
--- /dev/null
+++ b/e2e-tests/fixtures/execute-sql-1.md
@@ -0,0 +1,7 @@
+Example SQL
+
+
+CREATE TABLE users (id serial primary key);
+
+
+Done.
diff --git a/e2e-tests/fixtures/execute-sql-no-description.md b/e2e-tests/fixtures/execute-sql-no-description.md
new file mode 100644
index 0000000..cc709f2
--- /dev/null
+++ b/e2e-tests/fixtures/execute-sql-no-description.md
@@ -0,0 +1,7 @@
+No description!
+
+
+DROP TABLE users;
+
+
+Done.
diff --git a/e2e-tests/helpers/test_helper.ts b/e2e-tests/helpers/test_helper.ts
index ba5b62c..3bc5f83 100644
--- a/e2e-tests/helpers/test_helper.ts
+++ b/e2e-tests/helpers/test_helper.ts
@@ -579,6 +579,10 @@ export class PageObject {
await this.page.getByRole("link", { name: "Apps" }).click();
}
+ async goToChatTab() {
+ await this.page.getByRole("link", { name: "Chat" }).click();
+ }
+
async goToHubTab() {
await this.page.getByRole("link", { name: "Hub" }).click();
}
diff --git a/e2e-tests/supabase_migrations.spec.ts b/e2e-tests/supabase_migrations.spec.ts
new file mode 100644
index 0000000..4c9d4f5
--- /dev/null
+++ b/e2e-tests/supabase_migrations.spec.ts
@@ -0,0 +1,61 @@
+import { expect } from "@playwright/test";
+import { test } from "./helpers/test_helper";
+import fs from "fs-extra";
+import path from "path";
+
+test("supabase migrations", async ({ po }) => {
+ await po.setUp({ autoApprove: true });
+ await po.sendPrompt("tc=add-supabase");
+
+ // Connect to Supabase
+ await po.page.getByText("Set up supabase").click();
+ await po.clickConnectSupabaseButton();
+ await po.clickBackButton();
+
+ const appPath = await po.getCurrentAppPath();
+ const migrationsDir = path.join(appPath, "supabase", "migrations");
+
+ // --- SCENARIO 1: OFF BY DEFAULT ---
+ await po.sendPrompt("tc=execute-sql-1");
+ await po.waitForChatCompletion();
+
+ expect(fs.existsSync(migrationsDir)).toBe(false);
+
+ // --- SCENARIO 2: TOGGLE ON ---
+ // Go to settings to find the Supabase integration
+ await po.goToSettingsTab();
+ const migrationsSwitch = po.page.locator("#supabase-migrations");
+ await migrationsSwitch.click();
+ await po.goToChatTab();
+
+ // Send a prompt that triggers a migration
+ await po.sendPrompt("tc=execute-sql-1");
+ await po.waitForChatCompletion();
+
+ let files: string[] = [];
+ await expect(async () => {
+ // Check that one migration file was created
+ files = await fs.readdir(migrationsDir);
+ expect(files).toHaveLength(1);
+ }).toPass();
+
+ expect(files[0]).toMatch(/0000_create_users_table\.sql/);
+ expect(await fs.readFile(path.join(migrationsDir, files[0]), "utf8")).toEqual(
+ "CREATE TABLE users (id serial primary key);",
+ );
+
+ // Send a prompt that triggers a migration
+ await po.sendPrompt("tc=execute-sql-no-description");
+ await po.waitForChatCompletion();
+
+ await expect(async () => {
+ // Check that one migration file was created
+ files = await fs.readdir(migrationsDir);
+ expect(files).toHaveLength(2);
+ }).toPass();
+
+ expect(files[1]).toMatch(/0001_\w+_\w+_\w+\.sql/);
+ expect(await fs.readFile(path.join(migrationsDir, files[1]), "utf8")).toEqual(
+ "DROP TABLE users;",
+ );
+});
diff --git a/src/components/SupabaseIntegration.tsx b/src/components/SupabaseIntegration.tsx
index 4d72921..bef7157 100644
--- a/src/components/SupabaseIntegration.tsx
+++ b/src/components/SupabaseIntegration.tsx
@@ -1,5 +1,7 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
+import { Switch } from "@/components/ui/switch";
+import { Label } from "@/components/ui/label";
// We might need a Supabase icon here, but for now, let's use a generic one or text.
// import { Supabase } from "lucide-react"; // Placeholder
import { DatabaseZap } from "lucide-react"; // Using DatabaseZap as a placeholder
@@ -16,6 +18,8 @@ export function SupabaseIntegration() {
// Clear the entire supabase object in settings
const result = await updateSettings({
supabase: undefined,
+ // Also disable the migration setting on disconnect
+ enableSupabaseWriteSqlMigration: false,
});
if (result) {
showSuccess("Successfully disconnected from Supabase");
@@ -31,6 +35,17 @@ export function SupabaseIntegration() {
}
};
+ const handleMigrationSettingChange = async (enabled: boolean) => {
+ try {
+ await updateSettings({
+ enableSupabaseWriteSqlMigration: enabled,
+ });
+ showSuccess("Setting updated");
+ } catch (err: any) {
+ showError(err.message || "Failed to update setting");
+ }
+ };
+
// Check if there's any Supabase accessToken to determine connection status
const isConnected = !!settings?.supabase?.accessToken;
@@ -39,26 +54,50 @@ export function SupabaseIntegration() {
}
return (
-
-
-
- Supabase Integration
-
-
- Your account is connected to Supabase.
-
+
+
+
+
+ Supabase Integration
+
+
+ Your account is connected to Supabase.
+
+
+
+
+
+
+
+
+
+
+ Generate SQL migration files when modifying your Supabase schema.
+ This helps you track database changes in version control, though
+ these files aren't used for chat context, which uses the live
+ schema.
+