feat: add supabase and firebase setup wizard

This commit is contained in:
vgcman16 2025-06-05 19:18:32 -05:00
parent 407f60d74c
commit ed83aebf32
10 changed files with 214 additions and 1 deletions

View File

@ -120,3 +120,12 @@ VITE_GITHUB_TOKEN_TYPE=classic
# DEFAULT_NUM_CTX=12288 # Consumes 26GB of VRAM
# DEFAULT_NUM_CTX=6144 # Consumes 24GB of VRAM
DEFAULT_NUM_CTX=
# Supabase credentials
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
# Firebase credentials
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=

View File

@ -116,4 +116,13 @@ VITE_CLOUDFLARE_ACCOUNT_ID=
# DEFAULT_NUM_CTX=24576 # Consumes 32GB of VRAM
# DEFAULT_NUM_CTX=12288 # Consumes 26GB of VRAM
# DEFAULT_NUM_CTX=6144 # Consumes 24GB of VRAM
DEFAULT_NUM_CTX=
DEFAULT_NUM_CTX=
# Supabase credentials
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=
# Firebase credentials
VITE_FIREBASE_API_KEY=
VITE_FIREBASE_AUTH_DOMAIN=
VITE_FIREBASE_PROJECT_ID=

View File

@ -108,6 +108,7 @@ project, please check the [project management guide](./PROJECT.md) to get starte
- **Download projects as ZIP** for easy portability Sync to a folder on the host.
- **Integration-ready Docker support** for a hassle-free setup.
- **Deploy** directly to **Netlify**, **Vercel**, or **Cloudflare Pages**
- **Guided Setup Wizard** for Supabase and Firebase connections
- **Import Figma designs** to generate starter UI code.
## Setup

View File

@ -14,6 +14,7 @@ import { toast } from 'react-toastify';
import { extractTextFromFile } from '~/utils/fileExtract';
import { SpeechRecognitionButton } from '~/components/chat/SpeechRecognition';
import { SupabaseConnection } from './SupabaseConnection';
import { SetupWizard } from '~/components/setup/SetupWizard';
import { ExpoQrModal } from '~/components/workbench/ExpoQrModal';
import styles from './BaseChat.module.scss';
import type { ProviderInfo } from '~/types/model';
@ -353,6 +354,7 @@ export const ChatBox: React.FC<ChatBoxProps> = (props) => {
</div>
) : null}
<SupabaseConnection />
<SetupWizard />
<ExpoQrModal open={props.qrModalOpen} onClose={() => props.setQrModalOpen(false)} />
</div>
</div>

View File

@ -0,0 +1,135 @@
import { useStore } from '@nanostores/react';
import { useState } from 'react';
import { DialogRoot, Dialog, DialogTitle, DialogButton, DialogClose } from '~/components/ui/Dialog';
import { Input } from '~/components/ui/Input';
import { useSupabaseConnection } from '~/lib/hooks/useSupabaseConnection';
import { firebaseConfig, updateFirebaseConfig } from '~/lib/stores/firebase';
export function SetupWizard() {
const [open, setOpen] = useState(false);
const [provider, setProvider] = useState<'supabase' | 'firebase' | null>(null);
const [step, setStep] = useState(1);
const firebase = useStore(firebaseConfig);
const {
connection: supabaseConn,
connecting,
handleConnect,
selectProject,
fetchProjectApiKeys,
updateToken,
} = useSupabaseConnection();
const startWizard = () => {
setProvider(null);
setStep(1);
setOpen(true);
};
const handleFirebaseSave = () => {
updateFirebaseConfig(firebase);
setStep(3);
};
return (
<div className="relative">
<button
className="px-3 py-1.5 rounded-md text-xs bg-bolt-elements-item-backgroundDefault hover:bg-bolt-elements-item-backgroundActive"
onClick={startWizard}
>
Setup Wizard
</button>
<DialogRoot open={open} onOpenChange={setOpen}>
{open && (
<Dialog className="max-w-[520px] p-6 space-y-4">
{step === 1 && (
<div className="space-y-4">
<DialogTitle>Select a Provider</DialogTitle>
<div className="flex gap-2">
<DialogButton type="primary" onClick={() => { setProvider('supabase'); setStep(2); }}>
Supabase
</DialogButton>
<DialogButton type="primary" onClick={() => { setProvider('firebase'); setStep(2); }}>
Firebase
</DialogButton>
</div>
</div>
)}
{provider === 'supabase' && step === 2 && (
<div className="space-y-4">
<DialogTitle>Connect Supabase</DialogTitle>
<Input
placeholder="Supabase PAT"
value={supabaseConn.token}
onChange={(e) => updateToken(e.currentTarget.value)}
/>
<DialogButton type="primary" onClick={handleConnect} disabled={connecting}>
{connecting ? 'Connecting...' : 'Connect'}
</DialogButton>
{supabaseConn.stats?.projects && (
<div className="space-y-2 max-h-40 overflow-y-auto">
{supabaseConn.stats.projects.map((p) => (
<button
key={p.id}
className="block w-full text-left px-3 py-1 rounded hover:bg-bolt-elements-item-backgroundActive"
onClick={() => {
selectProject(p.id);
fetchProjectApiKeys(p.id).catch(console.error);
}}
>
{p.name}
</button>
))}
</div>
)}
{supabaseConn.credentials && (
<div className="space-y-2 text-xs bg-bolt-elements-background-depth-3 p-3 rounded">
<div>Add these to your <code>.env.local</code>:</div>
<pre>{`VITE_SUPABASE_URL=${supabaseConn.credentials.supabaseUrl}\nVITE_SUPABASE_ANON_KEY=${supabaseConn.credentials.anonKey}`}</pre>
<div className="mt-2">Sample code:</div>
<pre>{`import { createClient } from '@supabase/supabase-js';\n\nexport const supabase = createClient(import.meta.env.VITE_SUPABASE_URL!, import.meta.env.VITE_SUPABASE_ANON_KEY!);`}</pre>
</div>
)}
</div>
)}
{provider === 'firebase' && step === 2 && (
<div className="space-y-4">
<DialogTitle>Firebase Configuration</DialogTitle>
<Input
placeholder="API Key"
value={firebase.apiKey}
onChange={(e) => updateFirebaseConfig({ apiKey: e.currentTarget.value })}
/>
<Input
placeholder="Auth Domain"
value={firebase.authDomain}
onChange={(e) => updateFirebaseConfig({ authDomain: e.currentTarget.value })}
/>
<Input
placeholder="Project ID"
value={firebase.projectId}
onChange={(e) => updateFirebaseConfig({ projectId: e.currentTarget.value })}
/>
<DialogButton type="primary" onClick={handleFirebaseSave}>Save</DialogButton>
</div>
)}
{provider === 'firebase' && step === 3 && (
<div className="space-y-2 text-xs bg-bolt-elements-background-depth-3 p-3 rounded">
<div>Add these to your <code>.env.local</code>:</div>
<pre>{`VITE_FIREBASE_API_KEY=${firebase.apiKey}\nVITE_FIREBASE_AUTH_DOMAIN=${firebase.authDomain}\nVITE_FIREBASE_PROJECT_ID=${firebase.projectId}`}</pre>
<div className="mt-2">Sample code:</div>
<pre>{`import { initializeApp } from 'firebase/app';\nimport { getAuth } from 'firebase/auth';\nimport { getFirestore } from 'firebase/firestore';\n\nconst firebaseConfig = {\n apiKey: import.meta.env.VITE_FIREBASE_API_KEY!,\n authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN!,\n projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID!,\n};\n\nconst app = initializeApp(firebaseConfig);\nexport const auth = getAuth(app);\nexport const db = getFirestore(app);`}</pre>
</div>
)}
<div className="flex justify-end gap-2 pt-2">
<DialogClose asChild>
<DialogButton type="secondary">Close</DialogButton>
</DialogClose>
</div>
</Dialog>
)}
</DialogRoot>
</div>
);
}

View File

@ -0,0 +1,23 @@
import { atom } from 'nanostores';
export interface FirebaseConfig {
apiKey: string;
authDomain: string;
projectId: string;
}
const saved = typeof localStorage !== 'undefined' ? localStorage.getItem('firebase_config') : null;
export const firebaseConfig = atom<FirebaseConfig>(
saved ? JSON.parse(saved) : { apiKey: '', authDomain: '', projectId: '' },
);
export function updateFirebaseConfig(config: Partial<FirebaseConfig>) {
const current = firebaseConfig.get();
const newConfig = { ...current, ...config };
firebaseConfig.set(newConfig);
if (typeof localStorage !== 'undefined') {
localStorage.setItem('firebase_config', JSON.stringify(newConfig));
}
}

5
app/types/firebase.ts Normal file
View File

@ -0,0 +1,5 @@
export interface FirebaseConfig {
apiKey: string;
authDomain: string;
projectId: string;
}

View File

@ -12,6 +12,7 @@ bolt.diy allows you to choose the LLM that you use for each prompt! Currently, y
- [Entering API Keys](#entering-api-keys)
- [1. Set API Keys in the `.env.local` File](#1-set-api-keys-in-the-envlocal-file)
- [2. Configure API Keys Directly in the Application](#2-configure-api-keys-directly-in-the-application)
- [Supabase / Firebase Setup Wizard](#supabase--firebase-setup-wizard)
- [Run the Application](#run-the-application)
- [Option 1: Without Docker](#option-1-without-docker)
- [Option 2: With Docker](#option-2-with-docker)
@ -118,6 +119,15 @@ Once you've configured your keys, the application will be ready to use the selec
---
### Supabase / Firebase Setup Wizard
bolt.diy now includes a simple setup wizard for connecting to either Supabase or Firebase.
Open the **Setup Wizard** from the chat box to enter your API keys and automatically generate
the necessary environment variables. Once connected, the wizard provides sample code for
initializing the selected service using the values from your `.env.local` file.
---
## Run the Application
### Option 1: Without Docker

13
examples/firebase.ts Normal file
View File

@ -0,0 +1,13 @@
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY!,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN!,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID!,
};
const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);
export const db = getFirestore(app);

View File

@ -0,0 +1,6 @@
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL!;
const anonKey = import.meta.env.VITE_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, anonKey);