mirror of
https://github.com/stackblitz/bolt.new
synced 2025-02-06 04:48:04 +00:00
feat: Connections Tabs
Added a connections tab, now you can enter GitHub creds and store them in cookies like the API Keys
This commit is contained in:
parent
178653dbed
commit
9aaa3b560c
@ -18,7 +18,7 @@ interface SettingsProps {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabType = 'chat-history' | 'providers' | 'features' | 'debug';
|
type TabType = 'chat-history' | 'providers' | 'features' | 'debug' | 'connection';
|
||||||
|
|
||||||
// Providers that support base URL configuration
|
// Providers that support base URL configuration
|
||||||
const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
|
const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
|
||||||
@ -30,6 +30,8 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
const [isJustSayEnabled, setIsJustSayEnabled] = useState(false);
|
const [isJustSayEnabled, setIsJustSayEnabled] = useState(false);
|
||||||
|
const [githubUsername, setGithubUsername] = useState(Cookies.get('githubUsername') || '');
|
||||||
|
const [githubToken, setGithubToken] = useState(Cookies.get('githubToken') || '');
|
||||||
|
|
||||||
// Load base URLs from cookies
|
// Load base URLs from cookies
|
||||||
const [baseUrls, setBaseUrls] = useState(() => {
|
const [baseUrls, setBaseUrls] = useState(() => {
|
||||||
@ -68,6 +70,7 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|||||||
{ id: 'chat-history', label: 'Chat History', icon: 'i-ph:book' },
|
{ id: 'chat-history', label: 'Chat History', icon: 'i-ph:book' },
|
||||||
{ id: 'providers', label: 'Providers', icon: 'i-ph:key' },
|
{ id: 'providers', label: 'Providers', icon: 'i-ph:key' },
|
||||||
{ id: 'features', label: 'Features', icon: 'i-ph:star' },
|
{ id: 'features', label: 'Features', icon: 'i-ph:star' },
|
||||||
|
{ id: 'connection', label: 'Connection', icon: 'i-ph:link' },
|
||||||
...(isDebugEnabled ? [{ id: 'debug' as TabType, label: 'Debug Tab', icon: 'i-ph:bug' }] : []),
|
...(isDebugEnabled ? [{ id: 'debug' as TabType, label: 'Debug Tab', icon: 'i-ph:bug' }] : []),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -192,6 +195,18 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|||||||
|
|
||||||
const versionHash = commit.commit; // Get the version hash from commit.json
|
const versionHash = commit.commit; // Get the version hash from commit.json
|
||||||
|
|
||||||
|
const handleSaveConnection = () => {
|
||||||
|
Cookies.set('githubUsername', githubUsername);
|
||||||
|
Cookies.set('githubToken', githubToken);
|
||||||
|
toast.success('GitHub credentials saved successfully!');
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTestConnection = () => {
|
||||||
|
// Implement the logic to test the GitHub connection here
|
||||||
|
// For example, you could make an API call to GitHub to verify the credentials
|
||||||
|
toast.info('Testing GitHub connection...');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RadixDialog.Root open={open}>
|
<RadixDialog.Root open={open}>
|
||||||
<RadixDialog.Portal>
|
<RadixDialog.Portal>
|
||||||
@ -431,6 +446,45 @@ export const SettingsWindow = ({ open, onClose }: SettingsProps) => {
|
|||||||
<p className="text-bolt-elements-textSecondary">Version Hash: {versionHash}</p>
|
<p className="text-bolt-elements-textSecondary">Version Hash: {versionHash}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{activeTab === 'connection' && (
|
||||||
|
<div className="p-4 mb-4 border border-bolt-elements-borderColor rounded-lg bg-bolt-elements-background-depth-3">
|
||||||
|
<h3 className="text-lg font-medium text-bolt-elements-textPrimary mb-4">GitHub Connection</h3>
|
||||||
|
<div className="flex mb-4">
|
||||||
|
<div className="flex-1 mr-2">
|
||||||
|
<label className="block text-sm text-bolt-elements-textSecondary mb-1">GitHub Username:</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={githubUsername}
|
||||||
|
onChange={(e) => setGithubUsername(e.target.value)}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<label className="block text-sm text-bolt-elements-textSecondary mb-1">Personal Access Token:</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={githubToken}
|
||||||
|
onChange={(e) => setGithubToken(e.target.value)}
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex mb-4">
|
||||||
|
<button
|
||||||
|
onClick={handleSaveConnection}
|
||||||
|
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"
|
||||||
|
>
|
||||||
|
Save Connection
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleTestConnection}
|
||||||
|
className="bg-blue-500 rounded-lg px-4 py-2 transition-colors duration-200 hover:bg-blue-600 text-white"
|
||||||
|
>
|
||||||
|
Test Connection
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +17,7 @@ import { renderLogger } from '~/utils/logger';
|
|||||||
import { EditorPanel } from './EditorPanel';
|
import { EditorPanel } from './EditorPanel';
|
||||||
import { Preview } from './Preview';
|
import { Preview } from './Preview';
|
||||||
import useViewport from '~/lib/hooks';
|
import useViewport from '~/lib/hooks';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
interface WorkspaceProps {
|
interface WorkspaceProps {
|
||||||
chatStarted?: boolean;
|
chatStarted?: boolean;
|
||||||
@ -158,15 +159,6 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|||||||
{isSyncing ? <div className="i-ph:spinner" /> : <div className="i-ph:cloud-arrow-down" />}
|
{isSyncing ? <div className="i-ph:spinner" /> : <div className="i-ph:cloud-arrow-down" />}
|
||||||
{isSyncing ? 'Syncing...' : 'Sync Files'}
|
{isSyncing ? 'Syncing...' : 'Sync Files'}
|
||||||
</PanelHeaderButton>
|
</PanelHeaderButton>
|
||||||
<PanelHeaderButton
|
|
||||||
className="mr-1 text-sm"
|
|
||||||
onClick={() => {
|
|
||||||
workbenchStore.toggleTerminal(!workbenchStore.showTerminal.get());
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="i-ph:terminal" />
|
|
||||||
Toggle Terminal
|
|
||||||
</PanelHeaderButton>
|
|
||||||
<PanelHeaderButton
|
<PanelHeaderButton
|
||||||
className="mr-1 text-sm"
|
className="mr-1 text-sm"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -180,21 +172,22 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const githubUsername = prompt('Please enter your GitHub username:');
|
const githubUsername = Cookies.get('githubUsername');
|
||||||
|
const githubToken = Cookies.get('githubToken');
|
||||||
|
|
||||||
if (!githubUsername) {
|
if (!githubUsername || !githubToken) {
|
||||||
alert('GitHub username is required. Push to GitHub cancelled.');
|
const usernameInput = prompt('Please enter your GitHub username:');
|
||||||
return;
|
const tokenInput = prompt('Please enter your GitHub personal access token:');
|
||||||
|
|
||||||
|
if (!usernameInput || !tokenInput) {
|
||||||
|
alert('GitHub username and token are required. Push to GitHub cancelled.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
workbenchStore.pushToGitHub(repoName, usernameInput, tokenInput);
|
||||||
|
} else {
|
||||||
|
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
const githubToken = prompt('Please enter your GitHub personal access token:');
|
|
||||||
|
|
||||||
if (!githubToken) {
|
|
||||||
alert('GitHub token is required. Push to GitHub cancelled.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="i-ph:github-logo" />
|
<div className="i-ph:github-logo" />
|
||||||
|
@ -15,6 +15,7 @@ import { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';
|
|||||||
import * as nodePath from 'node:path';
|
import * as nodePath from 'node:path';
|
||||||
import { extractRelativePath } from '~/utils/diff';
|
import { extractRelativePath } from '~/utils/diff';
|
||||||
import { description } from '~/lib/persistence';
|
import { description } from '~/lib/persistence';
|
||||||
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
export interface ArtifactState {
|
export interface ArtifactState {
|
||||||
id: string;
|
id: string;
|
||||||
@ -396,15 +397,14 @@ export class WorkbenchStore {
|
|||||||
return syncedFiles;
|
return syncedFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
async pushToGitHub(repoName: string, githubUsername: string, ghToken: string) {
|
async pushToGitHub(repoName: string, githubUsername?: string, ghToken?: string) {
|
||||||
try {
|
try {
|
||||||
// Get the GitHub auth token from environment variables
|
// Use cookies if username and token are not provided
|
||||||
const githubToken = ghToken;
|
const githubToken = ghToken || Cookies.get('githubToken');
|
||||||
|
const owner = githubUsername || Cookies.get('githubUsername');
|
||||||
|
|
||||||
const owner = githubUsername;
|
if (!githubToken || !owner) {
|
||||||
|
throw new Error('GitHub token or username is not set in cookies or provided.');
|
||||||
if (!githubToken) {
|
|
||||||
throw new Error('GitHub token is not set in environment variables');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Octokit with the auth token
|
// Initialize Octokit with the auth token
|
||||||
@ -501,7 +501,8 @@ export class WorkbenchStore {
|
|||||||
|
|
||||||
alert(`Repository created and code pushed: ${repo.html_url}`);
|
alert(`Repository created and code pushed: ${repo.html_url}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error pushing to GitHub:', error instanceof Error ? error.message : String(error));
|
console.error('Error pushing to GitHub:', error);
|
||||||
|
throw error; // Rethrow the error for further handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user