Supabase integration experiment setting (off by default)

This commit is contained in:
Will Chen
2025-04-22 17:12:51 -07:00
parent 2a08f72378
commit bf70c1bb00
6 changed files with 108 additions and 12 deletions

View File

@@ -0,0 +1,64 @@
import { useState, useEffect } from "react";
import { Switch } from "@/components/ui/switch";
import { useSettings } from "@/hooks/useSettings";
import { showSuccess, showError } from "@/lib/toast";
interface SupabaseIntegrationSwitchProps {
showToast?: boolean;
}
export function SupabaseIntegrationSwitch({
showToast = true,
}: SupabaseIntegrationSwitchProps) {
const { settings, updateSettings, refreshSettings } = useSettings();
const [isEnabled, setIsEnabled] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
useEffect(() => {
if (settings) {
setIsEnabled(settings.experiments?.enableSupabaseIntegration || false);
}
}, [settings]);
const handleToggle = async () => {
try {
setIsUpdating(true);
const newValue = !isEnabled;
await updateSettings({
experiments: {
enableSupabaseIntegration: newValue,
},
});
setIsEnabled(newValue);
if (showToast) {
showSuccess(
`Supabase integration ${newValue ? "enabled" : "disabled"}`
);
}
refreshSettings();
} catch (error) {
console.error("Error toggling Supabase integration:", error);
if (showToast) {
showError("Failed to update Supabase integration setting");
}
} finally {
setIsUpdating(false);
}
};
return (
<div className="flex items-center justify-between">
<label className="text-sm font-medium text-gray-700 dark:text-gray-300">
Enable Supabase Integration
</label>
<Switch
checked={isEnabled}
onCheckedChange={handleToggle}
disabled={isUpdating}
className="data-[state=checked]:bg-blue-600"
/>
</div>
);
}

View File

@@ -167,16 +167,18 @@ export function registerChatStreamHandlers() {
messageHistory.pop();
}
let systemPrompt = SYSTEM_PROMPT;
if (updatedChat.app?.supabaseProjectId) {
systemPrompt +=
"\n\n" +
SUPABASE_AVAILABLE_SYSTEM_PROMPT +
"\n\n" +
(await getSupabaseContext({
supabaseProjectId: updatedChat.app.supabaseProjectId,
}));
} else {
systemPrompt += "\n\n" + SUPABASE_NOT_AVAILABLE_SYSTEM_PROMPT;
if (readSettings().experiments?.enableSupabaseIntegration) {
if (updatedChat.app?.supabaseProjectId) {
systemPrompt +=
"\n\n" +
SUPABASE_AVAILABLE_SYSTEM_PROMPT +
"\n\n" +
(await getSupabaseContext({
supabaseProjectId: updatedChat.app.supabaseProjectId,
}));
} else {
systemPrompt += "\n\n" + SUPABASE_NOT_AVAILABLE_SYSTEM_PROMPT;
}
}
const { textStream } = streamText({
maxTokens: 8_000,

View File

@@ -87,6 +87,11 @@ export const SupabaseSchema = z.object({
});
export type Supabase = z.infer<typeof SupabaseSchema>;
export const ExperimentsSchema = z.object({
enableSupabaseIntegration: z.boolean().optional(),
});
export type Experiments = z.infer<typeof ExperimentsSchema>;
/**
* Zod schema for user settings
*/
@@ -100,6 +105,8 @@ export const UserSettingsSchema = z.object({
telemetryConsent: z.enum(["opted_in", "opted_out", "unset"]).optional(),
telemetryUserId: z.string().optional(),
hasRunBefore: z.boolean().optional(),
experiments: ExperimentsSchema.optional(),
// DEPRECATED.
runtimeMode: RuntimeModeSchema.optional(),
});

View File

@@ -16,6 +16,9 @@ const DEFAULT_SETTINGS: UserSettings = {
telemetryConsent: "unset",
telemetryUserId: uuidv4(),
hasRunBefore: false,
experiments: {
enableSupabaseIntegration: false,
},
};
const SETTINGS_FILE = "user-settings.json";

View File

@@ -29,6 +29,7 @@ import {
} from "@/components/ui/dialog";
import { GitHubConnector } from "@/components/GitHubConnector";
import { SupabaseConnector } from "@/components/SupabaseConnector";
import { useSettings } from "@/hooks/useSettings";
export default function AppDetailsPage() {
const navigate = useNavigate();
@@ -48,7 +49,7 @@ export default function AppDetailsPage() {
const [newFolderName, setNewFolderName] = useState("");
const [isRenamingFolder, setIsRenamingFolder] = useState(false);
const appBasePath = useAtomValue(appBasePathAtom);
const { settings } = useSettings();
// Get the appId from search params and find the corresponding app
const appId = search.appId ? Number(search.appId) : null;
const selectedApp = appId ? appsList.find((app) => app.id === appId) : null;
@@ -241,7 +242,9 @@ export default function AppDetailsPage() {
<MessageCircle className="h-5 w-5" />
</Button>
<GitHubConnector appId={appId} folderName={selectedApp.path} />
{appId && <SupabaseConnector appId={appId} />}
{appId && settings?.experiments?.enableSupabaseIntegration && (
<SupabaseConnector appId={appId} />
)}
</div>
{/* Rename Dialog */}

View File

@@ -6,6 +6,7 @@ import { IpcClient } from "@/ipc/ipc_client";
import { showSuccess, showError } from "@/lib/toast";
import { AutoApproveSwitch } from "@/components/AutoApproveSwitch";
import { TelemetrySwitch } from "@/components/TelemetrySwitch";
import { SupabaseIntegrationSwitch } from "@/components/SupabaseIntegrationSwitch";
import { useSettings } from "@/hooks/useSettings";
import { Button } from "@/components/ui/button";
import { ArrowLeft } from "lucide-react";
@@ -145,6 +146,22 @@ export default function SettingsPage() {
</div>
</div>
{/* Experiments Section */}
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6">
<h2 className="text-lg font-medium text-gray-900 dark:text-white mb-4">
Experiments
</h2>
<div className="space-y-4">
<div className="space-y-2">
<SupabaseIntegrationSwitch />
<div className="text-sm text-gray-500 dark:text-gray-400">
Enable integration with Supabase for auth, database and server
function support.
</div>
</div>
</div>
</div>
{/* Danger Zone */}
<div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm p-6 border border-red-200 dark:border-red-800">
<h2 className="text-lg font-medium text-red-600 dark:text-red-400 mb-4">