Commit
·
9aaa3b5
1
Parent(s):
178653d
feat: Connections Tabs
Browse filesAdded a connections tab, now you can enter GitHub creds and store them in cookies like the API Keys
app/components/settings/SettingsWindow.tsx
CHANGED
@@ -18,7 +18,7 @@ interface SettingsProps {
|
|
18 |
onClose: () => void;
|
19 |
}
|
20 |
|
21 |
-
type TabType = 'chat-history' | 'providers' | 'features' | 'debug';
|
22 |
|
23 |
// Providers that support base URL configuration
|
24 |
const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
|
@@ -30,6 +30,8 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|
30 |
const [searchTerm, setSearchTerm] = useState('');
|
31 |
const [isDeleting, setIsDeleting] = useState(false);
|
32 |
const [isJustSayEnabled, setIsJustSayEnabled] = useState(false);
|
|
|
|
|
33 |
|
34 |
// Load base URLs from cookies
|
35 |
const [baseUrls, setBaseUrls] = useState(() => {
|
@@ -68,6 +70,7 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|
68 |
{ id: 'chat-history', label: 'Chat History', icon: 'i-ph:book' },
|
69 |
{ id: 'providers', label: 'Providers', icon: 'i-ph:key' },
|
70 |
{ id: 'features', label: 'Features', icon: 'i-ph:star' },
|
|
|
71 |
...(isDebugEnabled ? [{ id: 'debug' as TabType, label: 'Debug Tab', icon: 'i-ph:bug' }] : []),
|
72 |
];
|
73 |
|
@@ -192,6 +195,18 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|
192 |
|
193 |
const versionHash = commit.commit; // Get the version hash from commit.json
|
194 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
195 |
return (
|
196 |
<RadixDialog.Root open={open}>
|
197 |
<RadixDialog.Portal>
|
@@ -431,6 +446,45 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|
431 |
<p className="text-bolt-elements-textSecondary">Version Hash: {versionHash}</p>
|
432 |
</div>
|
433 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
434 |
</div>
|
435 |
</div>
|
436 |
</div>
|
|
|
18 |
onClose: () => void;
|
19 |
}
|
20 |
|
21 |
+
type TabType = 'chat-history' | 'providers' | 'features' | 'debug' | 'connection';
|
22 |
|
23 |
// Providers that support base URL configuration
|
24 |
const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
|
|
|
30 |
const [searchTerm, setSearchTerm] = useState('');
|
31 |
const [isDeleting, setIsDeleting] = useState(false);
|
32 |
const [isJustSayEnabled, setIsJustSayEnabled] = useState(false);
|
33 |
+
const [githubUsername, setGithubUsername] = useState(Cookies.get('githubUsername') || '');
|
34 |
+
const [githubToken, setGithubToken] = useState(Cookies.get('githubToken') || '');
|
35 |
|
36 |
// Load base URLs from cookies
|
37 |
const [baseUrls, setBaseUrls] = useState(() => {
|
|
|
70 |
{ id: 'chat-history', label: 'Chat History', icon: 'i-ph:book' },
|
71 |
{ id: 'providers', label: 'Providers', icon: 'i-ph:key' },
|
72 |
{ id: 'features', label: 'Features', icon: 'i-ph:star' },
|
73 |
+
{ id: 'connection', label: 'Connection', icon: 'i-ph:link' },
|
74 |
...(isDebugEnabled ? [{ id: 'debug' as TabType, label: 'Debug Tab', icon: 'i-ph:bug' }] : []),
|
75 |
];
|
76 |
|
|
|
195 |
|
196 |
const versionHash = commit.commit; // Get the version hash from commit.json
|
197 |
|
198 |
+
const handleSaveConnection = () => {
|
199 |
+
Cookies.set('githubUsername', githubUsername);
|
200 |
+
Cookies.set('githubToken', githubToken);
|
201 |
+
toast.success('GitHub credentials saved successfully!');
|
202 |
+
};
|
203 |
+
|
204 |
+
const handleTestConnection = () => {
|
205 |
+
// Implement the logic to test the GitHub connection here
|
206 |
+
// For example, you could make an API call to GitHub to verify the credentials
|
207 |
+
toast.info('Testing GitHub connection...');
|
208 |
+
};
|
209 |
+
|
210 |
return (
|
211 |
<RadixDialog.Root open={open}>
|
212 |
<RadixDialog.Portal>
|
|
|
446 |
<p className="text-bolt-elements-textSecondary">Version Hash: {versionHash}</p>
|
447 |
</div>
|
448 |
)}
|
449 |
+
{activeTab === 'connection' && (
|
450 |
+
<div className="p-4 mb-4 border border-bolt-elements-borderColor rounded-lg bg-bolt-elements-background-depth-3">
|
451 |
+
<h3 className="text-lg font-medium text-bolt-elements-textPrimary mb-4">GitHub Connection</h3>
|
452 |
+
<div className="flex mb-4">
|
453 |
+
<div className="flex-1 mr-2">
|
454 |
+
<label className="block text-sm text-bolt-elements-textSecondary mb-1">GitHub Username:</label>
|
455 |
+
<input
|
456 |
+
type="text"
|
457 |
+
value={githubUsername}
|
458 |
+
onChange={(e) => setGithubUsername(e.target.value)}
|
459 |
+
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"
|
460 |
+
/>
|
461 |
+
</div>
|
462 |
+
<div className="flex-1">
|
463 |
+
<label className="block text-sm text-bolt-elements-textSecondary mb-1">Personal Access Token:</label>
|
464 |
+
<input
|
465 |
+
type="password"
|
466 |
+
value={githubToken}
|
467 |
+
onChange={(e) => setGithubToken(e.target.value)}
|
468 |
+
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"
|
469 |
+
/>
|
470 |
+
</div>
|
471 |
+
</div>
|
472 |
+
<div className="flex mb-4">
|
473 |
+
<button
|
474 |
+
onClick={handleSaveConnection}
|
475 |
+
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"
|
476 |
+
>
|
477 |
+
Save Connection
|
478 |
+
</button>
|
479 |
+
<button
|
480 |
+
onClick={handleTestConnection}
|
481 |
+
className="bg-blue-500 rounded-lg px-4 py-2 transition-colors duration-200 hover:bg-blue-600 text-white"
|
482 |
+
>
|
483 |
+
Test Connection
|
484 |
+
</button>
|
485 |
+
</div>
|
486 |
+
</div>
|
487 |
+
)}
|
488 |
</div>
|
489 |
</div>
|
490 |
</div>
|
app/components/workbench/Workbench.client.tsx
CHANGED
@@ -17,6 +17,7 @@ import { renderLogger } from '~/utils/logger';
|
|
17 |
import { EditorPanel } from './EditorPanel';
|
18 |
import { Preview } from './Preview';
|
19 |
import useViewport from '~/lib/hooks';
|
|
|
20 |
|
21 |
interface WorkspaceProps {
|
22 |
chatStarted?: boolean;
|
@@ -158,15 +159,6 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|
158 |
{isSyncing ? <div className="i-ph:spinner" /> : <div className="i-ph:cloud-arrow-down" />}
|
159 |
{isSyncing ? 'Syncing...' : 'Sync Files'}
|
160 |
</PanelHeaderButton>
|
161 |
-
<PanelHeaderButton
|
162 |
-
className="mr-1 text-sm"
|
163 |
-
onClick={() => {
|
164 |
-
workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get());
|
165 |
-
}}
|
166 |
-
>
|
167 |
-
<div className="i-ph:terminal" />
|
168 |
-
Toggle Terminal
|
169 |
-
</PanelHeaderButton>
|
170 |
<PanelHeaderButton
|
171 |
className="mr-1 text-sm"
|
172 |
onClick={() => {
|
@@ -180,21 +172,22 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|
180 |
return;
|
181 |
}
|
182 |
|
183 |
-
const githubUsername =
|
|
|
184 |
|
185 |
-
if (!githubUsername) {
|
186 |
-
|
187 |
-
|
188 |
-
}
|
189 |
|
190 |
-
|
|
|
|
|
|
|
191 |
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
}
|
196 |
-
|
197 |
-
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
198 |
}}
|
199 |
>
|
200 |
<div className="i-ph:github-logo" />
|
|
|
17 |
import { EditorPanel } from './EditorPanel';
|
18 |
import { Preview } from './Preview';
|
19 |
import useViewport from '~/lib/hooks';
|
20 |
+
import Cookies from 'js-cookie';
|
21 |
|
22 |
interface WorkspaceProps {
|
23 |
chatStarted?: boolean;
|
|
|
159 |
{isSyncing ? <div className="i-ph:spinner" /> : <div className="i-ph:cloud-arrow-down" />}
|
160 |
{isSyncing ? 'Syncing...' : 'Sync Files'}
|
161 |
</PanelHeaderButton>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
<PanelHeaderButton
|
163 |
className="mr-1 text-sm"
|
164 |
onClick={() => {
|
|
|
172 |
return;
|
173 |
}
|
174 |
|
175 |
+
const githubUsername = Cookies.get('githubUsername');
|
176 |
+
const githubToken = Cookies.get('githubToken');
|
177 |
|
178 |
+
if (!githubUsername || !githubToken) {
|
179 |
+
const usernameInput = prompt('Please enter your GitHub username:');
|
180 |
+
const tokenInput = prompt('Please enter your GitHub personal access token:');
|
|
|
181 |
|
182 |
+
if (!usernameInput || !tokenInput) {
|
183 |
+
alert('GitHub username and token are required. Push to GitHub cancelled.');
|
184 |
+
return;
|
185 |
+
}
|
186 |
|
187 |
+
workbenchStore.pushToGitHub(repoName, usernameInput, tokenInput);
|
188 |
+
} else {
|
189 |
+
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
190 |
}
|
|
|
|
|
191 |
}}
|
192 |
>
|
193 |
<div className="i-ph:github-logo" />
|
app/lib/stores/workbench.ts
CHANGED
@@ -15,6 +15,7 @@ import { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';
|
|
15 |
import * as nodePath from 'node:path';
|
16 |
import { extractRelativePath } from '~/utils/diff';
|
17 |
import { description } from '~/lib/persistence';
|
|
|
18 |
|
19 |
export interface ArtifactState {
|
20 |
id: string;
|
@@ -396,15 +397,14 @@ export class WorkbenchStore {
|
|
396 |
return syncedFiles;
|
397 |
}
|
398 |
|
399 |
-
async pushToGitHub(repoName: string, githubUsername
|
400 |
try {
|
401 |
-
//
|
402 |
-
const githubToken = ghToken;
|
|
|
403 |
|
404 |
-
|
405 |
-
|
406 |
-
if (!githubToken) {
|
407 |
-
throw new Error('GitHub token is not set in environment variables');
|
408 |
}
|
409 |
|
410 |
// Initialize Octokit with the auth token
|
@@ -501,7 +501,8 @@ export class WorkbenchStore {
|
|
501 |
|
502 |
alert(`Repository created and code pushed: ${repo.html_url}`);
|
503 |
} catch (error) {
|
504 |
-
console.error('Error pushing to GitHub:', error
|
|
|
505 |
}
|
506 |
}
|
507 |
}
|
|
|
15 |
import * as nodePath from 'node:path';
|
16 |
import { extractRelativePath } from '~/utils/diff';
|
17 |
import { description } from '~/lib/persistence';
|
18 |
+
import Cookies from 'js-cookie';
|
19 |
|
20 |
export interface ArtifactState {
|
21 |
id: string;
|
|
|
397 |
return syncedFiles;
|
398 |
}
|
399 |
|
400 |
+
async pushToGitHub(repoName: string, githubUsername?: string, ghToken?: string) {
|
401 |
try {
|
402 |
+
// Use cookies if username and token are not provided
|
403 |
+
const githubToken = ghToken || Cookies.get('githubToken');
|
404 |
+
const owner = githubUsername || Cookies.get('githubUsername');
|
405 |
|
406 |
+
if (!githubToken || !owner) {
|
407 |
+
throw new Error('GitHub token or username is not set in cookies or provided.');
|
|
|
|
|
408 |
}
|
409 |
|
410 |
// Initialize Octokit with the auth token
|
|
|
501 |
|
502 |
alert(`Repository created and code pushed: ${repo.html_url}`);
|
503 |
} catch (error) {
|
504 |
+
console.error('Error pushing to GitHub:', error);
|
505 |
+
throw error; // Rethrow the error for further handling
|
506 |
}
|
507 |
}
|
508 |
}
|