mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-05-01 18:28:38 +00:00
feat(command-palette): add git fetch/pull/push and branch switch actions
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import * as React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
ArrowDownToLine,
|
||||
ArrowUpFromLine,
|
||||
Bell,
|
||||
Bot,
|
||||
FileText,
|
||||
GitBranch,
|
||||
GitCommit,
|
||||
GitMerge,
|
||||
Info,
|
||||
KeyRound,
|
||||
ListChecks,
|
||||
@@ -13,6 +16,7 @@ import {
|
||||
MessageSquarePlus,
|
||||
Palette,
|
||||
Plug,
|
||||
RefreshCw,
|
||||
Settings,
|
||||
SunMoon,
|
||||
} from 'lucide-react';
|
||||
@@ -35,6 +39,8 @@ import { useSessionsSource } from './sources/useSessionsSource';
|
||||
import { useFilesSource } from './sources/useFilesSource';
|
||||
import { useCommitsSource } from './sources/useCommitsSource';
|
||||
import { useSessionMessageSearch } from './sources/useSessionMessageSearch';
|
||||
import { useBranchesSource } from './sources/useBranchesSource';
|
||||
import { useGitActions } from './sources/useGitActions';
|
||||
|
||||
type Mode = 'mixed' | 'actions' | 'files' | 'commits';
|
||||
|
||||
@@ -104,6 +110,8 @@ export default function CommandPalette({
|
||||
const { items: messageMatches } = useSessionMessageSearch(projectId, query, open && mode === 'mixed');
|
||||
const { items: files } = useFilesSource(projectId, open && (mode === 'mixed' || mode === 'files'));
|
||||
const { items: commits } = useCommitsSource(projectId, open && (mode === 'mixed' || mode === 'commits'));
|
||||
const { items: branches } = useBranchesSource(projectId, open && (mode === 'mixed' || mode === 'actions'));
|
||||
const git = useGitActions(projectId);
|
||||
|
||||
const showActions = mode === 'mixed' || mode === 'actions';
|
||||
const showSessions = mode === 'mixed';
|
||||
@@ -206,6 +214,45 @@ export default function CommandPalette({
|
||||
</CommandGroup>
|
||||
)}
|
||||
|
||||
{showActions && projectId && (
|
||||
<CommandGroup heading="Git">
|
||||
<CommandItem
|
||||
value="git fetch remote"
|
||||
onSelect={() => run(() => { void git.fetch(); onShowTab?.('git'); })}
|
||||
>
|
||||
<RefreshCw className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
|
||||
<span className="flex-1">Git: Fetch</span>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
value="git pull merge upstream"
|
||||
onSelect={() => run(() => { void git.pull(); onShowTab?.('git'); })}
|
||||
>
|
||||
<ArrowDownToLine className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
|
||||
<span className="flex-1">Git: Pull</span>
|
||||
</CommandItem>
|
||||
<CommandItem
|
||||
value="git push origin remote"
|
||||
onSelect={() => run(() => { void git.push(); onShowTab?.('git'); })}
|
||||
>
|
||||
<ArrowUpFromLine className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
|
||||
<span className="flex-1">Git: Push</span>
|
||||
</CommandItem>
|
||||
{branches
|
||||
.filter((b) => !b.isCurrent && !b.isRemote)
|
||||
.slice(0, 30)
|
||||
.map((b) => (
|
||||
<CommandItem
|
||||
key={`branch-${b.name}`}
|
||||
value={`git switch checkout branch ${b.name}`}
|
||||
onSelect={() => run(() => { void git.checkout(b.name); onShowTab?.('git'); })}
|
||||
>
|
||||
<GitMerge className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
|
||||
<span className="flex-1 truncate">Switch to branch: {b.name}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
)}
|
||||
|
||||
{showActions && (
|
||||
<CommandGroup heading="Settings">
|
||||
{SETTINGS_TABS.map(({ id, label, keywords, icon: Icon }) => (
|
||||
|
||||
47
src/components/command-palette/sources/useBranchesSource.ts
Normal file
47
src/components/command-palette/sources/useBranchesSource.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { authenticatedFetch } from '../../../utils/api';
|
||||
|
||||
export type BranchResult = {
|
||||
name: string;
|
||||
isCurrent: boolean;
|
||||
isRemote: boolean;
|
||||
};
|
||||
|
||||
interface BranchesResponse {
|
||||
branches?: Array<{ name: string; current?: boolean; isRemote?: boolean }>;
|
||||
}
|
||||
|
||||
export function useBranchesSource(projectId: string | undefined, enabled: boolean) {
|
||||
const [items, setItems] = useState<BranchResult[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || !projectId) {
|
||||
setItems([]);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
const params = new URLSearchParams({ project: projectId });
|
||||
authenticatedFetch(`/api/git/branches?${params.toString()}`)
|
||||
.then((r) => r.json() as Promise<BranchesResponse>)
|
||||
.then((data) => {
|
||||
if (cancelled) return;
|
||||
const list = data.branches ?? [];
|
||||
setItems(
|
||||
list.map<BranchResult>((b) => ({
|
||||
name: b.name,
|
||||
isCurrent: Boolean(b.current),
|
||||
isRemote: Boolean(b.isRemote),
|
||||
})),
|
||||
);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) setItems([]);
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [projectId, enabled]);
|
||||
|
||||
return { items };
|
||||
}
|
||||
38
src/components/command-palette/sources/useGitActions.ts
Normal file
38
src/components/command-palette/sources/useGitActions.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { authenticatedFetch } from '../../../utils/api';
|
||||
|
||||
async function postGit(path: string, body: Record<string, unknown>) {
|
||||
const res = await authenticatedFetch(path, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export function useGitActions(projectId: string | undefined) {
|
||||
const fetch = useCallback(() => {
|
||||
if (!projectId) return Promise.resolve();
|
||||
return postGit('/api/git/fetch', { project: projectId });
|
||||
}, [projectId]);
|
||||
|
||||
const pull = useCallback(() => {
|
||||
if (!projectId) return Promise.resolve();
|
||||
return postGit('/api/git/pull', { project: projectId });
|
||||
}, [projectId]);
|
||||
|
||||
const push = useCallback(() => {
|
||||
if (!projectId) return Promise.resolve();
|
||||
return postGit('/api/git/push', { project: projectId });
|
||||
}, [projectId]);
|
||||
|
||||
const checkout = useCallback(
|
||||
(branch: string) => {
|
||||
if (!projectId) return Promise.resolve();
|
||||
return postGit('/api/git/checkout', { project: projectId, branch });
|
||||
},
|
||||
[projectId],
|
||||
);
|
||||
|
||||
return { fetch, pull, push, checkout };
|
||||
}
|
||||
Reference in New Issue
Block a user