Skip to content

Commit

Permalink
Merge pull request #2 from D-Byte/iAlsoWantGitLabTwo
Browse files Browse the repository at this point in the history
Take2
  • Loading branch information
D-Byte authored Dec 17, 2024
2 parents d6da850 + 761f142 commit f0f88ca
Show file tree
Hide file tree
Showing 14 changed files with 689 additions and 982 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Update commit file
run: |
echo "{ \"commit\": \"$COMMIT_HASH\" , \"version\": \"$CURRENT_VERSION\" }" > app/commit.json
echo "{ \"commit\": \"$COMMIT_HASH\", \"version\": \"$CURRENT_VERSION\" }" > app/commit.json
- name: Commit and push the update
run: |
Expand Down
32 changes: 32 additions & 0 deletions .github/workflows/semantic-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Semantic Pull Request
on:
pull_request_target:
types: [opened, reopened, edited, synchronize]
permissions:
pull-requests: read
jobs:
main:
name: Validate PR Title
runs-on: ubuntu-latest
steps:
# https://github.com/amannn/action-semantic-pull-request/releases/tag/v5.5.3
- uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
subjectPattern: ^(?![A-Z]).+$
subjectPatternError: |
The subject "{subject}" found in the pull request title "{title}"
didn't match the configured pattern. Please ensure that the subject
doesn't start with an uppercase character.
types: |
fix
feat
chore
build
ci
perf
docs
refactor
revert
test
4 changes: 2 additions & 2 deletions .github/workflows/update-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,12 @@ jobs:
- name: Get the latest commit hash and version tag
run: |
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> $GITHUB_ENV
echo "CURRENT_VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV
echo "NEW_VERSION=${{ steps.bump_version.outputs.new_version }}" >> $GITHUB_ENV
- name: Commit and Tag Release
run: |
git pull
echo "{ \"commit\": \"$COMMIT_HASH\" , \"version\": \"$CURRENT_VERSION\" }" > app/commit.json
echo "{ \"commit\": \"$COMMIT_HASH\", \"version\": \"$NEW_VERSION\" }" > app/commit.json
git add package.json pnpm-lock.yaml changelog.md app/commit.json
git commit -m "chore: release version ${{ steps.bump_version.outputs.new_version }}"
git tag "v${{ steps.bump_version.outputs.new_version }}"
Expand Down
2 changes: 1 addition & 1 deletion app/commit.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{ "commit": "25b80ab267541b6ea290985dde09863f1a29c85c" , "version": "0.0.1" }
{ "commit": "b9601b26d739f935eda935c61dea4c7c6b9c7220", "version": "0.0.2" }
182 changes: 21 additions & 161 deletions app/components/settings/connections/ConnectionsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,171 +1,31 @@
import React, { useState, useEffect } from 'react';
import { logStore } from '~/lib/stores/logs';
import { lookupSavedPassword, saveGitAuth, ensureEncryption } from '~/lib/hooks/useCredentials';
import React from 'react';
import { ProviderCard } from './ProviderCard';
import { useGitProviders } from '~/lib/hooks/useGitProviders';

export default function ConnectionsTab() {
const [credentials, setCredentials] = useState({
github: { username: '', token: '' },
gitlab: { username: '', token: '' },
});
const [expandedProviders, setExpandedProviders] = useState<Record<string, boolean>>({});

useEffect(() => {
initializeEncryption();
}, []);

const initializeEncryption = async () => {
const success = await ensureEncryption();

if (success) {
loadSavedCredentials();
}
};

const loadSavedCredentials = async () => {
for (const [, config] of Object.entries(providers)) {
const auth = await lookupSavedPassword(config.url);

if (auth?.username && auth?.password) {
config.setCredentials(auth.username, auth.password);
}
}
};

const toggleProvider = (provider: string) => {
setExpandedProviders((prev) => ({
...prev,
[provider]: !prev[provider],
}));
};

const providers = {
github: {
url: 'github.com',
username: credentials.github.username,
token: credentials.github.token,
title: 'GitHub',
instructions: 'Enter your GitHub username and personal access token.',
tokenSetupSteps: [
'1. Go to GitHub.com → Settings → Developer settings → Personal access tokens → Tokens (classic)',
'2. Generate new token (classic) with these scopes:',
' • repo (Full control of private repositories)',
' • workflow (Optional: Update GitHub Action workflows)',
'3. Copy the generated token and paste it here',
],
setCredentials: (username: string, token: string) =>
setCredentials((prev) => ({
...prev,
github: { username, token },
})),
},
gitlab: {
url: 'gitlab.com',
username: credentials.gitlab.username,
token: credentials.gitlab.token,
title: 'GitLab',
instructions: 'To set up GitLab access:',
tokenSetupSteps: [
'1. Go to GitLab.com → Profile Settings → Access Tokens',
'2. Create a new token with these scopes:',
' • api (Full API access)',
' • write_repository (Read/write access)',
'3. Copy the generated token and paste it here',
],
setCredentials: (username: string, token: string) =>
setCredentials((prev) => ({
...prev,
gitlab: { username, token },
})),
},
};

const handleSaveConnection = async (provider: keyof typeof providers) => {
const { url, username, token, title } = providers[provider];

await saveGitAuth(url, {
username,
password: token,
});

logStore.logSystem(`${title} connection settings updated`, {
username,
hasToken: !!token,
});
};
const {
providers,
credentials,
expandedProviders,
handleSaveConnection,
handleDisconnect,
updateProviderCredentials,
toggleProvider,
} = useGitProviders();

return (
<div className="space-y-4">
{/* Encryption status section remains the same */}

{Object.entries(providers).map(([key, provider]) => (
<div
<ProviderCard
key={key}
className="p-4 border border-bolt-elements-borderColor rounded-lg bg-bolt-elements-background-depth-3"
>
<div className="flex items-center justify-between cursor-pointer" onClick={() => toggleProvider(key)}>
<div className="flex items-center">
<h3 className="text-lg font-medium text-bolt-elements-textPrimary">{provider.title} Connection</h3>
{provider.username && (
<span className="ml-2 text-sm text-bolt-elements-textSecondary">({provider.username})</span>
)}
</div>
<div className="flex items-center">
{provider.username && provider.token && (
<div className="flex items-center mr-3">
<div className="w-2 h-2 rounded-full bg-green-500 mr-2" />
<span className="text-sm text-bolt-elements-textSecondary">Connected</span>
</div>
)}
<div className={`transform transition-transform ${expandedProviders[key] ? 'rotate-180' : ''}`}>
<div className="i-ph:caret-down text-bolt-elements-textSecondary" />
</div>
</div>
</div>

{expandedProviders[key] && (
<div className="mt-4">
<div className="mb-4 p-3 bg-bolt-elements-background-depth-4 rounded border border-bolt-elements-borderColor">
<p className="text-sm text-bolt-elements-textSecondary mb-2">{provider.instructions}</p>
<ul className="text-sm text-bolt-elements-textSecondary space-y-1">
{provider.tokenSetupSteps.map((step, index) => (
<li key={index}>{step}</li>
))}
</ul>
</div>

<div className="flex mb-4">
<div className="flex-1 mr-2">
<label className="block text-sm text-bolt-elements-textSecondary mb-1">
{provider.title} Username:
</label>
<input
type="text"
value={provider.username}
onChange={(e) => provider.setCredentials(e.target.value, provider.token)}
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={provider.token}
onChange={(e) => provider.setCredentials(provider.username, 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">
<button
onClick={() => handleSaveConnection(key as keyof typeof providers)}
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 {provider.title} Connection
</button>
</div>
</div>
)}
</div>
provider={provider}
credentials={credentials[key]}
isExpanded={expandedProviders[key]}
onToggle={() => toggleProvider(key)}
onUpdateCredentials={(updates) => updateProviderCredentials(key, updates)}
onSave={() => handleSaveConnection(key)}
onDisconnect={() => handleDisconnect(key)}
/>
))}
</div>
);
Expand Down
108 changes: 108 additions & 0 deletions app/components/settings/connections/ProviderCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React from 'react';
import type { GitProvider, ProviderCredentials } from '~/utils/gitProviders';

interface ProviderCardProps {
provider: GitProvider;
credentials: ProviderCredentials;
isExpanded: boolean;
onToggle: () => void;
onUpdateCredentials: (updates: Partial<ProviderCredentials>) => void;
onSave: () => void;
onDisconnect: () => void;
}

export function ProviderCard({
provider,
credentials,
isExpanded,
onToggle,
onUpdateCredentials,
onSave,
onDisconnect,
}: ProviderCardProps) {
return (
<div className="p-4 border border-bolt-elements-borderColor rounded-lg bg-bolt-elements-background-depth-3">
<div className="flex items-center justify-between cursor-pointer" onClick={onToggle}>
<div className="flex items-center">
<h3 className="text-lg font-medium text-bolt-elements-textPrimary">{provider.title} Connection</h3>
{credentials.username && (
<span className="ml-2 text-sm text-bolt-elements-textSecondary">({credentials.username})</span>
)}
</div>
<div className="flex items-center">
{credentials.isConnected && (
<div className="flex items-center mr-3">
<div className="w-2 h-2 rounded-full bg-green-500 mr-2" />
<span className="text-sm text-bolt-elements-textSecondary">Connected</span>
</div>
)}
<div className={`transform transition-transform ${isExpanded ? 'rotate-180' : ''}`}>
<div className="i-ph:caret-down text-bolt-elements-textSecondary" />
</div>
</div>
</div>

{isExpanded && (
<div className="mt-4">
<div className="mb-4 p-3 bg-bolt-elements-background-depth-4 rounded border border-bolt-elements-borderColor">
<p className="text-sm text-bolt-elements-textSecondary mb-2">{provider.instructions}</p>
<ul className="text-sm text-bolt-elements-textSecondary space-y-1">
{provider.tokenSetupSteps.map((step, index) => (
<li key={index}>{step}</li>
))}
</ul>
</div>

<div className="flex mb-4">
<div className="flex-1 mr-2">
<label className="block text-sm text-bolt-elements-textSecondary mb-1">{provider.title} Username:</label>
<input
type="text"
value={credentials.username}
onChange={(e) => onUpdateCredentials({ username: e.target.value })}
disabled={credentials.isVerifying}
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={credentials.token}
onChange={(e) => onUpdateCredentials({ token: e.target.value })}
disabled={credentials.isVerifying}
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">
{!credentials.isConnected ? (
<button
onClick={onSave}
disabled={credentials.isVerifying || !credentials.username || !credentials.token}
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"
>
{credentials.isVerifying ? (
<>
<div className="i-ph:spinner animate-spin mr-2" />
Verifying...
</>
) : (
'Connect'
)}
</button>
) : (
<button
onClick={onDisconnect}
className="bg-red-500 text-white rounded-lg px-4 py-2 mr-2 transition-colors duration-200 hover:bg-red-600"
>
Disconnect
</button>
)}
</div>
</div>
)}
</div>
);
}
4 changes: 3 additions & 1 deletion app/components/settings/features/FeaturesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ export default function FeaturesTab() {
className="flex-1 p-2 ml-auto rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary focus:outline-none focus:ring-2 focus:ring-bolt-elements-focus transition-all text-sm min-w-[100px]"
>
{PromptLibrary.getList().map((x) => (
<option value={x.id}>{x.label}</option>
<option key={x.id} value={x.id}>
{x.label}
</option>
))}
</select>
</div>
Expand Down
Loading

0 comments on commit f0f88ca

Please sign in to comment.