Merge pull request #5020 from menloresearch/chore/cleanup-assistant
chore: add function delete and params type assistant
This commit is contained in:
commit
b69a9ceb0f
@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
|
|||||||
<textarea
|
<textarea
|
||||||
data-slot="textarea"
|
data-slot="textarea"
|
||||||
className={cn(
|
className={cn(
|
||||||
'border-input placeholder:text-main-view-fg/40 border-main-view-fg/10 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 text-sm',
|
'placeholder:text-main-view-fg/40 border-main-view-fg/10 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 text-sm',
|
||||||
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[1px] ring-main-view-fg/10',
|
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[1px] ring-main-view-fg/10',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -8,31 +8,50 @@ import {
|
|||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
import { useAssistant } from '@/hooks/useAssistant'
|
import { useAssistant } from '@/hooks/useAssistant'
|
||||||
import AddEditAssistant from './dialogs/AddEditAssistant'
|
import AddEditAssistant from './dialogs/AddEditAssistant'
|
||||||
import { IconCirclePlus } from '@tabler/icons-react'
|
import { IconCirclePlus, IconSettings } from '@tabler/icons-react'
|
||||||
import type { Assistant } from '@/hooks/useAssistant'
|
|
||||||
|
|
||||||
const DropdownAssistant = () => {
|
const DropdownAssistant = () => {
|
||||||
// @ts-ignore
|
|
||||||
const { assistants, addAssistant, updateAssistant } = useAssistant()
|
const { assistants, addAssistant, updateAssistant } = useAssistant()
|
||||||
const [open, setOpen] = useState(false)
|
const [dropdownOpen, setDropdownOpen] = useState(false)
|
||||||
// @ts-ignore
|
const [dialogOpen, setDialogOpen] = useState(false)
|
||||||
const [editingKey, setEditingKey] = useState<string | null>(null)
|
const [editingAssistantId, setEditingAssistantId] = useState<string | null>(
|
||||||
|
null
|
||||||
|
)
|
||||||
|
const [selectedAssistantId, setSelectedAssistantId] = useState<string | null>(
|
||||||
|
assistants[0]?.id || null
|
||||||
|
)
|
||||||
|
|
||||||
const handleSave = (assistant: Assistant) => {
|
const selectedAssistant =
|
||||||
addAssistant(assistant)
|
assistants.find((a) => a.id === selectedAssistantId) || assistants[0]
|
||||||
setOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DropdownMenu>
|
<DropdownMenu open={dropdownOpen} onOpenChange={setDropdownOpen}>
|
||||||
<DropdownMenuTrigger asChild>
|
<div className="flex items-center justify-between gap-1">
|
||||||
<button className="rounded font-medium cursor-pointer flex items-center gap-1.5 relative z-20">
|
<DropdownMenuTrigger asChild>
|
||||||
<span className="text-main-view-fg/80">
|
<button className="bg-main-view-fg/5 py-0.5 hover:bg-main-view-fg/8 px-2 rounded font-medium cursor-pointer flex items-center gap-1.5 relative z-20 max-w-40">
|
||||||
{assistants[0]?.name || 'Jan'}
|
<span className="text-main-view-fg/80 truncate">
|
||||||
</span>
|
{selectedAssistant?.name || 'Jan'}
|
||||||
</button>
|
</span>
|
||||||
</DropdownMenuTrigger>
|
</button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<div
|
||||||
|
className="size-5 cursor-pointer relative z-10 flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||||
|
onClick={() => {
|
||||||
|
console.log('edit clicked', selectedAssistant)
|
||||||
|
if (selectedAssistant) {
|
||||||
|
setEditingAssistantId(selectedAssistant.id)
|
||||||
|
setDialogOpen(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconSettings
|
||||||
|
size={16}
|
||||||
|
className="text-main-view-fg/50"
|
||||||
|
title="Edit Assistant"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
className="w-44 max-h-[320px]"
|
className="w-44 max-h-[320px]"
|
||||||
side="bottom"
|
side="bottom"
|
||||||
@ -40,15 +59,36 @@ const DropdownAssistant = () => {
|
|||||||
align="start"
|
align="start"
|
||||||
>
|
>
|
||||||
{assistants.map((assistant) => (
|
{assistants.map((assistant) => (
|
||||||
<DropdownMenuItem key={assistant.id}>
|
<div className="relative" key={assistant.id}>
|
||||||
<span className="truncate text-main-view-fg/70">
|
<DropdownMenuItem className="flex justify-between items-center">
|
||||||
{assistant.name}
|
<span
|
||||||
</span>
|
className="truncate text-main-view-fg/70 flex-1 cursor-pointer"
|
||||||
</DropdownMenuItem>
|
onClick={() => setSelectedAssistantId(assistant.id)}
|
||||||
|
>
|
||||||
|
{assistant.name}
|
||||||
|
</span>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<div className="absolute top-1/2 -translate-y-1/2 right-2">
|
||||||
|
<div className="size-5 text-main-view-fg/50 cursor-pointer relative z-10 flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out">
|
||||||
|
<IconSettings
|
||||||
|
size={16}
|
||||||
|
onClick={() => {
|
||||||
|
setEditingAssistantId(assistant.id)
|
||||||
|
setDialogOpen(true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem onClick={() => setOpen(true)}>
|
<DropdownMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
setEditingAssistantId(null)
|
||||||
|
setDialogOpen(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
<IconCirclePlus />
|
<IconCirclePlus />
|
||||||
<span className="truncate text-main-view-fg/70">
|
<span className="truncate text-main-view-fg/70">
|
||||||
Create Assistant
|
Create Assistant
|
||||||
@ -57,10 +97,23 @@ const DropdownAssistant = () => {
|
|||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
<AddEditAssistant
|
<AddEditAssistant
|
||||||
open={open}
|
open={dialogOpen}
|
||||||
onOpenChange={setOpen}
|
onOpenChange={setDialogOpen}
|
||||||
editingKey={editingKey}
|
editingKey={editingAssistantId}
|
||||||
onSave={handleSave}
|
initialData={
|
||||||
|
editingAssistantId
|
||||||
|
? assistants.find((a) => a.id === editingAssistantId)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
onSave={(assistant) => {
|
||||||
|
if (editingAssistantId) {
|
||||||
|
updateAssistant(assistant)
|
||||||
|
} else {
|
||||||
|
addAssistant(assistant)
|
||||||
|
}
|
||||||
|
setEditingAssistantId(null)
|
||||||
|
setDialogOpen(false)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -8,10 +8,17 @@ import {
|
|||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { IconPlus, IconTrash } from '@tabler/icons-react'
|
import { IconPlus, IconTrash, IconChevronDown } from '@tabler/icons-react'
|
||||||
import { Assistant } from '@/hooks/useAssistant'
|
import { Assistant } from '@/hooks/useAssistant'
|
||||||
import { Textarea } from '@/components/ui/textarea'
|
import { Textarea } from '@/components/ui/textarea'
|
||||||
|
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from '@/components/ui/dropdown-menu'
|
||||||
|
|
||||||
interface AddEditAssistantProps {
|
interface AddEditAssistantProps {
|
||||||
open: boolean
|
open: boolean
|
||||||
onOpenChange: (open: boolean) => void
|
onOpenChange: (open: boolean) => void
|
||||||
@ -37,7 +44,8 @@ export default function AddEditAssistant({
|
|||||||
initialData?.instructions || ''
|
initialData?.instructions || ''
|
||||||
)
|
)
|
||||||
const [paramsKeys, setParamsKeys] = useState<string[]>([''])
|
const [paramsKeys, setParamsKeys] = useState<string[]>([''])
|
||||||
const [paramsValues, setParamsValues] = useState<string[]>([''])
|
const [paramsValues, setParamsValues] = useState<unknown[]>([''])
|
||||||
|
const [paramsTypes, setParamsTypes] = useState<string[]>(['string'])
|
||||||
|
|
||||||
// Reset form when modal opens/closes or editing key changes
|
// Reset form when modal opens/closes or editing key changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -50,8 +58,17 @@ export default function AddEditAssistant({
|
|||||||
const keys = Object.keys(initialData.parameters || {})
|
const keys = Object.keys(initialData.parameters || {})
|
||||||
const values = Object.values(initialData.parameters || {})
|
const values = Object.values(initialData.parameters || {})
|
||||||
|
|
||||||
|
// Determine parameter types based on values
|
||||||
|
const types = values.map((value) => {
|
||||||
|
if (typeof value === 'boolean') return 'boolean'
|
||||||
|
if (typeof value === 'number') return 'number'
|
||||||
|
if (typeof value === 'object') return 'json'
|
||||||
|
return 'string'
|
||||||
|
})
|
||||||
|
|
||||||
setParamsKeys(keys.length > 0 ? keys : [''])
|
setParamsKeys(keys.length > 0 ? keys : [''])
|
||||||
setParamsValues(values.length > 0 ? values : [''])
|
setParamsValues(values.length > 0 ? values : [''])
|
||||||
|
setParamsTypes(types.length > 0 ? types : ['string'])
|
||||||
} else if (open) {
|
} else if (open) {
|
||||||
// Add mode - reset form
|
// Add mode - reset form
|
||||||
resetForm()
|
resetForm()
|
||||||
@ -65,43 +82,88 @@ export default function AddEditAssistant({
|
|||||||
setInstructions('')
|
setInstructions('')
|
||||||
setParamsKeys([''])
|
setParamsKeys([''])
|
||||||
setParamsValues([''])
|
setParamsValues([''])
|
||||||
|
setParamsTypes(['string'])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleParameterChange = (
|
const handleParameterChange = (
|
||||||
index: number,
|
index: number,
|
||||||
value: string,
|
value: unknown,
|
||||||
isKey: boolean
|
field: 'key' | 'value' | 'type'
|
||||||
) => {
|
) => {
|
||||||
if (isKey) {
|
if (field === 'key') {
|
||||||
const newKeys = [...paramsKeys]
|
const newKeys = [...paramsKeys]
|
||||||
newKeys[index] = value
|
newKeys[index] = value as string
|
||||||
setParamsKeys(newKeys)
|
setParamsKeys(newKeys)
|
||||||
} else {
|
} else if (field === 'value') {
|
||||||
const newValues = [...paramsValues]
|
const newValues = [...paramsValues]
|
||||||
newValues[index] = value
|
|
||||||
|
// Convert value based on parameter type
|
||||||
|
if (paramsTypes[index] === 'number' && typeof value === 'string') {
|
||||||
|
newValues[index] = value === '' ? '' : Number(value)
|
||||||
|
} else if (
|
||||||
|
paramsTypes[index] === 'boolean' &&
|
||||||
|
typeof value === 'boolean'
|
||||||
|
) {
|
||||||
|
newValues[index] = value
|
||||||
|
} else if (paramsTypes[index] === 'json' && typeof value === 'string') {
|
||||||
|
try {
|
||||||
|
newValues[index] = value === '' ? {} : JSON.parse(value)
|
||||||
|
} catch {
|
||||||
|
// If JSON is invalid, keep as string
|
||||||
|
newValues[index] = value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newValues[index] = value
|
||||||
|
}
|
||||||
|
|
||||||
setParamsValues(newValues)
|
setParamsValues(newValues)
|
||||||
|
} else {
|
||||||
|
const newTypes = [...paramsTypes]
|
||||||
|
newTypes[index] = value as string
|
||||||
|
|
||||||
|
// Reset value based on the new type
|
||||||
|
const newValues = [...paramsValues]
|
||||||
|
|
||||||
|
if (value === 'string') {
|
||||||
|
newValues[index] = ''
|
||||||
|
} else if (value === 'number') {
|
||||||
|
newValues[index] = ''
|
||||||
|
} else if (value === 'boolean') {
|
||||||
|
newValues[index] = false
|
||||||
|
} else if (value === 'json') {
|
||||||
|
newValues[index] = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
setParamsValues(newValues)
|
||||||
|
setParamsTypes(newTypes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAddParameter = () => {
|
const handleAddParameter = () => {
|
||||||
setParamsKeys([...paramsKeys, ''])
|
setParamsKeys([...paramsKeys, ''])
|
||||||
setParamsValues([...paramsValues, ''])
|
setParamsValues([...paramsValues, ''])
|
||||||
|
setParamsTypes([...paramsTypes, 'string'])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemoveParameter = (index: number) => {
|
const handleRemoveParameter = (index: number) => {
|
||||||
const newKeys = [...paramsKeys]
|
const newKeys = [...paramsKeys]
|
||||||
const newValues = [...paramsValues]
|
const newValues = [...paramsValues]
|
||||||
|
const newTypes = [...paramsTypes]
|
||||||
newKeys.splice(index, 1)
|
newKeys.splice(index, 1)
|
||||||
newValues.splice(index, 1)
|
newValues.splice(index, 1)
|
||||||
|
newTypes.splice(index, 1)
|
||||||
setParamsKeys(newKeys.length > 0 ? newKeys : [''])
|
setParamsKeys(newKeys.length > 0 ? newKeys : [''])
|
||||||
setParamsValues(newValues.length > 0 ? newValues : [''])
|
setParamsValues(newValues.length > 0 ? newValues : [''])
|
||||||
|
setParamsTypes(newTypes.length > 0 ? newTypes : ['string'])
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
// Convert parameters arrays to object
|
// Convert parameters arrays to object
|
||||||
const parameters: Record<string, string> = {}
|
const parameters: Record<string, unknown> = {}
|
||||||
paramsKeys.forEach((key, index) => {
|
paramsKeys.forEach((key, index) => {
|
||||||
parameters[key] = paramsValues[index] || ''
|
if (key) {
|
||||||
|
parameters[key] = paramsValues[index]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const assistant: Assistant = {
|
const assistant: Assistant = {
|
||||||
@ -126,7 +188,7 @@ export default function AddEditAssistant({
|
|||||||
{editingKey ? 'Edit Assistant' : 'Add Assistant'}
|
{editingKey ? 'Edit Assistant' : 'Add Assistant'}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="space-y-4">
|
<div className="space-y-2">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm mb-2 inline-block">Name</label>
|
<label className="text-sm mb-2 inline-block">Name</label>
|
||||||
<Input
|
<Input
|
||||||
@ -152,10 +214,11 @@ export default function AddEditAssistant({
|
|||||||
<label className="text-sm mb-2 inline-block">
|
<label className="text-sm mb-2 inline-block">
|
||||||
Description (optional)
|
Description (optional)
|
||||||
</label>
|
</label>
|
||||||
<Input
|
<Textarea
|
||||||
value={description || ''}
|
value={description || ''}
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
placeholder="Enter description"
|
placeholder="Enter description"
|
||||||
|
className="resize-none"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -165,6 +228,8 @@ export default function AddEditAssistant({
|
|||||||
value={instructions}
|
value={instructions}
|
||||||
onChange={(e) => setInstructions(e.target.value)}
|
onChange={(e) => setInstructions(e.target.value)}
|
||||||
placeholder="Enter instructions"
|
placeholder="Enter instructions"
|
||||||
|
className="resize-none"
|
||||||
|
rows={4}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -184,19 +249,116 @@ export default function AddEditAssistant({
|
|||||||
<Input
|
<Input
|
||||||
value={key}
|
value={key}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleParameterChange(index, e.target.value, true)
|
handleParameterChange(index, e.target.value, 'key')
|
||||||
}
|
}
|
||||||
placeholder="Key"
|
placeholder="Key"
|
||||||
className="flex-1"
|
className="w-24"
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
value={paramsValues[index] || ''}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleParameterChange(index, e.target.value, false)
|
|
||||||
}
|
|
||||||
placeholder="Value"
|
|
||||||
className="flex-1"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<div className="relative w-30">
|
||||||
|
<Input
|
||||||
|
value={
|
||||||
|
paramsTypes[index].charAt(0).toUpperCase() +
|
||||||
|
paramsTypes[index].slice(1)
|
||||||
|
}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<IconChevronDown
|
||||||
|
size={14}
|
||||||
|
className="text-main-view-fg/50 absolute right-2 top-1/2 -translate-y-1/2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="w-32" align="start">
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, 'string', 'type')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
String
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, 'number', 'type')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Number
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, 'boolean', 'type')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Boolean
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, 'json', 'type')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
JSON
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
|
||||||
|
{paramsTypes[index] === 'boolean' ? (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<div className="relative flex-1">
|
||||||
|
<Input
|
||||||
|
value={paramsValues[index] ? 'True' : 'False'}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
<IconChevronDown
|
||||||
|
size={14}
|
||||||
|
className="text-main-view-fg/50 absolute right-2 top-1/2 -translate-y-1/2"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="w-24" align="start">
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, true, 'value')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
True
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
onClick={() =>
|
||||||
|
handleParameterChange(index, false, 'value')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
False
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
) : paramsTypes[index] === 'json' ? (
|
||||||
|
<Input
|
||||||
|
value={
|
||||||
|
typeof paramsValues[index] === 'object'
|
||||||
|
? JSON.stringify(paramsValues[index], null, 2)
|
||||||
|
: paramsValues[index]?.toString() || ''
|
||||||
|
}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleParameterChange(index, e.target.value, 'value')
|
||||||
|
}
|
||||||
|
placeholder="JSON Value"
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Input
|
||||||
|
value={paramsValues[index]?.toString() || ''}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleParameterChange(index, e.target.value, 'value')
|
||||||
|
}
|
||||||
|
type={paramsTypes[index] === 'number' ? 'number' : 'text'}
|
||||||
|
placeholder="Value"
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||||
onClick={() => handleRemoveParameter(index)}
|
onClick={() => handleRemoveParameter(index)}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export type Assistant = {
|
|||||||
created_at: number
|
created_at: number
|
||||||
description?: string
|
description?: string
|
||||||
instructions: string
|
instructions: string
|
||||||
parameters: Record<string, string>
|
parameters: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AssistantState {
|
interface AssistantState {
|
||||||
|
|||||||
@ -6,13 +6,17 @@ import { useAssistant } from '@/hooks/useAssistant'
|
|||||||
import type { Assistant } from '@/hooks/useAssistant'
|
import type { Assistant } from '@/hooks/useAssistant'
|
||||||
|
|
||||||
import HeaderPage from '@/containers/HeaderPage'
|
import HeaderPage from '@/containers/HeaderPage'
|
||||||
import {
|
import { IconCirclePlus, IconPencil, IconTrash } from '@tabler/icons-react'
|
||||||
IconCirclePlus,
|
|
||||||
IconCodeCircle,
|
|
||||||
IconPencil,
|
|
||||||
IconTrash,
|
|
||||||
} from '@tabler/icons-react'
|
|
||||||
import AddEditAssistant from '@/containers/dialogs/AddEditAssistant'
|
import AddEditAssistant from '@/containers/dialogs/AddEditAssistant'
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from '@/components/ui/dialog'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const Route = createFileRoute(route.assistant as any)({
|
export const Route = createFileRoute(route.assistant as any)({
|
||||||
@ -20,9 +24,25 @@ export const Route = createFileRoute(route.assistant as any)({
|
|||||||
})
|
})
|
||||||
|
|
||||||
function Assistant() {
|
function Assistant() {
|
||||||
const { assistants, addAssistant, updateAssistant } = useAssistant()
|
const { assistants, addAssistant, updateAssistant, deleteAssistant } =
|
||||||
|
useAssistant()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
const [editingKey, setEditingKey] = useState<string | null>(null)
|
const [editingKey, setEditingKey] = useState<string | null>(null)
|
||||||
|
const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false)
|
||||||
|
const [deletingId, setDeletingId] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const handleDelete = (id: string) => {
|
||||||
|
setDeletingId(id)
|
||||||
|
setDeleteConfirmOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmDelete = () => {
|
||||||
|
if (deletingId) {
|
||||||
|
deleteAssistant(deletingId)
|
||||||
|
setDeleteConfirmOpen(false)
|
||||||
|
setDeletingId(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleSave = (assistant: Assistant) => {
|
const handleSave = (assistant: Assistant) => {
|
||||||
if (editingKey) {
|
if (editingKey) {
|
||||||
@ -51,7 +71,7 @@ function Assistant() {
|
|||||||
{assistant.name}
|
{assistant.name}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="flex items-center gap-0.5">
|
<div className="flex items-center gap-0.5">
|
||||||
<div
|
{/* <div
|
||||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||||
title="Edit Assistant in JSON"
|
title="Edit Assistant in JSON"
|
||||||
>
|
>
|
||||||
@ -59,7 +79,7 @@ function Assistant() {
|
|||||||
size={18}
|
size={18}
|
||||||
className="text-main-view-fg/50"
|
className="text-main-view-fg/50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> */}
|
||||||
<div
|
<div
|
||||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||||
title="Edit Assistant"
|
title="Edit Assistant"
|
||||||
@ -73,12 +93,16 @@ function Assistant() {
|
|||||||
<div
|
<div
|
||||||
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/10 transition-all duration-200 ease-in-out"
|
||||||
title="Delete Assistant"
|
title="Delete Assistant"
|
||||||
|
onClick={() => handleDelete(assistant.id)}
|
||||||
>
|
>
|
||||||
<IconTrash size={18} className="text-main-view-fg/50" />
|
<IconTrash size={18} className="text-main-view-fg/50" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-main-view-fg/50 mt-1">
|
<p
|
||||||
|
className="text-main-view-fg/50 mt-1 line-clamp-2"
|
||||||
|
title={assistant.description}
|
||||||
|
>
|
||||||
{assistant.description}
|
{assistant.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -103,6 +127,28 @@ function Assistant() {
|
|||||||
}
|
}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
|
<Dialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Delete Assistant</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Are you sure you want to delete this assistant? This action
|
||||||
|
cannot be undone.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setDeleteConfirmOpen(false)}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button variant="destructive" onClick={confirmDelete} autoFocus>
|
||||||
|
Delete
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user