Skip to content

Commit c257129

Browse files
authored
Merge pull request #757 from dustinwloring1988/feat/enhanced-github-connection
feat: Improved GitHub connection
2 parents 0b47365 + 21bfcfc commit c257129

File tree

1 file changed

+110
-19
lines changed

1 file changed

+110
-19
lines changed

app/components/settings/connections/ConnectionsTab.tsx

Lines changed: 110 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,87 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { toast } from 'react-toastify';
33
import Cookies from 'js-cookie';
44
import { logStore } from '~/lib/stores/logs';
55

6+
interface GitHubUserResponse {
7+
login: string;
8+
id: number;
9+
[key: string]: any; // for other properties we don't explicitly need
10+
}
11+
612
export default function ConnectionsTab() {
713
const [githubUsername, setGithubUsername] = useState(Cookies.get('githubUsername') || '');
814
const [githubToken, setGithubToken] = useState(Cookies.get('githubToken') || '');
15+
const [isConnected, setIsConnected] = useState(false);
16+
const [isVerifying, setIsVerifying] = useState(false);
17+
18+
useEffect(() => {
19+
// Check if credentials exist and verify them
20+
if (githubUsername && githubToken) {
21+
verifyGitHubCredentials();
22+
}
23+
}, []);
924

10-
const handleSaveConnection = () => {
11-
Cookies.set('githubUsername', githubUsername);
12-
Cookies.set('githubToken', githubToken);
13-
logStore.logSystem('GitHub connection settings updated', {
14-
username: githubUsername,
15-
hasToken: !!githubToken,
16-
});
17-
toast.success('GitHub credentials saved successfully!');
18-
Cookies.set('git:github.com', JSON.stringify({ username: githubToken, password: 'x-oauth-basic' }));
25+
const verifyGitHubCredentials = async () => {
26+
setIsVerifying(true);
27+
try {
28+
const response = await fetch('https://api.github.com/user', {
29+
headers: {
30+
Authorization: `Bearer ${githubToken}`,
31+
},
32+
});
33+
34+
if (response.ok) {
35+
const data = (await response.json()) as GitHubUserResponse;
36+
if (data.login === githubUsername) {
37+
setIsConnected(true);
38+
return true;
39+
}
40+
}
41+
setIsConnected(false);
42+
return false;
43+
} catch (error) {
44+
console.error('Error verifying GitHub credentials:', error);
45+
setIsConnected(false);
46+
return false;
47+
} finally {
48+
setIsVerifying(false);
49+
}
50+
};
51+
52+
const handleSaveConnection = async () => {
53+
if (!githubUsername || !githubToken) {
54+
toast.error('Please provide both GitHub username and token');
55+
return;
56+
}
57+
58+
setIsVerifying(true);
59+
const isValid = await verifyGitHubCredentials();
60+
61+
if (isValid) {
62+
Cookies.set('githubUsername', githubUsername);
63+
Cookies.set('githubToken', githubToken);
64+
logStore.logSystem('GitHub connection settings updated', {
65+
username: githubUsername,
66+
hasToken: !!githubToken,
67+
});
68+
toast.success('GitHub credentials verified and saved successfully!');
69+
Cookies.set('git:github.com', JSON.stringify({ username: githubToken, password: 'x-oauth-basic' }));
70+
setIsConnected(true);
71+
} else {
72+
toast.error('Invalid GitHub credentials. Please check your username and token.');
73+
}
74+
};
75+
76+
const handleDisconnect = () => {
77+
Cookies.remove('githubUsername');
78+
Cookies.remove('githubToken');
79+
Cookies.remove('git:github.com');
80+
setGithubUsername('');
81+
setGithubToken('');
82+
setIsConnected(false);
83+
logStore.logSystem('GitHub connection removed');
84+
toast.success('GitHub connection removed successfully!');
1985
};
2086

2187
return (
@@ -28,7 +94,8 @@ export default function ConnectionsTab() {
2894
type="text"
2995
value={githubUsername}
3096
onChange={(e) => setGithubUsername(e.target.value)}
31-
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
97+
disabled={isVerifying}
98+
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor disabled:opacity-50"
3299
/>
33100
</div>
34101
<div className="flex-1">
@@ -37,17 +104,41 @@ export default function ConnectionsTab() {
37104
type="password"
38105
value={githubToken}
39106
onChange={(e) => setGithubToken(e.target.value)}
40-
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
107+
disabled={isVerifying}
108+
className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor disabled:opacity-50"
41109
/>
42110
</div>
43111
</div>
44-
<div className="flex mb-4">
45-
<button
46-
onClick={handleSaveConnection}
47-
className="bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 mr-2 transition-colors duration-200 hover:bg-bolt-elements-button-primary-backgroundHover text-bolt-elements-button-primary-text"
48-
>
49-
Save Connection
50-
</button>
112+
<div className="flex mb-4 items-center">
113+
{!isConnected ? (
114+
<button
115+
onClick={handleSaveConnection}
116+
disabled={isVerifying || !githubUsername || !githubToken}
117+
className="bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 mr-2 transition-colors duration-200 hover:bg-bolt-elements-button-primary-backgroundHover text-bolt-elements-button-primary-text disabled:opacity-50 disabled:cursor-not-allowed flex items-center"
118+
>
119+
{isVerifying ? (
120+
<>
121+
<div className="i-ph:spinner animate-spin mr-2" />
122+
Verifying...
123+
</>
124+
) : (
125+
'Connect'
126+
)}
127+
</button>
128+
) : (
129+
<button
130+
onClick={handleDisconnect}
131+
className="bg-bolt-elements-button-danger-background rounded-lg px-4 py-2 mr-2 transition-colors duration-200 hover:bg-bolt-elements-button-danger-backgroundHover text-bolt-elements-button-danger-text"
132+
>
133+
Disconnect
134+
</button>
135+
)}
136+
{isConnected && (
137+
<span className="text-sm text-green-600 flex items-center">
138+
<div className="i-ph:check-circle mr-1" />
139+
Connected to GitHub
140+
</span>
141+
)}
51142
</div>
52143
</div>
53144
);

0 commit comments

Comments
 (0)