token-modal.tsx•6.16 kB
import { useState } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useToast } from '@/hooks/use-toast';
import { X, Key, CheckCircle, AlertCircle } from 'lucide-react';
interface TokenModalProps {
isOpen: boolean;
onClose: () => void;
onUpdateToken: (token: string) => void;
}
export default function TokenModal({ isOpen, onClose, onUpdateToken }: TokenModalProps) {
const [newToken, setNewToken] = useState('');
const [isUpdating, setIsUpdating] = useState(false);
const { toast } = useToast();
const handleUpdateToken = async (e: React.FormEvent) => {
e.preventDefault();
if (!newToken.trim()) {
toast({
title: "Token Required",
description: "Please enter a valid GitHub token",
variant: "destructive",
});
return;
}
setIsUpdating(true);
try {
// Validate token first
const response = await fetch('/api/validate-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ token: newToken }),
});
if (!response.ok) {
throw new Error('Invalid token');
}
// Update token
onUpdateToken(newToken);
toast({
title: "Token Updated",
description: "GitHub token updated successfully. New session created.",
});
setNewToken('');
onClose();
} catch (error) {
toast({
title: "Update Failed",
description: error instanceof Error ? error.message : "Failed to update token",
variant: "destructive",
});
} finally {
setIsUpdating(false);
}
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent
className="w-full max-w-md border"
style={{
backgroundColor: 'var(--dark-card)',
borderColor: 'var(--dark-border)',
color: 'var(--text-primary)'
}}
>
<DialogHeader>
<DialogTitle className="flex items-center justify-between">
<span>GitHub Token Settings</span>
<Button
variant="ghost"
size="sm"
onClick={onClose}
className="h-auto p-1"
style={{ color: 'var(--text-muted)' }}
>
<X className="w-4 h-4" />
</Button>
</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label className="block text-sm font-medium mb-2" style={{ color: 'var(--text-secondary)' }}>
Current Token Status
</Label>
<div
className="flex items-center space-x-2 p-3 rounded-lg border"
style={{
backgroundColor: 'var(--success-green)',
opacity: 0.1,
borderColor: 'var(--success-green)'
}}
>
<CheckCircle className="w-3 h-3" style={{ color: 'var(--success-green)' }} />
<span className="text-sm" style={{ color: 'var(--success-green)' }}>
Connected and Active
</span>
</div>
</div>
<form onSubmit={handleUpdateToken} className="space-y-4">
<div>
<Label htmlFor="new-token" className="block text-sm font-medium mb-2" style={{ color: 'var(--text-secondary)' }}>
Update Token
</Label>
<Input
type="password"
id="new-token"
value={newToken}
onChange={(e) => setNewToken(e.target.value)}
className="w-full"
style={{
backgroundColor: 'var(--dark-bg)',
borderColor: 'var(--dark-border)',
color: 'var(--text-primary)'
}}
placeholder="Enter new GitHub token..."
disabled={isUpdating}
/>
<p className="text-xs mt-2" style={{ color: 'var(--text-muted)' }}>
This will create a new GitHub session and replace your current token
</p>
</div>
<div className="flex space-x-3 pt-4">
<Button
type="button"
variant="outline"
className="flex-1"
onClick={onClose}
disabled={isUpdating}
style={{
backgroundColor: 'var(--dark-bg)',
borderColor: 'var(--dark-border)',
color: 'var(--text-secondary)'
}}
>
Cancel
</Button>
<Button
type="submit"
className="flex-1"
disabled={isUpdating}
style={{ backgroundColor: 'var(--accent-blue)' }}
>
{isUpdating ? (
<div className="flex items-center space-x-2">
<div className="w-3 h-3 border border-white/20 border-t-white rounded-full animate-spin" />
<span>Updating...</span>
</div>
) : (
'Update Token'
)}
</Button>
</div>
</form>
<div className="pt-4 border-t" style={{ borderColor: 'var(--dark-border)' }}>
<h4 className="text-sm font-medium mb-2" style={{ color: 'var(--text-primary)' }}>
Token Permissions Required:
</h4>
<ul className="text-xs space-y-1" style={{ color: 'var(--text-muted)' }}>
<li>• Repository access (read/write)</li>
<li>• Issues and pull requests</li>
<li>• Actions and workflow runs</li>
<li>• Repository metadata</li>
</ul>
</div>
</div>
</DialogContent>
</Dialog>
);
}