From b93ec297e4d0b3a2bdf17e179bbd22b2cc83e228 Mon Sep 17 00:00:00 2001 From: John Cortright Date: Mon, 13 Jul 2026 18:18:10 -0700 Subject: [PATCH] feat(rag): broaden preset tags and add creatable collection combobox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the survival-specific preset list with general-purpose starter tags (recipes, diy, health, technology, finance, travel, hobbies, reference, survival, energy) so the Knowledge Base reads well for home-lab/reference use, not just prepping. Adds sanitizeCollectionName() (trim, lowercase, length cap) applied on every write path server-side, and a dependency-free CollectionCombobox component replacing the plain { + setQuery(e.target.value) + setIsOpen(true) + }} + onFocus={() => setIsOpen(true)} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + const trimmed = query.trim() + if (!trimmed) { + if (allowUncategorized) commit('') + return + } + commit(exactMatch ?? trimmed.toLowerCase()) + } else if (e.key === 'Escape') { + setIsOpen(false) + setQuery(value) + } + }} + placeholder={placeholder} + className="w-full rounded border border-border-subtle bg-surface-primary px-2 py-1 text-sm text-text-primary disabled:opacity-50" + /> + {isOpen && !disabled && ( +
+ {allowUncategorized && ( + + )} + {filtered.map((opt) => ( + + ))} + {showCreateOption && ( + + )} + {filtered.length === 0 && !showCreateOption && ( +
No matches
+ )} +
+ )} + + ) +} diff --git a/admin/inertia/components/chat/KnowledgeBaseModal.tsx b/admin/inertia/components/chat/KnowledgeBaseModal.tsx index 727f11c..77ac969 100644 --- a/admin/inertia/components/chat/KnowledgeBaseModal.tsx +++ b/admin/inertia/components/chat/KnowledgeBaseModal.tsx @@ -1,5 +1,5 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import FileUploader from '~/components/file-uploader' import StyledButton from '~/components/StyledButton' import type { DynamicIconName } from '~/lib/icons' @@ -28,6 +28,8 @@ import StyledModal from '../StyledModal' import ActiveEmbedJobs from '~/components/ActiveEmbedJobs' import { SERVICE_NAMES } from '../../../constants/service_names' import CollectionsManager from './CollectionsManager' +import { KB_COLLECTIONS } from '../../../constants/kb_collections' +import CollectionCombobox from './CollectionCombobox' interface KnowledgeBaseModalProps { aiAssistantName?: string @@ -165,6 +167,10 @@ export default function KnowledgeBaseModal({ aiAssistantName = "AI Assistant", o select: (data) => data?.collections ?? [], }) + const comboboxOptions = useMemo(() => { + return Array.from(new Set([...KB_COLLECTIONS, ...knownCollections])).sort() + }, [knownCollections]) + const { data: warningsResult } = useQuery({ queryKey: ['kbFileWarnings'], queryFn: () => api.getKbFileWarnings(), @@ -463,24 +469,12 @@ export default function KnowledgeBaseModal({ aiAssistantName = "AI Assistant", o
updateCollectionMutation.mutate({ source: record.source, collection: val })} + options={comboboxOptions} disabled={isSaving} - onChange={(e) => { - if (e.target.value === '__new__') { - const name = window.prompt('New collection name:') - if (name && name.trim()) { - updateCollectionMutation.mutate({ source: record.source, collection: name.trim() }) - } - return - } - updateCollectionMutation.mutate({ source: record.source, collection: e.target.value }) - }} - className="rounded border border-border-subtle bg-surface-primary px-2 py-1 text-xs text-text-primary" - > - - {knownCollections.map((c) => ( - - ))} - - + className="w-40" + /> ) }, },