47 lines
2.1 KiB
TypeScript
47 lines
2.1 KiB
TypeScript
import { useState } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
|
|
|
export function CodingConversationRenameDialog({ title, onSave, onClose }: {
|
|
title: string;
|
|
onSave(title: string): Promise<void>;
|
|
onClose(): void;
|
|
}) {
|
|
const [draft, setDraft] = useState(title);
|
|
const [saving, setSaving] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
return (
|
|
<Dialog open onOpenChange={(open) => { if (!open && !saving) onClose(); }}>
|
|
<DialogContent onOpenAutoFocus={(event) => {
|
|
event.preventDefault();
|
|
const input = document.getElementById('coding-rename-title') as HTMLInputElement | null;
|
|
input?.focus();
|
|
input?.select();
|
|
}}>
|
|
<form onSubmit={(event) => {
|
|
event.preventDefault();
|
|
if (!draft.trim() || saving) return;
|
|
setSaving(true);
|
|
setError(null);
|
|
void onSave(draft.trim()).then(onClose).catch((reason) => {
|
|
setError(reason instanceof Error ? reason.message : String(reason));
|
|
}).finally(() => setSaving(false));
|
|
}}>
|
|
<DialogHeader>
|
|
<DialogTitle>修改对话标题</DialogTitle>
|
|
<DialogDescription>手动命名后,标题不会再自动更新。</DialogDescription>
|
|
</DialogHeader>
|
|
<Input id="coding-rename-title" className="my-4" value={draft} maxLength={200}
|
|
aria-label="对话标题" disabled={saving} onChange={(event) => setDraft(event.target.value)} />
|
|
{error && <p role="alert" className="mb-3 text-sm text-destructive">{error}</p>}
|
|
<DialogFooter>
|
|
<Button type="button" variant="outline" disabled={saving} onClick={onClose}>取消</Button>
|
|
<Button type="submit" disabled={saving || !draft.trim()}>{saving ? '保存中…' : '保存'}</Button>
|
|
</DialogFooter>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|