@open-mercato/search 0.6.7-develop.6828.1.ab1620a63e → 0.6.7-develop.6842.1.8cd8a8883c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -634,7 +634,7 @@ function VectorSearchSection({
634
634
  ] }),
635
635
  /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
636
636
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: handleEmbeddingCancelChange, disabled: embeddingSaving, children: t("search.settings.actions.cancel", "Cancel") }),
637
- /* @__PURE__ */ jsxs(Button, { type: "button", variant: "destructive", onClick: handleEmbeddingConfirmChange, disabled: embeddingSaving, children: [
637
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "destructive-solid", onClick: handleEmbeddingConfirmChange, disabled: embeddingSaving, children: [
638
638
  embeddingSaving ? /* @__PURE__ */ jsx(Spinner, { size: "sm", className: "mr-2" }) : null,
639
639
  t("search.settings.actions.confirm", "Confirm")
640
640
  ] })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/search/frontend/components/sections/VectorSearchSection.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\nimport { Check, Plus } from 'lucide-react'\n\n// Types\ntype EmbeddingProviderId = 'openai' | 'google' | 'mistral' | 'cohere' | 'bedrock' | 'ollama'\n\ntype EmbeddingProviderConfig = {\n providerId: EmbeddingProviderId\n model: string\n dimension: number\n outputDimensionality?: number\n baseUrl?: string\n updatedAt: string\n}\n\ntype EmbeddingModelInfo = {\n id: string\n name: string\n dimension: number\n configurableDimension?: boolean\n minDimension?: number\n maxDimension?: number\n}\n\ntype EmbeddingProviderInfo = {\n name: string\n envKeyRequired: string\n defaultModel: string\n models: EmbeddingModelInfo[]\n}\n\ntype EmbeddingSettings = {\n openaiConfigured: boolean\n autoIndexingEnabled: boolean\n autoIndexingLocked: boolean\n lockReason: string | null\n embeddingConfig: EmbeddingProviderConfig | null\n embeddingConfigSource?: 'tenant' | 'instance' | 'env'\n configuredProviders: EmbeddingProviderId[]\n providerAvailability?: { providerId: EmbeddingProviderId; available: boolean; reason?: string; models?: number }[]\n indexedDimension: number | null\n reindexRequired: boolean\n documentCount: number | null\n}\n\ntype EmbeddingSettingsResponse = {\n settings?: EmbeddingSettings\n error?: string\n}\n\ntype VectorDriverId = 'pgvector' | 'qdrant' | 'chromadb'\n\ntype VectorDriverEnvVar = {\n name: string\n set: boolean\n hint: string\n}\n\ntype VectorDriverStatus = {\n id: VectorDriverId\n name: string\n configured: boolean\n implemented: boolean\n envVars: VectorDriverEnvVar[]\n}\n\ntype VectorStoreConfigResponse = {\n currentDriver: VectorDriverId\n configured: boolean\n drivers: VectorDriverStatus[]\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype ActivityLog = {\n id: string\n source: string\n handler: string\n level: 'info' | 'error' | 'warn'\n entityType: string | null\n recordId: string | null\n message: string\n details: unknown\n occurredAt: string\n}\n\nconst EMBEDDING_PROVIDERS: Record<EmbeddingProviderId, EmbeddingProviderInfo> = {\n openai: {\n name: 'OpenAI',\n envKeyRequired: 'OPENAI_API_KEY',\n defaultModel: 'text-embedding-3-small',\n models: [\n { id: 'text-embedding-3-small', name: 'text-embedding-3-small', dimension: 1536 },\n { id: 'text-embedding-3-large', name: 'text-embedding-3-large', dimension: 3072, configurableDimension: true, minDimension: 256, maxDimension: 3072 },\n { id: 'text-embedding-ada-002', name: 'text-embedding-ada-002', dimension: 1536 },\n ],\n },\n google: {\n name: 'Google Generative AI',\n envKeyRequired: 'GOOGLE_GENERATIVE_AI_API_KEY',\n defaultModel: 'text-embedding-004',\n models: [\n { id: 'text-embedding-004', name: 'text-embedding-004', dimension: 768, configurableDimension: true, minDimension: 1, maxDimension: 768 },\n { id: 'embedding-001', name: 'embedding-001', dimension: 768 },\n ],\n },\n mistral: {\n name: 'Mistral',\n envKeyRequired: 'MISTRAL_API_KEY',\n defaultModel: 'mistral-embed',\n models: [\n { id: 'mistral-embed', name: 'mistral-embed', dimension: 1024 },\n ],\n },\n cohere: {\n name: 'Cohere',\n envKeyRequired: 'COHERE_API_KEY',\n defaultModel: 'embed-english-v3.0',\n models: [\n { id: 'embed-english-v3.0', name: 'embed-english-v3.0', dimension: 1024 },\n { id: 'embed-multilingual-v3.0', name: 'embed-multilingual-v3.0', dimension: 1024 },\n { id: 'embed-english-light-v3.0', name: 'embed-english-light-v3.0', dimension: 384 },\n { id: 'embed-multilingual-light-v3.0', name: 'embed-multilingual-light-v3.0', dimension: 384 },\n ],\n },\n bedrock: {\n name: 'Amazon Bedrock',\n envKeyRequired: 'AWS_ACCESS_KEY_ID',\n defaultModel: 'amazon.titan-embed-text-v2:0',\n models: [\n { id: 'amazon.titan-embed-text-v2:0', name: 'Titan Embed Text v2', dimension: 1024, configurableDimension: true, minDimension: 256, maxDimension: 1024 },\n { id: 'amazon.titan-embed-text-v1', name: 'Titan Embed Text v1', dimension: 1536 },\n { id: 'cohere.embed-english-v3', name: 'Cohere Embed English v3', dimension: 1024 },\n { id: 'cohere.embed-multilingual-v3', name: 'Cohere Embed Multilingual v3', dimension: 1024 },\n ],\n },\n ollama: {\n name: 'Ollama (Local)',\n envKeyRequired: 'OLLAMA_BASE_URL',\n defaultModel: 'nomic-embed-text',\n models: [\n { id: 'nomic-embed-text', name: 'nomic-embed-text', dimension: 768 },\n { id: 'mxbai-embed-large', name: 'mxbai-embed-large', dimension: 1024 },\n { id: 'all-minilm', name: 'all-minilm', dimension: 384 },\n { id: 'snowflake-arctic-embed', name: 'snowflake-arctic-embed', dimension: 1024 },\n ],\n },\n}\n\nexport type VectorSearchSectionProps = {\n embeddingSettings: EmbeddingSettings | null\n embeddingLoading: boolean\n vectorStoreConfig: VectorStoreConfigResponse | null\n vectorStoreConfigLoading: boolean\n vectorReindexLock: ReindexLock | null\n onEmbeddingSettingsUpdate: (settings: EmbeddingSettings) => void\n onRefreshEmbeddings: () => Promise<void>\n}\n\nexport function VectorSearchSection({\n embeddingSettings,\n embeddingLoading,\n vectorStoreConfig,\n vectorStoreConfigLoading,\n vectorReindexLock,\n onEmbeddingSettingsUpdate,\n onRefreshEmbeddings,\n}: VectorSearchSectionProps) {\n const t = useT()\n const [embeddingSaving, setEmbeddingSaving] = React.useState(false)\n const autoIndexingPreviousRef = React.useRef<boolean>(true)\n\n // Staged embedding selection\n const [selectedProvider, setSelectedProvider] = React.useState<EmbeddingProviderId | null>(null)\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null)\n const [customModelName, setCustomModelName] = React.useState<string>('')\n const [customDimension, setCustomDimension] = React.useState<number>(768)\n\n const [pendingEmbeddingConfig, setPendingEmbeddingConfig] = React.useState<EmbeddingProviderConfig | null>(null)\n const [showEmbeddingConfirmDialog, setShowEmbeddingConfirmDialog] = React.useState(false)\n\n // Vector reindex state\n const [vectorReindexing, setVectorReindexing] = React.useState(false)\n const [showVectorReindexDialog, setShowVectorReindexDialog] = React.useState(false)\n\n // Activity logs state\n const [activityLogs, setActivityLogs] = React.useState<ActivityLog[]>([])\n const [activityLoading, setActivityLoading] = React.useState(true)\n\n // Fetch activity logs\n const fetchActivityLogs = React.useCallback(async () => {\n setActivityLoading(true)\n try {\n const response = await fetch('/api/query_index/status')\n if (response.ok) {\n const body = await response.json() as { logs?: ActivityLog[]; errors?: ActivityLog[] }\n const allLogs: ActivityLog[] = []\n if (body.logs) {\n allLogs.push(...body.logs)\n }\n if (body.errors) {\n allLogs.push(...body.errors.map(err => ({ ...err, level: 'error' as const })))\n }\n // Filter for vector-related logs\n const vectorLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n return lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n })\n vectorLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(vectorLogs.slice(0, 50))\n }\n } catch {\n // Silently fail\n } finally {\n setActivityLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.updated', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.completed', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('om:bridge:reconnected', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n // Update auto-indexing\n const updateAutoIndexing = React.useCallback(async (nextValue: boolean) => {\n autoIndexingPreviousRef.current = embeddingSettings?.autoIndexingEnabled ?? true\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: nextValue })\n }\n setEmbeddingSaving(true)\n try {\n const body = await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ autoIndexingEnabled: nextValue }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n if (body?.settings) {\n onEmbeddingSettingsUpdate(body.settings)\n autoIndexingPreviousRef.current = body.settings.autoIndexingEnabled\n }\n flash(t('search.settings.messages.saved', 'Settings saved'), 'success')\n } catch {\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: autoIndexingPreviousRef.current })\n }\n } finally {\n setEmbeddingSaving(false)\n }\n }, [embeddingSettings, onEmbeddingSettingsUpdate, t])\n\n // Provider handlers\n const handleProviderChange = (providerId: EmbeddingProviderId) => {\n setSelectedProvider(providerId)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const handleModelChange = (modelId: string) => {\n setSelectedModel(modelId)\n }\n\n const handleApplyEmbeddingChanges = () => {\n const newProviderId = selectedProvider ?? embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const newProviderInfo = EMBEDDING_PROVIDERS[newProviderId]\n const newModelId = selectedModel ?? (selectedProvider ? newProviderInfo.defaultModel : embeddingSettings?.embeddingConfig?.model ?? newProviderInfo.defaultModel)\n\n let modelName: string\n let dimension: number\n\n if (newModelId === 'custom') {\n modelName = customModelName.trim()\n dimension = customDimension\n if (!modelName) {\n flash(t('search.settings.errors.modelRequired', 'Please enter a model name'), 'error')\n return\n }\n if (dimension <= 0) {\n flash(t('search.settings.errors.dimensionRequired', 'Please enter a valid dimension'), 'error')\n return\n }\n } else {\n const newModel = newProviderInfo.models.find((m) => m.id === newModelId) ?? newProviderInfo.models[0]\n modelName = newModel.id\n dimension = newModel.dimension\n }\n\n const newConfig: EmbeddingProviderConfig = {\n providerId: newProviderId,\n model: modelName,\n dimension,\n updatedAt: new Date().toISOString(),\n }\n\n if (embeddingSettings?.indexedDimension || embeddingSettings?.embeddingConfig) {\n setPendingEmbeddingConfig(newConfig)\n setShowEmbeddingConfirmDialog(true)\n } else {\n applyEmbeddingConfig(newConfig)\n }\n }\n\n const handleCancelEmbeddingSelection = () => {\n setSelectedProvider(null)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const applyEmbeddingConfig = async (config: EmbeddingProviderConfig) => {\n setEmbeddingSaving(true)\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n\n try {\n await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeddingConfig: config }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n setSelectedProvider(null)\n setSelectedModel(null)\n flash(t('search.settings.messages.providerSaved', 'Embedding provider saved'), 'success')\n await onRefreshEmbeddings()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setEmbeddingSaving(false)\n }\n }\n\n const handleEmbeddingConfirmChange = () => {\n if (pendingEmbeddingConfig) {\n applyEmbeddingConfig(pendingEmbeddingConfig)\n }\n }\n\n const handleEmbeddingCancelChange = () => {\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n }\n\n // Vector reindex handlers\n const handleVectorReindexClick = () => {\n setShowVectorReindexDialog(true)\n }\n\n const handleVectorReindexConfirm = async () => {\n setShowVectorReindexDialog(false)\n setVectorReindexing(true)\n try {\n await readApiResultOrThrow<{ ok: boolean }>(\n '/api/search/embeddings/reindex',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ purgeFirst: true }),\n },\n { errorMessage: t('search.settings.errors.reindexFailed', 'Reindex failed'), allowNullResult: true },\n )\n flash(t('search.settings.messages.reindexStarted', 'Reindex started'), 'success')\n await fetchActivityLogs()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setVectorReindexing(false)\n }\n }\n\n const handleVectorReindexCancel = () => {\n setShowVectorReindexDialog(false)\n }\n\n // Computed values\n const savedProvider = embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const savedProviderInfo = EMBEDDING_PROVIDERS[savedProvider]\n const savedModel = embeddingSettings?.embeddingConfig?.model ?? savedProviderInfo.defaultModel\n const savedDimension = embeddingSettings?.embeddingConfig?.dimension ?? savedProviderInfo.models[0]?.dimension ?? 768\n\n const savedModelIsPredefined = savedProviderInfo.models.some((m) => m.id === savedModel)\n const savedCustomModel = !savedModelIsPredefined && savedModel ? { id: savedModel, name: savedModel, dimension: savedDimension } : null\n\n const displayProvider = selectedProvider ?? savedProvider\n const displayProviderInfo = EMBEDDING_PROVIDERS[displayProvider]\n const displayModel = selectedModel ?? (selectedProvider ? displayProviderInfo.defaultModel : savedModel)\n const isCustomModel = displayModel === 'custom'\n\n const displayModelIsSavedCustom = !isCustomModel && displayProvider === savedProvider && savedCustomModel && displayModel === savedCustomModel.id\n\n const displayModelInfo = isCustomModel\n ? null\n : displayModelIsSavedCustom\n ? savedCustomModel\n : displayProviderInfo.models.find((m) => m.id === displayModel) ?? displayProviderInfo.models[0]\n const displayDimension = isCustomModel ? customDimension : (displayModelInfo?.dimension ?? 768)\n\n const hasUnsavedEmbeddingChanges = (selectedProvider !== null && selectedProvider !== savedProvider) ||\n (selectedModel !== null && selectedModel !== savedModel) ||\n (selectedProvider !== null && selectedModel === null && displayProviderInfo.defaultModel !== savedModel) ||\n (isCustomModel && (customModelName.trim() !== '' || customDimension !== 768))\n\n const isEmbeddingConfigured = embeddingSettings?.configuredProviders?.includes(savedProvider)\n const providerOptions: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n\n const autoIndexingChecked = embeddingSettings ? embeddingSettings.autoIndexingEnabled : true\n const autoIndexingDisabled = embeddingLoading || embeddingSaving || Boolean(embeddingSettings?.autoIndexingLocked)\n\n return (\n <div className=\"rounded-lg border border-border bg-card p-5 shadow-sm\">\n <h2 className=\"text-lg font-semibold mb-2\">\n {t('search.settings.vector.sectionTitle', 'Vector Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.vector.sectionDescription', 'AI-powered semantic search using embeddings.')}\n </p>\n\n <Tabs defaultValue=\"configuration\">\n <TabsList className=\"mb-4\">\n <TabsTrigger value=\"configuration\">\n {t('search.settings.tabs.configuration', 'Configuration')}\n </TabsTrigger>\n <TabsTrigger value=\"index\">\n {t('search.settings.tabs.indexManagement', 'Index Management')}\n </TabsTrigger>\n <TabsTrigger value=\"activity\">\n {t('search.settings.tabs.activity', 'Activity')}\n </TabsTrigger>\n </TabsList>\n\n {/* Configuration Tab */}\n <TabsContent value=\"configuration\">\n {(embeddingLoading || vectorStoreConfigLoading) ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Vector Store Driver Status */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.store', 'Vector Store')}</h3>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {vectorStoreConfig?.drivers.map((driver) => {\n const isCurrent = driver.id === vectorStoreConfig.currentDriver\n const isReady = driver.configured && driver.implemented\n return (\n <div\n key={driver.id}\n className={`flex items-start gap-3 p-3 rounded-md border ${\n isCurrent && isReady\n ? 'border-status-success-border bg-status-success-bg'\n : !driver.implemented\n ? 'border-border bg-muted/30 opacity-60'\n : 'border-border bg-muted/30'\n }`}\n >\n <div className={`flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${\n isCurrent && isReady\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isCurrent && isReady ? 'text-status-success-text' : ''}`}>\n {driver.name}\n </p>\n {isCurrent && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n {!driver.implemented && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t('search.settings.vector.comingSoon', 'Coming soon')}\n </span>\n )}\n </div>\n <div className=\"mt-1 space-y-0.5\">\n {driver.envVars.map((envVar) => (\n <div key={envVar.name} className=\"flex items-center gap-1.5\">\n <div className={`h-1.5 w-1.5 rounded-full ${envVar.set ? 'bg-status-success-icon' : 'bg-muted-foreground/40'}`} />\n <code className=\"text-overline text-muted-foreground font-mono\">{envVar.name}</code>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Embedding Provider Selection */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.providers', 'Embedding Provider')}</h3>\n <p className=\"text-xs text-muted-foreground mb-1\">{t('search.settings.vector.providersHint', 'Select a provider to generate embeddings. Only reachable providers can be selected.')}</p>\n {embeddingSettings?.embeddingConfigSource && embeddingSettings.embeddingConfigSource !== 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.inheritingDefault', 'This tenant is inheriting the instance/environment default. Saving a provider creates an override for this tenant.')}\n </p>\n )}\n {embeddingSettings?.embeddingConfigSource === 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.usingTenantConfig', 'This tenant is using its own embedding settings.')}\n </p>\n )}\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 items-start\">\n {providerOptions.map((providerId) => {\n const info = EMBEDDING_PROVIDERS[providerId]\n const availability = embeddingSettings?.providerAvailability?.find((entry) => entry.providerId === providerId)\n const isConfigured = availability\n ? availability.available\n : embeddingSettings?.configuredProviders?.includes(providerId)\n const isSelected = displayProvider === providerId\n const isCurrentlySaved = savedProvider === providerId\n return (\n <div\n key={providerId}\n className={`rounded-lg border-2 transition-all ${\n isSelected\n ? 'border-primary bg-primary/5 ring-1 ring-primary/20'\n : isConfigured\n ? 'border-border hover:border-primary/50 hover:bg-muted/50'\n : 'cursor-not-allowed border-border bg-muted/30 opacity-50'\n }`}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => handleProviderChange(providerId)}\n disabled={!isConfigured || embeddingLoading || embeddingSaving}\n aria-pressed={isSelected}\n aria-expanded={isConfigured ? isSelected : undefined}\n aria-controls={isSelected && isConfigured ? `provider-${providerId}-configuration` : undefined}\n className=\"h-auto w-full justify-start whitespace-normal rounded-lg p-3 text-left\"\n >\n <div className=\"flex w-full items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isSelected ? 'text-primary' : isConfigured ? '' : 'text-muted-foreground'}`}>\n {info.name}\n </p>\n {isCurrentlySaved && isConfigured && (\n <span className=\"text-overline rounded bg-status-success-bg px-1.5 py-0.5 text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n </div>\n {isConfigured ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {info.models.length} {t('search.settings.vector.modelsAvailable', 'models available')}\n </p>\n ) : availability?.reason ? (\n <p className=\"mt-1 text-xs text-status-warning-text\">\n {availability.reason}\n </p>\n ) : (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t('search.settings.vector.setEnvVar', 'Set')} <code className=\"rounded bg-muted px-1 font-mono text-overline\">{info.envKeyRequired}</code>\n </p>\n )}\n </div>\n <div className={`flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full ${\n isSelected\n ? 'bg-primary text-primary-foreground'\n : isConfigured\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n {isConfigured ? (\n <Check className=\"size-3\" aria-hidden=\"true\" />\n ) : (\n <Plus className=\"size-3\" aria-hidden=\"true\" />\n )}\n </div>\n </div>\n </Button>\n\n {/* Model Selection */}\n {isSelected && isConfigured && (\n <div\n id={`provider-${providerId}-configuration`}\n className=\"mx-3 mb-3 space-y-2 border-t border-border pt-3\"\n >\n <div className=\"space-y-1\">\n <Label htmlFor={`model-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.label', 'Model')}\n </Label>\n <Select\n value={displayModel}\n onValueChange={handleModelChange}\n disabled={embeddingLoading || embeddingSaving}\n >\n <SelectTrigger id={`model-${providerId}`} size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {savedCustomModel && displayProvider === savedProvider && (\n <SelectItem key={savedCustomModel.id} value={savedCustomModel.id}>\n {savedCustomModel.name} ({savedCustomModel.dimension}d)\n </SelectItem>\n )}\n {displayProviderInfo.models.map((model) => (\n <SelectItem key={model.id} value={model.id}>\n {model.name} ({model.dimension}d)\n </SelectItem>\n ))}\n <SelectItem value=\"custom\">{t('search.settings.model.custom', 'Custom...')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {isCustomModel && (\n <div className=\"space-y-2 rounded border border-input bg-muted/30 p-2\">\n <div className=\"space-y-1\">\n <Label htmlFor={`custom-model-name-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.namePlaceholder', 'Model name')}\n </Label>\n <Input\n id={`custom-model-name-${providerId}`}\n type=\"text\"\n size=\"sm\"\n value={customModelName}\n onChange={(e) => setCustomModelName(e.target.value)}\n placeholder={t('search.settings.model.namePlaceholder', 'Model name')}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n <div className=\"space-y-1\">\n <Label htmlFor={`custom-model-dimension-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.dimension.label', 'Dimensions')}\n </Label>\n <Input\n id={`custom-model-dimension-${providerId}`}\n type=\"number\"\n size=\"sm\"\n value={customDimension}\n onChange={(e) => setCustomDimension(Number(e.target.value) || 768)}\n placeholder=\"768\"\n min={1}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n </div>\n )}\n\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground\">\n {t('search.settings.dimension.label', 'Dimensions')}: {displayDimension}\n </span>\n {embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && (\n <span className=\"text-status-warning-text\">\n {t('search.settings.dimension.mismatch', 'mismatch')}: {embeddingSettings.indexedDimension}\n </span>\n )}\n </div>\n\n {hasUnsavedEmbeddingChanges && (\n <div className=\"flex gap-2 pt-1\">\n <Button type=\"button\" variant=\"default\" size=\"sm\" className=\"flex-1\" onClick={handleApplyEmbeddingChanges} disabled={embeddingLoading || embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-1\" /> : null}\n {t('search.settings.actions.apply', 'Apply')}\n </Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancelEmbeddingSelection} disabled={embeddingLoading || embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Setup Instructions */}\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"h-5 w-5 text-status-info-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-sm text-status-info-text\">\n <p className=\"font-medium mb-1\">{t('search.settings.vector.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.vector.howToDescription', 'Add the API key for your preferred provider to your .env file. Only providers with configured API keys can be selected.')}</p>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {embeddingLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : !isEmbeddingConfigured ? (\n <div className=\"p-4 rounded-md bg-status-warning-bg border border-status-warning-border\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"h-5 w-5 text-status-warning-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n {t('search.settings.vectorNotConfigured', 'No embedding provider configured')}\n </p>\n <p className=\"text-xs text-status-warning-text mt-1\">\n {t('search.settings.vectorNotConfiguredHint', 'Configure an embedding provider in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Document Count */}\n {embeddingSettings?.documentCount !== null && embeddingSettings?.documentCount !== undefined && (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.vectorDocumentsLabel', 'Embeddings')}</p>\n <p className=\"text-2xl font-bold\">{embeddingSettings.documentCount.toLocaleString()}</p>\n </div>\n )}\n\n {/* Auto-Indexing Toggle */}\n <div className=\"flex items-start gap-4 p-4 rounded-md border border-border\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <input\n id=\"search-auto-indexing\"\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-muted-foreground/40\"\n checked={autoIndexingChecked}\n onChange={(event) => updateAutoIndexing(event.target.checked)}\n disabled={autoIndexingDisabled}\n />\n <Label htmlFor=\"search-auto-indexing\" className=\"text-sm font-medium\">\n {t('search.settings.autoIndexing.label', 'Enable auto-indexing')}\n </Label>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"text-muted-foreground\" /> : null}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n {t('search.settings.autoIndexing.description', 'Automatically index new and updated records for vector search.')}\n </p>\n {embeddingSettings?.autoIndexingLocked && (\n <p className=\"text-xs text-destructive mt-1 ml-6\">\n {t('search.settings.autoIndexing.locked', 'Disabled via environment variable.')}\n </p>\n )}\n </div>\n </div>\n\n {/* Reindex Actions */}\n <div className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{t('search.settings.vectorReindex.title', 'Reindex Data')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('search.settings.vectorReindex.description', 'Rebuild vector embeddings for all indexed entities. This will purge existing data and regenerate all embeddings.')}\n </p>\n\n {/* Active reindex lock banner */}\n {vectorReindexLock && (\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-3\">\n <Spinner size=\"sm\" className=\"flex-shrink-0 mt-0.5 text-status-info-icon\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('search.settings.reindexInProgress', 'Reindex operation in progress')}\n </p>\n <p className=\"text-xs text-status-info-text mt-1\">\n {t('search.settings.reindexInProgressDetails', 'Action: {{action}} | Started {{minutes}} minutes ago', {\n action: vectorReindexLock.action,\n minutes: vectorReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex items-center gap-2 p-2 rounded bg-status-warning-bg\">\n <svg className=\"h-4 w-4 text-status-warning-icon flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <p className=\"text-xs text-status-warning-text\">\n {t('search.settings.vectorReindex.warning', 'This may take a while for large datasets and will consume API credits.')}\n </p>\n </div>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleVectorReindexClick}\n disabled={embeddingLoading || embeddingSaving || vectorReindexing || vectorReindexLock !== null}\n >\n {vectorReindexing || vectorReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.vectorReindex.running', 'Reindexing...')}\n </>\n ) : (\n t('search.settings.vectorReindex.button', 'Full Reindex')\n )}\n </Button>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Activity Tab */}\n <TabsContent value=\"activity\">\n {activityLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading...')}</span>\n </div>\n ) : activityLogs.length === 0 ? (\n <div className=\"p-4 rounded-md bg-muted/50 text-center\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.activity.noLogs', 'No recent indexing activity')}\n </p>\n </div>\n ) : (\n <div className=\"space-y-2 max-h-80 overflow-y-auto\">\n {activityLogs.map((log) => (\n <div\n key={log.id}\n className={`p-2 rounded-md text-sm ${\n log.level === 'error'\n ? 'bg-status-error-bg border border-status-error-border'\n : 'bg-muted/50'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n {log.level === 'error' && (\n <svg className=\"h-4 w-4 text-status-error-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className={`text-xs ${log.level === 'error' ? 'text-status-error-text' : 'text-foreground'}`}>\n {log.message}\n </p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {(() => {\n const d = new Date(log.occurredAt)\n const pad = (n: number) => n.toString().padStart(2, '0')\n return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n })()}\n {log.entityType && ` \u00B7 ${log.entityType}`}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={fetchActivityLogs}\n disabled={activityLoading}\n >\n {activityLoading ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.loadingLabel', 'Loading...')}\n </>\n ) : (\n t('search.settings.refreshLabel', 'Refresh')\n )}\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n\n {/* Vector Reindex Confirmation Dialog */}\n {showVectorReindexDialog && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.reindex.confirmTitle', 'Confirm Reindex')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.reindex.confirmDescription', 'This will rebuild all vector embeddings. Existing data will be purged first.')}\n </p>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleVectorReindexCancel}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"default\" onClick={handleVectorReindexConfirm}>\n {t('search.settings.reindex.confirmButton', 'Start Reindex')}\n </Button>\n </div>\n </div>\n </div>\n )}\n\n {/* Embedding Provider Change Confirmation Dialog */}\n {showEmbeddingConfirmDialog && pendingEmbeddingConfig && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.change.title', 'Confirm Provider Change')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.change.description', 'Changing the embedding provider will require reindexing all data.')}\n </p>\n <div className=\"mb-4 p-3 rounded-md bg-muted/50 text-sm\">\n <p className=\"font-medium\">\n {embeddingSettings?.embeddingConfig\n ? `${EMBEDDING_PROVIDERS[embeddingSettings.embeddingConfig.providerId].name} (${embeddingSettings.embeddingConfig.model})`\n : 'Default'}\n {' \u2192 '}\n {EMBEDDING_PROVIDERS[pendingEmbeddingConfig.providerId].name} ({pendingEmbeddingConfig.model})\n </p>\n <p className=\"text-muted-foreground\">\n {embeddingSettings?.indexedDimension ?? 'N/A'} \u2192 {pendingEmbeddingConfig.dimension} dimensions\n </p>\n </div>\n <ul className=\"mb-4 space-y-1 text-sm\">\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet1', 'Existing vector data will be cleared')}</span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet2', 'Vector search will be unavailable during reindex')}</span>\n </li>\n </ul>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive\" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-2\" /> : null}\n {t('search.settings.actions.confirm', 'Confirm')}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default VectorSearchSection\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\nimport { Check, Plus } from 'lucide-react'\n\n// Types\ntype EmbeddingProviderId = 'openai' | 'google' | 'mistral' | 'cohere' | 'bedrock' | 'ollama'\n\ntype EmbeddingProviderConfig = {\n providerId: EmbeddingProviderId\n model: string\n dimension: number\n outputDimensionality?: number\n baseUrl?: string\n updatedAt: string\n}\n\ntype EmbeddingModelInfo = {\n id: string\n name: string\n dimension: number\n configurableDimension?: boolean\n minDimension?: number\n maxDimension?: number\n}\n\ntype EmbeddingProviderInfo = {\n name: string\n envKeyRequired: string\n defaultModel: string\n models: EmbeddingModelInfo[]\n}\n\ntype EmbeddingSettings = {\n openaiConfigured: boolean\n autoIndexingEnabled: boolean\n autoIndexingLocked: boolean\n lockReason: string | null\n embeddingConfig: EmbeddingProviderConfig | null\n embeddingConfigSource?: 'tenant' | 'instance' | 'env'\n configuredProviders: EmbeddingProviderId[]\n providerAvailability?: { providerId: EmbeddingProviderId; available: boolean; reason?: string; models?: number }[]\n indexedDimension: number | null\n reindexRequired: boolean\n documentCount: number | null\n}\n\ntype EmbeddingSettingsResponse = {\n settings?: EmbeddingSettings\n error?: string\n}\n\ntype VectorDriverId = 'pgvector' | 'qdrant' | 'chromadb'\n\ntype VectorDriverEnvVar = {\n name: string\n set: boolean\n hint: string\n}\n\ntype VectorDriverStatus = {\n id: VectorDriverId\n name: string\n configured: boolean\n implemented: boolean\n envVars: VectorDriverEnvVar[]\n}\n\ntype VectorStoreConfigResponse = {\n currentDriver: VectorDriverId\n configured: boolean\n drivers: VectorDriverStatus[]\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype ActivityLog = {\n id: string\n source: string\n handler: string\n level: 'info' | 'error' | 'warn'\n entityType: string | null\n recordId: string | null\n message: string\n details: unknown\n occurredAt: string\n}\n\nconst EMBEDDING_PROVIDERS: Record<EmbeddingProviderId, EmbeddingProviderInfo> = {\n openai: {\n name: 'OpenAI',\n envKeyRequired: 'OPENAI_API_KEY',\n defaultModel: 'text-embedding-3-small',\n models: [\n { id: 'text-embedding-3-small', name: 'text-embedding-3-small', dimension: 1536 },\n { id: 'text-embedding-3-large', name: 'text-embedding-3-large', dimension: 3072, configurableDimension: true, minDimension: 256, maxDimension: 3072 },\n { id: 'text-embedding-ada-002', name: 'text-embedding-ada-002', dimension: 1536 },\n ],\n },\n google: {\n name: 'Google Generative AI',\n envKeyRequired: 'GOOGLE_GENERATIVE_AI_API_KEY',\n defaultModel: 'text-embedding-004',\n models: [\n { id: 'text-embedding-004', name: 'text-embedding-004', dimension: 768, configurableDimension: true, minDimension: 1, maxDimension: 768 },\n { id: 'embedding-001', name: 'embedding-001', dimension: 768 },\n ],\n },\n mistral: {\n name: 'Mistral',\n envKeyRequired: 'MISTRAL_API_KEY',\n defaultModel: 'mistral-embed',\n models: [\n { id: 'mistral-embed', name: 'mistral-embed', dimension: 1024 },\n ],\n },\n cohere: {\n name: 'Cohere',\n envKeyRequired: 'COHERE_API_KEY',\n defaultModel: 'embed-english-v3.0',\n models: [\n { id: 'embed-english-v3.0', name: 'embed-english-v3.0', dimension: 1024 },\n { id: 'embed-multilingual-v3.0', name: 'embed-multilingual-v3.0', dimension: 1024 },\n { id: 'embed-english-light-v3.0', name: 'embed-english-light-v3.0', dimension: 384 },\n { id: 'embed-multilingual-light-v3.0', name: 'embed-multilingual-light-v3.0', dimension: 384 },\n ],\n },\n bedrock: {\n name: 'Amazon Bedrock',\n envKeyRequired: 'AWS_ACCESS_KEY_ID',\n defaultModel: 'amazon.titan-embed-text-v2:0',\n models: [\n { id: 'amazon.titan-embed-text-v2:0', name: 'Titan Embed Text v2', dimension: 1024, configurableDimension: true, minDimension: 256, maxDimension: 1024 },\n { id: 'amazon.titan-embed-text-v1', name: 'Titan Embed Text v1', dimension: 1536 },\n { id: 'cohere.embed-english-v3', name: 'Cohere Embed English v3', dimension: 1024 },\n { id: 'cohere.embed-multilingual-v3', name: 'Cohere Embed Multilingual v3', dimension: 1024 },\n ],\n },\n ollama: {\n name: 'Ollama (Local)',\n envKeyRequired: 'OLLAMA_BASE_URL',\n defaultModel: 'nomic-embed-text',\n models: [\n { id: 'nomic-embed-text', name: 'nomic-embed-text', dimension: 768 },\n { id: 'mxbai-embed-large', name: 'mxbai-embed-large', dimension: 1024 },\n { id: 'all-minilm', name: 'all-minilm', dimension: 384 },\n { id: 'snowflake-arctic-embed', name: 'snowflake-arctic-embed', dimension: 1024 },\n ],\n },\n}\n\nexport type VectorSearchSectionProps = {\n embeddingSettings: EmbeddingSettings | null\n embeddingLoading: boolean\n vectorStoreConfig: VectorStoreConfigResponse | null\n vectorStoreConfigLoading: boolean\n vectorReindexLock: ReindexLock | null\n onEmbeddingSettingsUpdate: (settings: EmbeddingSettings) => void\n onRefreshEmbeddings: () => Promise<void>\n}\n\nexport function VectorSearchSection({\n embeddingSettings,\n embeddingLoading,\n vectorStoreConfig,\n vectorStoreConfigLoading,\n vectorReindexLock,\n onEmbeddingSettingsUpdate,\n onRefreshEmbeddings,\n}: VectorSearchSectionProps) {\n const t = useT()\n const [embeddingSaving, setEmbeddingSaving] = React.useState(false)\n const autoIndexingPreviousRef = React.useRef<boolean>(true)\n\n // Staged embedding selection\n const [selectedProvider, setSelectedProvider] = React.useState<EmbeddingProviderId | null>(null)\n const [selectedModel, setSelectedModel] = React.useState<string | null>(null)\n const [customModelName, setCustomModelName] = React.useState<string>('')\n const [customDimension, setCustomDimension] = React.useState<number>(768)\n\n const [pendingEmbeddingConfig, setPendingEmbeddingConfig] = React.useState<EmbeddingProviderConfig | null>(null)\n const [showEmbeddingConfirmDialog, setShowEmbeddingConfirmDialog] = React.useState(false)\n\n // Vector reindex state\n const [vectorReindexing, setVectorReindexing] = React.useState(false)\n const [showVectorReindexDialog, setShowVectorReindexDialog] = React.useState(false)\n\n // Activity logs state\n const [activityLogs, setActivityLogs] = React.useState<ActivityLog[]>([])\n const [activityLoading, setActivityLoading] = React.useState(true)\n\n // Fetch activity logs\n const fetchActivityLogs = React.useCallback(async () => {\n setActivityLoading(true)\n try {\n const response = await fetch('/api/query_index/status')\n if (response.ok) {\n const body = await response.json() as { logs?: ActivityLog[]; errors?: ActivityLog[] }\n const allLogs: ActivityLog[] = []\n if (body.logs) {\n allLogs.push(...body.logs)\n }\n if (body.errors) {\n allLogs.push(...body.errors.map(err => ({ ...err, level: 'error' as const })))\n }\n // Filter for vector-related logs\n const vectorLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n return lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n })\n vectorLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(vectorLogs.slice(0, 50))\n }\n } catch {\n // Silently fail\n } finally {\n setActivityLoading(false)\n }\n }, [])\n\n React.useEffect(() => {\n fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.updated', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('progress.job.completed', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n useAppEvent('om:bridge:reconnected', () => {\n void fetchActivityLogs()\n }, [fetchActivityLogs])\n\n // Update auto-indexing\n const updateAutoIndexing = React.useCallback(async (nextValue: boolean) => {\n autoIndexingPreviousRef.current = embeddingSettings?.autoIndexingEnabled ?? true\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: nextValue })\n }\n setEmbeddingSaving(true)\n try {\n const body = await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ autoIndexingEnabled: nextValue }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n if (body?.settings) {\n onEmbeddingSettingsUpdate(body.settings)\n autoIndexingPreviousRef.current = body.settings.autoIndexingEnabled\n }\n flash(t('search.settings.messages.saved', 'Settings saved'), 'success')\n } catch {\n if (embeddingSettings) {\n onEmbeddingSettingsUpdate({ ...embeddingSettings, autoIndexingEnabled: autoIndexingPreviousRef.current })\n }\n } finally {\n setEmbeddingSaving(false)\n }\n }, [embeddingSettings, onEmbeddingSettingsUpdate, t])\n\n // Provider handlers\n const handleProviderChange = (providerId: EmbeddingProviderId) => {\n setSelectedProvider(providerId)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const handleModelChange = (modelId: string) => {\n setSelectedModel(modelId)\n }\n\n const handleApplyEmbeddingChanges = () => {\n const newProviderId = selectedProvider ?? embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const newProviderInfo = EMBEDDING_PROVIDERS[newProviderId]\n const newModelId = selectedModel ?? (selectedProvider ? newProviderInfo.defaultModel : embeddingSettings?.embeddingConfig?.model ?? newProviderInfo.defaultModel)\n\n let modelName: string\n let dimension: number\n\n if (newModelId === 'custom') {\n modelName = customModelName.trim()\n dimension = customDimension\n if (!modelName) {\n flash(t('search.settings.errors.modelRequired', 'Please enter a model name'), 'error')\n return\n }\n if (dimension <= 0) {\n flash(t('search.settings.errors.dimensionRequired', 'Please enter a valid dimension'), 'error')\n return\n }\n } else {\n const newModel = newProviderInfo.models.find((m) => m.id === newModelId) ?? newProviderInfo.models[0]\n modelName = newModel.id\n dimension = newModel.dimension\n }\n\n const newConfig: EmbeddingProviderConfig = {\n providerId: newProviderId,\n model: modelName,\n dimension,\n updatedAt: new Date().toISOString(),\n }\n\n if (embeddingSettings?.indexedDimension || embeddingSettings?.embeddingConfig) {\n setPendingEmbeddingConfig(newConfig)\n setShowEmbeddingConfirmDialog(true)\n } else {\n applyEmbeddingConfig(newConfig)\n }\n }\n\n const handleCancelEmbeddingSelection = () => {\n setSelectedProvider(null)\n setSelectedModel(null)\n setCustomModelName('')\n setCustomDimension(768)\n }\n\n const applyEmbeddingConfig = async (config: EmbeddingProviderConfig) => {\n setEmbeddingSaving(true)\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n\n try {\n await readApiResultOrThrow<EmbeddingSettingsResponse>(\n '/api/search/embeddings',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ embeddingConfig: config }),\n },\n { errorMessage: t('search.settings.errors.saveFailed', 'Failed to save settings'), allowNullResult: true },\n )\n setSelectedProvider(null)\n setSelectedModel(null)\n flash(t('search.settings.messages.providerSaved', 'Embedding provider saved'), 'success')\n await onRefreshEmbeddings()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setEmbeddingSaving(false)\n }\n }\n\n const handleEmbeddingConfirmChange = () => {\n if (pendingEmbeddingConfig) {\n applyEmbeddingConfig(pendingEmbeddingConfig)\n }\n }\n\n const handleEmbeddingCancelChange = () => {\n setShowEmbeddingConfirmDialog(false)\n setPendingEmbeddingConfig(null)\n }\n\n // Vector reindex handlers\n const handleVectorReindexClick = () => {\n setShowVectorReindexDialog(true)\n }\n\n const handleVectorReindexConfirm = async () => {\n setShowVectorReindexDialog(false)\n setVectorReindexing(true)\n try {\n await readApiResultOrThrow<{ ok: boolean }>(\n '/api/search/embeddings/reindex',\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ purgeFirst: true }),\n },\n { errorMessage: t('search.settings.errors.reindexFailed', 'Reindex failed'), allowNullResult: true },\n )\n flash(t('search.settings.messages.reindexStarted', 'Reindex started'), 'success')\n await fetchActivityLogs()\n } catch {\n // Error handled by readApiResultOrThrow\n } finally {\n setVectorReindexing(false)\n }\n }\n\n const handleVectorReindexCancel = () => {\n setShowVectorReindexDialog(false)\n }\n\n // Computed values\n const savedProvider = embeddingSettings?.embeddingConfig?.providerId ?? 'openai'\n const savedProviderInfo = EMBEDDING_PROVIDERS[savedProvider]\n const savedModel = embeddingSettings?.embeddingConfig?.model ?? savedProviderInfo.defaultModel\n const savedDimension = embeddingSettings?.embeddingConfig?.dimension ?? savedProviderInfo.models[0]?.dimension ?? 768\n\n const savedModelIsPredefined = savedProviderInfo.models.some((m) => m.id === savedModel)\n const savedCustomModel = !savedModelIsPredefined && savedModel ? { id: savedModel, name: savedModel, dimension: savedDimension } : null\n\n const displayProvider = selectedProvider ?? savedProvider\n const displayProviderInfo = EMBEDDING_PROVIDERS[displayProvider]\n const displayModel = selectedModel ?? (selectedProvider ? displayProviderInfo.defaultModel : savedModel)\n const isCustomModel = displayModel === 'custom'\n\n const displayModelIsSavedCustom = !isCustomModel && displayProvider === savedProvider && savedCustomModel && displayModel === savedCustomModel.id\n\n const displayModelInfo = isCustomModel\n ? null\n : displayModelIsSavedCustom\n ? savedCustomModel\n : displayProviderInfo.models.find((m) => m.id === displayModel) ?? displayProviderInfo.models[0]\n const displayDimension = isCustomModel ? customDimension : (displayModelInfo?.dimension ?? 768)\n\n const hasUnsavedEmbeddingChanges = (selectedProvider !== null && selectedProvider !== savedProvider) ||\n (selectedModel !== null && selectedModel !== savedModel) ||\n (selectedProvider !== null && selectedModel === null && displayProviderInfo.defaultModel !== savedModel) ||\n (isCustomModel && (customModelName.trim() !== '' || customDimension !== 768))\n\n const isEmbeddingConfigured = embeddingSettings?.configuredProviders?.includes(savedProvider)\n const providerOptions: EmbeddingProviderId[] = ['openai', 'google', 'mistral', 'cohere', 'bedrock', 'ollama']\n\n const autoIndexingChecked = embeddingSettings ? embeddingSettings.autoIndexingEnabled : true\n const autoIndexingDisabled = embeddingLoading || embeddingSaving || Boolean(embeddingSettings?.autoIndexingLocked)\n\n return (\n <div className=\"rounded-lg border border-border bg-card p-5 shadow-sm\">\n <h2 className=\"text-lg font-semibold mb-2\">\n {t('search.settings.vector.sectionTitle', 'Vector Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.vector.sectionDescription', 'AI-powered semantic search using embeddings.')}\n </p>\n\n <Tabs defaultValue=\"configuration\">\n <TabsList className=\"mb-4\">\n <TabsTrigger value=\"configuration\">\n {t('search.settings.tabs.configuration', 'Configuration')}\n </TabsTrigger>\n <TabsTrigger value=\"index\">\n {t('search.settings.tabs.indexManagement', 'Index Management')}\n </TabsTrigger>\n <TabsTrigger value=\"activity\">\n {t('search.settings.tabs.activity', 'Activity')}\n </TabsTrigger>\n </TabsList>\n\n {/* Configuration Tab */}\n <TabsContent value=\"configuration\">\n {(embeddingLoading || vectorStoreConfigLoading) ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Vector Store Driver Status */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.store', 'Vector Store')}</h3>\n <div className=\"grid gap-2 sm:grid-cols-3\">\n {vectorStoreConfig?.drivers.map((driver) => {\n const isCurrent = driver.id === vectorStoreConfig.currentDriver\n const isReady = driver.configured && driver.implemented\n return (\n <div\n key={driver.id}\n className={`flex items-start gap-3 p-3 rounded-md border ${\n isCurrent && isReady\n ? 'border-status-success-border bg-status-success-bg'\n : !driver.implemented\n ? 'border-border bg-muted/30 opacity-60'\n : 'border-border bg-muted/30'\n }`}\n >\n <div className={`flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${\n isCurrent && isReady\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4\" />\n </svg>\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isCurrent && isReady ? 'text-status-success-text' : ''}`}>\n {driver.name}\n </p>\n {isCurrent && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n {!driver.implemented && (\n <span className=\"text-overline px-1.5 py-0.5 rounded bg-muted text-muted-foreground\">\n {t('search.settings.vector.comingSoon', 'Coming soon')}\n </span>\n )}\n </div>\n <div className=\"mt-1 space-y-0.5\">\n {driver.envVars.map((envVar) => (\n <div key={envVar.name} className=\"flex items-center gap-1.5\">\n <div className={`h-1.5 w-1.5 rounded-full ${envVar.set ? 'bg-status-success-icon' : 'bg-muted-foreground/40'}`} />\n <code className=\"text-overline text-muted-foreground font-mono\">{envVar.name}</code>\n </div>\n ))}\n </div>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Embedding Provider Selection */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">{t('search.settings.vector.providers', 'Embedding Provider')}</h3>\n <p className=\"text-xs text-muted-foreground mb-1\">{t('search.settings.vector.providersHint', 'Select a provider to generate embeddings. Only reachable providers can be selected.')}</p>\n {embeddingSettings?.embeddingConfigSource && embeddingSettings.embeddingConfigSource !== 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.inheritingDefault', 'This tenant is inheriting the instance/environment default. Saving a provider creates an override for this tenant.')}\n </p>\n )}\n {embeddingSettings?.embeddingConfigSource === 'tenant' && (\n <p className=\"text-xs text-muted-foreground mb-3\">\n {t('search.settings.vector.usingTenantConfig', 'This tenant is using its own embedding settings.')}\n </p>\n )}\n <div className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3 items-start\">\n {providerOptions.map((providerId) => {\n const info = EMBEDDING_PROVIDERS[providerId]\n const availability = embeddingSettings?.providerAvailability?.find((entry) => entry.providerId === providerId)\n const isConfigured = availability\n ? availability.available\n : embeddingSettings?.configuredProviders?.includes(providerId)\n const isSelected = displayProvider === providerId\n const isCurrentlySaved = savedProvider === providerId\n return (\n <div\n key={providerId}\n className={`rounded-lg border-2 transition-all ${\n isSelected\n ? 'border-primary bg-primary/5 ring-1 ring-primary/20'\n : isConfigured\n ? 'border-border hover:border-primary/50 hover:bg-muted/50'\n : 'cursor-not-allowed border-border bg-muted/30 opacity-50'\n }`}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n onClick={() => handleProviderChange(providerId)}\n disabled={!isConfigured || embeddingLoading || embeddingSaving}\n aria-pressed={isSelected}\n aria-expanded={isConfigured ? isSelected : undefined}\n aria-controls={isSelected && isConfigured ? `provider-${providerId}-configuration` : undefined}\n className=\"h-auto w-full justify-start whitespace-normal rounded-lg p-3 text-left\"\n >\n <div className=\"flex w-full items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <p className={`text-sm font-medium ${isSelected ? 'text-primary' : isConfigured ? '' : 'text-muted-foreground'}`}>\n {info.name}\n </p>\n {isCurrentlySaved && isConfigured && (\n <span className=\"text-overline rounded bg-status-success-bg px-1.5 py-0.5 text-status-success-text\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n </div>\n {isConfigured ? (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {info.models.length} {t('search.settings.vector.modelsAvailable', 'models available')}\n </p>\n ) : availability?.reason ? (\n <p className=\"mt-1 text-xs text-status-warning-text\">\n {availability.reason}\n </p>\n ) : (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {t('search.settings.vector.setEnvVar', 'Set')} <code className=\"rounded bg-muted px-1 font-mono text-overline\">{info.envKeyRequired}</code>\n </p>\n )}\n </div>\n <div className={`flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-full ${\n isSelected\n ? 'bg-primary text-primary-foreground'\n : isConfigured\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-muted text-muted-foreground'\n }`}>\n {isConfigured ? (\n <Check className=\"size-3\" aria-hidden=\"true\" />\n ) : (\n <Plus className=\"size-3\" aria-hidden=\"true\" />\n )}\n </div>\n </div>\n </Button>\n\n {/* Model Selection */}\n {isSelected && isConfigured && (\n <div\n id={`provider-${providerId}-configuration`}\n className=\"mx-3 mb-3 space-y-2 border-t border-border pt-3\"\n >\n <div className=\"space-y-1\">\n <Label htmlFor={`model-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.label', 'Model')}\n </Label>\n <Select\n value={displayModel}\n onValueChange={handleModelChange}\n disabled={embeddingLoading || embeddingSaving}\n >\n <SelectTrigger id={`model-${providerId}`} size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {savedCustomModel && displayProvider === savedProvider && (\n <SelectItem key={savedCustomModel.id} value={savedCustomModel.id}>\n {savedCustomModel.name} ({savedCustomModel.dimension}d)\n </SelectItem>\n )}\n {displayProviderInfo.models.map((model) => (\n <SelectItem key={model.id} value={model.id}>\n {model.name} ({model.dimension}d)\n </SelectItem>\n ))}\n <SelectItem value=\"custom\">{t('search.settings.model.custom', 'Custom...')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n {isCustomModel && (\n <div className=\"space-y-2 rounded border border-input bg-muted/30 p-2\">\n <div className=\"space-y-1\">\n <Label htmlFor={`custom-model-name-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.model.namePlaceholder', 'Model name')}\n </Label>\n <Input\n id={`custom-model-name-${providerId}`}\n type=\"text\"\n size=\"sm\"\n value={customModelName}\n onChange={(e) => setCustomModelName(e.target.value)}\n placeholder={t('search.settings.model.namePlaceholder', 'Model name')}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n <div className=\"space-y-1\">\n <Label htmlFor={`custom-model-dimension-${providerId}`} className=\"text-xs font-medium\">\n {t('search.settings.dimension.label', 'Dimensions')}\n </Label>\n <Input\n id={`custom-model-dimension-${providerId}`}\n type=\"number\"\n size=\"sm\"\n value={customDimension}\n onChange={(e) => setCustomDimension(Number(e.target.value) || 768)}\n placeholder=\"768\"\n min={1}\n disabled={embeddingLoading || embeddingSaving}\n />\n </div>\n </div>\n )}\n\n <div className=\"flex items-center justify-between text-xs\">\n <span className=\"text-muted-foreground\">\n {t('search.settings.dimension.label', 'Dimensions')}: {displayDimension}\n </span>\n {embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && (\n <span className=\"text-status-warning-text\">\n {t('search.settings.dimension.mismatch', 'mismatch')}: {embeddingSettings.indexedDimension}\n </span>\n )}\n </div>\n\n {hasUnsavedEmbeddingChanges && (\n <div className=\"flex gap-2 pt-1\">\n <Button type=\"button\" variant=\"default\" size=\"sm\" className=\"flex-1\" onClick={handleApplyEmbeddingChanges} disabled={embeddingLoading || embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-1\" /> : null}\n {t('search.settings.actions.apply', 'Apply')}\n </Button>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={handleCancelEmbeddingSelection} disabled={embeddingLoading || embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n )\n })}\n </div>\n </div>\n\n {/* Setup Instructions */}\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"h-5 w-5 text-status-info-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n <div className=\"text-sm text-status-info-text\">\n <p className=\"font-medium mb-1\">{t('search.settings.vector.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.vector.howToDescription', 'Add the API key for your preferred provider to your .env file. Only providers with configured API keys can be selected.')}</p>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {embeddingLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading settings...')}</span>\n </div>\n ) : !isEmbeddingConfigured ? (\n <div className=\"p-4 rounded-md bg-status-warning-bg border border-status-warning-border\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"h-5 w-5 text-status-warning-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <div>\n <p className=\"text-sm font-medium text-status-warning-text\">\n {t('search.settings.vectorNotConfigured', 'No embedding provider configured')}\n </p>\n <p className=\"text-xs text-status-warning-text mt-1\">\n {t('search.settings.vectorNotConfiguredHint', 'Configure an embedding provider in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Document Count */}\n {embeddingSettings?.documentCount !== null && embeddingSettings?.documentCount !== undefined && (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.vectorDocumentsLabel', 'Embeddings')}</p>\n <p className=\"text-2xl font-bold\">{embeddingSettings.documentCount.toLocaleString()}</p>\n </div>\n )}\n\n {/* Auto-Indexing Toggle */}\n <div className=\"flex items-start gap-4 p-4 rounded-md border border-border\">\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <input\n id=\"search-auto-indexing\"\n type=\"checkbox\"\n className=\"h-4 w-4 rounded border-muted-foreground/40\"\n checked={autoIndexingChecked}\n onChange={(event) => updateAutoIndexing(event.target.checked)}\n disabled={autoIndexingDisabled}\n />\n <Label htmlFor=\"search-auto-indexing\" className=\"text-sm font-medium\">\n {t('search.settings.autoIndexing.label', 'Enable auto-indexing')}\n </Label>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"text-muted-foreground\" /> : null}\n </div>\n <p className=\"text-xs text-muted-foreground mt-1 ml-6\">\n {t('search.settings.autoIndexing.description', 'Automatically index new and updated records for vector search.')}\n </p>\n {embeddingSettings?.autoIndexingLocked && (\n <p className=\"text-xs text-destructive mt-1 ml-6\">\n {t('search.settings.autoIndexing.locked', 'Disabled via environment variable.')}\n </p>\n )}\n </div>\n </div>\n\n {/* Reindex Actions */}\n <div className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold\">{t('search.settings.vectorReindex.title', 'Reindex Data')}</h3>\n <p className=\"text-xs text-muted-foreground\">\n {t('search.settings.vectorReindex.description', 'Rebuild vector embeddings for all indexed entities. This will purge existing data and regenerate all embeddings.')}\n </p>\n\n {/* Active reindex lock banner */}\n {vectorReindexLock && (\n <div className=\"p-3 rounded-md bg-status-info-bg border border-status-info-border\">\n <div className=\"flex items-start gap-3\">\n <Spinner size=\"sm\" className=\"flex-shrink-0 mt-0.5 text-status-info-icon\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-status-info-text\">\n {t('search.settings.reindexInProgress', 'Reindex operation in progress')}\n </p>\n <p className=\"text-xs text-status-info-text mt-1\">\n {t('search.settings.reindexInProgressDetails', 'Action: {{action}} | Started {{minutes}} minutes ago', {\n action: vectorReindexLock.action,\n minutes: vectorReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n <div className=\"flex items-center gap-2 p-2 rounded bg-status-warning-bg\">\n <svg className=\"h-4 w-4 text-status-warning-icon flex-shrink-0\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\" />\n </svg>\n <p className=\"text-xs text-status-warning-text\">\n {t('search.settings.vectorReindex.warning', 'This may take a while for large datasets and will consume API credits.')}\n </p>\n </div>\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={handleVectorReindexClick}\n disabled={embeddingLoading || embeddingSaving || vectorReindexing || vectorReindexLock !== null}\n >\n {vectorReindexing || vectorReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.vectorReindex.running', 'Reindexing...')}\n </>\n ) : (\n t('search.settings.vectorReindex.button', 'Full Reindex')\n )}\n </Button>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Activity Tab */}\n <TabsContent value=\"activity\">\n {activityLoading ? (\n <div className=\"flex items-center gap-2 text-muted-foreground\">\n <Spinner size=\"sm\" />\n <span>{t('search.settings.loadingLabel', 'Loading...')}</span>\n </div>\n ) : activityLogs.length === 0 ? (\n <div className=\"p-4 rounded-md bg-muted/50 text-center\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.activity.noLogs', 'No recent indexing activity')}\n </p>\n </div>\n ) : (\n <div className=\"space-y-2 max-h-80 overflow-y-auto\">\n {activityLogs.map((log) => (\n <div\n key={log.id}\n className={`p-2 rounded-md text-sm ${\n log.level === 'error'\n ? 'bg-status-error-bg border border-status-error-border'\n : 'bg-muted/50'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n {log.level === 'error' && (\n <svg className=\"h-4 w-4 text-status-error-icon flex-shrink-0 mt-0.5\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\" />\n </svg>\n )}\n <div className=\"flex-1 min-w-0\">\n <p className={`text-xs ${log.level === 'error' ? 'text-status-error-text' : 'text-foreground'}`}>\n {log.message}\n </p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {(() => {\n const d = new Date(log.occurredAt)\n const pad = (n: number) => n.toString().padStart(2, '0')\n return `${pad(d.getDate())}-${pad(d.getMonth() + 1)}-${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n })()}\n {log.entityType && ` \u00B7 ${log.entityType}`}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n <div className=\"mt-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={fetchActivityLogs}\n disabled={activityLoading}\n >\n {activityLoading ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.loadingLabel', 'Loading...')}\n </>\n ) : (\n t('search.settings.refreshLabel', 'Refresh')\n )}\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n\n {/* Vector Reindex Confirmation Dialog */}\n {showVectorReindexDialog && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.reindex.confirmTitle', 'Confirm Reindex')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.reindex.confirmDescription', 'This will rebuild all vector embeddings. Existing data will be purged first.')}\n </p>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleVectorReindexCancel}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"default\" onClick={handleVectorReindexConfirm}>\n {t('search.settings.reindex.confirmButton', 'Start Reindex')}\n </Button>\n </div>\n </div>\n </div>\n )}\n\n {/* Embedding Provider Change Confirmation Dialog */}\n {showEmbeddingConfirmDialog && pendingEmbeddingConfig && (\n <div className=\"fixed inset-0 z-modal flex items-center justify-center bg-black/50\">\n <div className=\"mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg\">\n <h3 className=\"text-lg font-semibold mb-2\">{t('search.settings.change.title', 'Confirm Provider Change')}</h3>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.change.description', 'Changing the embedding provider will require reindexing all data.')}\n </p>\n <div className=\"mb-4 p-3 rounded-md bg-muted/50 text-sm\">\n <p className=\"font-medium\">\n {embeddingSettings?.embeddingConfig\n ? `${EMBEDDING_PROVIDERS[embeddingSettings.embeddingConfig.providerId].name} (${embeddingSettings.embeddingConfig.model})`\n : 'Default'}\n {' \u2192 '}\n {EMBEDDING_PROVIDERS[pendingEmbeddingConfig.providerId].name} ({pendingEmbeddingConfig.model})\n </p>\n <p className=\"text-muted-foreground\">\n {embeddingSettings?.indexedDimension ?? 'N/A'} \u2192 {pendingEmbeddingConfig.dimension} dimensions\n </p>\n </div>\n <ul className=\"mb-4 space-y-1 text-sm\">\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet1', 'Existing vector data will be cleared')}</span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"text-destructive\">\u2022</span>\n <span>{t('search.settings.change.bullet2', 'Vector search will be unavailable during reindex')}</span>\n </li>\n </ul>\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>\n {t('search.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" variant=\"destructive-solid\" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>\n {embeddingSaving ? <Spinner size=\"sm\" className=\"mr-2\" /> : null}\n {t('search.settings.actions.confirm', 'Confirm')}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default VectorSearchSection\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,237 @@
1
+ {
2
+ "search.api.errors.autoIndexingDisabled": "OM_DISABLE_VECTOR_SEARCH_AUTOINDEXING(레거시 별칭: DISABLE_VECTOR_SEARCH_AUTOINDEXING)에 의해 자동 인덱싱이 비활성화되어 있습니다.",
3
+ "search.api.errors.configUnavailable": "구성 서비스를 사용할 수 없습니다.",
4
+ "search.api.errors.confirmAllRequired": "모든 항목에 대한 확인이 필요합니다.",
5
+ "search.api.errors.indexFetchFailed": "인덱스 데이터를 가져오지 못했습니다.",
6
+ "search.api.errors.indexUnavailable": "검색 인덱스를 사용할 수 없습니다.",
7
+ "search.api.errors.indexerUnavailable": "검색 인덱서를 사용할 수 없습니다.",
8
+ "search.api.errors.invalidOllamaBaseUrl": "Ollama 기본 URL이 허용되지 않습니다. 환경 변수에 OLLAMA_BASE_URL을 설정하거나 OM_SEARCH_OLLAMA_BASE_URL_ALLOWLIST에 호스트를 추가하세요.",
9
+ "search.api.errors.invalidProvider": "잘못된 임베딩 제공업체입니다.",
10
+ "search.api.errors.invalidStrategies": "지정된 검색 전략이 잘못되었습니다.",
11
+ "search.api.errors.lockFailed": "인덱스 잠금을 획득하지 못했습니다.",
12
+ "search.api.errors.missingQuery": "검색어는 필수입니다.",
13
+ "search.api.errors.noIndexableStrategy": "사용 가능한 인덱싱 전략이 없습니다.",
14
+ "search.api.errors.providerNotConfigured": "제공업체가 구성되지 않았습니다. 필요한 환경 변수를 설정하세요.",
15
+ "search.api.errors.providerUnavailable": "선택한 제공자를 사용할 수 없습니다.",
16
+ "search.api.errors.purgeFailed": "검색 인덱스 삭제에 실패했습니다.",
17
+ "search.api.errors.recreateFailed": "새 차원으로 벡터 테이블을 재생성하지 못했습니다.",
18
+ "search.api.errors.reindexFailed": "재인덱싱 작업에 실패했습니다.",
19
+ "search.api.errors.reindexInProgress": "이미 재인덱싱이 진행 중입니다.",
20
+ "search.api.errors.scopedQueueCancelFailed": "대기 중인 재인덱싱 작업 취소에 실패했습니다.",
21
+ "search.api.errors.scopedQueueCancelUnavailable": "범위 지정 대기열 취소를 사용할 수 없습니다.",
22
+ "search.api.errors.searchFailed": "검색 작업에 실패했습니다.",
23
+ "search.api.errors.serviceUnavailable": "검색 서비스를 사용할 수 없습니다.",
24
+ "search.api.errors.strategyUnavailable": "요청한 검색 전략을 사용할 수 없습니다.",
25
+ "search.api.errors.updateFailed": "검색 설정 업데이트에 실패했습니다.",
26
+ "search.api.errors.vectorUnavailable": "벡터 검색을 사용할 수 없습니다.",
27
+ "search.config.nav.hybridSearch": "검색 설정",
28
+ "search.dialog.actions.cancel": "취소 (Esc)",
29
+ "search.dialog.actions.clear": "검색 지우기",
30
+ "search.dialog.actions.openGlobalSearch": "전역 검색 열기",
31
+ "search.dialog.actions.openSelected": "열기 (Enter)",
32
+ "search.dialog.actions.search": "검색",
33
+ "search.dialog.empty.hint": "인덱싱된 레코드를 검색하려면 최소 {{count}}자를 입력하세요.",
34
+ "search.dialog.empty.none": "결과를 찾을 수 없습니다.",
35
+ "search.dialog.errors.noPermission": "전역 검색을 사용할 권한이 없습니다.",
36
+ "search.dialog.errors.searchFailed": "검색에 실패했습니다.",
37
+ "search.dialog.input.placeholder": "고객, 메모, 딜, 할 일 검색...",
38
+ "search.dialog.instructions": "인덱싱된 레코드를 검색하려면 입력하세요. 화살표 키로 결과를 탐색하세요.",
39
+ "search.dialog.noLink": "링크 없음",
40
+ "search.dialog.noLinkHint": "이 엔터티 유형에 대한 search.ts 구성이 없습니다",
41
+ "search.dialog.score.title": "관련성 점수",
42
+ "search.dialog.shortcuts.hint": "Cmd+K를 눌러 전환하세요. Enter로 엽니다",
43
+ "search.dialog.strategies.exact": "정확히 일치",
44
+ "search.dialog.strategies.exactDescription": "정확한 키워드 매칭",
45
+ "search.dialog.strategies.fuzzy": "유사 검색",
46
+ "search.dialog.strategies.fuzzyDescription": "오타에 강한 전체 텍스트 검색",
47
+ "search.dialog.strategies.label": "검색 방식:",
48
+ "search.dialog.strategies.semantic": "의미 기반",
49
+ "search.dialog.strategies.semanticDescription": "AI 기반 의미 기반 검색",
50
+ "search.dialog.strategies.toggle": "검색 옵션",
51
+ "search.dialog.title": "전역 검색",
52
+ "search.dialog.warnings.configureLink": "검색 설정 구성",
53
+ "search.entityType.catalog.catalog_offer": "권하다",
54
+ "search.entityType.catalog.catalog_option_schema_template": "옵션 템플릿",
55
+ "search.entityType.catalog.catalog_price_kind": "가격 유형",
56
+ "search.entityType.catalog.catalog_product": "제품",
57
+ "search.entityType.catalog.catalog_product_category": "범주",
58
+ "search.entityType.catalog.catalog_product_tag": "꼬리표",
59
+ "search.entityType.catalog.catalog_product_unit_conversion": "단위 변환",
60
+ "search.entityType.catalog.catalog_product_variant": "변종",
61
+ "search.entityType.customer_accounts.customer_role": "고객 역할",
62
+ "search.entityType.customer_accounts.customer_user": "고객 사용자",
63
+ "search.entityType.customers.customer_activity": "활동",
64
+ "search.entityType.customers.customer_comment": "논평",
65
+ "search.entityType.customers.customer_company_profile": "회사",
66
+ "search.entityType.customers.customer_deal": "거래",
67
+ "search.entityType.customers.customer_entity": "고객",
68
+ "search.entityType.customers.customer_person_profile": "사람",
69
+ "search.entityType.customers.customer_todo_link": "일",
70
+ "search.entityType.inbox_ops.inbox_proposal": "받은 편지함 제안",
71
+ "search.entityType.messages.message": "메시지",
72
+ "search.entityType.planner.planner_availability_rule_set": "가용성 규칙",
73
+ "search.entityType.resources.resources_resource": "의지",
74
+ "search.entityType.resources.resources_resource_type": "리소스 유형",
75
+ "search.entityType.sales.sales_channel": "채널",
76
+ "search.entityType.sales.sales_credit_memo": "신용 메모",
77
+ "search.entityType.sales.sales_credit_memo_line": "대변 ​​메모 라인",
78
+ "search.entityType.sales.sales_delivery_window": "배송 기간",
79
+ "search.entityType.sales.sales_document_address": "문서 주소",
80
+ "search.entityType.sales.sales_document_tag": "문서 태그",
81
+ "search.entityType.sales.sales_invoice": "송장",
82
+ "search.entityType.sales.sales_invoice_line": "송장 라인",
83
+ "search.entityType.sales.sales_note": "메모",
84
+ "search.entityType.sales.sales_order": "주문하다",
85
+ "search.entityType.sales.sales_order_adjustment": "주문 조정",
86
+ "search.entityType.sales.sales_order_line": "주문 라인",
87
+ "search.entityType.sales.sales_payment": "지불",
88
+ "search.entityType.sales.sales_payment_allocation": "지불 할당",
89
+ "search.entityType.sales.sales_payment_method": "결제수단",
90
+ "search.entityType.sales.sales_quote": "인용하다",
91
+ "search.entityType.sales.sales_quote_adjustment": "견적 조정",
92
+ "search.entityType.sales.sales_quote_line": "견적 라인",
93
+ "search.entityType.sales.sales_shipment": "선적",
94
+ "search.entityType.sales.sales_shipment_item": "배송 품목",
95
+ "search.entityType.sales.sales_shipping_method": "배송 방법",
96
+ "search.entityType.sales.sales_tax_rate": "세율",
97
+ "search.entityType.staff.staff_team": "팀",
98
+ "search.entityType.staff.staff_team_member": "팀원",
99
+ "search.entityType.staff.staff_team_role": "팀 역할",
100
+ "search.messages.missingConfig": "의미 기반 검색을 사용하려면 임베딩 제공업체를 구성해야 합니다.",
101
+ "search.nav.hybridSearch": "검색",
102
+ "search.scopeHint.currentOrg": "현재 조직으로 범위 지정됨",
103
+ "search.settings.actions.apply": "적용",
104
+ "search.settings.actions.cancel": "취소",
105
+ "search.settings.actions.confirm": "확인",
106
+ "search.settings.actions.loading": "불러오는 중...",
107
+ "search.settings.actions.refresh": "새로고침",
108
+ "search.settings.activity.noLogs": "아직 활동 로그가 없습니다.",
109
+ "search.settings.autoIndexing.description": "새로 생성되거나 업데이트된 레코드를 벡터 검색을 위해 자동으로 인덱싱합니다.",
110
+ "search.settings.autoIndexing.label": "자동 인덱싱 활성화",
111
+ "search.settings.autoIndexing.locked": "환경 변수를 통해 비활성화되었습니다.",
112
+ "search.settings.badge.ready": "준비됨",
113
+ "search.settings.badge.setup": "설정 필요",
114
+ "search.settings.cancelLabel": "취소",
115
+ "search.settings.change.bullet1": "기존 벡터 데이터가 지워집니다",
116
+ "search.settings.change.bullet2": "재인덱싱하는 동안 벡터 검색을 사용할 수 없습니다",
117
+ "search.settings.change.description": "임베딩 제공업체를 변경하려면 모든 데이터를 재인덱싱해야 합니다.",
118
+ "search.settings.change.title": "제공업체 변경 확인",
119
+ "search.settings.clearIndexDescription": "검색 엔진에서 모든 인덱싱된 데이터를 제거합니다.",
120
+ "search.settings.clearIndexDialogDescription": "인덱싱된 모든 데이터가 영구적으로 제거됩니다.",
121
+ "search.settings.clearIndexDialogTitle": "검색 인덱스 지우기",
122
+ "search.settings.clearIndexDialogWarning": "이 작업은 되돌릴 수 없습니다.",
123
+ "search.settings.clearIndexLabel": "인덱스 지우기",
124
+ "search.settings.dimension.label": "차원",
125
+ "search.settings.dimension.mismatch": "불일치",
126
+ "search.settings.documentsLabel": "문서",
127
+ "search.settings.errorLabel": "오류",
128
+ "search.settings.errors.dimensionRequired": "유효한 차원을 입력하세요",
129
+ "search.settings.errors.loadFailed": "설정을 불러오지 못했습니다",
130
+ "search.settings.errors.modelRequired": "모델 이름을 입력하세요",
131
+ "search.settings.errors.reindexFailed": "재인덱싱에 실패했습니다",
132
+ "search.settings.errors.saveFailed": "설정 저장에 실패했습니다",
133
+ "search.settings.fullReindexDescription": "전체 검색 인덱스를 처음부터 다시 빌드합니다.",
134
+ "search.settings.fullReindexDialogDescription": "모든 검색 인덱스를 다시 빌드합니다.",
135
+ "search.settings.fullReindexDialogTitle": "전체 재인덱싱",
136
+ "search.settings.fullReindexDialogWarning": "대용량 데이터셋의 경우 시간이 걸릴 수 있습니다.",
137
+ "search.settings.fullReindexLabel": "전체 재인덱싱",
138
+ "search.settings.fulltext.currentValue": "현재 값",
139
+ "search.settings.fulltext.defaultValue": "기본값",
140
+ "search.settings.fulltext.driver": "드라이버",
141
+ "search.settings.fulltext.envMissing": "환경 변수가 설정되지 않았습니다.",
142
+ "search.settings.fulltext.envSet": "환경 변수가 설정되어 있습니다.",
143
+ "search.settings.fulltext.envVars": "환경 변수",
144
+ "search.settings.fulltext.howTo": "구성 방법",
145
+ "search.settings.fulltext.howToDescription": "전체 텍스트 검색을 활성화하려면 필요한 환경 변수를 설정하세요.",
146
+ "search.settings.fulltext.learnMore": "더 알아보기",
147
+ "search.settings.fulltext.noDriver": "구성된 전체 텍스트 드라이버가 없습니다.",
148
+ "search.settings.fulltext.notReady": "준비되지 않음",
149
+ "search.settings.fulltext.optional": "선택 사항",
150
+ "search.settings.fulltext.ready": "준비됨",
151
+ "search.settings.fulltext.sectionDescription": "Meilisearch로 구동되는 전체 텍스트 검색을 구성합니다.",
152
+ "search.settings.fulltext.sectionTitle": "전체 텍스트 검색",
153
+ "search.settings.fulltextNotConfigured": "전체 텍스트 검색이 구성되지 않았습니다.",
154
+ "search.settings.fulltextNotConfiguredHint": "전체 텍스트 검색을 활성화하려면 MEILISEARCH_HOST를 설정하세요.",
155
+ "search.settings.globalSearch.description": "전역 검색 대화상자(Cmd+K)를 구동할 전략을 구성합니다.",
156
+ "search.settings.globalSearch.fulltext": "전체 텍스트",
157
+ "search.settings.globalSearch.fulltextDescription": "Meilisearch로 구동되는 오타에 강한 검색입니다.",
158
+ "search.settings.globalSearch.notConfigured": "구성되지 않음",
159
+ "search.settings.globalSearch.saveError": "전역 검색 설정 저장에 실패했습니다.",
160
+ "search.settings.globalSearch.title": "전역 검색",
161
+ "search.settings.globalSearch.tokens": "토큰",
162
+ "search.settings.globalSearch.tokensDescription": "PostgreSQL을 사용한 키워드 기반 검색입니다.",
163
+ "search.settings.globalSearch.vector": "벡터",
164
+ "search.settings.globalSearch.vectorDescription": "임베딩을 사용한 AI 기반 의미 기반 검색입니다.",
165
+ "search.settings.loading": "불러오는 중...",
166
+ "search.settings.loadingLabel": "불러오는 중…",
167
+ "search.settings.messages.providerSaved": "임베딩 제공업체가 저장되었습니다",
168
+ "search.settings.messages.reindexStarted": "재인덱싱이 시작되었습니다",
169
+ "search.settings.messages.saved": "설정이 저장되었습니다",
170
+ "search.settings.model.custom": "커스텀...",
171
+ "search.settings.model.label": "모델",
172
+ "search.settings.model.namePlaceholder": "모델 이름",
173
+ "search.settings.noIndexMessage": "아직 생성된 검색 인덱스가 없습니다.",
174
+ "search.settings.pageDescription": "검색 전략을 구성하고, 인덱스를 관리하고, 활동을 모니터링합니다.",
175
+ "search.settings.pageTitle": "검색 설정",
176
+ "search.settings.processingLabel": "처리 중…",
177
+ "search.settings.provider.label": "제공업체",
178
+ "search.settings.provider.notConfigured": "구성되지 않음",
179
+ "search.settings.provider.title": "임베딩 제공업체",
180
+ "search.settings.recreateIndexDescription": "검색 인덱스 구조를 삭제하고 다시 생성합니다.",
181
+ "search.settings.recreateIndexDialogDescription": "검색 인덱스를 삭제하고 다시 생성합니다.",
182
+ "search.settings.recreateIndexDialogTitle": "검색 인덱스 재생성",
183
+ "search.settings.recreateIndexDialogWarning": "인덱싱된 모든 데이터가 손실됩니다.",
184
+ "search.settings.recreateIndexLabel": "인덱스 재생성",
185
+ "search.settings.refreshLabel": "새로고침",
186
+ "search.settings.reindex.button": "재인덱싱 시작",
187
+ "search.settings.reindex.confirmButton": "재인덱싱 시작",
188
+ "search.settings.reindex.confirmDescription": "모든 벡터 임베딩을 다시 빌드합니다. 기존 데이터가 먼저 삭제됩니다.",
189
+ "search.settings.reindex.confirmTitle": "재인덱싱 확인",
190
+ "search.settings.reindex.description": "인덱싱된 모든 엔터티에 대해 벡터 임베딩을 다시 빌드합니다.",
191
+ "search.settings.reindex.running": "재인덱싱 중...",
192
+ "search.settings.reindex.title": "데이터 재인덱싱",
193
+ "search.settings.reindex.warning": "대용량 데이터셋의 경우 시간이 걸릴 수 있습니다.",
194
+ "search.settings.reindexErrorLabel": "재인덱싱 실패",
195
+ "search.settings.reindexInProgress": "재인덱싱 진행 중",
196
+ "search.settings.reindexInProgressDetails": "현재 재인덱싱 작업이 실행 중입니다. 완료될 때까지 기다려 주세요.",
197
+ "search.settings.reindexSuccessLabel": "재인덱싱 완료",
198
+ "search.settings.status.configured": "벡터 검색이 구성됨",
199
+ "search.settings.status.notConfigured": "벡터 검색이 구성되지 않음",
200
+ "search.settings.status.title": "자동 인덱싱",
201
+ "search.settings.tabs.activity": "활동",
202
+ "search.settings.tabs.configuration": "구성",
203
+ "search.settings.tabs.indexManagement": "인덱스 관리",
204
+ "search.settings.title": "검색 설정",
205
+ "search.settings.vector.active": "활성",
206
+ "search.settings.vector.comingSoon": "출시 예정",
207
+ "search.settings.vector.howTo": "구성 방법",
208
+ "search.settings.vector.howToDescription": "벡터 검색을 활성화하려면 임베딩 제공업체를 설정하세요.",
209
+ "search.settings.vector.inheritingDefault": "이 테넌트는 인스턴스/환경 기본값을 상속받고 있습니다. 제공자를 저장하면 이 테넌트에 대한 오버라이드가 생성됩니다.",
210
+ "search.settings.vector.modelsAvailable": "사용 가능한 모델",
211
+ "search.settings.vector.providers": "제공업체",
212
+ "search.settings.vector.providersHint": "환경 변수를 통해 임베딩 제공업체를 구성하세요.",
213
+ "search.settings.vector.sectionDescription": "벡터 임베딩을 사용한 AI 기반 의미 기반 검색을 구성합니다.",
214
+ "search.settings.vector.sectionTitle": "벡터 검색",
215
+ "search.settings.vector.setEnvVar": "환경 변수 설정",
216
+ "search.settings.vector.store": "벡터 저장소",
217
+ "search.settings.vector.usingTenantConfig": "이 테넌트는 자체 임베딩 설정을 사용하고 있습니다.",
218
+ "search.settings.vectorDocumentsLabel": "벡터 문서",
219
+ "search.settings.vectorNotConfigured": "벡터 검색이 구성되지 않았습니다.",
220
+ "search.settings.vectorNotConfiguredHint": "벡터 검색을 활성화하려면 임베딩 제공업체 API 키를 설정하세요.",
221
+ "search.settings.vectorReindex.button": "벡터 재인덱싱 시작",
222
+ "search.settings.vectorReindex.description": "원본 데이터로부터 모든 벡터 임베딩을 다시 빌드합니다.",
223
+ "search.settings.vectorReindex.running": "벡터 재인덱싱 진행 중…",
224
+ "search.settings.vectorReindex.title": "벡터 재인덱싱",
225
+ "search.settings.vectorReindex.warning": "기존 임베딩을 삭제하고 다시 생성합니다.",
226
+ "search.table.actions.open": "열기",
227
+ "search.table.columns.result": "결과",
228
+ "search.table.columns.score": "점수",
229
+ "search.table.columns.source": "소스",
230
+ "search.table.errors.noSources": "사용 가능한 검색 소스가 없습니다.",
231
+ "search.table.errors.searchFailed": "검색에 실패했습니다.",
232
+ "search.table.searchPlaceholder": "검색…",
233
+ "search.table.sources": "소스",
234
+ "search.table.stats.results": "결과",
235
+ "search.table.stats.sources": "소스",
236
+ "search.table.title": "검색 결과"
237
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/search",
3
- "version": "0.6.7-develop.6828.1.ab1620a63e",
3
+ "version": "0.6.7-develop.6842.1.8cd8a8883c",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -127,9 +127,9 @@
127
127
  "zod": "^4.4.3"
128
128
  },
129
129
  "peerDependencies": {
130
- "@open-mercato/core": "0.6.7-develop.6828.1.ab1620a63e",
131
- "@open-mercato/queue": "0.6.7-develop.6828.1.ab1620a63e",
132
- "@open-mercato/shared": "0.6.7-develop.6828.1.ab1620a63e"
130
+ "@open-mercato/core": "0.6.7-develop.6842.1.8cd8a8883c",
131
+ "@open-mercato/queue": "0.6.7-develop.6842.1.8cd8a8883c",
132
+ "@open-mercato/shared": "0.6.7-develop.6842.1.8cd8a8883c"
133
133
  },
134
134
  "devDependencies": {
135
135
  "@types/jest": "^30.0.0",
@@ -979,7 +979,7 @@ export function VectorSearchSection({
979
979
  <Button type="button" variant="outline" onClick={handleEmbeddingCancelChange} disabled={embeddingSaving}>
980
980
  {t('search.settings.actions.cancel', 'Cancel')}
981
981
  </Button>
982
- <Button type="button" variant="destructive" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>
982
+ <Button type="button" variant="destructive-solid" onClick={handleEmbeddingConfirmChange} disabled={embeddingSaving}>
983
983
  {embeddingSaving ? <Spinner size="sm" className="mr-2" /> : null}
984
984
  {t('search.settings.actions.confirm', 'Confirm')}
985
985
  </Button>
@@ -0,0 +1,237 @@
1
+ {
2
+ "search.api.errors.autoIndexingDisabled": "OM_DISABLE_VECTOR_SEARCH_AUTOINDEXING(레거시 별칭: DISABLE_VECTOR_SEARCH_AUTOINDEXING)에 의해 자동 인덱싱이 비활성화되어 있습니다.",
3
+ "search.api.errors.configUnavailable": "구성 서비스를 사용할 수 없습니다.",
4
+ "search.api.errors.confirmAllRequired": "모든 항목에 대한 확인이 필요합니다.",
5
+ "search.api.errors.indexFetchFailed": "인덱스 데이터를 가져오지 못했습니다.",
6
+ "search.api.errors.indexUnavailable": "검색 인덱스를 사용할 수 없습니다.",
7
+ "search.api.errors.indexerUnavailable": "검색 인덱서를 사용할 수 없습니다.",
8
+ "search.api.errors.invalidOllamaBaseUrl": "Ollama 기본 URL이 허용되지 않습니다. 환경 변수에 OLLAMA_BASE_URL을 설정하거나 OM_SEARCH_OLLAMA_BASE_URL_ALLOWLIST에 호스트를 추가하세요.",
9
+ "search.api.errors.invalidProvider": "잘못된 임베딩 제공업체입니다.",
10
+ "search.api.errors.invalidStrategies": "지정된 검색 전략이 잘못되었습니다.",
11
+ "search.api.errors.lockFailed": "인덱스 잠금을 획득하지 못했습니다.",
12
+ "search.api.errors.missingQuery": "검색어는 필수입니다.",
13
+ "search.api.errors.noIndexableStrategy": "사용 가능한 인덱싱 전략이 없습니다.",
14
+ "search.api.errors.providerNotConfigured": "제공업체가 구성되지 않았습니다. 필요한 환경 변수를 설정하세요.",
15
+ "search.api.errors.providerUnavailable": "선택한 제공자를 사용할 수 없습니다.",
16
+ "search.api.errors.purgeFailed": "검색 인덱스 삭제에 실패했습니다.",
17
+ "search.api.errors.recreateFailed": "새 차원으로 벡터 테이블을 재생성하지 못했습니다.",
18
+ "search.api.errors.reindexFailed": "재인덱싱 작업에 실패했습니다.",
19
+ "search.api.errors.reindexInProgress": "이미 재인덱싱이 진행 중입니다.",
20
+ "search.api.errors.scopedQueueCancelFailed": "대기 중인 재인덱싱 작업 취소에 실패했습니다.",
21
+ "search.api.errors.scopedQueueCancelUnavailable": "범위 지정 대기열 취소를 사용할 수 없습니다.",
22
+ "search.api.errors.searchFailed": "검색 작업에 실패했습니다.",
23
+ "search.api.errors.serviceUnavailable": "검색 서비스를 사용할 수 없습니다.",
24
+ "search.api.errors.strategyUnavailable": "요청한 검색 전략을 사용할 수 없습니다.",
25
+ "search.api.errors.updateFailed": "검색 설정 업데이트에 실패했습니다.",
26
+ "search.api.errors.vectorUnavailable": "벡터 검색을 사용할 수 없습니다.",
27
+ "search.config.nav.hybridSearch": "검색 설정",
28
+ "search.dialog.actions.cancel": "취소 (Esc)",
29
+ "search.dialog.actions.clear": "검색 지우기",
30
+ "search.dialog.actions.openGlobalSearch": "전역 검색 열기",
31
+ "search.dialog.actions.openSelected": "열기 (Enter)",
32
+ "search.dialog.actions.search": "검색",
33
+ "search.dialog.empty.hint": "인덱싱된 레코드를 검색하려면 최소 {{count}}자를 입력하세요.",
34
+ "search.dialog.empty.none": "결과를 찾을 수 없습니다.",
35
+ "search.dialog.errors.noPermission": "전역 검색을 사용할 권한이 없습니다.",
36
+ "search.dialog.errors.searchFailed": "검색에 실패했습니다.",
37
+ "search.dialog.input.placeholder": "고객, 메모, 딜, 할 일 검색...",
38
+ "search.dialog.instructions": "인덱싱된 레코드를 검색하려면 입력하세요. 화살표 키로 결과를 탐색하세요.",
39
+ "search.dialog.noLink": "링크 없음",
40
+ "search.dialog.noLinkHint": "이 엔터티 유형에 대한 search.ts 구성이 없습니다",
41
+ "search.dialog.score.title": "관련성 점수",
42
+ "search.dialog.shortcuts.hint": "Cmd+K를 눌러 전환하세요. Enter로 엽니다",
43
+ "search.dialog.strategies.exact": "정확히 일치",
44
+ "search.dialog.strategies.exactDescription": "정확한 키워드 매칭",
45
+ "search.dialog.strategies.fuzzy": "유사 검색",
46
+ "search.dialog.strategies.fuzzyDescription": "오타에 강한 전체 텍스트 검색",
47
+ "search.dialog.strategies.label": "검색 방식:",
48
+ "search.dialog.strategies.semantic": "의미 기반",
49
+ "search.dialog.strategies.semanticDescription": "AI 기반 의미 기반 검색",
50
+ "search.dialog.strategies.toggle": "검색 옵션",
51
+ "search.dialog.title": "전역 검색",
52
+ "search.dialog.warnings.configureLink": "검색 설정 구성",
53
+ "search.entityType.catalog.catalog_offer": "권하다",
54
+ "search.entityType.catalog.catalog_option_schema_template": "옵션 템플릿",
55
+ "search.entityType.catalog.catalog_price_kind": "가격 유형",
56
+ "search.entityType.catalog.catalog_product": "제품",
57
+ "search.entityType.catalog.catalog_product_category": "범주",
58
+ "search.entityType.catalog.catalog_product_tag": "꼬리표",
59
+ "search.entityType.catalog.catalog_product_unit_conversion": "단위 변환",
60
+ "search.entityType.catalog.catalog_product_variant": "변종",
61
+ "search.entityType.customer_accounts.customer_role": "고객 역할",
62
+ "search.entityType.customer_accounts.customer_user": "고객 사용자",
63
+ "search.entityType.customers.customer_activity": "활동",
64
+ "search.entityType.customers.customer_comment": "논평",
65
+ "search.entityType.customers.customer_company_profile": "회사",
66
+ "search.entityType.customers.customer_deal": "거래",
67
+ "search.entityType.customers.customer_entity": "고객",
68
+ "search.entityType.customers.customer_person_profile": "사람",
69
+ "search.entityType.customers.customer_todo_link": "일",
70
+ "search.entityType.inbox_ops.inbox_proposal": "받은 편지함 제안",
71
+ "search.entityType.messages.message": "메시지",
72
+ "search.entityType.planner.planner_availability_rule_set": "가용성 규칙",
73
+ "search.entityType.resources.resources_resource": "의지",
74
+ "search.entityType.resources.resources_resource_type": "리소스 유형",
75
+ "search.entityType.sales.sales_channel": "채널",
76
+ "search.entityType.sales.sales_credit_memo": "신용 메모",
77
+ "search.entityType.sales.sales_credit_memo_line": "대변 ​​메모 라인",
78
+ "search.entityType.sales.sales_delivery_window": "배송 기간",
79
+ "search.entityType.sales.sales_document_address": "문서 주소",
80
+ "search.entityType.sales.sales_document_tag": "문서 태그",
81
+ "search.entityType.sales.sales_invoice": "송장",
82
+ "search.entityType.sales.sales_invoice_line": "송장 라인",
83
+ "search.entityType.sales.sales_note": "메모",
84
+ "search.entityType.sales.sales_order": "주문하다",
85
+ "search.entityType.sales.sales_order_adjustment": "주문 조정",
86
+ "search.entityType.sales.sales_order_line": "주문 라인",
87
+ "search.entityType.sales.sales_payment": "지불",
88
+ "search.entityType.sales.sales_payment_allocation": "지불 할당",
89
+ "search.entityType.sales.sales_payment_method": "결제수단",
90
+ "search.entityType.sales.sales_quote": "인용하다",
91
+ "search.entityType.sales.sales_quote_adjustment": "견적 조정",
92
+ "search.entityType.sales.sales_quote_line": "견적 라인",
93
+ "search.entityType.sales.sales_shipment": "선적",
94
+ "search.entityType.sales.sales_shipment_item": "배송 품목",
95
+ "search.entityType.sales.sales_shipping_method": "배송 방법",
96
+ "search.entityType.sales.sales_tax_rate": "세율",
97
+ "search.entityType.staff.staff_team": "팀",
98
+ "search.entityType.staff.staff_team_member": "팀원",
99
+ "search.entityType.staff.staff_team_role": "팀 역할",
100
+ "search.messages.missingConfig": "의미 기반 검색을 사용하려면 임베딩 제공업체를 구성해야 합니다.",
101
+ "search.nav.hybridSearch": "검색",
102
+ "search.scopeHint.currentOrg": "현재 조직으로 범위 지정됨",
103
+ "search.settings.actions.apply": "적용",
104
+ "search.settings.actions.cancel": "취소",
105
+ "search.settings.actions.confirm": "확인",
106
+ "search.settings.actions.loading": "불러오는 중...",
107
+ "search.settings.actions.refresh": "새로고침",
108
+ "search.settings.activity.noLogs": "아직 활동 로그가 없습니다.",
109
+ "search.settings.autoIndexing.description": "새로 생성되거나 업데이트된 레코드를 벡터 검색을 위해 자동으로 인덱싱합니다.",
110
+ "search.settings.autoIndexing.label": "자동 인덱싱 활성화",
111
+ "search.settings.autoIndexing.locked": "환경 변수를 통해 비활성화되었습니다.",
112
+ "search.settings.badge.ready": "준비됨",
113
+ "search.settings.badge.setup": "설정 필요",
114
+ "search.settings.cancelLabel": "취소",
115
+ "search.settings.change.bullet1": "기존 벡터 데이터가 지워집니다",
116
+ "search.settings.change.bullet2": "재인덱싱하는 동안 벡터 검색을 사용할 수 없습니다",
117
+ "search.settings.change.description": "임베딩 제공업체를 변경하려면 모든 데이터를 재인덱싱해야 합니다.",
118
+ "search.settings.change.title": "제공업체 변경 확인",
119
+ "search.settings.clearIndexDescription": "검색 엔진에서 모든 인덱싱된 데이터를 제거합니다.",
120
+ "search.settings.clearIndexDialogDescription": "인덱싱된 모든 데이터가 영구적으로 제거됩니다.",
121
+ "search.settings.clearIndexDialogTitle": "검색 인덱스 지우기",
122
+ "search.settings.clearIndexDialogWarning": "이 작업은 되돌릴 수 없습니다.",
123
+ "search.settings.clearIndexLabel": "인덱스 지우기",
124
+ "search.settings.dimension.label": "차원",
125
+ "search.settings.dimension.mismatch": "불일치",
126
+ "search.settings.documentsLabel": "문서",
127
+ "search.settings.errorLabel": "오류",
128
+ "search.settings.errors.dimensionRequired": "유효한 차원을 입력하세요",
129
+ "search.settings.errors.loadFailed": "설정을 불러오지 못했습니다",
130
+ "search.settings.errors.modelRequired": "모델 이름을 입력하세요",
131
+ "search.settings.errors.reindexFailed": "재인덱싱에 실패했습니다",
132
+ "search.settings.errors.saveFailed": "설정 저장에 실패했습니다",
133
+ "search.settings.fullReindexDescription": "전체 검색 인덱스를 처음부터 다시 빌드합니다.",
134
+ "search.settings.fullReindexDialogDescription": "모든 검색 인덱스를 다시 빌드합니다.",
135
+ "search.settings.fullReindexDialogTitle": "전체 재인덱싱",
136
+ "search.settings.fullReindexDialogWarning": "대용량 데이터셋의 경우 시간이 걸릴 수 있습니다.",
137
+ "search.settings.fullReindexLabel": "전체 재인덱싱",
138
+ "search.settings.fulltext.currentValue": "현재 값",
139
+ "search.settings.fulltext.defaultValue": "기본값",
140
+ "search.settings.fulltext.driver": "드라이버",
141
+ "search.settings.fulltext.envMissing": "환경 변수가 설정되지 않았습니다.",
142
+ "search.settings.fulltext.envSet": "환경 변수가 설정되어 있습니다.",
143
+ "search.settings.fulltext.envVars": "환경 변수",
144
+ "search.settings.fulltext.howTo": "구성 방법",
145
+ "search.settings.fulltext.howToDescription": "전체 텍스트 검색을 활성화하려면 필요한 환경 변수를 설정하세요.",
146
+ "search.settings.fulltext.learnMore": "더 알아보기",
147
+ "search.settings.fulltext.noDriver": "구성된 전체 텍스트 드라이버가 없습니다.",
148
+ "search.settings.fulltext.notReady": "준비되지 않음",
149
+ "search.settings.fulltext.optional": "선택 사항",
150
+ "search.settings.fulltext.ready": "준비됨",
151
+ "search.settings.fulltext.sectionDescription": "Meilisearch로 구동되는 전체 텍스트 검색을 구성합니다.",
152
+ "search.settings.fulltext.sectionTitle": "전체 텍스트 검색",
153
+ "search.settings.fulltextNotConfigured": "전체 텍스트 검색이 구성되지 않았습니다.",
154
+ "search.settings.fulltextNotConfiguredHint": "전체 텍스트 검색을 활성화하려면 MEILISEARCH_HOST를 설정하세요.",
155
+ "search.settings.globalSearch.description": "전역 검색 대화상자(Cmd+K)를 구동할 전략을 구성합니다.",
156
+ "search.settings.globalSearch.fulltext": "전체 텍스트",
157
+ "search.settings.globalSearch.fulltextDescription": "Meilisearch로 구동되는 오타에 강한 검색입니다.",
158
+ "search.settings.globalSearch.notConfigured": "구성되지 않음",
159
+ "search.settings.globalSearch.saveError": "전역 검색 설정 저장에 실패했습니다.",
160
+ "search.settings.globalSearch.title": "전역 검색",
161
+ "search.settings.globalSearch.tokens": "토큰",
162
+ "search.settings.globalSearch.tokensDescription": "PostgreSQL을 사용한 키워드 기반 검색입니다.",
163
+ "search.settings.globalSearch.vector": "벡터",
164
+ "search.settings.globalSearch.vectorDescription": "임베딩을 사용한 AI 기반 의미 기반 검색입니다.",
165
+ "search.settings.loading": "불러오는 중...",
166
+ "search.settings.loadingLabel": "불러오는 중…",
167
+ "search.settings.messages.providerSaved": "임베딩 제공업체가 저장되었습니다",
168
+ "search.settings.messages.reindexStarted": "재인덱싱이 시작되었습니다",
169
+ "search.settings.messages.saved": "설정이 저장되었습니다",
170
+ "search.settings.model.custom": "커스텀...",
171
+ "search.settings.model.label": "모델",
172
+ "search.settings.model.namePlaceholder": "모델 이름",
173
+ "search.settings.noIndexMessage": "아직 생성된 검색 인덱스가 없습니다.",
174
+ "search.settings.pageDescription": "검색 전략을 구성하고, 인덱스를 관리하고, 활동을 모니터링합니다.",
175
+ "search.settings.pageTitle": "검색 설정",
176
+ "search.settings.processingLabel": "처리 중…",
177
+ "search.settings.provider.label": "제공업체",
178
+ "search.settings.provider.notConfigured": "구성되지 않음",
179
+ "search.settings.provider.title": "임베딩 제공업체",
180
+ "search.settings.recreateIndexDescription": "검색 인덱스 구조를 삭제하고 다시 생성합니다.",
181
+ "search.settings.recreateIndexDialogDescription": "검색 인덱스를 삭제하고 다시 생성합니다.",
182
+ "search.settings.recreateIndexDialogTitle": "검색 인덱스 재생성",
183
+ "search.settings.recreateIndexDialogWarning": "인덱싱된 모든 데이터가 손실됩니다.",
184
+ "search.settings.recreateIndexLabel": "인덱스 재생성",
185
+ "search.settings.refreshLabel": "새로고침",
186
+ "search.settings.reindex.button": "재인덱싱 시작",
187
+ "search.settings.reindex.confirmButton": "재인덱싱 시작",
188
+ "search.settings.reindex.confirmDescription": "모든 벡터 임베딩을 다시 빌드합니다. 기존 데이터가 먼저 삭제됩니다.",
189
+ "search.settings.reindex.confirmTitle": "재인덱싱 확인",
190
+ "search.settings.reindex.description": "인덱싱된 모든 엔터티에 대해 벡터 임베딩을 다시 빌드합니다.",
191
+ "search.settings.reindex.running": "재인덱싱 중...",
192
+ "search.settings.reindex.title": "데이터 재인덱싱",
193
+ "search.settings.reindex.warning": "대용량 데이터셋의 경우 시간이 걸릴 수 있습니다.",
194
+ "search.settings.reindexErrorLabel": "재인덱싱 실패",
195
+ "search.settings.reindexInProgress": "재인덱싱 진행 중",
196
+ "search.settings.reindexInProgressDetails": "현재 재인덱싱 작업이 실행 중입니다. 완료될 때까지 기다려 주세요.",
197
+ "search.settings.reindexSuccessLabel": "재인덱싱 완료",
198
+ "search.settings.status.configured": "벡터 검색이 구성됨",
199
+ "search.settings.status.notConfigured": "벡터 검색이 구성되지 않음",
200
+ "search.settings.status.title": "자동 인덱싱",
201
+ "search.settings.tabs.activity": "활동",
202
+ "search.settings.tabs.configuration": "구성",
203
+ "search.settings.tabs.indexManagement": "인덱스 관리",
204
+ "search.settings.title": "검색 설정",
205
+ "search.settings.vector.active": "활성",
206
+ "search.settings.vector.comingSoon": "출시 예정",
207
+ "search.settings.vector.howTo": "구성 방법",
208
+ "search.settings.vector.howToDescription": "벡터 검색을 활성화하려면 임베딩 제공업체를 설정하세요.",
209
+ "search.settings.vector.inheritingDefault": "이 테넌트는 인스턴스/환경 기본값을 상속받고 있습니다. 제공자를 저장하면 이 테넌트에 대한 오버라이드가 생성됩니다.",
210
+ "search.settings.vector.modelsAvailable": "사용 가능한 모델",
211
+ "search.settings.vector.providers": "제공업체",
212
+ "search.settings.vector.providersHint": "환경 변수를 통해 임베딩 제공업체를 구성하세요.",
213
+ "search.settings.vector.sectionDescription": "벡터 임베딩을 사용한 AI 기반 의미 기반 검색을 구성합니다.",
214
+ "search.settings.vector.sectionTitle": "벡터 검색",
215
+ "search.settings.vector.setEnvVar": "환경 변수 설정",
216
+ "search.settings.vector.store": "벡터 저장소",
217
+ "search.settings.vector.usingTenantConfig": "이 테넌트는 자체 임베딩 설정을 사용하고 있습니다.",
218
+ "search.settings.vectorDocumentsLabel": "벡터 문서",
219
+ "search.settings.vectorNotConfigured": "벡터 검색이 구성되지 않았습니다.",
220
+ "search.settings.vectorNotConfiguredHint": "벡터 검색을 활성화하려면 임베딩 제공업체 API 키를 설정하세요.",
221
+ "search.settings.vectorReindex.button": "벡터 재인덱싱 시작",
222
+ "search.settings.vectorReindex.description": "원본 데이터로부터 모든 벡터 임베딩을 다시 빌드합니다.",
223
+ "search.settings.vectorReindex.running": "벡터 재인덱싱 진행 중…",
224
+ "search.settings.vectorReindex.title": "벡터 재인덱싱",
225
+ "search.settings.vectorReindex.warning": "기존 임베딩을 삭제하고 다시 생성합니다.",
226
+ "search.table.actions.open": "열기",
227
+ "search.table.columns.result": "결과",
228
+ "search.table.columns.score": "점수",
229
+ "search.table.columns.source": "소스",
230
+ "search.table.errors.noSources": "사용 가능한 검색 소스가 없습니다.",
231
+ "search.table.errors.searchFailed": "검색에 실패했습니다.",
232
+ "search.table.searchPlaceholder": "검색…",
233
+ "search.table.sources": "소스",
234
+ "search.table.stats.results": "결과",
235
+ "search.table.stats.sources": "소스",
236
+ "search.table.title": "검색 결과"
237
+ }