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.6
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