From 7ae7896b8e2889a557d7697f3a4735b37a28a03b Mon Sep 17 00:00:00 2001 From: Strider Wilson Date: Tue, 10 Jun 2025 14:12:08 -0400 Subject: [PATCH] Update deploy modal to clarify process and update Header buttons --- .../header/DeployChat/DeployChatButton.tsx | 59 +++- .../DeployChat/components/DeployChatModal.tsx | 291 +++++++++--------- .../components/DeploymentSuccessful.tsx | 29 ++ app/components/header/DownloadButton.tsx | 1 + app/components/header/Header.tsx | 4 +- 5 files changed, 224 insertions(+), 160 deletions(-) create mode 100644 app/components/header/DeployChat/components/DeploymentSuccessful.tsx diff --git a/app/components/header/DeployChat/DeployChatButton.tsx b/app/components/header/DeployChat/DeployChatButton.tsx index d91eefec..cc3cea6c 100644 --- a/app/components/header/DeployChat/DeployChatButton.tsx +++ b/app/components/header/DeployChat/DeployChatButton.tsx @@ -6,7 +6,7 @@ import { generateRandomId } from '~/lib/replay/ReplayProtocolClient'; import { workbenchStore } from '~/lib/stores/workbench'; import { chatStore } from '~/lib/stores/chat'; import { database } from '~/lib/persistence/chats'; -import { deployRepository } from '~/lib/replay/Deploy'; +import { deployRepository, downloadRepository } from '~/lib/replay/Deploy'; import DeployChatModal from './components/DeployChatModal'; ReactModal.setAppElement('#root'); @@ -22,14 +22,61 @@ export function DeployChatButton() { const [deploySettings, setDeploySettings] = useState(null); const [error, setError] = useState(null); const [status, setStatus] = useState(DeployStatus.NotStarted); + const [databaseFound, setDatabaseFound] = useState(false); + + const handleCheckDatabase = async () => { + const repositoryId = workbenchStore.repositoryId.get(); + if (!repositoryId) { + toast.error('No repository ID found'); + return; + } + + try { + const repositoryContents = await downloadRepository(repositoryId); + + // Convert base64 to blob + const byteCharacters = atob(repositoryContents); + const byteNumbers = new Array(byteCharacters.length); + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i); + } + const byteArray = new Uint8Array(byteNumbers); + const blob = new Blob([byteArray], { type: 'application/zip' }); + + const reader = new FileReader(); + reader.onload = (event) => { + if (!event.target?.result) { + setIsModalOpen(false); + toast.error('Could not read repository contents'); + return; + } + + const zipContents = event.target.result as string; + const directoryToFind = 'supabase'; + + if (zipContents.includes(directoryToFind)) { + setDatabaseFound(true); + } else { + setDatabaseFound(false); + } + }; + + reader.readAsText(blob); + } catch (error) { + setIsModalOpen(false); + console.error('Error downloading repository:', error); + toast.error('Failed to download repository'); + } + }; const handleOpenModal = async () => { const chatId = chatStore.currentChat.get()?.id; if (!chatId) { - toast.error('No chat open'); + toast.error('No chat ID found'); return; } + await handleCheckDatabase(); const existingSettings = await database.getChatDeploySettings(chatId); setIsModalOpen(true); @@ -146,11 +193,10 @@ export function DeployChatButton() { <> ); diff --git a/app/components/header/DeployChat/components/DeployChatModal.tsx b/app/components/header/DeployChat/components/DeployChatModal.tsx index 269f9e4e..172ea525 100644 --- a/app/components/header/DeployChat/components/DeployChatModal.tsx +++ b/app/components/header/DeployChat/components/DeployChatModal.tsx @@ -1,4 +1,5 @@ import { DeployStatus } from '~/components/header/DeployChat/DeployChatButton'; +import DeploymentSuccessful from './DeploymentSuccessful'; interface DeployChatModalProps { isModalOpen: boolean; @@ -8,6 +9,7 @@ interface DeployChatModalProps { setDeploySettings: (settings: any) => void; error: string | null; handleDeploy: () => void; + databaseFound: boolean; } const DeployChatModal = ({ @@ -18,6 +20,7 @@ const DeployChatModal = ({ setDeploySettings, error, handleDeploy, + databaseFound, }: DeployChatModalProps) => { const handleOverlayClick = (e: React.MouseEvent) => { if (e.target === e.currentTarget) { @@ -32,51 +35,31 @@ const DeployChatModal = ({ className="fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm z-40 flex items-center justify-center" onClick={handleOverlayClick} > -
e.stopPropagation()}> +
e.stopPropagation()}> {status === DeployStatus.Succeeded ? ( - <> -

- Deployment Succeeded! 🎉 -

-
-

- Your application has been successfully deployed. You can now access it at the URL below. -

-
- - - - -
-
- - ) : ( + + ) : ( <>

Deploy Your Application

-

Deploy your chat application to production using Netlify and Supabase.

+

Deploy your chat application to production using Netlify{databaseFound ? ' and Supabase' : ''}.

This process will:

-
    -
  • Create a new Netlify site or update an existing one
  • -
  • Set up your database with Supabase
  • -
  • Configure all necessary environment variables
  • -
  • Deploy your application with production settings
  • -
+
+
    +
  • Create a new Netlify site or update an existing one
  • + {databaseFound &&
  • Set up your database with Supabase
  • } +
  • Configure all necessary environment variables
  • +
  • Deploy your application with production settings
  • +
+

Before you begin:

- You'll need accounts with both Netlify and Supabase to deploy your application. If you haven't already, please sign up using the links below: + You'll need accounts with both Netlify and {databaseFound ? 'Supabase ' : ''}to deploy your application. If you haven't already, please sign up using the links below:

@@ -230,121 +213,125 @@ const DeployChatModal = ({ />
-
- -
-

- The URL of your Supabase project, used to connect to your database. -

-
- { - const supabase = { - databaseURL: e.target.value, - anonKey: deploySettings?.supabase?.anonKey || '', - serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', - postgresURL: deploySettings?.supabase?.postgresURL || '', - }; - setDeploySettings({ - ...deploySettings, - supabase, - }); - }} - /> -
+ {databaseFound && ( + <> +
+ +
+

+ The URL of your Supabase project, used to connect to your database. +

+
+ { + const supabase = { + databaseURL: e.target.value, + anonKey: deploySettings?.supabase?.anonKey || '', + serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', + postgresURL: deploySettings?.supabase?.postgresURL || '', + }; + setDeploySettings({ + ...deploySettings, + supabase, + }); + }} + /> +
-
- -
-

- Public API key for client-side database access with restricted permissions. -

-
- { - const supabase = { - databaseURL: deploySettings?.supabase?.databaseURL || '', - anonKey: e.target.value, - serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', - postgresURL: deploySettings?.supabase?.postgresURL || '', - }; - setDeploySettings({ - ...deploySettings, - supabase, - }); - }} - /> -
+
+ +
+

+ Public API key for client-side database access with restricted permissions. +

+
+ { + const supabase = { + databaseURL: deploySettings?.supabase?.databaseURL || '', + anonKey: e.target.value, + serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', + postgresURL: deploySettings?.supabase?.postgresURL || '', + }; + setDeploySettings({ + ...deploySettings, + supabase, + }); + }} + /> +
-
- -
-

- Admin API key for server-side operations with full database access. -

-
- { - const supabase = { - databaseURL: deploySettings?.supabase?.databaseURL || '', - anonKey: deploySettings?.supabase?.anonKey || '', - serviceRoleKey: e.target.value, - postgresURL: deploySettings?.supabase?.postgresURL || '', - }; - setDeploySettings({ - ...deploySettings, - supabase, - }); - }} - /> -
+
+ +
+

+ Admin API key for server-side operations with full database access. +

+
+ { + const supabase = { + databaseURL: deploySettings?.supabase?.databaseURL || '', + anonKey: deploySettings?.supabase?.anonKey || '', + serviceRoleKey: e.target.value, + postgresURL: deploySettings?.supabase?.postgresURL || '', + }; + setDeploySettings({ + ...deploySettings, + supabase, + }); + }} + /> +
-
- -
-

- Direct connection URL to your Postgres database for advanced operations. -

-
- { - const supabase = { - databaseURL: deploySettings?.supabase?.databaseURL || '', - anonKey: deploySettings?.supabase?.anonKey || '', - serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', - postgresURL: e.target.value, - }; - setDeploySettings({ - ...deploySettings, - supabase, - }); - }} - /> -
+
+ +
+

+ Direct connection URL to your Postgres database for advanced operations. +

+
+ { + const supabase = { + databaseURL: deploySettings?.supabase?.databaseURL || '', + anonKey: deploySettings?.supabase?.anonKey || '', + serviceRoleKey: deploySettings?.supabase?.serviceRoleKey || '', + postgresURL: e.target.value, + }; + setDeploySettings({ + ...deploySettings, + supabase, + }); + }} + /> +
+ + )}
diff --git a/app/components/header/DeployChat/components/DeploymentSuccessful.tsx b/app/components/header/DeployChat/components/DeploymentSuccessful.tsx new file mode 100644 index 00000000..fa6f7bcb --- /dev/null +++ b/app/components/header/DeployChat/components/DeploymentSuccessful.tsx @@ -0,0 +1,29 @@ +const DeploymentSuccessful = ({ deploySettings, setIsModalOpen }: { deploySettings: any, setIsModalOpen: (isOpen: boolean) => void }) => { + return ( + <> +

+ Deployment Succeeded! 🎉 +

+
+

+ Your application has been successfully deployed. You can now access it at the URL below. +

+
+ + + + +
+
+ + ); +}; + +export default DeploymentSuccessful; diff --git a/app/components/header/DownloadButton.tsx b/app/components/header/DownloadButton.tsx index a2bc727a..22a23b3c 100644 --- a/app/components/header/DownloadButton.tsx +++ b/app/components/header/DownloadButton.tsx @@ -51,6 +51,7 @@ export function DownloadButton() { onClick={handleDownload} >
+ Download Repo ); diff --git a/app/components/header/Header.tsx b/app/components/header/Header.tsx index 1d004407..c0b33596 100644 --- a/app/components/header/Header.tsx +++ b/app/components/header/Header.tsx @@ -45,10 +45,10 @@ export function Header() { {chatStarted && ( <> - + {() => } - + {() => }