Skip to content

Commit 2eb3139

Browse files
rootroot
authored andcommitted
feat: Add Netlify Quick Deploy and Claude 4 models
This commit introduces two major features contributed by Keoma Wright: 1. Netlify Quick Deploy Feature: - One-click deployment to Netlify without authentication - Automatic framework detection (React, Vue, Angular, Next.js, etc.) - Smart build configuration and output directory selection - Enhanced deploy button with modal interface - Comprehensive deployment configuration utilities 2. Claude AI Model Integration: - Added Claude Sonnet 4 (claude-sonnet-4-20250514) - Added Claude Opus 4.1 (claude-opus-4-1-20250805) - Integration across Anthropic, OpenRouter, and AWS Bedrock providers - Increased token limits to 200,000 for new models Files added: - app/components/deploy/QuickNetlifyDeploy.client.tsx - app/components/deploy/EnhancedDeployButton.tsx - app/routes/api.netlify-quick-deploy.ts - app/lib/deployment/netlify-config.ts Files modified: - app/components/header/HeaderActionButtons.client.tsx - app/lib/modules/llm/providers/anthropic.ts - app/lib/modules/llm/providers/open-router.ts - app/lib/modules/llm/providers/amazon-bedrock.ts Contributed by: Keoma Wright
1 parent bab9a64 commit 2eb3139

File tree

8 files changed

+1185
-2
lines changed

8 files changed

+1185
-2
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/**
2+
* Enhanced Deploy Button with Quick Deploy Option
3+
* Contributed by Keoma Wright
4+
*
5+
* This component provides both authenticated and quick deployment options
6+
*/
7+
8+
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
9+
import { useStore } from '@nanostores/react';
10+
import { netlifyConnection } from '~/lib/stores/netlify';
11+
import { vercelConnection } from '~/lib/stores/vercel';
12+
import { workbenchStore } from '~/lib/stores/workbench';
13+
import { streamingState } from '~/lib/stores/streaming';
14+
import { classNames } from '~/utils/classNames';
15+
import { useState } from 'react';
16+
import { NetlifyDeploymentLink } from '~/components/chat/NetlifyDeploymentLink.client';
17+
import { VercelDeploymentLink } from '~/components/chat/VercelDeploymentLink.client';
18+
import { useVercelDeploy } from '~/components/deploy/VercelDeploy.client';
19+
import { useNetlifyDeploy } from '~/components/deploy/NetlifyDeploy.client';
20+
import { QuickNetlifyDeploy } from '~/components/deploy/QuickNetlifyDeploy.client';
21+
import * as Dialog from '@radix-ui/react-dialog';
22+
23+
interface EnhancedDeployButtonProps {
24+
onVercelDeploy?: () => Promise<void>;
25+
onNetlifyDeploy?: () => Promise<void>;
26+
}
27+
28+
export const EnhancedDeployButton = ({ onVercelDeploy, onNetlifyDeploy }: EnhancedDeployButtonProps) => {
29+
const netlifyConn = useStore(netlifyConnection);
30+
const vercelConn = useStore(vercelConnection);
31+
const [activePreviewIndex] = useState(0);
32+
const previews = useStore(workbenchStore.previews);
33+
const activePreview = previews[activePreviewIndex];
34+
const [isDeploying, setIsDeploying] = useState(false);
35+
const [deployingTo, setDeployingTo] = useState<'netlify' | 'vercel' | 'quick' | null>(null);
36+
const [showQuickDeploy, setShowQuickDeploy] = useState(false);
37+
const isStreaming = useStore(streamingState);
38+
const { handleVercelDeploy } = useVercelDeploy();
39+
const { handleNetlifyDeploy } = useNetlifyDeploy();
40+
41+
const handleVercelDeployClick = async () => {
42+
setIsDeploying(true);
43+
setDeployingTo('vercel');
44+
45+
try {
46+
if (onVercelDeploy) {
47+
await onVercelDeploy();
48+
} else {
49+
await handleVercelDeploy();
50+
}
51+
} finally {
52+
setIsDeploying(false);
53+
setDeployingTo(null);
54+
}
55+
};
56+
57+
const handleNetlifyDeployClick = async () => {
58+
setIsDeploying(true);
59+
setDeployingTo('netlify');
60+
61+
try {
62+
if (onNetlifyDeploy) {
63+
await onNetlifyDeploy();
64+
} else {
65+
await handleNetlifyDeploy();
66+
}
67+
} finally {
68+
setIsDeploying(false);
69+
setDeployingTo(null);
70+
}
71+
};
72+
73+
return (
74+
<>
75+
<div className="flex border border-bolt-elements-borderColor rounded-md overflow-hidden text-sm">
76+
<DropdownMenu.Root>
77+
<DropdownMenu.Trigger
78+
disabled={isDeploying || !activePreview || isStreaming}
79+
className="rounded-md items-center justify-center [&:is(:disabled,.disabled)]:cursor-not-allowed [&:is(:disabled,.disabled)]:opacity-60 px-3 py-1.5 text-xs bg-accent-500 text-white hover:text-bolt-elements-item-contentAccent [&:not(:disabled,.disabled)]:hover:bg-bolt-elements-button-primary-backgroundHover outline-accent-500 flex gap-1.7"
80+
>
81+
{isDeploying ? `Deploying${deployingTo ? ` to ${deployingTo}` : ''}...` : 'Deploy'}
82+
<span className={classNames('i-ph:caret-down transition-transform')} />
83+
</DropdownMenu.Trigger>
84+
<DropdownMenu.Content
85+
className={classNames(
86+
'z-[250]',
87+
'bg-bolt-elements-background-depth-2',
88+
'rounded-lg shadow-lg',
89+
'border border-bolt-elements-borderColor',
90+
'animate-in fade-in-0 zoom-in-95',
91+
'py-1',
92+
)}
93+
sideOffset={5}
94+
align="end"
95+
>
96+
{/* Quick Deploy Option - Always Available */}
97+
<DropdownMenu.Item
98+
className={classNames(
99+
'cursor-pointer flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md group relative',
100+
{
101+
'opacity-60 cursor-not-allowed': isDeploying || !activePreview,
102+
},
103+
)}
104+
disabled={isDeploying || !activePreview}
105+
onClick={() => setShowQuickDeploy(true)}
106+
>
107+
<div className="relative">
108+
<img
109+
className="w-5 h-5"
110+
height="24"
111+
width="24"
112+
crossOrigin="anonymous"
113+
src="https://cdn.simpleicons.org/netlify"
114+
alt="Netlify Quick Deploy"
115+
/>
116+
<span className="absolute -top-1 -right-1 bg-green-500 text-white text-[8px] px-1 rounded">NEW</span>
117+
</div>
118+
<span className="mx-auto font-medium">Quick Deploy to Netlify (No Login)</span>
119+
</DropdownMenu.Item>
120+
121+
<DropdownMenu.Separator className="h-px bg-bolt-elements-borderColor my-1" />
122+
123+
{/* Authenticated Netlify Deploy */}
124+
<DropdownMenu.Item
125+
className={classNames(
126+
'cursor-pointer flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md group relative',
127+
{
128+
'opacity-60 cursor-not-allowed': isDeploying || !activePreview || !netlifyConn.user,
129+
},
130+
)}
131+
disabled={isDeploying || !activePreview || !netlifyConn.user}
132+
onClick={handleNetlifyDeployClick}
133+
>
134+
<img
135+
className="w-5 h-5"
136+
height="24"
137+
width="24"
138+
crossOrigin="anonymous"
139+
src="https://cdn.simpleicons.org/netlify"
140+
/>
141+
<span className="mx-auto">{!netlifyConn.user ? 'No Netlify Account Connected' : 'Deploy to Netlify'}</span>
142+
{netlifyConn.user && <NetlifyDeploymentLink />}
143+
</DropdownMenu.Item>
144+
145+
{/* Vercel Deploy */}
146+
<DropdownMenu.Item
147+
className={classNames(
148+
'cursor-pointer flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md group relative',
149+
{
150+
'opacity-60 cursor-not-allowed': isDeploying || !activePreview || !vercelConn.user,
151+
},
152+
)}
153+
disabled={isDeploying || !activePreview || !vercelConn.user}
154+
onClick={handleVercelDeployClick}
155+
>
156+
<img
157+
className="w-5 h-5 bg-black p-1 rounded"
158+
height="24"
159+
width="24"
160+
crossOrigin="anonymous"
161+
src="https://cdn.simpleicons.org/vercel/white"
162+
alt="vercel"
163+
/>
164+
<span className="mx-auto">{!vercelConn.user ? 'No Vercel Account Connected' : 'Deploy to Vercel'}</span>
165+
{vercelConn.user && <VercelDeploymentLink />}
166+
</DropdownMenu.Item>
167+
168+
{/* Cloudflare - Coming Soon */}
169+
<DropdownMenu.Item
170+
disabled
171+
className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2 opacity-60 cursor-not-allowed"
172+
>
173+
<img
174+
className="w-5 h-5"
175+
height="24"
176+
width="24"
177+
crossOrigin="anonymous"
178+
src="https://cdn.simpleicons.org/cloudflare"
179+
alt="cloudflare"
180+
/>
181+
<span className="mx-auto">Deploy to Cloudflare (Coming Soon)</span>
182+
</DropdownMenu.Item>
183+
</DropdownMenu.Content>
184+
</DropdownMenu.Root>
185+
</div>
186+
187+
{/* Quick Deploy Dialog */}
188+
<Dialog.Root open={showQuickDeploy} onOpenChange={setShowQuickDeploy}>
189+
<Dialog.Portal>
190+
<Dialog.Overlay className="fixed inset-0 bg-black/50 z-[999] animate-in fade-in-0" />
191+
<Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-[1000] w-full max-w-2xl animate-in fade-in-0 zoom-in-95">
192+
<div className="bg-bolt-elements-background rounded-lg shadow-xl border border-bolt-elements-borderColor">
193+
<div className="flex items-center justify-between p-4 border-b border-bolt-elements-borderColor">
194+
<h2 className="text-lg font-semibold text-bolt-elements-textPrimary">Quick Deploy to Netlify</h2>
195+
<Dialog.Close className="p-1 rounded hover:bg-bolt-elements-item-backgroundActive transition-colors">
196+
<span className="i-ph:x text-lg text-bolt-elements-textSecondary" />
197+
</Dialog.Close>
198+
</div>
199+
<div className="p-4">
200+
<QuickNetlifyDeploy />
201+
</div>
202+
</div>
203+
</Dialog.Content>
204+
</Dialog.Portal>
205+
</Dialog.Root>
206+
</>
207+
);
208+
};

0 commit comments

Comments
 (0)