KevIsDev commited on
Commit
19137c9
·
1 Parent(s): 96a0b2a

add: various improvements to connections

Browse files

- improved organisation of connections (collapsibles)
- improved deploy button
- improved unique chat deployments

app/components/@settings/tabs/connections/ConnectionsTab.tsx CHANGED
@@ -1,73 +1,8 @@
1
- import React, { useState, useEffect } from 'react';
2
- import { logStore } from '~/lib/stores/logs';
3
  import { motion } from 'framer-motion';
4
- import { toast } from 'react-toastify';
5
  import { GithubConnection } from './GithubConnection';
6
  import { NetlifyConnection } from './NetlifyConnection';
7
 
8
- interface GitHubUserResponse {
9
- login: string;
10
- avatar_url: string;
11
- html_url: string;
12
- name: string;
13
- bio: string;
14
- public_repos: number;
15
- followers: number;
16
- following: number;
17
- created_at: string;
18
- public_gists: number;
19
- }
20
-
21
- interface GitHubRepoInfo {
22
- name: string;
23
- full_name: string;
24
- html_url: string;
25
- description: string;
26
- stargazers_count: number;
27
- forks_count: number;
28
- default_branch: string;
29
- updated_at: string;
30
- languages_url: string;
31
- }
32
-
33
- interface GitHubOrganization {
34
- login: string;
35
- avatar_url: string;
36
- html_url: string;
37
- }
38
-
39
- interface GitHubEvent {
40
- id: string;
41
- type: string;
42
- repo: {
43
- name: string;
44
- };
45
- created_at: string;
46
- }
47
-
48
- interface GitHubLanguageStats {
49
- [language: string]: number;
50
- }
51
-
52
- interface GitHubStats {
53
- repos: GitHubRepoInfo[];
54
- totalStars: number;
55
- totalForks: number;
56
- organizations: GitHubOrganization[];
57
- recentActivity: GitHubEvent[];
58
- languages: GitHubLanguageStats;
59
- totalGists: number;
60
- }
61
-
62
- interface GitHubConnection {
63
- user: GitHubUserResponse | null;
64
- token: string;
65
- tokenType: 'classic' | 'fine-grained';
66
- stats?: GitHubStats;
67
- }
68
-
69
  export default function ConnectionsTab() {
70
-
71
  return (
72
  <div className="space-y-4">
73
  {/* Header */}
@@ -85,9 +20,7 @@ export default function ConnectionsTab() {
85
  </p>
86
 
87
  <div className="grid grid-cols-1 gap-4">
88
- {/* GitHub Connection */}
89
  <GithubConnection />
90
- {/* Netlify Connection */}
91
  <NetlifyConnection />
92
  </div>
93
  </div>
 
 
 
1
  import { motion } from 'framer-motion';
 
2
  import { GithubConnection } from './GithubConnection';
3
  import { NetlifyConnection } from './NetlifyConnection';
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  export default function ConnectionsTab() {
 
6
  return (
7
  <div className="space-y-4">
8
  {/* Header */}
 
20
  </p>
21
 
22
  <div className="grid grid-cols-1 gap-4">
 
23
  <GithubConnection />
 
24
  <NetlifyConnection />
25
  </div>
26
  </div>
app/components/@settings/tabs/connections/GithubConnection.tsx CHANGED
@@ -73,7 +73,6 @@ export function GithubConnection() {
73
  });
74
  const [isLoading, setIsLoading] = useState(true);
75
  const [isConnecting, setIsConnecting] = useState(false);
76
- const [isFetchingStats, setIsFetchingStats] = useState(false);
77
  const [expandedSections, setExpandedSections] = useState({
78
  organizations: false,
79
  languages: false,
@@ -82,16 +81,14 @@ export function GithubConnection() {
82
  });
83
 
84
  const toggleSection = (section: keyof typeof expandedSections) => {
85
- setExpandedSections(prev => ({
86
  ...prev,
87
- [section]: !prev[section]
88
  }));
89
  };
90
 
91
  const fetchGitHubStats = async (token: string) => {
92
  try {
93
- setIsFetchingStats(true);
94
-
95
  const reposResponse = await fetch(
96
  'https://api.github.com/user/repos?sort=updated&per_page=10&affiliation=owner,organization_member,collaborator',
97
  {
@@ -168,7 +165,6 @@ export function GithubConnection() {
168
  logStore.logError('Failed to fetch GitHub stats', { error });
169
  toast.error('Failed to fetch GitHub statistics');
170
  } finally {
171
- setIsFetchingStats(false);
172
  }
173
  };
174
 
@@ -188,6 +184,7 @@ export function GithubConnection() {
188
  fetchGitHubStats(parsed.token);
189
  }
190
  }
 
191
  setIsLoading(false);
192
  }, []);
193
 
@@ -401,16 +398,18 @@ export function GithubConnection() {
401
  {/* Organizations Section */}
402
  {connection.stats.organizations.length > 0 && (
403
  <div className="space-y-3">
404
- <button
405
  onClick={() => toggleSection('organizations')}
406
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
407
  >
408
  <div className="i-ph:buildings w-4 h-4" />
409
  Organizations ({connection.stats.organizations.length})
410
- <div className={classNames(
411
- "i-ph:caret-down w-4 h-4 ml-auto transition-transform",
412
- expandedSections.organizations ? "rotate-180" : ""
413
- )} />
 
 
414
  </button>
415
  {expandedSections.organizations && (
416
  <div className="flex flex-wrap gap-3 pb-4">
@@ -433,16 +432,18 @@ export function GithubConnection() {
433
 
434
  {/* Languages Section */}
435
  <div className="space-y-3">
436
- <button
437
  onClick={() => toggleSection('languages')}
438
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
439
  >
440
  <div className="i-ph:code w-4 h-4" />
441
  Top Languages ({Object.keys(connection.stats.languages).length})
442
- <div className={classNames(
443
- "i-ph:caret-down w-4 h-4 ml-auto transition-transform",
444
- expandedSections.languages ? "rotate-180" : ""
445
- )} />
 
 
446
  </button>
447
  {expandedSections.languages && (
448
  <div className="flex flex-wrap gap-2 pb-4">
@@ -463,16 +464,18 @@ export function GithubConnection() {
463
 
464
  {/* Recent Activity Section */}
465
  <div className="space-y-3">
466
- <button
467
  onClick={() => toggleSection('recentActivity')}
468
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
469
  >
470
  <div className="i-ph:activity w-4 h-4" />
471
  Recent Activity ({connection.stats.recentActivity.length})
472
- <div className={classNames(
473
- "i-ph:caret-down w-4 h-4 ml-auto transition-transform",
474
- expandedSections.recentActivity ? "rotate-180" : ""
475
- )} />
 
 
476
  </button>
477
  {expandedSections.recentActivity && (
478
  <div className="space-y-3 pb-4">
@@ -503,16 +506,18 @@ export function GithubConnection() {
503
 
504
  {/* Repositories Section */}
505
  <div className="space-y-3">
506
- <button
507
  onClick={() => toggleSection('repositories')}
508
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
509
  >
510
  <div className="i-ph:clock-counter-clockwise w-4 h-4" />
511
  Recent Repositories ({connection.stats.repos.length})
512
- <div className={classNames(
513
- "i-ph:caret-down w-4 h-4 ml-auto transition-transform",
514
- expandedSections.repositories ? "rotate-180" : ""
515
- )} />
 
 
516
  </button>
517
  {expandedSections.repositories && (
518
  <div className="space-y-3">
@@ -574,4 +579,4 @@ function LoadingSpinner() {
574
  </div>
575
  </div>
576
  );
577
- }
 
73
  });
74
  const [isLoading, setIsLoading] = useState(true);
75
  const [isConnecting, setIsConnecting] = useState(false);
 
76
  const [expandedSections, setExpandedSections] = useState({
77
  organizations: false,
78
  languages: false,
 
81
  });
82
 
83
  const toggleSection = (section: keyof typeof expandedSections) => {
84
+ setExpandedSections((prev) => ({
85
  ...prev,
86
+ [section]: !prev[section],
87
  }));
88
  };
89
 
90
  const fetchGitHubStats = async (token: string) => {
91
  try {
 
 
92
  const reposResponse = await fetch(
93
  'https://api.github.com/user/repos?sort=updated&per_page=10&affiliation=owner,organization_member,collaborator',
94
  {
 
165
  logStore.logError('Failed to fetch GitHub stats', { error });
166
  toast.error('Failed to fetch GitHub statistics');
167
  } finally {
 
168
  }
169
  };
170
 
 
184
  fetchGitHubStats(parsed.token);
185
  }
186
  }
187
+
188
  setIsLoading(false);
189
  }, []);
190
 
 
398
  {/* Organizations Section */}
399
  {connection.stats.organizations.length > 0 && (
400
  <div className="space-y-3">
401
+ <button
402
  onClick={() => toggleSection('organizations')}
403
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
404
  >
405
  <div className="i-ph:buildings w-4 h-4" />
406
  Organizations ({connection.stats.organizations.length})
407
+ <div
408
+ className={classNames(
409
+ 'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
410
+ expandedSections.organizations ? 'rotate-180' : '',
411
+ )}
412
+ />
413
  </button>
414
  {expandedSections.organizations && (
415
  <div className="flex flex-wrap gap-3 pb-4">
 
432
 
433
  {/* Languages Section */}
434
  <div className="space-y-3">
435
+ <button
436
  onClick={() => toggleSection('languages')}
437
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
438
  >
439
  <div className="i-ph:code w-4 h-4" />
440
  Top Languages ({Object.keys(connection.stats.languages).length})
441
+ <div
442
+ className={classNames(
443
+ 'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
444
+ expandedSections.languages ? 'rotate-180' : '',
445
+ )}
446
+ />
447
  </button>
448
  {expandedSections.languages && (
449
  <div className="flex flex-wrap gap-2 pb-4">
 
464
 
465
  {/* Recent Activity Section */}
466
  <div className="space-y-3">
467
+ <button
468
  onClick={() => toggleSection('recentActivity')}
469
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
470
  >
471
  <div className="i-ph:activity w-4 h-4" />
472
  Recent Activity ({connection.stats.recentActivity.length})
473
+ <div
474
+ className={classNames(
475
+ 'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
476
+ expandedSections.recentActivity ? 'rotate-180' : '',
477
+ )}
478
+ />
479
  </button>
480
  {expandedSections.recentActivity && (
481
  <div className="space-y-3 pb-4">
 
506
 
507
  {/* Repositories Section */}
508
  <div className="space-y-3">
509
+ <button
510
  onClick={() => toggleSection('repositories')}
511
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary flex items-center gap-2"
512
  >
513
  <div className="i-ph:clock-counter-clockwise w-4 h-4" />
514
  Recent Repositories ({connection.stats.repos.length})
515
+ <div
516
+ className={classNames(
517
+ 'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
518
+ expandedSections.repositories ? 'rotate-180' : '',
519
+ )}
520
+ />
521
  </button>
522
  {expandedSections.repositories && (
523
  <div className="space-y-3">
 
579
  </div>
580
  </div>
581
  );
582
+ }
app/components/@settings/tabs/connections/NetlifyConnection.tsx CHANGED
@@ -214,16 +214,18 @@ export function NetlifyConnection() {
214
  </div>
215
  ) : (
216
  <div>
217
- <button
218
  onClick={() => setIsSitesExpanded(!isSitesExpanded)}
219
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary mb-3 flex items-center gap-2"
220
  >
221
  <div className="i-ph:buildings w-4 h-4" />
222
  Your Sites ({connection.stats?.totalSites || 0})
223
- <div className={classNames(
224
- "i-ph:caret-down w-4 h-4 ml-auto transition-transform",
225
- isSitesExpanded ? "rotate-180" : ""
226
- )} />
 
 
227
  </button>
228
  {isSitesExpanded && connection.stats?.sites?.length ? (
229
  <div className="grid gap-3">
 
214
  </div>
215
  ) : (
216
  <div>
217
+ <button
218
  onClick={() => setIsSitesExpanded(!isSitesExpanded)}
219
  className="w-full bg-transparent text-left text-sm font-medium text-bolt-elements-textPrimary mb-3 flex items-center gap-2"
220
  >
221
  <div className="i-ph:buildings w-4 h-4" />
222
  Your Sites ({connection.stats?.totalSites || 0})
223
+ <div
224
+ className={classNames(
225
+ 'i-ph:caret-down w-4 h-4 ml-auto transition-transform',
226
+ isSitesExpanded ? 'rotate-180' : '',
227
+ )}
228
+ />
229
  </button>
230
  {isSitesExpanded && connection.stats?.sites?.length ? (
231
  <div className="grid gap-3">
app/components/header/HeaderActionButtons.client.tsx CHANGED
@@ -33,6 +33,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
33
  }
34
  }
35
  document.addEventListener('mousedown', handleClickOutside);
 
36
  return () => document.removeEventListener('mousedown', handleClickOutside);
37
  }, []);
38
 
@@ -109,6 +110,7 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
109
  }
110
 
111
  const fileContents = await getAllFiles(buildPath);
 
112
  // Use chatId instead of artifact.id
113
  const existingSiteId = localStorage.getItem(`netlify-site-${currentChatId}`);
114
 
@@ -209,65 +211,64 @@ export function HeaderActionButtons({}: HeaderActionButtonsProps) {
209
  className="px-4 hover:bg-bolt-elements-item-backgroundActive flex items-center gap-2"
210
  >
211
  {isDeploying ? 'Deploying...' : 'Deploy'}
212
- <div className={classNames(
213
- "i-ph:caret-down w-4 h-4 transition-transform",
214
- isDropdownOpen ? "rotate-180" : ""
215
- )} />
216
  </Button>
217
  </div>
218
 
219
  {isDropdownOpen && (
220
  <div className="absolute right-2 flex flex-col gap-1 z-50 p-1 mt-1 min-w-[13.5rem] bg-bolt-elements-background-depth-2 rounded-md shadow-lg bg-bolt-elements-backgroundDefault border border-bolt-elements-borderColor">
221
- <Button
222
- active
223
- onClick={() => {
224
- handleDeploy();
225
- setIsDropdownOpen(false);
226
- }}
227
- disabled={isDeploying || !activePreview}
228
- className="flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md"
229
- >
230
- <img
231
- className="w-5 h-5"
232
- height="24"
233
- width="24"
234
- crossOrigin="anonymous"
235
- src="https://cdn.simpleicons.org/netlify"
236
- />
237
- <span className='mx-auto'>Deploy to Netlify</span>
238
- </Button>
239
- <Button
240
- active={false}
241
- disabled
242
- className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
243
- >
244
- <span className='sr-only'>Coming Soon</span>
245
- <img
246
- className="w-5 h-5 bg-black p-1 rounded"
247
- height="24"
248
- width="24"
249
- crossOrigin="anonymous"
250
- src="https://cdn.simpleicons.org/vercel/white"
251
- alt='vercel'
252
- />
253
- <span className='mx-auto'>Deploy to Vercel (Coming Soon)</span>
254
- </Button>
255
- <Button
256
- active={false}
257
- disabled
258
- className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
259
- >
260
- <span className='sr-only'>Coming Soon</span>
261
- <img
262
- className="w-5 h-5"
263
- height="24"
264
- width="24"
265
- crossOrigin="anonymous"
266
- src="https://cdn.simpleicons.org/cloudflare"
267
- alt='vercel'
268
- />
269
- <span className='mx-auto'>Deploy to Cloudflare (Coming Soon)</span>
270
- </Button>
271
  </div>
272
  )}
273
  </div>
 
33
  }
34
  }
35
  document.addEventListener('mousedown', handleClickOutside);
36
+
37
  return () => document.removeEventListener('mousedown', handleClickOutside);
38
  }, []);
39
 
 
110
  }
111
 
112
  const fileContents = await getAllFiles(buildPath);
113
+
114
  // Use chatId instead of artifact.id
115
  const existingSiteId = localStorage.getItem(`netlify-site-${currentChatId}`);
116
 
 
211
  className="px-4 hover:bg-bolt-elements-item-backgroundActive flex items-center gap-2"
212
  >
213
  {isDeploying ? 'Deploying...' : 'Deploy'}
214
+ <div
215
+ className={classNames('i-ph:caret-down w-4 h-4 transition-transform', isDropdownOpen ? 'rotate-180' : '')}
216
+ />
 
217
  </Button>
218
  </div>
219
 
220
  {isDropdownOpen && (
221
  <div className="absolute right-2 flex flex-col gap-1 z-50 p-1 mt-1 min-w-[13.5rem] bg-bolt-elements-background-depth-2 rounded-md shadow-lg bg-bolt-elements-backgroundDefault border border-bolt-elements-borderColor">
222
+ <Button
223
+ active
224
+ onClick={() => {
225
+ handleDeploy();
226
+ setIsDropdownOpen(false);
227
+ }}
228
+ disabled={isDeploying || !activePreview}
229
+ className="flex items-center w-full px-4 py-2 text-sm text-bolt-elements-textPrimary hover:bg-bolt-elements-item-backgroundActive gap-2 rounded-md"
230
+ >
231
+ <img
232
+ className="w-5 h-5"
233
+ height="24"
234
+ width="24"
235
+ crossOrigin="anonymous"
236
+ src="https://cdn.simpleicons.org/netlify"
237
+ />
238
+ <span className="mx-auto">Deploy to Netlify</span>
239
+ </Button>
240
+ <Button
241
+ active={false}
242
+ disabled
243
+ className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
244
+ >
245
+ <span className="sr-only">Coming Soon</span>
246
+ <img
247
+ className="w-5 h-5 bg-black p-1 rounded"
248
+ height="24"
249
+ width="24"
250
+ crossOrigin="anonymous"
251
+ src="https://cdn.simpleicons.org/vercel/white"
252
+ alt="vercel"
253
+ />
254
+ <span className="mx-auto">Deploy to Vercel (Coming Soon)</span>
255
+ </Button>
256
+ <Button
257
+ active={false}
258
+ disabled
259
+ className="flex items-center w-full rounded-md px-4 py-2 text-sm text-bolt-elements-textTertiary gap-2"
260
+ >
261
+ <span className="sr-only">Coming Soon</span>
262
+ <img
263
+ className="w-5 h-5"
264
+ height="24"
265
+ width="24"
266
+ crossOrigin="anonymous"
267
+ src="https://cdn.simpleicons.org/cloudflare"
268
+ alt="vercel"
269
+ />
270
+ <span className="mx-auto">Deploy to Cloudflare (Coming Soon)</span>
271
+ </Button>
272
  </div>
273
  )}
274
  </div>
app/lib/persistence/db.ts CHANGED
@@ -5,7 +5,7 @@ import type { ChatHistoryItem } from './useChatHistory';
5
  export interface IChatMetadata {
6
  gitUrl: string;
7
  gitBranch?: string;
8
- netlifySiteId?: string; // Add this field
9
  }
10
 
11
  const logger = createScopedLogger('ChatHistory');
 
5
  export interface IChatMetadata {
6
  gitUrl: string;
7
  gitBranch?: string;
8
+ netlifySiteId?: string;
9
  }
10
 
11
  const logger = createScopedLogger('ChatHistory');