diff --git a/frontend/src/app/git-projects/page.tsx b/frontend/src/app/git-projects/page.tsx index b5c6b67..46dd73d 100644 --- a/frontend/src/app/git-projects/page.tsx +++ b/frontend/src/app/git-projects/page.tsx @@ -40,6 +40,7 @@ import { getApiBaseUrl } from "@/lib/api-base"; import { getForgejoRepositories, deleteForgejoRepository, + refreshRepositoryRecentIssues, syncRepository, validateRepository, type ForgejoRepository, @@ -531,10 +532,10 @@ export default function ForgejoRepositoriesPage() { const handleSync = async (repository: ForgejoRepository) => { try { - const result = await syncRepository(repository.id); + const result = await refreshRepositoryRecentIssues(repository.id); setNotice({ tone: "success", - message: `${repositoryName(repository)} synced: ${result.created} created, ${result.updated} updated, ${result.open} open, ${result.closed} closed.`, + message: `${repositoryName(repository)} refreshed: ${result.created} created, ${result.updated} updated, ${result.open} open, ${result.closed} closed.`, }); // Refetch to update last_sync_at const data = await getForgejoRepositories(); diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 2b1b018..7c46d3d 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -272,7 +272,7 @@ textarea::placeholder { animation: progress-shimmer 1.8s linear infinite; } .animate-ticker { - animation: ticker-scroll 45s linear infinite; + animation: ticker-scroll 70s linear infinite; } .ticker-fade-mask { -webkit-mask-image: linear-gradient(to right, transparent 0px, black 48px, black calc(100% - 48px), transparent 100%); diff --git a/frontend/src/components/git/ForgejoRepositoriesTable.tsx b/frontend/src/components/git/ForgejoRepositoriesTable.tsx index 65a9cb9..3471246 100644 --- a/frontend/src/components/git/ForgejoRepositoriesTable.tsx +++ b/frontend/src/components/git/ForgejoRepositoriesTable.tsx @@ -22,6 +22,7 @@ import { Archive, CheckCircle2, CircleDot, + ExternalLink, Eye, GitBranch, GitCommitHorizontal, @@ -51,6 +52,25 @@ const formatConnectionUrl = (value?: string | null) => { return value.replace(/^https?:\/\//i, "").replace(/\/$/, ""); }; +const buildRepositoryUrl = (repo: ForgejoRepository) => { + const baseUrl = repo.connection?.base_url; + if (!baseUrl) return null; + const normalizedBaseUrl = /^https?:\/\//i.test(baseUrl) + ? baseUrl + : `https://${baseUrl}`; + try { + const base = normalizedBaseUrl.endsWith("/") + ? normalizedBaseUrl + : `${normalizedBaseUrl}/`; + return new URL( + `${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.repo)}`, + base, + ).toString(); + } catch { + return null; + } +}; + const repositoryTone = (repo: ForgejoRepository) => { if (repo.last_sync_error) return "danger"; if (!repo.active || repo.is_archived) return "muted"; @@ -300,12 +320,31 @@ const columns = ( accessorKey: "connection", header: "Connection", cell: ({ row }) => { - const connection = row.original.connection; + const repo = row.original; + const repositoryUrl = buildRepositoryUrl(repo); + const label = formatConnectionUrl(repo.connection?.base_url); + if (!repositoryUrl) { + return ( +