chore: delete SaveToLibraryDialog, replaced by ParameterizeAndSavePanel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,186 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { X, Loader2 } from 'lucide-react'
|
|
||||||
import { cn } from '@/lib/utils'
|
|
||||||
import { scriptBuilderApi, scriptsApi } from '@/api'
|
|
||||||
import type { ScriptCategoryResponse } from '@/types'
|
|
||||||
|
|
||||||
interface SaveToLibraryDialogProps {
|
|
||||||
sessionId: string
|
|
||||||
defaultName: string
|
|
||||||
defaultDescription?: string
|
|
||||||
onClose: () => void
|
|
||||||
onSaved: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SaveToLibraryDialog({
|
|
||||||
sessionId,
|
|
||||||
defaultName,
|
|
||||||
defaultDescription,
|
|
||||||
onClose,
|
|
||||||
onSaved,
|
|
||||||
}: SaveToLibraryDialogProps) {
|
|
||||||
const [name, setName] = useState(defaultName)
|
|
||||||
const [description, setDescription] = useState(defaultDescription || '')
|
|
||||||
const [categoryId, setCategoryId] = useState('')
|
|
||||||
const [shareWithTeam, setShareWithTeam] = useState(false)
|
|
||||||
const [categories, setCategories] = useState<ScriptCategoryResponse[]>([])
|
|
||||||
const [isSaving, setIsSaving] = useState(false)
|
|
||||||
const [error, setError] = useState<string | null>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
scriptsApi.getCategories().then(setCategories).catch(() => {})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
|
||||||
if (e.key === 'Escape') onClose()
|
|
||||||
}
|
|
||||||
document.addEventListener('keydown', handleKeyDown)
|
|
||||||
return () => document.removeEventListener('keydown', handleKeyDown)
|
|
||||||
}, [onClose])
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault()
|
|
||||||
if (!name.trim()) return
|
|
||||||
|
|
||||||
setIsSaving(true)
|
|
||||||
setError(null)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await scriptBuilderApi.saveToLibrary(sessionId, {
|
|
||||||
name: name.trim(),
|
|
||||||
description: description.trim() || undefined,
|
|
||||||
category_id: categoryId || undefined,
|
|
||||||
share_with_team: shareWithTeam,
|
|
||||||
})
|
|
||||||
onSaved()
|
|
||||||
} catch (err) {
|
|
||||||
setError(err instanceof Error ? err.message : 'Failed to save script. Please try again.')
|
|
||||||
} finally {
|
|
||||||
setIsSaving(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center"
|
|
||||||
onClick={(e) => { if (e.target === e.currentTarget) onClose() }}
|
|
||||||
>
|
|
||||||
<div className="card-flat max-w-md w-full mx-4 rounded-xl overflow-hidden">
|
|
||||||
{/* Header */}
|
|
||||||
<div className="flex items-center justify-between px-5 py-3.5 border-b border-[rgba(255,255,255,0.06)]">
|
|
||||||
<h3 className="text-sm font-heading font-bold text-foreground">Save to Library</h3>
|
|
||||||
<button
|
|
||||||
onClick={onClose}
|
|
||||||
className="p-1.5 rounded-lg text-muted-foreground hover:text-foreground hover:bg-[rgba(255,255,255,0.06)] transition-colors"
|
|
||||||
>
|
|
||||||
<X size={18} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Form */}
|
|
||||||
<form onSubmit={handleSubmit} className="p-5 space-y-4">
|
|
||||||
{/* Name */}
|
|
||||||
<div>
|
|
||||||
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
|
||||||
Name *
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
value={name}
|
|
||||||
onChange={(e) => setName(e.target.value)}
|
|
||||||
required
|
|
||||||
className={cn(
|
|
||||||
"w-full rounded-lg px-3 py-2 text-sm",
|
|
||||||
"border border-border bg-card text-foreground placeholder:text-muted-foreground",
|
|
||||||
"focus:outline-none focus:border-[rgba(249,115,22,0.3)] transition-colors"
|
|
||||||
)}
|
|
||||||
placeholder="Script name"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Description */}
|
|
||||||
<div>
|
|
||||||
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
|
||||||
Description
|
|
||||||
</label>
|
|
||||||
<textarea
|
|
||||||
value={description}
|
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
|
||||||
rows={3}
|
|
||||||
className={cn(
|
|
||||||
"w-full rounded-lg px-3 py-2 text-sm resize-none",
|
|
||||||
"border border-border bg-card text-foreground placeholder:text-muted-foreground",
|
|
||||||
"focus:outline-none focus:border-[rgba(249,115,22,0.3)] transition-colors"
|
|
||||||
)}
|
|
||||||
placeholder="What does this script do?"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Category */}
|
|
||||||
<div>
|
|
||||||
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground mb-1.5 block">
|
|
||||||
Category
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
value={categoryId}
|
|
||||||
onChange={(e) => setCategoryId(e.target.value)}
|
|
||||||
className={cn(
|
|
||||||
"w-full rounded-lg px-3 py-2 text-sm",
|
|
||||||
"border border-border bg-card text-foreground",
|
|
||||||
"focus:outline-none focus:border-[rgba(249,115,22,0.3)] transition-colors"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<option value="">No category</option>
|
|
||||||
{categories.map((cat) => (
|
|
||||||
<option key={cat.id} value={cat.id}>{cat.name}</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Share with team */}
|
|
||||||
<label className="flex items-center gap-3 cursor-pointer">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={shareWithTeam}
|
|
||||||
onChange={(e) => setShareWithTeam(e.target.checked)}
|
|
||||||
className="w-4 h-4 rounded border-border bg-card text-orange-500 focus:ring-orange-500/20"
|
|
||||||
/>
|
|
||||||
<span className="text-sm text-foreground">Share with team</span>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
{/* Error */}
|
|
||||||
{error && (
|
|
||||||
<p className="text-xs text-rose-400">{error}</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Actions */}
|
|
||||||
<div className="flex items-center justify-end gap-2 pt-2">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={onClose}
|
|
||||||
className={cn(
|
|
||||||
"px-4 py-2 rounded-lg text-sm font-medium transition-colors",
|
|
||||||
"bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground hover:border-[rgba(255,255,255,0.12)]"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
disabled={!name.trim() || isSaving}
|
|
||||||
className={cn(
|
|
||||||
"flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-semibold transition-all",
|
|
||||||
"bg-primary text-white hover:brightness-110 active:scale-[0.98]",
|
|
||||||
"disabled:opacity-50 disabled:cursor-not-allowed"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{isSaving && <Loader2 size={14} className="animate-spin" />}
|
|
||||||
{isSaving ? 'Saving...' : 'Save to Library'}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user