mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-17 08:17:22 +00:00
feat(ui): add copilot-api install button and version display
- add CopilotInfo type and install mutation to useCopilot hook - show version in status card when installed - add Install button with loading state when not installed
This commit is contained in:
@@ -8,7 +8,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useCopilot } from '@/hooks/use-copilot';
|
||||
import { CheckCircle2, XCircle, AlertTriangle, Loader2 } from 'lucide-react';
|
||||
import { CheckCircle2, XCircle, AlertTriangle, Loader2, Download } from 'lucide-react';
|
||||
|
||||
export function CopilotStatusCard() {
|
||||
const {
|
||||
@@ -20,6 +20,8 @@ export function CopilotStatusCard() {
|
||||
isStartingDaemon,
|
||||
stopDaemon,
|
||||
isStoppingDaemon,
|
||||
install,
|
||||
isInstalling,
|
||||
} = useCopilot();
|
||||
|
||||
if (statusLoading) {
|
||||
@@ -80,7 +82,7 @@ export function CopilotStatusCard() {
|
||||
<XCircle className="h-5 w-5 text-red-500" />
|
||||
)}
|
||||
<span className="text-sm">
|
||||
copilot-api {status.installed ? 'Installed' : 'Not Installed'}
|
||||
copilot-api {status.installed ? `v${status.version}` : 'Not Installed'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -116,6 +118,22 @@ export function CopilotStatusCard() {
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex flex-wrap gap-2 pt-2">
|
||||
{!status.installed && (
|
||||
<Button onClick={() => install(undefined)} disabled={isInstalling} size="sm">
|
||||
{isInstalling ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Installing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Install copilot-api
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!status.authenticated && (
|
||||
<Button
|
||||
onClick={() => startAuth()}
|
||||
|
||||
@@ -12,6 +12,7 @@ const API_BASE = '/api';
|
||||
export interface CopilotStatus {
|
||||
enabled: boolean;
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
authenticated: boolean;
|
||||
daemon_running: boolean;
|
||||
port: number;
|
||||
@@ -22,6 +23,20 @@ export interface CopilotStatus {
|
||||
wait_on_limit: boolean;
|
||||
}
|
||||
|
||||
export interface CopilotInfo {
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
path: string;
|
||||
pinnedVersion: string | null;
|
||||
}
|
||||
|
||||
export interface CopilotInstallResult {
|
||||
success: boolean;
|
||||
installed: boolean;
|
||||
version: string | null;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface CopilotConfig {
|
||||
enabled: boolean;
|
||||
auto_start: boolean;
|
||||
@@ -120,6 +135,22 @@ async function stopCopilotDaemon(): Promise<{ success: boolean; error?: string }
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function fetchCopilotInfo(): Promise<CopilotInfo> {
|
||||
const res = await fetch(`${API_BASE}/copilot/info`);
|
||||
if (!res.ok) throw new Error('Failed to fetch copilot info');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
async function installCopilotApi(version?: string): Promise<CopilotInstallResult> {
|
||||
const res = await fetch(`${API_BASE}/copilot/install`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(version ? { version } : {}),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to install copilot-api');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
// Hook
|
||||
export function useCopilot() {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -146,6 +177,11 @@ export function useCopilot() {
|
||||
queryFn: fetchCopilotRawSettings,
|
||||
});
|
||||
|
||||
const infoQuery = useQuery({
|
||||
queryKey: ['copilot-info'],
|
||||
queryFn: fetchCopilotInfo,
|
||||
});
|
||||
|
||||
// Mutations
|
||||
const updateConfigMutation = useMutation({
|
||||
mutationFn: updateCopilotConfig,
|
||||
@@ -189,6 +225,14 @@ export function useCopilot() {
|
||||
},
|
||||
});
|
||||
|
||||
const installMutation = useMutation({
|
||||
mutationFn: installCopilotApi,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['copilot-status'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['copilot-info'] });
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
// Status
|
||||
status: statusQuery.data,
|
||||
@@ -227,5 +271,14 @@ export function useCopilot() {
|
||||
|
||||
stopDaemon: stopDaemonMutation.mutate,
|
||||
isStoppingDaemon: stopDaemonMutation.isPending,
|
||||
|
||||
// Install
|
||||
info: infoQuery.data,
|
||||
infoLoading: infoQuery.isLoading,
|
||||
refetchInfo: infoQuery.refetch,
|
||||
|
||||
install: installMutation.mutate,
|
||||
installAsync: installMutation.mutateAsync,
|
||||
isInstalling: installMutation.isPending,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user