Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
ChipInput,
ChipModal,
ChipModalBody,
ChipModalError,
ChipModalField,
ChipModalFooter,
ChipModalHeader,
Expand All @@ -23,7 +22,7 @@ import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { X } from 'lucide-react'
import { useParams } from 'next/navigation'
import { type FieldErrors, useForm } from 'react-hook-form'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import type { StrategyOptions } from '@/lib/chunkers/types'
import { KNOWLEDGE_BASE_DESCRIPTION_MAX_LENGTH } from '@/lib/knowledge/constants'
Expand Down Expand Up @@ -119,11 +118,6 @@ const FormSchema = z
type FormInputValues = z.input<typeof FormSchema>
type FormValues = z.output<typeof FormSchema>

interface SubmitStatus {
type: 'success' | 'error'
message: string
}

export const CreateBaseModal = memo(function CreateBaseModal({
open,
onOpenChange,
Expand All @@ -134,11 +128,10 @@ export const CreateBaseModal = memo(function CreateBaseModal({
const createKnowledgeBaseMutation = useCreateKnowledgeBase(workspaceId)
const deleteKnowledgeBaseMutation = useDeleteKnowledgeBase(workspaceId)

const [submitStatus, setSubmitStatus] = useState<SubmitStatus | null>(null)
const [files, setFiles] = useState<File[]>([])
const [fileError, setFileError] = useState<string | null>(null)

const { uploadFiles, isUploading, uploadProgress, uploadError, clearError } = useKnowledgeUpload({
const { uploadFiles, isUploading, uploadProgress, clearError } = useKnowledgeUpload({
workspaceId,
})

Expand Down Expand Up @@ -178,7 +171,6 @@ export const CreateBaseModal = memo(function CreateBaseModal({

useEffect(() => {
if (open) {
setSubmitStatus(null)
setFileError(null)
setFiles([])
reset({
Expand Down Expand Up @@ -231,18 +223,7 @@ export const CreateBaseModal = memo(function CreateBaseModal({
const isSubmitting =
createKnowledgeBaseMutation.isPending || deleteKnowledgeBaseMutation.isPending || isUploading

const onInvalid = (formErrors: FieldErrors<FormInputValues>) => {
const firstMessage = Object.values(formErrors).find(
(fieldError) => typeof fieldError?.message === 'string'
)?.message
toast.error(
typeof firstMessage === 'string' ? firstMessage : 'Please fix the highlighted fields'
)
}

const onSubmit = async (data: FormValues) => {
setSubmitStatus(null)

try {
const strategyOptions: StrategyOptions | undefined =
data.strategy === 'regex' && data.regexPattern
Expand Down Expand Up @@ -289,7 +270,8 @@ export const CreateBaseModal = memo(function CreateBaseModal({
} catch (deleteError) {
logger.error('Failed to delete orphaned knowledge base:', deleteError)
}
throw uploadError
toast.error(getErrorMessage(uploadError, 'Failed to upload files'))
return
}
}

Expand All @@ -298,18 +280,14 @@ export const CreateBaseModal = memo(function CreateBaseModal({
handleClose(false)
} catch (error) {
logger.error('Error creating knowledge base:', error)
setSubmitStatus({
type: 'error',
message: getErrorMessage(error, 'An unknown error occurred'),
})
}
}

return (
<ChipModal open={open} onOpenChange={handleClose} srTitle='Create Knowledge Base' size='lg'>
<ChipModalHeader onClose={() => handleClose(false)}>Create Knowledge Base</ChipModalHeader>

<form onSubmit={handleSubmit(onSubmit, onInvalid)} className='flex min-h-0 flex-1 flex-col'>
<form onSubmit={handleSubmit(onSubmit)} className='flex min-h-0 flex-1 flex-col'>
<button type='submit' hidden disabled={isSubmitting || !nameValue?.trim()} />
<ChipModalBody>
<input
Expand All @@ -321,7 +299,7 @@ export const CreateBaseModal = memo(function CreateBaseModal({
readOnly
/>

<ChipModalField type='custom' title='Name'>
<ChipModalField type='custom' title='Name' error={errors.name?.message}>
<ChipInput
placeholder='Enter knowledge base name'
{...register('name')}
Expand All @@ -344,7 +322,12 @@ export const CreateBaseModal = memo(function CreateBaseModal({
</ChipModalField>

<div className='flex gap-3'>
<ChipModalField type='custom' title='Min Chunk Size (characters)' className='flex-1'>
<ChipModalField
type='custom'
title='Min Chunk Size (characters)'
className='flex-1'
error={errors.minChunkSize?.message}
>
<ChipInput
type='number'
min={1}
Expand All @@ -358,7 +341,12 @@ export const CreateBaseModal = memo(function CreateBaseModal({
/>
</ChipModalField>

<ChipModalField type='custom' title='Max Chunk Size (tokens)' className='flex-1'>
<ChipModalField
type='custom'
title='Max Chunk Size (tokens)'
className='flex-1'
error={errors.maxChunkSize?.message}
>
<ChipInput
type='number'
min={100}
Expand All @@ -377,6 +365,7 @@ export const CreateBaseModal = memo(function CreateBaseModal({
type='custom'
title='Overlap (tokens)'
hint='1 token ≈ 4 characters. Max chunk size and overlap are in tokens.'
error={errors.overlapSize?.message}
>
<ChipInput
type='number'
Expand Down Expand Up @@ -410,8 +399,8 @@ export const CreateBaseModal = memo(function CreateBaseModal({
<ChipModalField
type='custom'
title='Regex Pattern'
error={errors.regexPattern?.message}
hint='Text will be split at each match of this regex pattern.'
error={errors.regexPattern?.message}
>
<ChipInput
placeholder='e.g. \\n\\n or (?<=\\})\\s*(?=\\{)'
Expand Down Expand Up @@ -520,8 +509,6 @@ export const CreateBaseModal = memo(function CreateBaseModal({
</div>
</ChipModalField>
)}

<ChipModalError>{uploadError?.message || submitStatus?.message}</ChipModalError>
</ChipModalBody>

<ChipModalFooter
Expand All @@ -537,7 +524,7 @@ export const CreateBaseModal = memo(function CreateBaseModal({
: 'Creating...'
: 'Creating...'
: 'Create',
onClick: handleSubmit(onSubmit, onInvalid),
onClick: handleSubmit(onSubmit),
disabled: isSubmitting || !nameValue?.trim(),
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@ import { memo, useRef, useState } from 'react'
import {
ChipModal,
ChipModalBody,
ChipModalError,
ChipModalField,
ChipModalFooter,
ChipModalHeader,
toast,
} from '@sim/emcn'
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { KNOWLEDGE_BASE_DESCRIPTION_MAX_LENGTH } from '@/lib/knowledge/constants'
import type { ChunkingConfig } from '@/lib/knowledge/types'

Expand Down Expand Up @@ -44,7 +41,6 @@ export const EditKnowledgeBaseModal = memo(function EditKnowledgeBaseModal({
const [nameError, setNameError] = useState<string | null>(null)
const [descriptionError, setDescriptionError] = useState<string | null>(null)
const [isSubmitting, setIsSubmitting] = useState(false)
const [error, setError] = useState<string | null>(null)

/**
* Seed the fields only on the closed → open transition (render-phase reset),
Expand All @@ -58,50 +54,44 @@ export const EditKnowledgeBaseModal = memo(function EditKnowledgeBaseModal({
setDescription(initialDescription)
setNameError(null)
setDescriptionError(null)
setError(null)
}
}

const validate = (): string | null => {
let firstError: string | null = null
const validate = (): boolean => {
let valid = true

if (!name.trim()) {
setNameError('Name is required')
firstError ??= 'Name is required'
valid = false
} else if (name.trim().length > 100) {
setNameError('Name must be less than 100 characters')
firstError ??= 'Name must be less than 100 characters'
valid = false
} else {
setNameError(null)
}

if (description.length > KNOWLEDGE_BASE_DESCRIPTION_MAX_LENGTH) {
const message = `Description must be ${KNOWLEDGE_BASE_DESCRIPTION_MAX_LENGTH} characters or less`
setDescriptionError(message)
firstError ??= message
setDescriptionError(
`Description must be ${KNOWLEDGE_BASE_DESCRIPTION_MAX_LENGTH} characters or less`
)
valid = false
} else {
setDescriptionError(null)
}

return firstError
return valid
}

const handleSubmit = async () => {
const validationError = validate()
if (validationError) {
toast.error(validationError)
return
}
if (!validate()) return

setIsSubmitting(true)
setError(null)

try {
await onSave(knowledgeBaseId, name.trim(), description.trim())
onOpenChange(false)
} catch (err) {
logger.error('Error updating knowledge base:', err)
setError(getErrorMessage(err, 'Failed to update knowledge base'))
} finally {
setIsSubmitting(false)
}
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Expand Down Expand Up @@ -166,7 +156,6 @@ export const EditKnowledgeBaseModal = memo(function EditKnowledgeBaseModal({
</div>
</ChipModalField>
)}
<ChipModalError>{error}</ChipModalError>
</ChipModalBody>
<ChipModalFooter
onCancel={() => onOpenChange(false)}
Expand Down
3 changes: 3 additions & 0 deletions apps/sim/hooks/queries/kb/knowledge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,9 @@ export function useCreateKnowledgeBase(workspaceId?: string) {

return useMutation({
mutationFn: createKnowledgeBase,
onError: (error) => {
toast.error(error.message, { duration: 5000 })
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: knowledgeKeys.lists(),
Expand Down
Loading