mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 18:26:38 +00:00
Fix notes tab handler guard and lint
This commit is contained in:
parent
10d192667a
commit
7912933c34
@ -10,7 +10,11 @@ export default function NotesTab() {
|
|||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
const text = noteText.trim();
|
const text = noteText.trim();
|
||||||
if (!text) return;
|
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
addNote(text);
|
addNote(text);
|
||||||
setNoteText('');
|
setNoteText('');
|
||||||
};
|
};
|
||||||
@ -27,7 +31,7 @@ export default function NotesTab() {
|
|||||||
'border border-bolt-elements-borderColor',
|
'border border-bolt-elements-borderColor',
|
||||||
'text-bolt-elements-textPrimary',
|
'text-bolt-elements-textPrimary',
|
||||||
'focus:outline-none focus:ring-2 focus:ring-purple-500/30',
|
'focus:outline-none focus:ring-2 focus:ring-purple-500/30',
|
||||||
'min-h-[80px] resize-vertical'
|
'min-h-[80px] resize-vertical',
|
||||||
)}
|
)}
|
||||||
placeholder="Add a note for the AI"
|
placeholder="Add a note for the AI"
|
||||||
/>
|
/>
|
||||||
@ -37,25 +41,14 @@ export default function NotesTab() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{notes.map((n) => (
|
{notes.map((n) => (
|
||||||
<div
|
<div key={n.id} className="flex items-start gap-2 p-2 rounded-lg bg-bolt-elements-background-depth-2">
|
||||||
key={n.id}
|
<div className="flex-1 whitespace-pre-wrap text-sm text-bolt-elements-textPrimary">{n.text}</div>
|
||||||
className="flex items-start gap-2 p-2 rounded-lg bg-bolt-elements-background-depth-2"
|
<Button size="sm" variant="ghost" onClick={() => removeNote(n.id)}>
|
||||||
>
|
|
||||||
<div className="flex-1 whitespace-pre-wrap text-sm text-bolt-elements-textPrimary">
|
|
||||||
{n.text}
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="ghost"
|
|
||||||
onClick={() => removeNote(n.id)}
|
|
||||||
>
|
|
||||||
<div className="i-ph:trash w-4 h-4" />
|
<div className="i-ph:trash w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
{notes.length === 0 && (
|
{notes.length === 0 && <p className="text-sm text-bolt-elements-textSecondary">No notes added.</p>}
|
||||||
<p className="text-sm text-bolt-elements-textSecondary">No notes added.</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -485,11 +485,7 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
|
|||||||
</div>
|
</div>
|
||||||
</StickToBottom>
|
</StickToBottom>
|
||||||
<div className="flex flex-col justify-center">
|
<div className="flex flex-col justify-center">
|
||||||
{!chatStarted && (
|
{!chatStarted && <div className="flex justify-center gap-2">{ImportButtons(importChat)}</div>}
|
||||||
<div className="flex justify-center gap-2">
|
|
||||||
{ImportButtons(importChat)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="flex flex-col gap-5">
|
<div className="flex flex-col gap-5">
|
||||||
{!chatStarted &&
|
{!chatStarted &&
|
||||||
ExamplePrompts((event, messageInput) => {
|
ExamplePrompts((event, messageInput) => {
|
||||||
|
@ -82,6 +82,7 @@ export const CodeBlock = memo(
|
|||||||
title="Ask Bolt about this code"
|
title="Ask Bolt about this code"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const askFn = (window as any).__BOLT_ASK_SNIPPET__;
|
const askFn = (window as any).__BOLT_ASK_SNIPPET__;
|
||||||
|
|
||||||
if (typeof askFn === 'function') {
|
if (typeof askFn === 'function') {
|
||||||
askFn(code, language);
|
askFn(code, language);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { Message } from 'ai';
|
import type { Message } from 'ai';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { ImportFolderButton } from '~/components/chat/ImportFolderButton';
|
import { ImportFolderButton } from '~/components/chat/ImportFolderButton';
|
||||||
import GitCloneButton from '../GitCloneButton';
|
import GitCloneButton from '~/components/chat/GitCloneButton';
|
||||||
import { Button } from '~/components/ui/Button';
|
import { Button } from '~/components/ui/Button';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
|
|
||||||
|
@ -47,10 +47,22 @@ export function SetupWizard() {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<DialogTitle>Select a Provider</DialogTitle>
|
<DialogTitle>Select a Provider</DialogTitle>
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<DialogButton type="primary" onClick={() => { setProvider('supabase'); setStep(2); }}>
|
<DialogButton
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setProvider('supabase');
|
||||||
|
setStep(2);
|
||||||
|
}}
|
||||||
|
>
|
||||||
Supabase
|
Supabase
|
||||||
</DialogButton>
|
</DialogButton>
|
||||||
<DialogButton type="primary" onClick={() => { setProvider('firebase'); setStep(2); }}>
|
<DialogButton
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
setProvider('firebase');
|
||||||
|
setStep(2);
|
||||||
|
}}
|
||||||
|
>
|
||||||
Firebase
|
Firebase
|
||||||
</DialogButton>
|
</DialogButton>
|
||||||
</div>
|
</div>
|
||||||
@ -85,7 +97,9 @@ export function SetupWizard() {
|
|||||||
)}
|
)}
|
||||||
{supabaseConn.credentials && (
|
{supabaseConn.credentials && (
|
||||||
<div className="space-y-2 text-xs bg-bolt-elements-background-depth-3 p-3 rounded">
|
<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>
|
<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>
|
<pre>{`VITE_SUPABASE_URL=${supabaseConn.credentials.supabaseUrl}\nVITE_SUPABASE_ANON_KEY=${supabaseConn.credentials.anonKey}`}</pre>
|
||||||
<div className="mt-2">Sample code:</div>
|
<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>
|
<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>
|
||||||
@ -111,12 +125,16 @@ export function SetupWizard() {
|
|||||||
value={firebase.projectId}
|
value={firebase.projectId}
|
||||||
onChange={(e) => updateFirebaseConfig({ projectId: e.currentTarget.value })}
|
onChange={(e) => updateFirebaseConfig({ projectId: e.currentTarget.value })}
|
||||||
/>
|
/>
|
||||||
<DialogButton type="primary" onClick={handleFirebaseSave}>Save</DialogButton>
|
<DialogButton type="primary" onClick={handleFirebaseSave}>
|
||||||
|
Save
|
||||||
|
</DialogButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{provider === 'firebase' && step === 3 && (
|
{provider === 'firebase' && step === 3 && (
|
||||||
<div className="space-y-2 text-xs bg-bolt-elements-background-depth-3 p-3 rounded">
|
<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>
|
<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>
|
<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>
|
<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>
|
<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>
|
||||||
|
@ -3,18 +3,22 @@ export interface Feature {
|
|||||||
* Unique identifier for the feature.
|
* Unique identifier for the feature.
|
||||||
*/
|
*/
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Short title of the feature to display in the UI.
|
* Short title of the feature to display in the UI.
|
||||||
*/
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Description of what the feature does.
|
* Description of what the feature does.
|
||||||
*/
|
*/
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user has already viewed/acknowledged this feature.
|
* Whether the user has already viewed/acknowledged this feature.
|
||||||
*/
|
*/
|
||||||
viewed: boolean;
|
viewed: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ISO date string for when the feature was released.
|
* ISO date string for when the feature was released.
|
||||||
*/
|
*/
|
||||||
|
@ -31,24 +31,12 @@ export class PromptLibrary {
|
|||||||
default: {
|
default: {
|
||||||
label: 'Default Prompt',
|
label: 'Default Prompt',
|
||||||
description: 'This is the battle tested default system Prompt',
|
description: 'This is the battle tested default system Prompt',
|
||||||
get: (options) =>
|
get: (options) => getSystemPrompt(options.cwd, options.supabase, options.designScheme, options.userNotes),
|
||||||
getSystemPrompt(
|
|
||||||
options.cwd,
|
|
||||||
options.supabase,
|
|
||||||
options.designScheme,
|
|
||||||
options.userNotes,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
enhanced: {
|
enhanced: {
|
||||||
label: 'Fine Tuned Prompt',
|
label: 'Fine Tuned Prompt',
|
||||||
description: 'An fine tuned prompt for better results',
|
description: 'An fine tuned prompt for better results',
|
||||||
get: (options) =>
|
get: (options) => getFineTunedPrompt(options.cwd, options.supabase, options.designScheme, options.userNotes),
|
||||||
getFineTunedPrompt(
|
|
||||||
options.cwd,
|
|
||||||
options.supabase,
|
|
||||||
options.designScheme,
|
|
||||||
options.userNotes,
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
optimized: {
|
optimized: {
|
||||||
label: 'Optimized Prompt (experimental)',
|
label: 'Optimized Prompt (experimental)',
|
||||||
|
@ -12,6 +12,7 @@ function loadNotes(): Note[] {
|
|||||||
if (typeof localStorage === 'undefined') {
|
if (typeof localStorage === 'undefined') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const json = localStorage.getItem(NOTES_KEY);
|
const json = localStorage.getItem(NOTES_KEY);
|
||||||
return json ? JSON.parse(json) : [];
|
return json ? JSON.parse(json) : [];
|
||||||
@ -21,7 +22,10 @@ function loadNotes(): Note[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveNotes(notes: Note[]) {
|
function saveNotes(notes: Note[]) {
|
||||||
if (typeof localStorage === 'undefined') return;
|
if (typeof localStorage === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
|
localStorage.setItem(NOTES_KEY, JSON.stringify(notes));
|
||||||
} catch {}
|
} catch {}
|
||||||
|
@ -629,12 +629,9 @@ export class WorkbenchStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actionStreamSampler = createSampler(
|
actionStreamSampler = createSampler(async (data: ActionCallbackData, isStreaming: boolean = false) => {
|
||||||
async (data: ActionCallbackData, isStreaming: boolean = false) => {
|
return await this._runAction(data, isStreaming);
|
||||||
return await this._runAction(data, isStreaming);
|
}, ACTION_STREAM_SAMPLE_INTERVAL);
|
||||||
},
|
|
||||||
ACTION_STREAM_SAMPLE_INTERVAL,
|
|
||||||
);
|
|
||||||
|
|
||||||
#getArtifact(id: string) {
|
#getArtifact(id: string) {
|
||||||
const artifacts = this.artifacts.get();
|
const artifacts = this.artifacts.get();
|
||||||
|
@ -38,23 +38,24 @@ function parseCookies(cookieHeader: string): Record<string, string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function chatAction({ context, request }: ActionFunctionArgs) {
|
async function chatAction({ context, request }: ActionFunctionArgs) {
|
||||||
const { messages, files, promptId, contextOptimization, supabase, chatMode, designScheme, userNotes } = await request.json<{
|
const { messages, files, promptId, contextOptimization, supabase, chatMode, designScheme, userNotes } =
|
||||||
messages: Messages;
|
await request.json<{
|
||||||
files: any;
|
messages: Messages;
|
||||||
promptId?: string;
|
files: any;
|
||||||
contextOptimization: boolean;
|
promptId?: string;
|
||||||
chatMode: 'discuss' | 'build';
|
contextOptimization: boolean;
|
||||||
designScheme?: DesignScheme;
|
chatMode: 'discuss' | 'build';
|
||||||
userNotes?: string;
|
designScheme?: DesignScheme;
|
||||||
supabase?: {
|
userNotes?: string;
|
||||||
isConnected: boolean;
|
supabase?: {
|
||||||
hasSelectedProject: boolean;
|
isConnected: boolean;
|
||||||
credentials?: {
|
hasSelectedProject: boolean;
|
||||||
anonKey?: string;
|
credentials?: {
|
||||||
supabaseUrl?: string;
|
anonKey?: string;
|
||||||
|
supabaseUrl?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}>();
|
||||||
}>();
|
|
||||||
|
|
||||||
const cookieHeader = request.headers.get('Cookie');
|
const cookieHeader = request.headers.get('Cookie');
|
||||||
const apiKeys = JSON.parse(parseCookies(cookieHeader || '').apiKeys || '{}');
|
const apiKeys = JSON.parse(parseCookies(cookieHeader || '').apiKeys || '{}');
|
||||||
|
@ -8,6 +8,7 @@ export const MODEL_REGEX = /^\[Model: (.*?)\]\n\n/;
|
|||||||
export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/;
|
export const PROVIDER_REGEX = /\[Provider: (.*?)\]\n\n/;
|
||||||
export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest';
|
export const DEFAULT_MODEL = 'claude-3-5-sonnet-latest';
|
||||||
export const PROMPT_COOKIE_KEY = 'cachedPrompt';
|
export const PROMPT_COOKIE_KEY = 'cachedPrompt';
|
||||||
|
|
||||||
// Interval used by actionStreamSampler in ms
|
// Interval used by actionStreamSampler in ms
|
||||||
export const ACTION_STREAM_SAMPLE_INTERVAL = 100;
|
export const ACTION_STREAM_SAMPLE_INTERVAL = 100;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user