init: fuzzygraph app from fn_registry
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import { useState } from 'react'
|
||||
import type { Entity, RelationInputDTO } from '../types'
|
||||
import { SimpleSelect } from '@fn_library'
|
||||
import { X } from 'lucide-react'
|
||||
|
||||
interface Props {
|
||||
entities: Entity[]
|
||||
relationPresets: string[]
|
||||
onSubmit: (input: RelationInputDTO) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
export function RelationDialog({ entities, relationPresets, onSubmit, onClose }: Props) {
|
||||
const [name, setName] = useState(relationPresets[0] ?? '')
|
||||
const [fromEntity, setFromEntity] = useState(entities[0]?.id ?? '')
|
||||
const [toEntity, setToEntity] = useState(entities[1]?.id ?? entities[0]?.id ?? '')
|
||||
const [description, setDescription] = useState('')
|
||||
const [weight, setWeight] = useState('1.0')
|
||||
const [notes, setNotes] = useState('')
|
||||
|
||||
const handleSubmit = () => {
|
||||
const w = parseFloat(weight)
|
||||
onSubmit({
|
||||
name,
|
||||
from_entity: fromEntity,
|
||||
to_entity: toEntity,
|
||||
description,
|
||||
weight: isNaN(w) ? null : w,
|
||||
tags: [],
|
||||
notes,
|
||||
})
|
||||
}
|
||||
|
||||
const inputStyle = {
|
||||
background: 'var(--input)',
|
||||
color: 'var(--foreground)',
|
||||
border: '1px solid var(--border)',
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center" style={{ background: 'rgba(0,0,0,0.6)' }}>
|
||||
<div className="w-[480px] rounded-lg p-5" style={{ background: 'var(--card)', border: '1px solid var(--border)' }}>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-base font-semibold">New Relation</h3>
|
||||
<button onClick={onClose} className="p-1"><X size={16} style={{ color: 'var(--muted-foreground)' }} /></button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>Relation Type</label>
|
||||
<SimpleSelect
|
||||
value={name}
|
||||
onValueChange={setName}
|
||||
options={relationPresets.map(p => ({ value: p, label: p }))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="flex-1">
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>From</label>
|
||||
<SimpleSelect
|
||||
value={fromEntity}
|
||||
onValueChange={setFromEntity}
|
||||
options={entities.map(e => ({ value: e.id, label: e.name }))}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>To</label>
|
||||
<SimpleSelect
|
||||
value={toEntity}
|
||||
onValueChange={setToEntity}
|
||||
options={entities.map(e => ({ value: e.id, label: e.name }))}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>Description</label>
|
||||
<input value={description} onChange={e => setDescription(e.target.value)} className="w-full px-3 py-1.5 rounded text-sm" style={inputStyle} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>Weight (0.0 - 1.0)</label>
|
||||
<input value={weight} onChange={e => setWeight(e.target.value)} type="number" step="0.1" min="0" max="1" className="w-full px-3 py-1.5 rounded text-sm" style={inputStyle} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs mb-1" style={{ color: 'var(--muted-foreground)' }}>Notes</label>
|
||||
<textarea value={notes} onChange={e => setNotes(e.target.value)} rows={2} className="w-full px-3 py-1.5 rounded text-sm resize-none" style={inputStyle} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<button onClick={onClose} className="px-3 py-1.5 rounded text-sm" style={{ background: 'var(--secondary)', color: 'var(--secondary-foreground)' }}>Cancel</button>
|
||||
<button
|
||||
onClick={handleSubmit}
|
||||
disabled={!name || fromEntity === toEntity}
|
||||
className="px-3 py-1.5 rounded text-sm font-medium disabled:opacity-40"
|
||||
style={{ background: 'var(--primary)', color: 'var(--primary-foreground)' }}
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user