Stijnus
commited on
Commit
·
505f1db
1
Parent(s):
56783ae
Connection improvements
Browse files
app/components/settings/connections/ConnectionsTab.tsx
CHANGED
@@ -13,6 +13,8 @@ interface GitHubUserResponse {
|
|
13 |
public_repos: number;
|
14 |
followers: number;
|
15 |
following: number;
|
|
|
|
|
16 |
}
|
17 |
|
18 |
interface GitHubRepoInfo {
|
@@ -24,12 +26,36 @@ interface GitHubRepoInfo {
|
|
24 |
forks_count: number;
|
25 |
default_branch: string;
|
26 |
updated_at: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
interface GitHubStats {
|
30 |
repos: GitHubRepoInfo[];
|
31 |
totalStars: number;
|
32 |
totalForks: number;
|
|
|
|
|
|
|
|
|
33 |
}
|
34 |
|
35 |
interface GitHubConnection {
|
@@ -88,9 +114,54 @@ export default function ConnectionsTab() {
|
|
88 |
|
89 |
const repos = (await reposResponse.json()) as GitHubRepoInfo[];
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
// Calculate total stats
|
92 |
const totalStars = repos.reduce((acc, repo) => acc + repo.stargazers_count, 0);
|
93 |
const totalForks = repos.reduce((acc, repo) => acc + repo.forks_count, 0);
|
|
|
94 |
|
95 |
setConnection((prev) => ({
|
96 |
...prev,
|
@@ -98,6 +169,10 @@ export default function ConnectionsTab() {
|
|
98 |
repos,
|
99 |
totalStars,
|
100 |
totalForks,
|
|
|
|
|
|
|
|
|
101 |
},
|
102 |
}));
|
103 |
} catch (error) {
|
@@ -360,6 +435,102 @@ export default function ConnectionsTab() {
|
|
360 |
</div>
|
361 |
</div>
|
362 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
363 |
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Recent Repositories</h4>
|
364 |
<div className="space-y-3">
|
365 |
{connection.stats.repos.map((repo) => (
|
|
|
13 |
public_repos: number;
|
14 |
followers: number;
|
15 |
following: number;
|
16 |
+
created_at: string;
|
17 |
+
public_gists: number;
|
18 |
}
|
19 |
|
20 |
interface GitHubRepoInfo {
|
|
|
26 |
forks_count: number;
|
27 |
default_branch: string;
|
28 |
updated_at: string;
|
29 |
+
languages_url: string;
|
30 |
+
}
|
31 |
+
|
32 |
+
interface GitHubOrganization {
|
33 |
+
login: string;
|
34 |
+
avatar_url: string;
|
35 |
+
html_url: string;
|
36 |
+
}
|
37 |
+
|
38 |
+
interface GitHubEvent {
|
39 |
+
id: string;
|
40 |
+
type: string;
|
41 |
+
repo: {
|
42 |
+
name: string;
|
43 |
+
};
|
44 |
+
created_at: string;
|
45 |
+
}
|
46 |
+
|
47 |
+
interface GitHubLanguageStats {
|
48 |
+
[language: string]: number;
|
49 |
}
|
50 |
|
51 |
interface GitHubStats {
|
52 |
repos: GitHubRepoInfo[];
|
53 |
totalStars: number;
|
54 |
totalForks: number;
|
55 |
+
organizations: GitHubOrganization[];
|
56 |
+
recentActivity: GitHubEvent[];
|
57 |
+
languages: GitHubLanguageStats;
|
58 |
+
totalGists: number;
|
59 |
}
|
60 |
|
61 |
interface GitHubConnection {
|
|
|
114 |
|
115 |
const repos = (await reposResponse.json()) as GitHubRepoInfo[];
|
116 |
|
117 |
+
// Fetch organizations
|
118 |
+
const orgsResponse = await fetch('https://api.github.com/user/orgs', {
|
119 |
+
headers: {
|
120 |
+
Authorization: `Bearer ${token}`,
|
121 |
+
},
|
122 |
+
});
|
123 |
+
|
124 |
+
if (!orgsResponse.ok) {
|
125 |
+
throw new Error('Failed to fetch organizations');
|
126 |
+
}
|
127 |
+
|
128 |
+
const organizations = (await orgsResponse.json()) as GitHubOrganization[];
|
129 |
+
|
130 |
+
// Fetch recent activity
|
131 |
+
const eventsResponse = await fetch('https://api.github.com/users/' + connection.user?.login + '/events/public', {
|
132 |
+
headers: {
|
133 |
+
Authorization: `Bearer ${token}`,
|
134 |
+
},
|
135 |
+
});
|
136 |
+
|
137 |
+
if (!eventsResponse.ok) {
|
138 |
+
throw new Error('Failed to fetch events');
|
139 |
+
}
|
140 |
+
|
141 |
+
const recentActivity = ((await eventsResponse.json()) as GitHubEvent[]).slice(0, 5);
|
142 |
+
|
143 |
+
// Fetch languages for each repository
|
144 |
+
const languagePromises = repos.map((repo) =>
|
145 |
+
fetch(repo.languages_url, {
|
146 |
+
headers: {
|
147 |
+
Authorization: `Bearer ${token}`,
|
148 |
+
},
|
149 |
+
}).then((res) => res.json() as Promise<Record<string, number>>),
|
150 |
+
);
|
151 |
+
|
152 |
+
const repoLanguages = await Promise.all(languagePromises);
|
153 |
+
const languages: GitHubLanguageStats = {};
|
154 |
+
|
155 |
+
repoLanguages.forEach((repoLang) => {
|
156 |
+
Object.entries(repoLang).forEach(([lang, bytes]) => {
|
157 |
+
languages[lang] = (languages[lang] || 0) + bytes;
|
158 |
+
});
|
159 |
+
});
|
160 |
+
|
161 |
// Calculate total stats
|
162 |
const totalStars = repos.reduce((acc, repo) => acc + repo.stargazers_count, 0);
|
163 |
const totalForks = repos.reduce((acc, repo) => acc + repo.forks_count, 0);
|
164 |
+
const totalGists = connection.user?.public_gists || 0;
|
165 |
|
166 |
setConnection((prev) => ({
|
167 |
...prev,
|
|
|
169 |
repos,
|
170 |
totalStars,
|
171 |
totalForks,
|
172 |
+
organizations,
|
173 |
+
recentActivity,
|
174 |
+
languages,
|
175 |
+
totalGists,
|
176 |
},
|
177 |
}));
|
178 |
} catch (error) {
|
|
|
435 |
</div>
|
436 |
</div>
|
437 |
|
438 |
+
{/* Organizations Section */}
|
439 |
+
{connection.stats.organizations.length > 0 && (
|
440 |
+
<div className="mb-6">
|
441 |
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Organizations</h4>
|
442 |
+
<div className="flex flex-wrap gap-3">
|
443 |
+
{connection.stats.organizations.map((org) => (
|
444 |
+
<a
|
445 |
+
key={org.login}
|
446 |
+
href={org.html_url}
|
447 |
+
target="_blank"
|
448 |
+
rel="noopener noreferrer"
|
449 |
+
className="flex items-center gap-2 p-2 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A] hover:bg-[#F0F0F0] dark:hover:bg-[#252525] transition-colors"
|
450 |
+
>
|
451 |
+
<img src={org.avatar_url} alt={org.login} className="w-6 h-6 rounded-md" />
|
452 |
+
<span className="text-sm text-bolt-elements-textPrimary">{org.login}</span>
|
453 |
+
</a>
|
454 |
+
))}
|
455 |
+
</div>
|
456 |
+
</div>
|
457 |
+
)}
|
458 |
+
|
459 |
+
{/* Languages Section */}
|
460 |
+
<div className="mb-6">
|
461 |
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Top Languages</h4>
|
462 |
+
<div className="flex flex-wrap gap-2">
|
463 |
+
{Object.entries(connection.stats.languages)
|
464 |
+
.sort(([, a], [, b]) => b - a)
|
465 |
+
.slice(0, 5)
|
466 |
+
.map(([language]) => (
|
467 |
+
<span
|
468 |
+
key={language}
|
469 |
+
className="px-3 py-1 text-xs rounded-full bg-purple-500/10 text-purple-500 dark:bg-purple-500/20"
|
470 |
+
>
|
471 |
+
{language}
|
472 |
+
</span>
|
473 |
+
))}
|
474 |
+
</div>
|
475 |
+
</div>
|
476 |
+
|
477 |
+
{/* Recent Activity Section */}
|
478 |
+
<div className="mb-6">
|
479 |
+
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Recent Activity</h4>
|
480 |
+
<div className="space-y-3">
|
481 |
+
{connection.stats.recentActivity.map((event) => (
|
482 |
+
<div key={event.id} className="p-3 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A] text-sm">
|
483 |
+
<div className="flex items-center gap-2 text-bolt-elements-textPrimary">
|
484 |
+
<div className="i-ph:git-commit w-4 h-4 text-bolt-elements-textSecondary" />
|
485 |
+
<span className="font-medium">{event.type.replace('Event', '')}</span>
|
486 |
+
<span>on</span>
|
487 |
+
<a
|
488 |
+
href={`https://github.com/${event.repo.name}`}
|
489 |
+
target="_blank"
|
490 |
+
rel="noopener noreferrer"
|
491 |
+
className="text-purple-500 hover:underline"
|
492 |
+
>
|
493 |
+
{event.repo.name}
|
494 |
+
</a>
|
495 |
+
</div>
|
496 |
+
<div className="mt-1 text-xs text-bolt-elements-textSecondary">
|
497 |
+
{new Date(event.created_at).toLocaleDateString()} at{' '}
|
498 |
+
{new Date(event.created_at).toLocaleTimeString()}
|
499 |
+
</div>
|
500 |
+
</div>
|
501 |
+
))}
|
502 |
+
</div>
|
503 |
+
</div>
|
504 |
+
|
505 |
+
{/* Additional Stats */}
|
506 |
+
<div className="grid grid-cols-4 gap-4 mb-6">
|
507 |
+
<div className="p-4 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A]">
|
508 |
+
<div className="text-sm text-bolt-elements-textSecondary">Member Since</div>
|
509 |
+
<div className="text-lg font-medium text-bolt-elements-textPrimary">
|
510 |
+
{new Date(connection.user.created_at).toLocaleDateString()}
|
511 |
+
</div>
|
512 |
+
</div>
|
513 |
+
<div className="p-4 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A]">
|
514 |
+
<div className="text-sm text-bolt-elements-textSecondary">Public Gists</div>
|
515 |
+
<div className="text-lg font-medium text-bolt-elements-textPrimary">
|
516 |
+
{connection.stats.totalGists}
|
517 |
+
</div>
|
518 |
+
</div>
|
519 |
+
<div className="p-4 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A]">
|
520 |
+
<div className="text-sm text-bolt-elements-textSecondary">Organizations</div>
|
521 |
+
<div className="text-lg font-medium text-bolt-elements-textPrimary">
|
522 |
+
{connection.stats.organizations.length}
|
523 |
+
</div>
|
524 |
+
</div>
|
525 |
+
<div className="p-4 rounded-lg bg-[#F8F8F8] dark:bg-[#1A1A1A]">
|
526 |
+
<div className="text-sm text-bolt-elements-textSecondary">Languages</div>
|
527 |
+
<div className="text-lg font-medium text-bolt-elements-textPrimary">
|
528 |
+
{Object.keys(connection.stats.languages).length}
|
529 |
+
</div>
|
530 |
+
</div>
|
531 |
+
</div>
|
532 |
+
|
533 |
+
{/* Existing repositories section */}
|
534 |
<h4 className="text-sm font-medium text-bolt-elements-textPrimary mb-3">Recent Repositories</h4>
|
535 |
<div className="space-y-3">
|
536 |
{connection.stats.repos.map((repo) => (
|
app/components/settings/connections/types/GitHub.ts
CHANGED
@@ -7,6 +7,9 @@ export interface GitHubUserResponse {
|
|
7 |
public_repos: number;
|
8 |
followers: number;
|
9 |
following: number;
|
|
|
|
|
|
|
10 |
}
|
11 |
|
12 |
export interface GitHubRepoInfo {
|
@@ -18,12 +21,45 @@ export interface GitHubRepoInfo {
|
|
18 |
forks_count: number;
|
19 |
default_branch: string;
|
20 |
updated_at: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
|
23 |
export interface GitHubStats {
|
24 |
repos: GitHubRepoInfo[];
|
25 |
totalStars: number;
|
26 |
totalForks: number;
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
export interface GitHubConnection {
|
|
|
7 |
public_repos: number;
|
8 |
followers: number;
|
9 |
following: number;
|
10 |
+
public_gists: number;
|
11 |
+
created_at: string;
|
12 |
+
updated_at: string;
|
13 |
}
|
14 |
|
15 |
export interface GitHubRepoInfo {
|
|
|
21 |
forks_count: number;
|
22 |
default_branch: string;
|
23 |
updated_at: string;
|
24 |
+
language: string;
|
25 |
+
languages_url: string;
|
26 |
+
}
|
27 |
+
|
28 |
+
export interface GitHubOrganization {
|
29 |
+
login: string;
|
30 |
+
avatar_url: string;
|
31 |
+
description: string;
|
32 |
+
html_url: string;
|
33 |
+
}
|
34 |
+
|
35 |
+
export interface GitHubEvent {
|
36 |
+
id: string;
|
37 |
+
type: string;
|
38 |
+
created_at: string;
|
39 |
+
repo: {
|
40 |
+
name: string;
|
41 |
+
url: string;
|
42 |
+
};
|
43 |
+
payload: {
|
44 |
+
action?: string;
|
45 |
+
ref?: string;
|
46 |
+
ref_type?: string;
|
47 |
+
description?: string;
|
48 |
+
};
|
49 |
+
}
|
50 |
+
|
51 |
+
export interface GitHubLanguageStats {
|
52 |
+
[key: string]: number;
|
53 |
}
|
54 |
|
55 |
export interface GitHubStats {
|
56 |
repos: GitHubRepoInfo[];
|
57 |
totalStars: number;
|
58 |
totalForks: number;
|
59 |
+
organizations: GitHubOrganization[];
|
60 |
+
recentActivity: GitHubEvent[];
|
61 |
+
languages: GitHubLanguageStats;
|
62 |
+
totalGists: number;
|
63 |
}
|
64 |
|
65 |
export interface GitHubConnection {
|
pnpm-lock.yaml
CHANGED
@@ -9935,7 +9935,7 @@ snapshots:
|
|
9935 |
'@babel/plugin-syntax-typescript': 7.25.9(@babel/[email protected])
|
9936 |
'@vanilla-extract/babel-plugin-debug-ids': 1.2.0
|
9937 |
'@vanilla-extract/css': 1.17.0
|
9938 |
-
esbuild: 0.17.
|
9939 |
eval: 0.1.8
|
9940 |
find-up: 5.0.0
|
9941 |
javascript-stringify: 2.1.0
|
|
|
9935 |
'@babel/plugin-syntax-typescript': 7.25.9(@babel/[email protected])
|
9936 |
'@vanilla-extract/babel-plugin-debug-ids': 1.2.0
|
9937 |
'@vanilla-extract/css': 1.17.0
|
9938 |
+
esbuild: 0.17.19
|
9939 |
eval: 0.1.8
|
9940 |
find-up: 5.0.0
|
9941 |
javascript-stringify: 2.1.0
|