diff --git a/frontend/src/components/dialogs/shared/RepoPickerDialog.tsx b/frontend/src/components/dialogs/shared/RepoPickerDialog.tsx index a1658862..6cda0717 100644 --- a/frontend/src/components/dialogs/shared/RepoPickerDialog.tsx +++ b/frontend/src/components/dialogs/shared/RepoPickerDialog.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -38,6 +39,7 @@ const RepoPickerDialogImpl = NiceModal.create( title = 'Select Repository', description = 'Choose or create a git repository', }) => { + const { t } = useTranslation('projects'); const modal = useModal(); const [stage, setStage] = useState('options'); const [error, setError] = useState(''); @@ -47,6 +49,8 @@ const RepoPickerDialogImpl = NiceModal.create( const [allRepos, setAllRepos] = useState([]); const [reposLoading, setReposLoading] = useState(false); const [showMoreRepos, setShowMoreRepos] = useState(false); + const [loadingDuration, setLoadingDuration] = useState(0); + const [hasSearched, setHasSearched] = useState(false); // Stage: new const [repoName, setRepoName] = useState(''); @@ -60,12 +64,15 @@ const RepoPickerDialogImpl = NiceModal.create( setShowMoreRepos(false); setRepoName(''); setParentPath(''); + setLoadingDuration(0); + setHasSearched(false); } }, [modal.visible]); const loadRecentRepos = useCallback(async () => { setReposLoading(true); setError(''); + setLoadingDuration(0); try { const repos = await fileSystemApi.listGitRepos(); setAllRepos(repos); @@ -74,14 +81,33 @@ const RepoPickerDialogImpl = NiceModal.create( console.error('Failed to load repos:', err); } finally { setReposLoading(false); + setHasSearched(true); } }, []); useEffect(() => { - if (stage === 'existing' && allRepos.length === 0 && !reposLoading) { + if ( + stage === 'existing' && + allRepos.length === 0 && + !reposLoading && + !hasSearched + ) { loadRecentRepos(); } - }, [stage, allRepos.length, reposLoading, loadRecentRepos]); + }, [stage, allRepos.length, reposLoading, hasSearched, loadRecentRepos]); + + // Track loading duration to show timeout message + useEffect(() => { + if (!reposLoading) { + return; + } + + const interval = setInterval(() => { + setLoadingDuration((prev) => prev + 1); + }, 1000); + + return () => clearInterval(interval); + }, [reposLoading]); const registerAndReturn = async (path: string) => { setIsWorking(true); @@ -220,9 +246,18 @@ const RepoPickerDialogImpl = NiceModal.create(
- Loading repositories... + {loadingDuration < 2 + ? t('repoSearch.searching') + : t('repoSearch.stillSearching', { + seconds: loadingDuration, + })}
+ {loadingDuration >= 3 && ( +
+ {t('repoSearch.takingLonger')} +
+ )}
)} @@ -269,6 +304,26 @@ const RepoPickerDialogImpl = NiceModal.create( )} + {/* No repos found state */} + {!reposLoading && + hasSearched && + allRepos.length === 0 && + !error && ( +
+
+ +
+
+ {t('repoSearch.noReposFound')} +
+
+ {t('repoSearch.browseHint')} +
+
+
+
+ )} +
!isWorking && handleBrowseForRepo()} diff --git a/frontend/src/i18n/locales/en/projects.json b/frontend/src/i18n/locales/en/projects.json index e8179e45..9f951ae4 100644 --- a/frontend/src/i18n/locales/en/projects.json +++ b/frontend/src/i18n/locales/en/projects.json @@ -4,6 +4,13 @@ "createProject": "Create Project", "linkToOrganization": "Link to Remote Project", "loading": "Loading projects...", + "repoSearch": { + "searching": "Searching for repositories...", + "stillSearching": "Still searching... ({{seconds}}s)", + "takingLonger": "This is taking longer than usual. You can browse manually below.", + "noReposFound": "No repositories found in common locations.", + "browseHint": "Use the option below to browse for a repository." + }, "errors": { "fetchFailed": "Failed to fetch projects", "deleteFailed": "Failed to delete project" diff --git a/frontend/src/i18n/locales/es/projects.json b/frontend/src/i18n/locales/es/projects.json index 7a8431af..9b92f813 100644 --- a/frontend/src/i18n/locales/es/projects.json +++ b/frontend/src/i18n/locales/es/projects.json @@ -4,6 +4,13 @@ "createProject": "Crear Proyecto", "linkToOrganization": "Vincular a Proyecto Remoto", "loading": "Cargando proyectos...", + "repoSearch": { + "searching": "Buscando repositorios...", + "stillSearching": "Aún buscando... ({{seconds}}s)", + "takingLonger": "Esto está tardando más de lo habitual. Puedes buscar manualmente abajo.", + "noReposFound": "No se encontraron repositorios en ubicaciones comunes.", + "browseHint": "Usa la opción de abajo para buscar un repositorio." + }, "errors": { "fetchFailed": "Error al cargar proyectos", "deleteFailed": "Error al eliminar el proyecto" diff --git a/frontend/src/i18n/locales/ja/projects.json b/frontend/src/i18n/locales/ja/projects.json index fb548905..33283127 100644 --- a/frontend/src/i18n/locales/ja/projects.json +++ b/frontend/src/i18n/locales/ja/projects.json @@ -4,6 +4,13 @@ "createProject": "プロジェクトを作成", "linkToOrganization": "リモートプロジェクトにリンク", "loading": "プロジェクトを読み込み中...", + "repoSearch": { + "searching": "リポジトリを検索中...", + "stillSearching": "検索中... ({{seconds}}秒)", + "takingLonger": "通常より時間がかかっています。下から手動で選択できます。", + "noReposFound": "一般的な場所にリポジトリが見つかりませんでした。", + "browseHint": "下のオプションを使用してリポジトリを参照してください。" + }, "errors": { "fetchFailed": "プロジェクトの取得に失敗しました", "deleteFailed": "プロジェクトの削除に失敗しました" diff --git a/frontend/src/i18n/locales/ko/projects.json b/frontend/src/i18n/locales/ko/projects.json index a2c52ce9..7789e472 100644 --- a/frontend/src/i18n/locales/ko/projects.json +++ b/frontend/src/i18n/locales/ko/projects.json @@ -4,6 +4,13 @@ "createProject": "프로젝트 생성", "linkToOrganization": "원격 프로젝트에 연결", "loading": "프로젝트 로딩 중...", + "repoSearch": { + "searching": "저장소 검색 중...", + "stillSearching": "검색 중... ({{seconds}}초)", + "takingLonger": "평소보다 시간이 오래 걸리고 있습니다. 아래에서 수동으로 찾아볼 수 있습니다.", + "noReposFound": "일반적인 위치에서 저장소를 찾을 수 없습니다.", + "browseHint": "아래 옵션을 사용하여 저장소를 찾아보세요." + }, "errors": { "fetchFailed": "프로젝트를 불러오지 못했습니다", "deleteFailed": "프로젝트 삭제에 실패했습니다" diff --git a/frontend/src/i18n/locales/zh-Hans/projects.json b/frontend/src/i18n/locales/zh-Hans/projects.json index 64f78825..0aadc6f6 100644 --- a/frontend/src/i18n/locales/zh-Hans/projects.json +++ b/frontend/src/i18n/locales/zh-Hans/projects.json @@ -4,6 +4,13 @@ "createProject": "创建项目", "linkToOrganization": "链接到远程项目", "loading": "加载项目中...", + "repoSearch": { + "searching": "正在搜索仓库...", + "stillSearching": "仍在搜索... ({{seconds}}秒)", + "takingLonger": "搜索时间比平时长。您可以在下方手动浏览。", + "noReposFound": "在常见位置未找到仓库。", + "browseHint": "使用下方选项浏览仓库。" + }, "errors": { "fetchFailed": "获取项目失败", "deleteFailed": "删除项目失败" diff --git a/frontend/src/i18n/locales/zh-Hant/projects.json b/frontend/src/i18n/locales/zh-Hant/projects.json index f63f388f..5815e7ea 100644 --- a/frontend/src/i18n/locales/zh-Hant/projects.json +++ b/frontend/src/i18n/locales/zh-Hant/projects.json @@ -4,6 +4,13 @@ "createProject": "建立專案", "linkToOrganization": "連結到遠端專案", "loading": "載入專案中...", + "repoSearch": { + "searching": "正在搜尋儲存庫...", + "stillSearching": "仍在搜尋... ({{seconds}}秒)", + "takingLonger": "搜尋時間比平時長。您可以在下方手動瀏覽。", + "noReposFound": "在常見位置未找到儲存庫。", + "browseHint": "使用下方選項瀏覽儲存庫。" + }, "errors": { "fetchFailed": "取得專案失敗", "deleteFailed": "刪除專案失敗"