mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 22:14: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:
1 parent
fee241d00b
commit
f813ad06f6
2 files changed
+73
-2
No files matched your search
@@ -8,7 +8,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
|
|||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { useCopilot } from '@/hooks/use-copilot';
|
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() {
|
export function CopilotStatusCard() {
|
||||||
const {
|
const {
|
||||||
@@ -20,6 +20,8 @@ export function CopilotStatusCard() {
|
|||||||
isStartingDaemon,
|
isStartingDaemon,
|
||||||
stopDaemon,
|
stopDaemon,
|
||||||
isStoppingDaemon,
|
isStoppingDaemon,
|
||||||
|
install,
|
||||||
|
isInstalling,
|
||||||
} = useCopilot();
|
} = useCopilot();
|
||||||
|
|
||||||
if (statusLoading) {
|
if (statusLoading) {
|
||||||
@@ -80,7 +82,7 @@ export function CopilotStatusCard() {
|
|||||||
<XCircle className="h-5 w-5 text-red-500" />
|
<XCircle className="h-5 w-5 text-red-500" />
|
||||||
)}
|
)}
|
||||||
<span className="text-sm">
|
<span className="text-sm">
|
||||||
copilot-api {status.installed ? 'Installed' : 'Not Installed'}
|
copilot-api {status.installed ? `v${status.version}` : 'Not Installed'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -116,6 +118,22 @@ export function CopilotStatusCard() {
|
|||||||
|
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
<div className="flex flex-wrap gap-2 pt-2">
|
<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 && (
|
{!status.authenticated && (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => startAuth()}
|
onClick={() => startAuth()}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const API_BASE = '/api';
|
|||||||
export interface CopilotStatus {
|
export interface CopilotStatus {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
installed: boolean;
|
installed: boolean;
|
||||||
|
version: string | null;
|
||||||
authenticated: boolean;
|
authenticated: boolean;
|
||||||
daemon_running: boolean;
|
daemon_running: boolean;
|
||||||
port: number;
|
port: number;
|
||||||
@@ -22,6 +23,20 @@ export interface CopilotStatus {
|
|||||||
wait_on_limit: boolean;
|
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 {
|
export interface CopilotConfig {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
auto_start: boolean;
|
auto_start: boolean;
|
||||||
@@ -120,6 +135,22 @@ async function stopCopilotDaemon(): Promise<{ success: boolean; error?: string }
|
|||||||
return res.json();
|
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
|
// Hook
|
||||||
export function useCopilot() {
|
export function useCopilot() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@@ -146,6 +177,11 @@ export function useCopilot() {
|
|||||||
queryFn: fetchCopilotRawSettings,
|
queryFn: fetchCopilotRawSettings,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const infoQuery = useQuery({
|
||||||
|
queryKey: ['copilot-info'],
|
||||||
|
queryFn: fetchCopilotInfo,
|
||||||
|
});
|
||||||
|
|
||||||
// Mutations
|
// Mutations
|
||||||
const updateConfigMutation = useMutation({
|
const updateConfigMutation = useMutation({
|
||||||
mutationFn: updateCopilotConfig,
|
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 {
|
return {
|
||||||
// Status
|
// Status
|
||||||
status: statusQuery.data,
|
status: statusQuery.data,
|
||||||
@@ -227,5 +271,14 @@ export function useCopilot() {
|
|||||||
|
|
||||||
stopDaemon: stopDaemonMutation.mutate,
|
stopDaemon: stopDaemonMutation.mutate,
|
||||||
isStoppingDaemon: stopDaemonMutation.isPending,
|
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