openclaw-dashboard/components/QuickActions.tsx
AI Assistant c7f037c58a feat: Complete OpenClaw Dashboard with all features
- Dashboard Overview with real-time status display
- Live Log Viewer (scrollable, filterable)
- Config Editor with JSON syntax highlighting
- Model Switcher for provider management
- Provider Manager for API key configuration
- Quick Actions for common tasks
- API Routes: status, logs, config, actions, models, providers

Tech Stack:
- Next.js 14 (App Router)
- TypeScript
- Tailwind CSS
- shadcn/ui components
- CodeMirror for JSON editing
- Docker support with docker-compose
2026-02-27 05:55:23 +00:00

163 lines
5.5 KiB
TypeScript

'use client';
import { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Power, RefreshCw, Check, X, Play, Square, RotateCcw, AlertTriangle } from 'lucide-react';
export function QuickActions() {
const [loading, setLoading] = useState<string | null>(null);
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const handleAction = async (action: 'start' | 'stop' | 'restart') => {
setLoading(action);
setMessage(null);
try {
const response = await fetch('/api/actions', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action }),
});
const result = await response.json();
if (result.success) {
setMessage({ type: 'success', text: result.message });
} else {
setMessage({ type: 'error', text: result.message || 'Action failed' });
}
} catch (error) {
setMessage({ type: 'error', text: 'Failed to execute action' });
} finally {
setLoading(null);
}
};
const actions = [
{
id: 'start' as const,
title: 'Start Gateway',
description: 'Start the OpenClaw Gateway daemon',
icon: Play,
variant: 'default' as const,
color: 'bg-green-600 hover:bg-green-700',
},
{
id: 'stop' as const,
title: 'Stop Gateway',
description: 'Stop the OpenClaw Gateway daemon',
icon: Square,
variant: 'outline' as const,
color: 'border-red-600 text-red-400 hover:bg-red-600/10',
},
{
id: 'restart' as const,
title: 'Restart Gateway',
description: 'Restart the OpenClaw Gateway daemon',
icon: RotateCcw,
variant: 'outline' as const,
color: 'border-orange-600 text-orange-400 hover:bg-orange-600/10',
},
];
return (
<div className="space-y-6">
{/* Warning */}
<Alert className="bg-yellow-500/10 border-yellow-500/20 text-yellow-400">
<AlertTriangle className="h-4 w-4" />
<AlertDescription>
These actions affect the entire Gateway. Be careful when stopping or restarting.
</AlertDescription>
</Alert>
{/* Message */}
{message && (
<Alert variant={message.type === 'error' ? 'destructive' : 'default'} className={
message.type === 'success' ? 'bg-green-500/10 border-green-500/20 text-green-400' : ''
}>
{message.type === 'success' ? (
<Check className="h-4 w-4" />
) : (
<X className="h-4 w-4" />
)}
<AlertDescription>{message.text}</AlertDescription>
</Alert>
)}
{/* Action Cards */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{actions.map((action) => {
const Icon = action.icon;
const isLoading = loading === action.id;
return (
<Card
key={action.id}
className="bg-zinc-900/50 border-zinc-800 hover:border-zinc-700 transition-all hover:scale-[1.02]"
>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Icon className="w-5 h-5" />
{action.title}
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-zinc-400 mb-4">
{action.description}
</p>
<Button
onClick={() => handleAction(action.id)}
disabled={isLoading}
className={`w-full ${action.id === 'start' ? action.color : ''} ${
action.id !== 'start'
? 'border-zinc-700 hover:bg-zinc-800'
: ''
}`}
variant={action.variant}
>
{isLoading ? (
<>
<RefreshCw className="w-4 h-4 mr-2 animate-spin" />
{action.id.charAt(0).toUpperCase() + action.id.slice(1)}ing...
</>
) : (
<>
{action.id === 'start' && <Power className="w-4 h-4 mr-2" />}
{action.id === 'stop' && <Square className="w-4 h-4 mr-2" />}
{action.id === 'restart' && <RotateCcw className="w-4 h-4 mr-2" />}
{action.title}
</>
)}
</Button>
</CardContent>
</Card>
);
})}
</div>
{/* Info */}
<Card className="bg-zinc-900/50 border-zinc-800">
<CardHeader>
<CardTitle className="text-lg">Quick Actions Info</CardTitle>
</CardHeader>
<CardContent className="space-y-3 text-sm text-zinc-400">
<div>
<strong className="text-zinc-300">Start Gateway:</strong> Launches the OpenClaw
Gateway daemon if it's not running.
</div>
<div>
<strong className="text-zinc-300">Stop Gateway:</strong> Gracefully stops the Gateway.
All active sessions will be terminated.
</div>
<div>
<strong className="text-zinc-300">Restart Gateway:</strong> Stops and immediately
starts the Gateway again. Useful for applying config changes.
</div>
</CardContent>
</Card>
</div>
);
}