add: connection improvements

Improve connections visually and functionality
This commit is contained in:
KevIsDev
2025-02-25 00:39:39 +00:00
parent 4da13d1edc
commit 96a0b2a066
5 changed files with 312 additions and 329 deletions

View File

@@ -67,124 +67,6 @@ interface GitHubConnection {
}
export default function ConnectionsTab() {
const [connection, setConnection] = useState<GitHubConnection>({
user: null,
token: '',
tokenType: 'classic',
});
const [isLoading, setIsLoading] = useState(true);
// Load saved connection on mount
useEffect(() => {
const savedConnection = localStorage.getItem('github_connection');
if (savedConnection) {
const parsed = JSON.parse(savedConnection);
// Ensure backward compatibility with existing connections
if (!parsed.tokenType) {
parsed.tokenType = 'classic';
}
setConnection(parsed);
if (parsed.user && parsed.token) {
fetchGitHubStats(parsed.token);
}
}
setIsLoading(false);
}, []);
const fetchGitHubStats = async (token: string) => {
try {
// Fetch repositories - only owned by the authenticated user
const reposResponse = await fetch(
'https://api.github.com/user/repos?sort=updated&per_page=10&affiliation=owner,organization_member,collaborator',
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);
if (!reposResponse.ok) {
throw new Error('Failed to fetch repositories');
}
const repos = (await reposResponse.json()) as GitHubRepoInfo[];
// Fetch organizations
const orgsResponse = await fetch('https://api.github.com/user/orgs', {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!orgsResponse.ok) {
throw new Error('Failed to fetch organizations');
}
const organizations = (await orgsResponse.json()) as GitHubOrganization[];
// Fetch recent activity
const eventsResponse = await fetch('https://api.github.com/users/' + connection.user?.login + '/events/public', {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!eventsResponse.ok) {
throw new Error('Failed to fetch events');
}
const recentActivity = ((await eventsResponse.json()) as GitHubEvent[]).slice(0, 5);
// Fetch languages for each repository
const languagePromises = repos.map((repo) =>
fetch(repo.languages_url, {
headers: {
Authorization: `Bearer ${token}`,
},
}).then((res) => res.json() as Promise<Record<string, number>>),
);
const repoLanguages = await Promise.all(languagePromises);
const languages: GitHubLanguageStats = {};
repoLanguages.forEach((repoLang) => {
Object.entries(repoLang).forEach(([lang, bytes]) => {
languages[lang] = (languages[lang] || 0) + bytes;
});
});
// Calculate total stats
const totalStars = repos.reduce((acc, repo) => acc + repo.stargazers_count, 0);
const totalForks = repos.reduce((acc, repo) => acc + repo.forks_count, 0);
const totalGists = connection.user?.public_gists || 0;
setConnection((prev) => ({
...prev,
stats: {
repos,
totalStars,
totalForks,
organizations,
recentActivity,
languages,
totalGists,
},
}));
} catch (error) {
logStore.logError('Failed to fetch GitHub stats', { error });
toast.error('Failed to fetch GitHub statistics');
} finally {
}
};
if (isLoading) {
return <LoadingSpinner />;
}
return (
<div className="space-y-4">
@@ -211,14 +93,3 @@ export default function ConnectionsTab() {
</div>
);
}
function LoadingSpinner() {
return (
<div className="flex items-center justify-center p-4">
<div className="flex items-center gap-2">
<div className="i-ph:spinner-gap-bold animate-spin w-4 h-4" />
<span className="text-bolt-elements-textSecondary">Loading...</span>
</div>
</div>
);
}