From 6a5deaf5357e9b9d76ae9c44921e1534e6bd376a Mon Sep 17 00:00:00 2001 From: Ed McConnell Date: Fri, 20 Dec 2024 20:17:35 -0500 Subject: [PATCH] more changes --- app/commit.json | 2 +- app/components/git/GitCloneModal.tsx | 201 +++++++++++++------------ app/components/git/GitCloneSpinner.tsx | 23 +++ app/lib/hooks/useGit.ts | 22 ++- 4 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 app/components/git/GitCloneSpinner.tsx diff --git a/app/commit.json b/app/commit.json index cb35a07f6..bd19aaa45 100644 --- a/app/commit.json +++ b/app/commit.json @@ -1 +1 @@ -{ "commit": "d37cf4ecb8460c28aa24b5374da2b3239359da94" } +{ "commit": "18d72e9fc93307d3c5ebcbfbb1361967fa28e961" } diff --git a/app/components/git/GitCloneModal.tsx b/app/components/git/GitCloneModal.tsx index 0b98f59b5..01010dc02 100644 --- a/app/components/git/GitCloneModal.tsx +++ b/app/components/git/GitCloneModal.tsx @@ -3,6 +3,7 @@ import { Dialog, DialogRoot } from '~/components/ui/Dialog'; import { GitHubAuth } from '~/lib/github/GitHubAuth'; import { getGitHubUser, getUserRepos } from '~/lib/github/github.client'; import { toast } from 'react-toastify'; +import { GitCloneSpinner } from './GitCloneSpinner'; interface GitCloneModalProps { open: boolean; @@ -15,6 +16,7 @@ export function GitCloneModal({ open, onClose, onClone }: GitCloneModalProps) { const [userRepos, setUserRepos] = useState>([]); const [selectedRepo, setSelectedRepo] = useState(''); const [isLoading, setIsLoading] = useState(false); + const [isCloning, setIsCloning] = useState(false); const [isAuthenticated, setIsAuthenticated] = useState(false); const [username, setUsername] = useState(''); @@ -78,115 +80,120 @@ export function GitCloneModal({ open, onClose, onClone }: GitCloneModalProps) { const handleClone = useCallback(async () => { try { - if (selectedRepo) { - await onClone(selectedRepo); - } else if (publicUrl) { - await onClone(publicUrl); + const cloneUrl = selectedRepo || publicUrl; + + if (cloneUrl) { + setIsCloning(true); + onClose(); // Close the modal immediately when starting clone + await onClone(cloneUrl); + setIsCloning(false); } - - onClose(); } catch (error) { console.error('Clone error:', error); toast.error('Failed to clone repository'); + setIsCloning(false); } }, [selectedRepo, publicUrl, onClone, onClose]); return ( - - -
-

Clone Repository

- -
- -
- {(!selectedRepo || !isAuthenticated) && ( -
-
Public Repository
- { - setPublicUrl(e.target.value); - - if (e.target.value && selectedRepo) { - setSelectedRepo(''); - } - }} - className="w-full p-2 h-[32px] rounded bg-[#2D2D2D] border border-[#383838] text-white placeholder-[#8B8B8B] focus:outline-none focus:border-[#525252]" - /> -
- )} + <> + + +
+

Clone Repository

+ +
-
-
- {isAuthenticated ? `${username}'s Repositories` : 'Private Repository'} -
- {isAuthenticated ? ( - - ) : ( - toast.error(error.message)}> - - - )} - {isLoading && ( -
-
+
+ {(!selectedRepo || !isAuthenticated) && ( +
+
Public Repository
+ { + setPublicUrl(e.target.value); + + if (e.target.value && selectedRepo) { + setSelectedRepo(''); + } + }} + className="w-full p-2 h-[32px] rounded bg-[#2D2D2D] border border-[#383838] text-white placeholder-[#8B8B8B] focus:outline-none focus:border-[#525252]" + />
)} -
-
- - +
+
+ {isAuthenticated ? `${username}'s Repositories` : 'Private Repository'} +
+ {isAuthenticated ? ( + + ) : ( + toast.error(error.message)}> + + + )} + {isLoading && ( +
+
+
+ )} +
+ +
+ + +
-
-
-
+
+
+ + ); } diff --git a/app/components/git/GitCloneSpinner.tsx b/app/components/git/GitCloneSpinner.tsx new file mode 100644 index 000000000..19e6183c0 --- /dev/null +++ b/app/components/git/GitCloneSpinner.tsx @@ -0,0 +1,23 @@ +interface GitCloneSpinnerProps { + isOpen: boolean; +} + +export function GitCloneSpinner({ isOpen }: GitCloneSpinnerProps) { + if (!isOpen) return null; + + return ( + <> + {/* Full screen blocker that prevents all interactions */} +
+ + {/* Spinner overlay */} +
+
+
+
Cloning Repository...
+
This may take a few moments
+
+
+ + ); +} diff --git a/app/lib/hooks/useGit.ts b/app/lib/hooks/useGit.ts index 3c8c61bb2..539c316a5 100644 --- a/app/lib/hooks/useGit.ts +++ b/app/lib/hooks/useGit.ts @@ -49,6 +49,11 @@ export function useGit() { } fileData.current = {}; + + // Check if this is a GitHub URL and we have a token + const isGithubUrl = url.includes('github.com'); + const githubToken = isGithubUrl ? localStorage.getItem('github_token') : null; + await git.clone({ fs, http, @@ -58,10 +63,16 @@ export function useGit() { singleBranch: true, corsProxy: 'https://cors.isomorphic-git.org', onAuth: (url) => { - // let domain=url.split("/")[2] + // If we have a GitHub token, use it + if (isGithubUrl && githubToken) { + return { + username: githubToken, + password: 'x-oauth-basic' + }; + } + // For non-GitHub repos, use saved credentials let auth = lookupSavedPassword(url); - if (auth) { return auth; } @@ -80,7 +91,10 @@ export function useGit() { toast.error(`Error Authenticating with ${url.split('/')[2]}`); }, onAuthSuccess: (url, auth) => { - saveGitAuth(url, auth); + // Only save non-GitHub credentials + if (!isGithubUrl) { + saveGitAuth(url, auth); + } }, }); @@ -92,7 +106,7 @@ export function useGit() { return { workdir: webcontainer.workdir, data }; }, - [webcontainer], + [webcontainer, fs, ready], ); return { ready, gitClone };