@open-mercato/search 0.4.2-canary-c02407ff85

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.
Files changed (237) hide show
  1. package/AGENTS.md +678 -0
  2. package/build.mjs +92 -0
  3. package/dist/di.js +157 -0
  4. package/dist/di.js.map +7 -0
  5. package/dist/fulltext/drivers/index.js +21 -0
  6. package/dist/fulltext/drivers/index.js.map +7 -0
  7. package/dist/fulltext/drivers/meilisearch/index.js +320 -0
  8. package/dist/fulltext/drivers/meilisearch/index.js.map +7 -0
  9. package/dist/fulltext/index.js +7 -0
  10. package/dist/fulltext/index.js.map +7 -0
  11. package/dist/fulltext/types.js +1 -0
  12. package/dist/fulltext/types.js.map +7 -0
  13. package/dist/index.js +12 -0
  14. package/dist/index.js.map +7 -0
  15. package/dist/indexer/index.js +8 -0
  16. package/dist/indexer/index.js.map +7 -0
  17. package/dist/indexer/search-indexer.js +848 -0
  18. package/dist/indexer/search-indexer.js.map +7 -0
  19. package/dist/indexer/subscribers/delete.js +41 -0
  20. package/dist/indexer/subscribers/delete.js.map +7 -0
  21. package/dist/lib/debug.js +34 -0
  22. package/dist/lib/debug.js.map +7 -0
  23. package/dist/lib/fallback-presenter.js +107 -0
  24. package/dist/lib/fallback-presenter.js.map +7 -0
  25. package/dist/lib/field-policy.js +75 -0
  26. package/dist/lib/field-policy.js.map +7 -0
  27. package/dist/lib/index.js +19 -0
  28. package/dist/lib/index.js.map +7 -0
  29. package/dist/lib/merger.js +93 -0
  30. package/dist/lib/merger.js.map +7 -0
  31. package/dist/lib/presenter-enricher.js +192 -0
  32. package/dist/lib/presenter-enricher.js.map +7 -0
  33. package/dist/modules/search/acl.js +14 -0
  34. package/dist/modules/search/acl.js.map +7 -0
  35. package/dist/modules/search/ai-tools.js +284 -0
  36. package/dist/modules/search/ai-tools.js.map +7 -0
  37. package/dist/modules/search/api/embeddings/reindex/cancel/route.js +65 -0
  38. package/dist/modules/search/api/embeddings/reindex/cancel/route.js.map +7 -0
  39. package/dist/modules/search/api/embeddings/reindex/route.js +165 -0
  40. package/dist/modules/search/api/embeddings/reindex/route.js.map +7 -0
  41. package/dist/modules/search/api/embeddings/route.js +246 -0
  42. package/dist/modules/search/api/embeddings/route.js.map +7 -0
  43. package/dist/modules/search/api/index/route.js +245 -0
  44. package/dist/modules/search/api/index/route.js.map +7 -0
  45. package/dist/modules/search/api/reindex/cancel/route.js +65 -0
  46. package/dist/modules/search/api/reindex/cancel/route.js.map +7 -0
  47. package/dist/modules/search/api/reindex/route.js +332 -0
  48. package/dist/modules/search/api/reindex/route.js.map +7 -0
  49. package/dist/modules/search/api/search/global/route.js +100 -0
  50. package/dist/modules/search/api/search/global/route.js.map +7 -0
  51. package/dist/modules/search/api/search/route.js +101 -0
  52. package/dist/modules/search/api/search/route.js.map +7 -0
  53. package/dist/modules/search/api/settings/fulltext/route.js +55 -0
  54. package/dist/modules/search/api/settings/fulltext/route.js.map +7 -0
  55. package/dist/modules/search/api/settings/global-search/route.js +80 -0
  56. package/dist/modules/search/api/settings/global-search/route.js.map +7 -0
  57. package/dist/modules/search/api/settings/route.js +118 -0
  58. package/dist/modules/search/api/settings/route.js.map +7 -0
  59. package/dist/modules/search/api/settings/vector-store/route.js +77 -0
  60. package/dist/modules/search/api/settings/vector-store/route.js.map +7 -0
  61. package/dist/modules/search/backend/config/search/page.js +10 -0
  62. package/dist/modules/search/backend/config/search/page.js.map +7 -0
  63. package/dist/modules/search/backend/config/search/page.meta.js +24 -0
  64. package/dist/modules/search/backend/config/search/page.meta.js.map +7 -0
  65. package/dist/modules/search/cli.js +698 -0
  66. package/dist/modules/search/cli.js.map +7 -0
  67. package/dist/modules/search/di.js +32 -0
  68. package/dist/modules/search/di.js.map +7 -0
  69. package/dist/modules/search/frontend/components/GlobalSearchDialog.js +357 -0
  70. package/dist/modules/search/frontend/components/GlobalSearchDialog.js.map +7 -0
  71. package/dist/modules/search/frontend/components/HybridSearchTable.js +343 -0
  72. package/dist/modules/search/frontend/components/HybridSearchTable.js.map +7 -0
  73. package/dist/modules/search/frontend/components/SearchSettingsPageClient.js +303 -0
  74. package/dist/modules/search/frontend/components/SearchSettingsPageClient.js.map +7 -0
  75. package/dist/modules/search/frontend/components/sections/FulltextSearchSection.js +360 -0
  76. package/dist/modules/search/frontend/components/sections/FulltextSearchSection.js.map +7 -0
  77. package/dist/modules/search/frontend/components/sections/GlobalSearchSection.js +101 -0
  78. package/dist/modules/search/frontend/components/sections/GlobalSearchSection.js.map +7 -0
  79. package/dist/modules/search/frontend/components/sections/VectorSearchSection.js +608 -0
  80. package/dist/modules/search/frontend/components/sections/VectorSearchSection.js.map +7 -0
  81. package/dist/modules/search/frontend/index.js +9 -0
  82. package/dist/modules/search/frontend/index.js.map +7 -0
  83. package/dist/modules/search/frontend/utils.js +41 -0
  84. package/dist/modules/search/frontend/utils.js.map +7 -0
  85. package/dist/modules/search/i18n/de.json +61 -0
  86. package/dist/modules/search/i18n/en.json +72 -0
  87. package/dist/modules/search/i18n/es.json +61 -0
  88. package/dist/modules/search/i18n/pl.json +61 -0
  89. package/dist/modules/search/index.js +11 -0
  90. package/dist/modules/search/index.js.map +7 -0
  91. package/dist/modules/search/lib/auto-indexing.js +29 -0
  92. package/dist/modules/search/lib/auto-indexing.js.map +7 -0
  93. package/dist/modules/search/lib/embedding-config.js +131 -0
  94. package/dist/modules/search/lib/embedding-config.js.map +7 -0
  95. package/dist/modules/search/lib/global-search-config.js +45 -0
  96. package/dist/modules/search/lib/global-search-config.js.map +7 -0
  97. package/dist/modules/search/lib/reindex-lock.js +99 -0
  98. package/dist/modules/search/lib/reindex-lock.js.map +7 -0
  99. package/dist/modules/search/subscribers/fulltext_upsert.js +64 -0
  100. package/dist/modules/search/subscribers/fulltext_upsert.js.map +7 -0
  101. package/dist/modules/search/subscribers/vector_delete.js +58 -0
  102. package/dist/modules/search/subscribers/vector_delete.js.map +7 -0
  103. package/dist/modules/search/subscribers/vector_purge.js +142 -0
  104. package/dist/modules/search/subscribers/vector_purge.js.map +7 -0
  105. package/dist/modules/search/subscribers/vector_upsert.js +58 -0
  106. package/dist/modules/search/subscribers/vector_upsert.js.map +7 -0
  107. package/dist/modules/search/workers/fulltext-index.worker.js +240 -0
  108. package/dist/modules/search/workers/fulltext-index.worker.js.map +7 -0
  109. package/dist/modules/search/workers/vector-index.worker.js +234 -0
  110. package/dist/modules/search/workers/vector-index.worker.js.map +7 -0
  111. package/dist/queue/fulltext-indexing.js +15 -0
  112. package/dist/queue/fulltext-indexing.js.map +7 -0
  113. package/dist/queue/index.js +3 -0
  114. package/dist/queue/index.js.map +7 -0
  115. package/dist/queue/vector-indexing.js +15 -0
  116. package/dist/queue/vector-indexing.js.map +7 -0
  117. package/dist/service.js +286 -0
  118. package/dist/service.js.map +7 -0
  119. package/dist/strategies/fulltext.strategy.js +116 -0
  120. package/dist/strategies/fulltext.strategy.js.map +7 -0
  121. package/dist/strategies/index.js +12 -0
  122. package/dist/strategies/index.js.map +7 -0
  123. package/dist/strategies/token.strategy.js +80 -0
  124. package/dist/strategies/token.strategy.js.map +7 -0
  125. package/dist/strategies/vector.strategy.js +137 -0
  126. package/dist/strategies/vector.strategy.js.map +7 -0
  127. package/dist/types.js +1 -0
  128. package/dist/types.js.map +7 -0
  129. package/dist/vector/drivers/chromadb/index.js +44 -0
  130. package/dist/vector/drivers/chromadb/index.js.map +7 -0
  131. package/dist/vector/drivers/index.js +9 -0
  132. package/dist/vector/drivers/index.js.map +7 -0
  133. package/dist/vector/drivers/pgvector/index.js +509 -0
  134. package/dist/vector/drivers/pgvector/index.js.map +7 -0
  135. package/dist/vector/drivers/qdrant/index.js +44 -0
  136. package/dist/vector/drivers/qdrant/index.js.map +7 -0
  137. package/dist/vector/index.js +4 -0
  138. package/dist/vector/index.js.map +7 -0
  139. package/dist/vector/lib/vector-logs.js +33 -0
  140. package/dist/vector/lib/vector-logs.js.map +7 -0
  141. package/dist/vector/services/checksum.js +20 -0
  142. package/dist/vector/services/checksum.js.map +7 -0
  143. package/dist/vector/services/embedding.js +222 -0
  144. package/dist/vector/services/embedding.js.map +7 -0
  145. package/dist/vector/services/index.js +4 -0
  146. package/dist/vector/services/index.js.map +7 -0
  147. package/dist/vector/services/vector-index.service.js +960 -0
  148. package/dist/vector/services/vector-index.service.js.map +7 -0
  149. package/dist/vector/types/pg.d.js +1 -0
  150. package/dist/vector/types/pg.d.js.map +7 -0
  151. package/dist/vector/types.js +75 -0
  152. package/dist/vector/types.js.map +7 -0
  153. package/jest.config.cjs +19 -0
  154. package/package.json +142 -0
  155. package/src/__tests__/queue.test.ts +148 -0
  156. package/src/__tests__/service.test.ts +345 -0
  157. package/src/__tests__/workers.test.ts +319 -0
  158. package/src/di.ts +291 -0
  159. package/src/fulltext/drivers/index.ts +41 -0
  160. package/src/fulltext/drivers/meilisearch/index.ts +410 -0
  161. package/src/fulltext/index.ts +13 -0
  162. package/src/fulltext/types.ts +115 -0
  163. package/src/index.ts +36 -0
  164. package/src/indexer/index.ts +13 -0
  165. package/src/indexer/search-indexer.ts +1141 -0
  166. package/src/indexer/subscribers/delete.ts +49 -0
  167. package/src/lib/debug.ts +46 -0
  168. package/src/lib/fallback-presenter.ts +106 -0
  169. package/src/lib/field-policy.ts +169 -0
  170. package/src/lib/index.ts +13 -0
  171. package/src/lib/merger.ts +159 -0
  172. package/src/lib/presenter-enricher.ts +323 -0
  173. package/src/modules/search/README.md +694 -0
  174. package/src/modules/search/acl.ts +10 -0
  175. package/src/modules/search/ai-tools.ts +467 -0
  176. package/src/modules/search/api/embeddings/reindex/cancel/route.ts +77 -0
  177. package/src/modules/search/api/embeddings/reindex/route.ts +197 -0
  178. package/src/modules/search/api/embeddings/route.ts +304 -0
  179. package/src/modules/search/api/index/route.ts +297 -0
  180. package/src/modules/search/api/reindex/cancel/route.ts +77 -0
  181. package/src/modules/search/api/reindex/route.ts +419 -0
  182. package/src/modules/search/api/search/global/route.ts +120 -0
  183. package/src/modules/search/api/search/route.ts +121 -0
  184. package/src/modules/search/api/settings/fulltext/route.ts +82 -0
  185. package/src/modules/search/api/settings/global-search/route.ts +91 -0
  186. package/src/modules/search/api/settings/route.ts +187 -0
  187. package/src/modules/search/api/settings/vector-store/route.ts +105 -0
  188. package/src/modules/search/backend/config/search/page.meta.ts +22 -0
  189. package/src/modules/search/backend/config/search/page.tsx +12 -0
  190. package/src/modules/search/cli.ts +818 -0
  191. package/src/modules/search/di.ts +50 -0
  192. package/src/modules/search/frontend/components/GlobalSearchDialog.tsx +436 -0
  193. package/src/modules/search/frontend/components/HybridSearchTable.tsx +418 -0
  194. package/src/modules/search/frontend/components/SearchSettingsPageClient.tsx +476 -0
  195. package/src/modules/search/frontend/components/sections/FulltextSearchSection.tsx +624 -0
  196. package/src/modules/search/frontend/components/sections/GlobalSearchSection.tsx +124 -0
  197. package/src/modules/search/frontend/components/sections/VectorSearchSection.tsx +943 -0
  198. package/src/modules/search/frontend/index.ts +3 -0
  199. package/src/modules/search/frontend/utils.ts +82 -0
  200. package/src/modules/search/i18n/de.json +61 -0
  201. package/src/modules/search/i18n/en.json +72 -0
  202. package/src/modules/search/i18n/es.json +61 -0
  203. package/src/modules/search/i18n/pl.json +61 -0
  204. package/src/modules/search/index.ts +9 -0
  205. package/src/modules/search/lib/auto-indexing.ts +35 -0
  206. package/src/modules/search/lib/embedding-config.ts +161 -0
  207. package/src/modules/search/lib/global-search-config.ts +69 -0
  208. package/src/modules/search/lib/reindex-lock.ts +201 -0
  209. package/src/modules/search/subscribers/fulltext_upsert.ts +83 -0
  210. package/src/modules/search/subscribers/vector_delete.ts +75 -0
  211. package/src/modules/search/subscribers/vector_purge.ts +161 -0
  212. package/src/modules/search/subscribers/vector_upsert.ts +75 -0
  213. package/src/modules/search/workers/fulltext-index.worker.ts +318 -0
  214. package/src/modules/search/workers/vector-index.worker.ts +292 -0
  215. package/src/queue/fulltext-indexing.ts +87 -0
  216. package/src/queue/index.ts +2 -0
  217. package/src/queue/vector-indexing.ts +66 -0
  218. package/src/service.ts +397 -0
  219. package/src/strategies/fulltext.strategy.ts +155 -0
  220. package/src/strategies/index.ts +17 -0
  221. package/src/strategies/token.strategy.ts +153 -0
  222. package/src/strategies/vector.strategy.ts +234 -0
  223. package/src/types.ts +38 -0
  224. package/src/vector/drivers/chromadb/index.ts +49 -0
  225. package/src/vector/drivers/index.ts +4 -0
  226. package/src/vector/drivers/pgvector/index.ts +627 -0
  227. package/src/vector/drivers/qdrant/index.ts +49 -0
  228. package/src/vector/index.ts +3 -0
  229. package/src/vector/lib/vector-logs.ts +46 -0
  230. package/src/vector/services/checksum.ts +18 -0
  231. package/src/vector/services/embedding.ts +275 -0
  232. package/src/vector/services/index.ts +3 -0
  233. package/src/vector/services/vector-index.service.ts +1234 -0
  234. package/src/vector/types/pg.d.ts +1 -0
  235. package/src/vector/types.ts +220 -0
  236. package/tsconfig.json +9 -0
  237. package/watch.mjs +6 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 { Button } from '@open-mercato/ui/primitives/button'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\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 configuredProviders: EmbeddingProviderId[]\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 // Poll for activity when reindexing\n React.useEffect(() => {\n if (vectorReindexLock || vectorReindexing) {\n const interval = setInterval(fetchActivityLogs, 5000)\n return () => clearInterval(interval)\n }\n }, [vectorReindexLock, vectorReindexing, 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-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-900/20'\n : !driver.implemented\n ? 'border-border bg-muted/20 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-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400'\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-emerald-700 dark:text-emerald-300' : ''}`}>\n {driver.name}\n </p>\n {isCurrent && (\n <span className=\"text-[10px] px-1.5 py-0.5 rounded bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n {!driver.implemented && (\n <span className=\"text-[10px] 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-emerald-500' : 'bg-muted-foreground/40'}`} />\n <code className=\"text-[10px] 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-3\">{t('search.settings.vector.providersHint', 'Select a provider to generate embeddings. Only providers with configured API keys can be selected.')}</p>\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 isConfigured = embeddingSettings?.configuredProviders?.includes(providerId)\n const isSelected = displayProvider === providerId\n const isCurrentlySaved = savedProvider === providerId\n return (\n <button\n key={providerId}\n type=\"button\"\n onClick={() => isConfigured && handleProviderChange(providerId)}\n disabled={!isConfigured || embeddingLoading || embeddingSaving}\n className={`text-left p-3 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 cursor-pointer'\n : 'border-border bg-muted/20 opacity-50 cursor-not-allowed'\n }`}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex-1 min-w-0\">\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-[10px] px-1.5 py-0.5 rounded bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300\">\n {t('search.settings.vector.active', 'Active')}\n </span>\n )}\n </div>\n {isConfigured ? (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {info.models.length} {t('search.settings.vector.modelsAvailable', 'models available')}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.vector.setEnvVar', 'Set')} <code className=\"font-mono text-[10px] bg-muted px-1 rounded\">{info.envKeyRequired}</code>\n </p>\n )}\n </div>\n <div className={`flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 ${\n isSelected\n ? 'bg-primary text-primary-foreground'\n : isConfigured\n ? 'bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400'\n : 'bg-muted text-muted-foreground'\n }`}>\n {isSelected ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : isConfigured ? (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n ) : (\n <svg className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M12 4v16m8-8H4\" />\n </svg>\n )}\n </div>\n </div>\n\n {/* Model Selection */}\n {isSelected && isConfigured && (\n <div className=\"mt-3 pt-3 border-t border-border space-y-2\" onClick={(e) => e.stopPropagation()}>\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 id={`model-${providerId}`}\n className=\"w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60\"\n value={displayModel}\n onChange={(e) => handleModelChange(e.target.value)}\n disabled={embeddingLoading || embeddingSaving}\n >\n {savedCustomModel && displayProvider === savedProvider && (\n <option key={savedCustomModel.id} value={savedCustomModel.id}>\n {savedCustomModel.name} ({savedCustomModel.dimension}d)\n </option>\n )}\n {displayProviderInfo.models.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} ({model.dimension}d)\n </option>\n ))}\n <option value=\"custom\">{t('search.settings.model.custom', 'Custom...')}</option>\n </select>\n </div>\n\n {isCustomModel && (\n <div className=\"space-y-2 p-2 rounded border border-input bg-muted/30\">\n <input\n type=\"text\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-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 <input\n type=\"number\"\n className=\"w-full rounded border border-input bg-background px-2 py-1 text-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 )}\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-amber-600 dark:text-amber-400\">\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 </button>\n )\n })}\n </div>\n </div>\n\n {/* Setup Instructions */}\n <div className=\"p-3 rounded-md bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800\">\n <div className=\"flex items-start gap-2\">\n <svg className=\"h-5 w-5 text-blue-600 dark:text-blue-400 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-blue-800 dark:text-blue-200\">\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-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800\">\n <div className=\"flex items-start gap-3\">\n <svg className=\"h-5 w-5 text-amber-600 dark:text-amber-400 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-amber-800 dark:text-amber-200\">\n {t('search.settings.vectorNotConfigured', 'No embedding provider configured')}\n </p>\n <p className=\"text-xs text-amber-700 dark:text-amber-300 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-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800\">\n <div className=\"flex items-start gap-3\">\n <Spinner size=\"sm\" className=\"flex-shrink-0 mt-0.5 text-blue-600 dark:text-blue-400\" />\n <div className=\"flex-1\">\n <p className=\"text-sm font-medium text-blue-800 dark:text-blue-200\">\n {t('search.settings.reindexInProgress', 'Reindex operation in progress')}\n </p>\n <p className=\"text-xs text-blue-700 dark:text-blue-300 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-amber-50 dark:bg-amber-900/20\">\n <svg className=\"h-4 w-4 text-amber-600 dark:text-amber-400 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-amber-800 dark:text-amber-200\">\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-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800'\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-red-600 dark:text-red-400 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-red-800 dark:text-red-200' : '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-50 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-50 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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",
6
+ "names": []
7
+ }
@@ -0,0 +1,9 @@
1
+ import { GlobalSearchDialog } from "./components/GlobalSearchDialog.js";
2
+ import { SearchSettingsPageClient } from "./components/SearchSettingsPageClient.js";
3
+ import { HybridSearchTable } from "./components/HybridSearchTable.js";
4
+ export {
5
+ GlobalSearchDialog,
6
+ HybridSearchTable,
7
+ SearchSettingsPageClient
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/search/frontend/index.ts"],
4
+ "sourcesContent": ["export { GlobalSearchDialog } from './components/GlobalSearchDialog'\nexport { SearchSettingsPageClient } from './components/SearchSettingsPageClient'\nexport { HybridSearchTable } from './components/HybridSearchTable'\n"],
5
+ "mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,gCAAgC;AACzC,SAAS,yBAAyB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,41 @@
1
+ import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
2
+ async function fetchHybridSearchResults(query, opts = {}) {
3
+ const params = new URLSearchParams();
4
+ params.set("q", query);
5
+ const limit = Math.max(1, Math.min(opts.limit ?? 50, 100));
6
+ params.set("limit", String(limit));
7
+ if (opts.strategies && opts.strategies.length > 0) {
8
+ params.set("strategies", opts.strategies.join(","));
9
+ }
10
+ const body = await readApiResultOrThrow(
11
+ `/api/search/search?${params.toString()}`,
12
+ { signal: opts.signal },
13
+ { errorMessage: "Hybrid search failed", allowNullResult: true }
14
+ );
15
+ return {
16
+ results: Array.isArray(body?.results) ? body.results : [],
17
+ strategiesUsed: Array.isArray(body?.strategiesUsed) ? body.strategiesUsed : [],
18
+ timing: typeof body?.timing === "number" ? body.timing : 0,
19
+ error: typeof body?.error === "string" ? body.error : null
20
+ };
21
+ }
22
+ async function fetchGlobalSearchResults(query, opts = {}) {
23
+ const params = new URLSearchParams();
24
+ params.set("q", query);
25
+ const limit = Math.max(1, Math.min(opts.limit ?? 10, 50));
26
+ params.set("limit", String(limit));
27
+ const body = await readApiResultOrThrow(
28
+ `/api/search/search/global?${params.toString()}`,
29
+ { signal: opts.signal },
30
+ { errorMessage: "Search failed", allowNullResult: true }
31
+ );
32
+ return {
33
+ results: Array.isArray(body?.results) ? body.results : [],
34
+ error: typeof body?.error === "string" ? body.error : null
35
+ };
36
+ }
37
+ export {
38
+ fetchGlobalSearchResults,
39
+ fetchHybridSearchResults
40
+ };
41
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/search/frontend/utils.ts"],
4
+ "sourcesContent": ["import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { SearchResult, SearchStrategyId } from '@open-mercato/shared/modules/search'\n\nexport type HybridSearchResponse = {\n results: SearchResult[]\n strategiesUsed: string[]\n timing: number\n error?: string | null\n}\n\nexport type FetchHybridSearchOptions = {\n limit?: number\n strategies?: SearchStrategyId[]\n signal?: AbortSignal\n}\n\nexport async function fetchHybridSearchResults(\n query: string,\n opts: FetchHybridSearchOptions = {}\n): Promise<HybridSearchResponse> {\n const params = new URLSearchParams()\n params.set('q', query)\n\n const limit = Math.max(1, Math.min(opts.limit ?? 50, 100))\n params.set('limit', String(limit))\n\n if (opts.strategies && opts.strategies.length > 0) {\n params.set('strategies', opts.strategies.join(','))\n }\n\n const body = await readApiResultOrThrow<{\n results?: SearchResult[]\n strategiesUsed?: string[]\n timing?: number\n error?: string\n }>(\n `/api/search/search?${params.toString()}`,\n { signal: opts.signal },\n { errorMessage: 'Hybrid search failed', allowNullResult: true }\n )\n\n return {\n results: Array.isArray(body?.results) ? body.results : [],\n strategiesUsed: Array.isArray(body?.strategiesUsed) ? body.strategiesUsed : [],\n timing: typeof body?.timing === 'number' ? body.timing : 0,\n error: typeof body?.error === 'string' ? body.error : null,\n }\n}\n\n/**\n * Fetch global search results for the Cmd+K dialog.\n * Uses the global search API which respects saved strategy settings.\n */\nexport type FetchGlobalSearchOptions = {\n limit?: number\n signal?: AbortSignal\n}\n\nexport async function fetchGlobalSearchResults(\n query: string,\n opts: FetchGlobalSearchOptions = {}\n): Promise<{ results: SearchResult[]; error?: string | null }> {\n const params = new URLSearchParams()\n params.set('q', query)\n\n const limit = Math.max(1, Math.min(opts.limit ?? 10, 50))\n params.set('limit', String(limit))\n\n const body = await readApiResultOrThrow<{\n results?: SearchResult[]\n error?: string\n }>(\n `/api/search/search/global?${params.toString()}`,\n { signal: opts.signal },\n { errorMessage: 'Search failed', allowNullResult: true }\n )\n\n return {\n results: Array.isArray(body?.results) ? body.results : [],\n error: typeof body?.error === 'string' ? body.error : null,\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,4BAA4B;AAgBrC,eAAsB,yBACpB,OACA,OAAiC,CAAC,GACH;AAC/B,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,KAAK,KAAK;AAErB,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC;AACzD,SAAO,IAAI,SAAS,OAAO,KAAK,CAAC;AAEjC,MAAI,KAAK,cAAc,KAAK,WAAW,SAAS,GAAG;AACjD,WAAO,IAAI,cAAc,KAAK,WAAW,KAAK,GAAG,CAAC;AAAA,EACpD;AAEA,QAAM,OAAO,MAAM;AAAA,IAMjB,sBAAsB,OAAO,SAAS,CAAC;AAAA,IACvC,EAAE,QAAQ,KAAK,OAAO;AAAA,IACtB,EAAE,cAAc,wBAAwB,iBAAiB,KAAK;AAAA,EAChE;AAEA,SAAO;AAAA,IACL,SAAS,MAAM,QAAQ,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC;AAAA,IACxD,gBAAgB,MAAM,QAAQ,MAAM,cAAc,IAAI,KAAK,iBAAiB,CAAC;AAAA,IAC7E,QAAQ,OAAO,MAAM,WAAW,WAAW,KAAK,SAAS;AAAA,IACzD,OAAO,OAAO,MAAM,UAAU,WAAW,KAAK,QAAQ;AAAA,EACxD;AACF;AAWA,eAAsB,yBACpB,OACA,OAAiC,CAAC,GAC2B;AAC7D,QAAM,SAAS,IAAI,gBAAgB;AACnC,SAAO,IAAI,KAAK,KAAK;AAErB,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,IAAI,EAAE,CAAC;AACxD,SAAO,IAAI,SAAS,OAAO,KAAK,CAAC;AAEjC,QAAM,OAAO,MAAM;AAAA,IAIjB,6BAA6B,OAAO,SAAS,CAAC;AAAA,IAC9C,EAAE,QAAQ,KAAK,OAAO;AAAA,IACtB,EAAE,cAAc,iBAAiB,iBAAiB,KAAK;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,SAAS,MAAM,QAAQ,MAAM,OAAO,IAAI,KAAK,UAAU,CAAC;AAAA,IACxD,OAAO,OAAO,MAAM,UAAU,WAAW,KAAK,QAAQ;AAAA,EACxD;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "search.nav.hybridSearch": "Suche",
3
+ "search.config.nav.hybridSearch": "Sucheinstellungen",
4
+ "search.config.nav.embeddings": "Einbettungen",
5
+ "search.messages.missingConfig": "Die Suche erfordert die Konfiguration eines Embedding-Anbieters für die semantische Suche.",
6
+ "search.dialog.actions.search": "Suchen",
7
+ "search.dialog.actions.openGlobalSearch": "Globale Suche öffnen",
8
+ "search.dialog.actions.cancel": "Abbrechen (Esc)",
9
+ "search.dialog.actions.openSelected": "Öffnen (Enter)",
10
+ "search.dialog.instructions": "Tippe, um in indizierten Datensätzen zu suchen. Verwende die Pfeiltasten, um Ergebnisse zu navigieren.",
11
+ "search.dialog.input.placeholder": "Suche nach Kunden, Notizen, Deals, Aufgaben...",
12
+ "search.dialog.errors.searchFailed": "Suche ist fehlgeschlagen.",
13
+ "search.dialog.empty.hint": "Mindestens zwei Zeichen eingeben, um in indizierten Datensätzen zu suchen.",
14
+ "search.dialog.empty.none": "Keine Ergebnisse gefunden.",
15
+ "search.dialog.score.title": "Relevanz-Score",
16
+ "search.dialog.shortcuts.hint": "Drücke Cmd+K zum Umschalten. Enter zum Öffnen",
17
+ "search.dialog.noLink": "Kein Link",
18
+ "search.dialog.noLinkHint": "Keine search.ts Konfiguration für diesen Entitätstyp",
19
+ "search.settings.statusTitle": "Status der Suche",
20
+ "search.settings.statusEnabled": "Embedding-Anbieter konfiguriert. Semantische Suche ist verfügbar.",
21
+ "search.settings.statusDisabled": "Embedding-Anbieter nicht konfiguriert. Semantische Suche ist deaktiviert.",
22
+ "search.settings.autoIndexingLabel": "Datenbankänderungen automatisch indexieren",
23
+ "search.settings.autoIndexingDescription": "Hält den Suchindex bei Änderungen an Datensätzen automatisch synchron.",
24
+ "search.settings.autoIndexingLocked": "Auto-Indexierung wird durch die Umgebungsvariable DISABLE_VECTOR_SEARCH_AUTOINDEXING gesperrt.",
25
+ "search.settings.toggleSuccess": "Einstellung zur Auto-Indexierung gespeichert.",
26
+ "search.settings.toggleError": "Fehler beim Aktualisieren der Auto-Indexierung.",
27
+ "search.settings.refresh": "Status aktualisieren",
28
+ "search.settings.saving": "Speichern...",
29
+ "search.settings.loading": "Einstellungen werden geladen...",
30
+ "search.settings.embeddingProviderTitle": "Embedding-Anbieter",
31
+ "search.settings.embeddingProviderLabel": "Anbieter",
32
+ "search.settings.embeddingModelLabel": "Modell",
33
+ "search.settings.embeddingDimensionLabel": "Dimension",
34
+ "search.settings.embeddingNotConfigured": "nicht konfiguriert",
35
+ "search.settings.embeddingCustomModelOption": "Benutzerdefiniert...",
36
+ "search.settings.embeddingCustomModelNameLabel": "Modellname",
37
+ "search.settings.embeddingCustomDimensionLabel": "Dimensionen",
38
+ "search.settings.embeddingChangeWarningTitle": "Warnung: Diese Änderung erfordert vollständige Neuindexierung",
39
+ "search.settings.embeddingChangeWarningDescription": "Das Ändern des Embedding-Anbieters oder Modells erfordert die Neuerstellung aller Vektor-Einbettungen.",
40
+ "search.settings.embeddingChangeWarningBullet1": "Löscht ALLE vorhandenen Vektor-Einbettungen",
41
+ "search.settings.embeddingChangeWarningBullet2": "Löscht und erstellt die vector_search Tabelle neu",
42
+ "search.settings.embeddingChangeWarningBullet3": "Erfordert Neugenerierung der Einbettungen für alle indizierten Datensätze",
43
+ "search.settings.embeddingChangeWarningNote": "Die semantische Suche ist bis zum Abschluss der Neuindexierung nicht verfügbar.",
44
+ "search.settings.embeddingCancelLabel": "Abbrechen",
45
+ "search.settings.embeddingConfirmLabel": "Bestätigen & Anwenden",
46
+ "search.settings.embeddingProviderSuccess": "Embedding-Anbieter erfolgreich aktualisiert.",
47
+ "search.settings.embeddingProviderError": "Fehler beim Aktualisieren des Embedding-Anbieters.",
48
+ "search.api.errors.invalidProvider": "Ungültiger Embedding-Anbieter.",
49
+ "search.api.errors.providerNotConfigured": "Anbieter ist nicht konfiguriert. Setzen Sie die erforderliche Umgebungsvariable.",
50
+ "search.api.errors.recreateFailed": "Fehler beim Neuerstellen der Vektortabelle mit neuer Dimension.",
51
+ "search.settings.reindexTitle": "Suchdaten neu indexieren",
52
+ "search.settings.reindexDescription": "Einbettungen für alle indizierten Datensätze mit dem aktuellen Anbieter neu generieren.",
53
+ "search.settings.reindexButton": "Alles neu indexieren",
54
+ "search.settings.reindexWarning": "Dies führt zu API-Aufrufen an Ihren Embedding-Anbieter, was je nach Tarif Kosten verursachen kann.",
55
+ "search.settings.reindexConfirmTitle": "Neuindexierung bestätigen",
56
+ "search.settings.reindexConfirmDescription": "Dies wird Einbettungen für alle indizierten Datensätze neu generieren.",
57
+ "search.settings.reindexConfirmButton": "Neuindexierung starten",
58
+ "search.settings.reindexSuccess": "Neuindexierung erfolgreich gestartet.",
59
+ "search.settings.reindexError": "Fehler beim Starten der Neuindexierung.",
60
+ "search.settings.reindexing": "Neuindexierung..."
61
+ }
@@ -0,0 +1,72 @@
1
+ {
2
+ "search.nav.hybridSearch": "Search",
3
+ "search.config.nav.hybridSearch": "Search Settings",
4
+ "search.messages.missingConfig": "Search requires configuring an embedding provider for semantic search.",
5
+ "search.dialog.actions.search": "Search",
6
+ "search.dialog.actions.openGlobalSearch": "Open global search",
7
+ "search.dialog.actions.cancel": "Cancel (Esc)",
8
+ "search.dialog.actions.openSelected": "Open (Enter)",
9
+ "search.dialog.instructions": "Type to search across indexed records. Use arrow keys to navigate results.",
10
+ "search.dialog.input.placeholder": "Search customers, notes, deals, todos...",
11
+ "search.dialog.errors.searchFailed": "Search failed.",
12
+ "search.dialog.empty.hint": "Type at least two characters to search indexed records.",
13
+ "search.dialog.empty.none": "No results found.",
14
+ "search.dialog.score.title": "Relevance score",
15
+ "search.dialog.shortcuts.hint": "Press Cmd+K to toggle. Enter to open",
16
+ "search.dialog.noLink": "No link",
17
+ "search.dialog.noLinkHint": "No search.ts config for this entity type",
18
+ "search.dialog.strategies.toggle": "Search options",
19
+ "search.dialog.strategies.label": "Search with:",
20
+ "search.dialog.strategies.fuzzy": "Fuzzy",
21
+ "search.dialog.strategies.fuzzyDescription": "Typo-tolerant full-text search",
22
+ "search.dialog.strategies.semantic": "Semantic",
23
+ "search.dialog.strategies.semanticDescription": "AI-powered meaning-based search",
24
+ "search.dialog.strategies.exact": "Exact",
25
+ "search.dialog.strategies.exactDescription": "Precise keyword matching",
26
+ "search.settings.title": "Search Settings",
27
+ "search.settings.loading": "Loading...",
28
+ "search.settings.status.configured": "Vector search configured",
29
+ "search.settings.status.notConfigured": "Vector search not configured",
30
+ "search.settings.badge.ready": "Ready",
31
+ "search.settings.badge.setup": "Setup Required",
32
+ "search.settings.errors.loadFailed": "Failed to load settings",
33
+ "search.settings.errors.saveFailed": "Failed to save settings",
34
+ "search.settings.errors.reindexFailed": "Reindex failed",
35
+ "search.settings.errors.modelRequired": "Please enter a model name",
36
+ "search.settings.errors.dimensionRequired": "Please enter a valid dimension",
37
+ "search.settings.messages.saved": "Settings saved",
38
+ "search.settings.messages.providerSaved": "Embedding provider saved",
39
+ "search.settings.messages.reindexStarted": "Reindex started",
40
+ "search.settings.provider.title": "Embedding Provider",
41
+ "search.settings.provider.label": "Provider",
42
+ "search.settings.provider.notConfigured": "not configured",
43
+ "search.settings.model.label": "Model",
44
+ "search.settings.model.custom": "Custom...",
45
+ "search.settings.model.namePlaceholder": "Model name",
46
+ "search.settings.dimension.label": "Dimensions",
47
+ "search.settings.dimension.mismatch": "mismatch",
48
+ "search.settings.status.title": "Auto-Indexing",
49
+ "search.settings.autoIndexing.label": "Enable auto-indexing",
50
+ "search.settings.autoIndexing.description": "Automatically index new and updated records for vector search.",
51
+ "search.settings.autoIndexing.locked": "Disabled via environment variable.",
52
+ "search.settings.reindex.title": "Reindex Data",
53
+ "search.settings.reindex.description": "Rebuild vector embeddings for all indexed entities.",
54
+ "search.settings.reindex.warning": "This may take a while for large datasets.",
55
+ "search.settings.reindex.button": "Start Reindex",
56
+ "search.settings.reindex.running": "Reindexing...",
57
+ "search.settings.reindex.confirmTitle": "Confirm Reindex",
58
+ "search.settings.reindex.confirmDescription": "This will rebuild all vector embeddings. Existing data will be purged first.",
59
+ "search.settings.reindex.confirmButton": "Start Reindex",
60
+ "search.settings.change.title": "Confirm Provider Change",
61
+ "search.settings.change.description": "Changing the embedding provider will require reindexing all data.",
62
+ "search.settings.change.bullet1": "Existing vector data will be cleared",
63
+ "search.settings.change.bullet2": "Vector search will be unavailable during reindex",
64
+ "search.settings.actions.apply": "Apply",
65
+ "search.settings.actions.cancel": "Cancel",
66
+ "search.settings.actions.confirm": "Confirm",
67
+ "search.settings.actions.loading": "Loading...",
68
+ "search.settings.actions.refresh": "Refresh",
69
+ "search.api.errors.invalidProvider": "Invalid embedding provider.",
70
+ "search.api.errors.providerNotConfigured": "Provider is not configured. Set the required environment variable.",
71
+ "search.api.errors.recreateFailed": "Failed to recreate vector table with new dimension."
72
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "search.nav.hybridSearch": "Búsqueda",
3
+ "search.config.nav.hybridSearch": "Configuración de búsqueda",
4
+ "search.config.nav.embeddings": "Embeddings",
5
+ "search.messages.missingConfig": "La búsqueda requiere configurar un proveedor de embeddings para la búsqueda semántica.",
6
+ "search.dialog.actions.search": "Buscar",
7
+ "search.dialog.actions.openGlobalSearch": "Abrir búsqueda global",
8
+ "search.dialog.actions.cancel": "Cancelar (Esc)",
9
+ "search.dialog.actions.openSelected": "Abrir (Enter)",
10
+ "search.dialog.instructions": "Escribe para buscar en los registros indexados. Usa las flechas para navegar por los resultados.",
11
+ "search.dialog.input.placeholder": "Busca clientes, notas, oportunidades, tareas...",
12
+ "search.dialog.errors.searchFailed": "La búsqueda falló.",
13
+ "search.dialog.empty.hint": "Escribe al menos dos caracteres para buscar en los registros indexados.",
14
+ "search.dialog.empty.none": "No se encontraron resultados.",
15
+ "search.dialog.score.title": "Puntuación de relevancia",
16
+ "search.dialog.shortcuts.hint": "Pulsa Cmd+K para alternar. Enter para abrir",
17
+ "search.dialog.noLink": "Sin enlace",
18
+ "search.dialog.noLinkHint": "No hay configuración search.ts para este tipo de entidad",
19
+ "search.settings.statusTitle": "Estado de la búsqueda",
20
+ "search.settings.statusEnabled": "Proveedor de embeddings configurado. La búsqueda semántica está disponible.",
21
+ "search.settings.statusDisabled": "Proveedor de embeddings no configurado. La búsqueda semántica está deshabilitada.",
22
+ "search.settings.autoIndexingLabel": "Indexar automáticamente los cambios en la base de datos",
23
+ "search.settings.autoIndexingDescription": "Mantiene el índice de búsqueda sincronizado cuando cambian los registros.",
24
+ "search.settings.autoIndexingLocked": "La indexación automática está bloqueada por la variable de entorno DISABLE_VECTOR_SEARCH_AUTOINDEXING.",
25
+ "search.settings.toggleSuccess": "Preferencia de indexación automática guardada.",
26
+ "search.settings.toggleError": "No se pudo actualizar la indexación automática.",
27
+ "search.settings.refresh": "Actualizar estado",
28
+ "search.settings.saving": "Guardando...",
29
+ "search.settings.loading": "Cargando ajustes...",
30
+ "search.settings.embeddingProviderTitle": "Proveedor de Embeddings",
31
+ "search.settings.embeddingProviderLabel": "Proveedor",
32
+ "search.settings.embeddingModelLabel": "Modelo",
33
+ "search.settings.embeddingDimensionLabel": "Dimensión",
34
+ "search.settings.embeddingNotConfigured": "no configurado",
35
+ "search.settings.embeddingCustomModelOption": "Personalizado...",
36
+ "search.settings.embeddingCustomModelNameLabel": "Nombre del modelo",
37
+ "search.settings.embeddingCustomDimensionLabel": "Dimensiones",
38
+ "search.settings.embeddingChangeWarningTitle": "Advertencia: Este cambio requiere reindexación completa",
39
+ "search.settings.embeddingChangeWarningDescription": "Cambiar el proveedor o modelo de embeddings requiere reconstruir todos los embeddings vectoriales.",
40
+ "search.settings.embeddingChangeWarningBullet1": "Eliminar TODOS los embeddings vectoriales existentes",
41
+ "search.settings.embeddingChangeWarningBullet2": "Eliminar y recrear la tabla vector_search",
42
+ "search.settings.embeddingChangeWarningBullet3": "Regenerar los embeddings para todos los registros indexados",
43
+ "search.settings.embeddingChangeWarningNote": "La búsqueda semántica no estará disponible hasta que se complete la reindexación.",
44
+ "search.settings.embeddingCancelLabel": "Cancelar",
45
+ "search.settings.embeddingConfirmLabel": "Confirmar y Aplicar",
46
+ "search.settings.embeddingProviderSuccess": "Proveedor de embeddings actualizado correctamente.",
47
+ "search.settings.embeddingProviderError": "No se pudo actualizar el proveedor de embeddings.",
48
+ "search.api.errors.invalidProvider": "Proveedor de embeddings no válido.",
49
+ "search.api.errors.providerNotConfigured": "El proveedor no está configurado. Configure la variable de entorno requerida.",
50
+ "search.api.errors.recreateFailed": "No se pudo recrear la tabla vectorial con la nueva dimensión.",
51
+ "search.settings.reindexTitle": "Reindexar datos de búsqueda",
52
+ "search.settings.reindexDescription": "Regenerar embeddings para todos los registros indexados usando el proveedor actual.",
53
+ "search.settings.reindexButton": "Reindexar todo",
54
+ "search.settings.reindexWarning": "Esto realizará llamadas API a su proveedor de embeddings, lo que puede generar costos según su plan.",
55
+ "search.settings.reindexConfirmTitle": "Confirmar reindexación",
56
+ "search.settings.reindexConfirmDescription": "Esto regenerará los embeddings para todos los registros indexados.",
57
+ "search.settings.reindexConfirmButton": "Iniciar reindexación",
58
+ "search.settings.reindexSuccess": "Reindexación iniciada correctamente.",
59
+ "search.settings.reindexError": "No se pudo iniciar la reindexación.",
60
+ "search.settings.reindexing": "Reindexando..."
61
+ }
@@ -0,0 +1,61 @@
1
+ {
2
+ "search.nav.hybridSearch": "Wyszukiwanie",
3
+ "search.config.nav.hybridSearch": "Ustawienia wyszukiwania",
4
+ "search.config.nav.embeddings": "Osadzenia",
5
+ "search.messages.missingConfig": "Wyszukiwanie wymaga skonfigurowania dostawcy embeddingów dla wyszukiwania semantycznego.",
6
+ "search.dialog.actions.search": "Szukaj",
7
+ "search.dialog.actions.openGlobalSearch": "Otwórz globalne wyszukiwanie",
8
+ "search.dialog.actions.cancel": "Anuluj (Esc)",
9
+ "search.dialog.actions.openSelected": "Otwórz (Enter)",
10
+ "search.dialog.instructions": "Wpisz tekst, aby przeszukać zindeksowane rekordy. Użyj strzałek do nawigacji po wynikach.",
11
+ "search.dialog.input.placeholder": "Szukaj klientów, notatek, szans, zadań...",
12
+ "search.dialog.errors.searchFailed": "Wyszukiwanie nie powiodło się.",
13
+ "search.dialog.empty.hint": "Wpisz co najmniej dwa znaki, aby przeszukać zindeksowane rekordy.",
14
+ "search.dialog.empty.none": "Brak wyników.",
15
+ "search.dialog.score.title": "Wynik trafności",
16
+ "search.dialog.shortcuts.hint": "Naciśnij Cmd+K, aby przełączyć. Enter, aby otworzyć",
17
+ "search.dialog.noLink": "Brak linku",
18
+ "search.dialog.noLinkHint": "Brak konfiguracji search.ts dla tego typu encji",
19
+ "search.settings.statusTitle": "Status wyszukiwania",
20
+ "search.settings.statusEnabled": "Dostawca osadzeń skonfigurowany. Wyszukiwanie semantyczne jest dostępne.",
21
+ "search.settings.statusDisabled": "Dostawca osadzeń nie skonfigurowany. Wyszukiwanie semantyczne jest wyłączone.",
22
+ "search.settings.autoIndexingLabel": "Automatycznie indeksuj zmiany w bazie danych",
23
+ "search.settings.autoIndexingDescription": "Utrzymuje aktualny indeks wyszukiwania przy każdej zmianie rekordów.",
24
+ "search.settings.autoIndexingLocked": "Automatyczne indeksowanie jest zablokowane przez zmienną środowiskową DISABLE_VECTOR_SEARCH_AUTOINDEXING.",
25
+ "search.settings.toggleSuccess": "Zapisano preferencję automatycznego indeksowania.",
26
+ "search.settings.toggleError": "Nie udało się zaktualizować automatycznego indeksowania.",
27
+ "search.settings.refresh": "Odśwież status",
28
+ "search.settings.saving": "Zapisywanie...",
29
+ "search.settings.loading": "Ładowanie ustawień...",
30
+ "search.settings.embeddingProviderTitle": "Dostawca osadzeń",
31
+ "search.settings.embeddingProviderLabel": "Dostawca",
32
+ "search.settings.embeddingModelLabel": "Model",
33
+ "search.settings.embeddingDimensionLabel": "Wymiar",
34
+ "search.settings.embeddingNotConfigured": "nie skonfigurowany",
35
+ "search.settings.embeddingCustomModelOption": "Niestandardowy...",
36
+ "search.settings.embeddingCustomModelNameLabel": "Nazwa modelu",
37
+ "search.settings.embeddingCustomDimensionLabel": "Wymiary",
38
+ "search.settings.embeddingChangeWarningTitle": "Uwaga: Ta zmiana wymaga pełnego reindeksowania",
39
+ "search.settings.embeddingChangeWarningDescription": "Zmiana dostawcy lub modelu osadzeń wymaga odbudowania wszystkich osadzeń wektorowych.",
40
+ "search.settings.embeddingChangeWarningBullet1": "Usunięcie WSZYSTKICH istniejących osadzeń wektorowych",
41
+ "search.settings.embeddingChangeWarningBullet2": "Usunięcie i ponowne utworzenie tabeli vector_search",
42
+ "search.settings.embeddingChangeWarningBullet3": "Ponowne generowanie osadzeń dla wszystkich zindeksowanych rekordów",
43
+ "search.settings.embeddingChangeWarningNote": "Wyszukiwanie semantyczne będzie niedostępne do zakończenia reindeksowania.",
44
+ "search.settings.embeddingCancelLabel": "Anuluj",
45
+ "search.settings.embeddingConfirmLabel": "Potwierdź i zastosuj",
46
+ "search.settings.embeddingProviderSuccess": "Dostawca osadzeń zaktualizowany pomyślnie.",
47
+ "search.settings.embeddingProviderError": "Nie udało się zaktualizować dostawcy embeddingów.",
48
+ "search.api.errors.invalidProvider": "Nieprawidłowy dostawca embeddingów.",
49
+ "search.api.errors.providerNotConfigured": "Dostawca nie jest skonfigurowany. Ustaw wymaganą zmienną środowiskową.",
50
+ "search.api.errors.recreateFailed": "Nie udało się odtworzyć tabeli wektorowej z nowym wymiarem.",
51
+ "search.settings.reindexTitle": "Reindeksacja danych wyszukiwania",
52
+ "search.settings.reindexDescription": "Wygeneruj ponownie osadzenia dla wszystkich zindeksowanych rekordów używając bieżącego dostawcy.",
53
+ "search.settings.reindexButton": "Reindeksuj wszystko",
54
+ "search.settings.reindexWarning": "To spowoduje wywołania API do dostawcy osadzeń, co może wiązać się z kosztami w zależności od planu.",
55
+ "search.settings.reindexConfirmTitle": "Potwierdź reindeksację",
56
+ "search.settings.reindexConfirmDescription": "To wygeneruje ponownie osadzenia dla wszystkich zindeksowanych rekordów.",
57
+ "search.settings.reindexConfirmButton": "Rozpocznij reindeksację",
58
+ "search.settings.reindexSuccess": "Reindeksacja rozpoczęta pomyślnie.",
59
+ "search.settings.reindexError": "Nie udało się rozpocząć reindeksacji.",
60
+ "search.settings.reindexing": "Reindeksowanie..."
61
+ }
@@ -0,0 +1,11 @@
1
+ const metadata = {
2
+ name: "search",
3
+ title: "Search",
4
+ version: "0.1.0",
5
+ description: "Unified search module with pluggable strategies (Meilisearch, Vector, Tokens).",
6
+ author: "FreightTech Team"
7
+ };
8
+ export {
9
+ metadata
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/modules/search/index.ts"],
4
+ "sourcesContent": ["import type { ModuleInfo } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: ModuleInfo = {\n name: 'search',\n title: 'Search',\n version: '0.1.0',\n description: 'Unified search module with pluggable strategies (Meilisearch, Vector, Tokens).',\n author: 'FreightTech Team',\n}\n"],
5
+ "mappings": "AAEO,MAAM,WAAuB;AAAA,EAClC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AACV;",
6
+ "names": []
7
+ }
@@ -0,0 +1,29 @@
1
+ import { parseBooleanToken } from "@open-mercato/shared/lib/boolean";
2
+ const SEARCH_AUTO_INDEX_CONFIG_KEY = "auto_index_enabled";
3
+ function envDisablesAutoIndexing() {
4
+ const raw = process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING;
5
+ if (!raw) return false;
6
+ return parseBooleanToken(raw) === true;
7
+ }
8
+ async function resolveAutoIndexingEnabled(resolver, options) {
9
+ if (envDisablesAutoIndexing()) return false;
10
+ const fallback = options?.defaultValue ?? true;
11
+ let service;
12
+ try {
13
+ service = resolver.resolve("moduleConfigService");
14
+ } catch {
15
+ return fallback;
16
+ }
17
+ try {
18
+ const value = await service.getValue("vector", SEARCH_AUTO_INDEX_CONFIG_KEY, { defaultValue: fallback });
19
+ return value !== false;
20
+ } catch {
21
+ return fallback;
22
+ }
23
+ }
24
+ export {
25
+ SEARCH_AUTO_INDEX_CONFIG_KEY,
26
+ envDisablesAutoIndexing,
27
+ resolveAutoIndexingEnabled
28
+ };
29
+ //# sourceMappingURL=auto-indexing.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/search/lib/auto-indexing.ts"],
4
+ "sourcesContent": ["import type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nexport const SEARCH_AUTO_INDEX_CONFIG_KEY = 'auto_index_enabled'\n\nexport function envDisablesAutoIndexing(): boolean {\n const raw = process.env.DISABLE_VECTOR_SEARCH_AUTOINDEXING\n if (!raw) return false\n return parseBooleanToken(raw) === true\n}\n\ntype Resolver = {\n resolve: <T = unknown>(name: string) => T\n}\n\nexport async function resolveAutoIndexingEnabled(\n resolver: Resolver,\n options?: { defaultValue?: boolean },\n): Promise<boolean> {\n if (envDisablesAutoIndexing()) return false\n const fallback = options?.defaultValue ?? true\n let service: ModuleConfigService\n try {\n service = resolver.resolve<ModuleConfigService>('moduleConfigService')\n } catch {\n return fallback\n }\n try {\n // Still use 'vector' module key for backwards compatibility\n const value = await service.getValue<boolean>('vector', SEARCH_AUTO_INDEX_CONFIG_KEY, { defaultValue: fallback })\n return value !== false\n } catch {\n return fallback\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,yBAAyB;AAE3B,MAAM,+BAA+B;AAErC,SAAS,0BAAmC;AACjD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,kBAAkB,GAAG,MAAM;AACpC;AAMA,eAAsB,2BACpB,UACA,SACkB;AAClB,MAAI,wBAAwB,EAAG,QAAO;AACtC,QAAM,WAAW,SAAS,gBAAgB;AAC1C,MAAI;AACJ,MAAI;AACF,cAAU,SAAS,QAA6B,qBAAqB;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI;AAEF,UAAM,QAAQ,MAAM,QAAQ,SAAkB,UAAU,8BAA8B,EAAE,cAAc,SAAS,CAAC;AAChH,WAAO,UAAU;AAAA,EACnB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }