@open-mercato/search 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/search/frontend/components/sections/FulltextSearchSection.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 { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\n\n// Types\ntype FulltextStats = {\n numberOfDocuments: number\n isIndexing: boolean\n fieldDistribution: Record<string, number>\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype FulltextEnvVarStatus = {\n set: boolean\n hint: string\n}\n\ntype FulltextOptionalEnvVarStatus = {\n set: boolean\n value?: string | boolean\n default?: string | boolean\n hint: string\n}\n\ntype FulltextConfigResponse = {\n driver: 'meilisearch' | null\n configured: boolean\n envVars: {\n MEILISEARCH_HOST: FulltextEnvVarStatus\n MEILISEARCH_API_KEY: FulltextEnvVarStatus\n }\n optionalEnvVars: {\n MEILISEARCH_INDEX_PREFIX: FulltextOptionalEnvVarStatus\n SEARCH_EXCLUDE_ENCRYPTED_FIELDS: FulltextOptionalEnvVarStatus\n }\n}\n\ntype ReindexResponse = {\n ok: boolean\n action: string\n entityId?: string | null\n result?: {\n entitiesProcessed: number\n recordsIndexed: number\n errors?: Array<{ entityId: string; error: string }>\n }\n stats?: FulltextStats | null\n error?: string\n}\n\ntype ReindexAction = 'clear' | 'recreate' | 'reindex'\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\nexport type FulltextSearchSectionProps = {\n fulltextConfig: FulltextConfigResponse | null\n fulltextConfigLoading: boolean\n fulltextStats: FulltextStats | null\n fulltextReindexLock: ReindexLock | null\n loading: boolean\n onStatsUpdate: (stats: FulltextStats | null) => void\n onRefresh: () => Promise<void>\n}\n\nconst normalizeErrorMessage = (error: unknown, fallback: string): string => {\n if (typeof error === 'string' && error.trim().length) return error.trim()\n if (error instanceof Error && error.message.trim().length) return error.message.trim()\n return fallback\n}\n\nexport function FulltextSearchSection({\n fulltextConfig,\n fulltextConfigLoading,\n fulltextStats,\n fulltextReindexLock,\n loading,\n onStatsUpdate,\n onRefresh,\n}: FulltextSearchSectionProps) {\n const t = useT()\n const [reindexing, setReindexing] = React.useState<ReindexAction | null>(null)\n const [showReindexDialog, setShowReindexDialog] = React.useState<ReindexAction | null>(null)\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 // Combine logs and errors\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 fulltext-related logs (exclude vector/embedding related)\n const fulltextLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n const isVector = lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n return !isVector\n })\n // Sort by occurredAt descending\n fulltextLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(fulltextLogs.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 const handleReindexClick = (action: ReindexAction) => {\n setShowReindexDialog(action)\n }\n\n const handleReindexCancel = () => {\n setShowReindexDialog(null)\n }\n\n const handleReindexConfirm = React.useCallback(async () => {\n const action = showReindexDialog\n if (!action) return\n\n setShowReindexDialog(null)\n setReindexing(action)\n\n try {\n const response = await fetch('/api/search/reindex', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action, useQueue: action === 'reindex' }),\n })\n\n const body = await response.json() as ReindexResponse\n\n if (!response.ok || body.error) {\n throw new Error(body.error || t('search.settings.reindexErrorLabel', 'Failed to reindex'))\n }\n\n if (body.stats) {\n onStatsUpdate(body.stats)\n }\n\n const successLabel = t('search.settings.reindexSuccessLabel', 'Operation completed successfully')\n const successMessage = action === 'reindex' && body.result\n ? `${successLabel}: ${body.result.recordsIndexed} documents indexed`\n : successLabel\n\n flash(successMessage, 'success')\n await onRefresh()\n await fetchActivityLogs()\n } catch (err) {\n const message = normalizeErrorMessage(err, t('search.settings.reindexErrorLabel', 'Failed to reindex'))\n flash(message, 'error')\n } finally {\n setReindexing(null)\n }\n }, [showReindexDialog, t, onStatsUpdate, onRefresh, fetchActivityLogs])\n\n const getDialogContent = (action: ReindexAction) => {\n switch (action) {\n case 'clear':\n return {\n title: t('search.settings.clearIndexDialogTitle', 'Clear Index'),\n description: t('search.settings.clearIndexDialogDescription', 'This will remove all documents from the Meilisearch index but keep the index settings.'),\n warning: t('search.settings.clearIndexDialogWarning', 'Search will not work until documents are re-indexed.'),\n confirmLabel: t('search.settings.clearIndexLabel', 'Clear Index'),\n }\n case 'recreate':\n return {\n title: t('search.settings.recreateIndexDialogTitle', 'Recreate Index'),\n description: t('search.settings.recreateIndexDialogDescription', 'This will delete the index completely and recreate it with fresh settings.'),\n warning: t('search.settings.recreateIndexDialogWarning', 'All indexed documents will be permanently removed.'),\n confirmLabel: t('search.settings.recreateIndexLabel', 'Recreate Index'),\n }\n case 'reindex':\n return {\n title: t('search.settings.fullReindexDialogTitle', 'Full Reindex'),\n description: t('search.settings.fullReindexDialogDescription', 'This will recreate the index and re-index all data from the database.'),\n warning: t('search.settings.fullReindexDialogWarning', 'This operation may take a while depending on the amount of data.'),\n confirmLabel: t('search.settings.fullReindexLabel', 'Full Reindex'),\n }\n }\n }\n\n const getStrategyIcon = () => (\n <svg className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z\" />\n </svg>\n )\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.fulltext.sectionTitle', 'Full-Text Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.fulltext.sectionDescription', 'Fast, typo-tolerant search using Meilisearch.')}\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 {fulltextConfigLoading ? (\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 {/* Driver Status */}\n <div className=\"flex items-center gap-3 p-3 rounded-md border border-border bg-muted/30\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-full ${\n fulltextConfig?.configured\n ? 'bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400'\n : 'bg-amber-100 text-amber-600 dark:bg-amber-900/40 dark:text-amber-400'\n }`}>\n {getStrategyIcon()}\n </div>\n <div>\n <p className=\"font-medium\">\n {t('search.settings.fulltext.driver', 'Current Driver')}: {fulltextConfig?.driver ? 'Meilisearch' : t('search.settings.fulltext.noDriver', 'None')}\n </p>\n <p className={`text-sm ${\n fulltextConfig?.configured\n ? 'text-emerald-600 dark:text-emerald-400'\n : 'text-amber-600 dark:text-amber-400'\n }`}>\n {fulltextConfig?.configured\n ? t('search.settings.fulltext.ready', 'Ready to use')\n : t('search.settings.fulltext.notReady', 'Not configured - set environment variables below')}\n </p>\n </div>\n </div>\n\n {/* Required Environment Variables */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">\n {t('search.settings.fulltext.envVars', 'Required Environment Variables')}\n </h3>\n <div className=\"space-y-2\">\n {fulltextConfig?.envVars && Object.entries(fulltextConfig.envVars).map(([key, status]) => (\n <div key={key} className=\"flex items-start gap-3 p-3 rounded-md border border-border\">\n <div className={`flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 mt-0.5 ${\n status.set\n ? 'bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400'\n : 'bg-red-100 text-red-600 dark:bg-red-900/40 dark:text-red-400'\n }`}>\n {status.set ? (\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 ) : (\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=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n )}\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <code className=\"text-sm font-mono bg-muted px-1.5 py-0.5 rounded\">{key}</code>\n <span className={`text-xs ${status.set ? 'text-emerald-600 dark:text-emerald-400' : 'text-red-600 dark:text-red-400'}`}>\n {status.set ? t('search.settings.fulltext.envSet', 'Set') : t('search.settings.fulltext.envMissing', 'Missing')}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">{status.hint}</p>\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Optional Settings */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">\n {t('search.settings.fulltext.optional', 'Optional Settings')}\n </h3>\n <div className=\"space-y-2\">\n {fulltextConfig?.optionalEnvVars && Object.entries(fulltextConfig.optionalEnvVars).map(([key, status]) => (\n <div key={key} className=\"flex items-start gap-3 p-2 rounded-md bg-muted/30\">\n <code className=\"text-xs font-mono bg-muted px-1.5 py-0.5 rounded\">{key}</code>\n <div className=\"flex-1 text-xs text-muted-foreground\">\n <span>{status.hint}</span>\n {status.set ? (\n <span className=\"ml-2 text-emerald-600 dark:text-emerald-400\">\n ({t('search.settings.fulltext.currentValue', 'Current')}: {String(status.value)})\n </span>\n ) : (\n <span className=\"ml-2\">\n ({t('search.settings.fulltext.defaultValue', 'Default')}: {String(status.default)})\n </span>\n )}\n </div>\n </div>\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.fulltext.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.fulltext.howToDescription', 'Add these variables to your .env file or deployment environment. You can use a hosted Meilisearch instance or run it locally with Docker.')}</p>\n <a\n href=\"https://www.meilisearch.com/docs/learn/getting_started/quick_start\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-blue-600 dark:text-blue-400 hover:underline mt-1 inline-block\"\n >\n {t('search.settings.fulltext.learnMore', 'Learn more: Meilisearch Quick Start')} \u2192\n </a>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {(loading || fulltextConfigLoading) ? (\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 ) : !fulltextConfig?.configured ? (\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.fulltextNotConfigured', 'Full-text search driver not configured')}\n </p>\n <p className=\"text-xs text-amber-700 dark:text-amber-300 mt-1\">\n {t('search.settings.fulltextNotConfiguredHint', 'Configure the required environment variables in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Stats */}\n {fulltextStats ? (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.documentsLabel', 'Documents')}</p>\n <p className=\"text-2xl font-bold\">{fulltextStats.numberOfDocuments.toLocaleString()}</p>\n </div>\n ) : (\n <div className=\"p-3 rounded-md bg-muted/50\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.noIndexMessage', \"No index found for this tenant. Click 'Full Reindex' to create one.\")}\n </p>\n </div>\n )}\n\n {/* Active reindex lock banner */}\n {fulltextReindexLock && (\n <div className=\"p-4 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: fulltextReindexLock.action,\n minutes: fulltextReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3 pt-2\">\n {fulltextStats && (\n <>\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleReindexClick('clear')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'clear' ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.clearIndexLabel', 'Clear Index')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.clearIndexDescription', 'Remove all documents but keep index settings')}\n </span>\n </div>\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleReindexClick('recreate')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'recreate' ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.recreateIndexLabel', 'Recreate Index')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.recreateIndexDescription', 'Delete and recreate the index with fresh settings')}\n </span>\n </div>\n </>\n )}\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={() => handleReindexClick('reindex')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'reindex' || fulltextReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.fullReindexLabel', 'Full Reindex')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.fullReindexDescription', 'Recreate index and re-index all data from database')}\n </span>\n </div>\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 {/* Reindex Confirmation Dialog */}\n {showReindexDialog && (\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 <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-amber-100 dark:bg-amber-900/40\">\n <svg className=\"h-5 w-5 text-amber-600 dark:text-amber-400\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </div>\n <div>\n <h3 className=\"text-lg font-semibold\">{getDialogContent(showReindexDialog).title}</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">{getDialogContent(showReindexDialog).description}</p>\n </div>\n </div>\n\n <div className=\"mb-4 p-3 rounded-md bg-amber-50 dark:bg-amber-900/20\">\n <div className=\"flex items-start gap-2\">\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 <p className=\"text-sm text-amber-800 dark:text-amber-200\">{getDialogContent(showReindexDialog).warning}</p>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleReindexCancel}>\n {t('search.settings.cancelLabel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n variant={showReindexDialog === 'reindex' ? 'default' : 'destructive'}\n onClick={handleReindexConfirm}\n >\n {getDialogContent(showReindexDialog).confirmLabel}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default FulltextSearchSection\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 { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { Tabs, TabsList, TabsTrigger, TabsContent } from '@open-mercato/ui/primitives/tabs'\n\n// Types\ntype FulltextStats = {\n numberOfDocuments: number\n isIndexing: boolean\n fieldDistribution: Record<string, number>\n}\n\ntype ReindexLock = {\n type: 'fulltext' | 'vector'\n action: string\n startedAt: string\n elapsedMinutes: number\n}\n\ntype FulltextEnvVarStatus = {\n set: boolean\n hint: string\n}\n\ntype FulltextOptionalEnvVarStatus = {\n set: boolean\n value?: string | boolean\n default?: string | boolean\n hint: string\n}\n\ntype FulltextConfigResponse = {\n driver: 'meilisearch' | null\n configured: boolean\n envVars: {\n MEILISEARCH_HOST: FulltextEnvVarStatus\n MEILISEARCH_API_KEY: FulltextEnvVarStatus\n }\n optionalEnvVars: {\n MEILISEARCH_INDEX_PREFIX: FulltextOptionalEnvVarStatus\n SEARCH_EXCLUDE_ENCRYPTED_FIELDS: FulltextOptionalEnvVarStatus\n }\n}\n\ntype ReindexResponse = {\n ok: boolean\n action: string\n entityId?: string | null\n result?: {\n entitiesProcessed: number\n recordsIndexed: number\n errors?: Array<{ entityId: string; error: string }>\n }\n stats?: FulltextStats | null\n error?: string\n}\n\ntype ReindexAction = 'clear' | 'recreate' | 'reindex'\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\nexport type FulltextSearchSectionProps = {\n fulltextConfig: FulltextConfigResponse | null\n fulltextConfigLoading: boolean\n fulltextStats: FulltextStats | null\n fulltextReindexLock: ReindexLock | null\n loading: boolean\n onStatsUpdate: (stats: FulltextStats | null) => void\n onRefresh: () => Promise<void>\n}\n\nconst normalizeErrorMessage = (error: unknown, fallback: string): string => {\n if (typeof error === 'string' && error.trim().length) return error.trim()\n if (error instanceof Error && error.message.trim().length) return error.message.trim()\n return fallback\n}\n\nexport function FulltextSearchSection({\n fulltextConfig,\n fulltextConfigLoading,\n fulltextStats,\n fulltextReindexLock,\n loading,\n onStatsUpdate,\n onRefresh,\n}: FulltextSearchSectionProps) {\n const t = useT()\n const [reindexing, setReindexing] = React.useState<ReindexAction | null>(null)\n const [showReindexDialog, setShowReindexDialog] = React.useState<ReindexAction | null>(null)\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 // Combine logs and errors\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 fulltext-related logs (exclude vector/embedding related)\n const fulltextLogs = allLogs.filter(log => {\n const lowerSource = log.source?.toLowerCase() ?? ''\n const lowerMessage = log.message?.toLowerCase() ?? ''\n const lowerHandler = log.handler?.toLowerCase() ?? ''\n const isVector = lowerSource.includes('vector') || lowerMessage.includes('vector') ||\n lowerMessage.includes('embedding') || lowerHandler.includes('vector')\n return !isVector\n })\n // Sort by occurredAt descending\n fulltextLogs.sort((a, b) => new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime())\n setActivityLogs(fulltextLogs.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 const handleReindexClick = (action: ReindexAction) => {\n setShowReindexDialog(action)\n }\n\n const handleReindexCancel = () => {\n setShowReindexDialog(null)\n }\n\n const handleReindexConfirm = React.useCallback(async () => {\n const action = showReindexDialog\n if (!action) return\n\n setShowReindexDialog(null)\n setReindexing(action)\n\n try {\n const response = await fetch('/api/search/reindex', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action, useQueue: action === 'reindex' }),\n })\n\n const body = await response.json() as ReindexResponse\n\n if (!response.ok || body.error) {\n throw new Error(body.error || t('search.settings.reindexErrorLabel', 'Failed to reindex'))\n }\n\n if (body.stats) {\n onStatsUpdate(body.stats)\n }\n\n const successLabel = t('search.settings.reindexSuccessLabel', 'Operation completed successfully')\n const successMessage = action === 'reindex' && body.result\n ? `${successLabel}: ${body.result.recordsIndexed} documents indexed`\n : successLabel\n\n flash(successMessage, 'success')\n await onRefresh()\n await fetchActivityLogs()\n } catch (err) {\n const message = normalizeErrorMessage(err, t('search.settings.reindexErrorLabel', 'Failed to reindex'))\n flash(message, 'error')\n } finally {\n setReindexing(null)\n }\n }, [showReindexDialog, t, onStatsUpdate, onRefresh, fetchActivityLogs])\n\n const getDialogContent = (action: ReindexAction) => {\n switch (action) {\n case 'clear':\n return {\n title: t('search.settings.clearIndexDialogTitle', 'Clear Index'),\n description: t('search.settings.clearIndexDialogDescription', 'This will remove all documents from the Meilisearch index but keep the index settings.'),\n warning: t('search.settings.clearIndexDialogWarning', 'Search will not work until documents are re-indexed.'),\n confirmLabel: t('search.settings.clearIndexLabel', 'Clear Index'),\n }\n case 'recreate':\n return {\n title: t('search.settings.recreateIndexDialogTitle', 'Recreate Index'),\n description: t('search.settings.recreateIndexDialogDescription', 'This will delete the index completely and recreate it with fresh settings.'),\n warning: t('search.settings.recreateIndexDialogWarning', 'All indexed documents will be permanently removed.'),\n confirmLabel: t('search.settings.recreateIndexLabel', 'Recreate Index'),\n }\n case 'reindex':\n return {\n title: t('search.settings.fullReindexDialogTitle', 'Full Reindex'),\n description: t('search.settings.fullReindexDialogDescription', 'This will recreate the index and re-index all data from the database.'),\n warning: t('search.settings.fullReindexDialogWarning', 'This operation may take a while depending on the amount of data.'),\n confirmLabel: t('search.settings.fullReindexLabel', 'Full Reindex'),\n }\n }\n }\n\n const getStrategyIcon = () => (\n <svg className=\"h-5 w-5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z\" />\n </svg>\n )\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.fulltext.sectionTitle', 'Full-Text Search')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.fulltext.sectionDescription', 'Fast, typo-tolerant search using Meilisearch.')}\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 {fulltextConfigLoading ? (\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 {/* Driver Status */}\n <div className=\"flex items-center gap-3 p-3 rounded-md border border-border bg-muted/30\">\n <div className={`flex h-10 w-10 items-center justify-center rounded-full ${\n fulltextConfig?.configured\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-status-warning-bg text-status-warning-icon'\n }`}>\n {getStrategyIcon()}\n </div>\n <div>\n <p className=\"font-medium\">\n {t('search.settings.fulltext.driver', 'Current Driver')}: {fulltextConfig?.driver ? 'Meilisearch' : t('search.settings.fulltext.noDriver', 'None')}\n </p>\n <p className={`text-sm ${\n fulltextConfig?.configured\n ? 'text-status-success-text'\n : 'text-status-warning-text'\n }`}>\n {fulltextConfig?.configured\n ? t('search.settings.fulltext.ready', 'Ready to use')\n : t('search.settings.fulltext.notReady', 'Not configured - set environment variables below')}\n </p>\n </div>\n </div>\n\n {/* Required Environment Variables */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">\n {t('search.settings.fulltext.envVars', 'Required Environment Variables')}\n </h3>\n <div className=\"space-y-2\">\n {fulltextConfig?.envVars && Object.entries(fulltextConfig.envVars).map(([key, status]) => (\n <div key={key} className=\"flex items-start gap-3 p-3 rounded-md border border-border\">\n <div className={`flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 mt-0.5 ${\n status.set\n ? 'bg-status-success-bg text-status-success-icon'\n : 'bg-status-error-bg text-status-error-icon'\n }`}>\n {status.set ? (\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 ) : (\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=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n )}\n </div>\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <code className=\"text-sm font-mono bg-muted px-1.5 py-0.5 rounded\">{key}</code>\n <span className={`text-xs ${status.set ? 'text-status-success-text' : 'text-status-error-text'}`}>\n {status.set ? t('search.settings.fulltext.envSet', 'Set') : t('search.settings.fulltext.envMissing', 'Missing')}\n </span>\n </div>\n <p className=\"text-xs text-muted-foreground mt-1\">{status.hint}</p>\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Optional Settings */}\n <div>\n <h3 className=\"text-sm font-semibold mb-2\">\n {t('search.settings.fulltext.optional', 'Optional Settings')}\n </h3>\n <div className=\"space-y-2\">\n {fulltextConfig?.optionalEnvVars && Object.entries(fulltextConfig.optionalEnvVars).map(([key, status]) => (\n <div key={key} className=\"flex items-start gap-3 p-2 rounded-md bg-muted/30\">\n <code className=\"text-xs font-mono bg-muted px-1.5 py-0.5 rounded\">{key}</code>\n <div className=\"flex-1 text-xs text-muted-foreground\">\n <span>{status.hint}</span>\n {status.set ? (\n <span className=\"ml-2 text-status-success-text\">\n ({t('search.settings.fulltext.currentValue', 'Current')}: {String(status.value)})\n </span>\n ) : (\n <span className=\"ml-2\">\n ({t('search.settings.fulltext.defaultValue', 'Default')}: {String(status.default)})\n </span>\n )}\n </div>\n </div>\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.fulltext.howTo', 'How to set up')}</p>\n <p className=\"text-xs\">{t('search.settings.fulltext.howToDescription', 'Add these variables to your .env file or deployment environment. You can use a hosted Meilisearch instance or run it locally with Docker.')}</p>\n <a\n href=\"https://www.meilisearch.com/docs/learn/getting_started/quick_start\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-xs text-status-info-text hover:underline mt-1 inline-block\"\n >\n {t('search.settings.fulltext.learnMore', 'Learn more: Meilisearch Quick Start')} \u2192\n </a>\n </div>\n </div>\n </div>\n </div>\n )}\n </TabsContent>\n\n {/* Index Management Tab */}\n <TabsContent value=\"index\">\n {(loading || fulltextConfigLoading) ? (\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 ) : !fulltextConfig?.configured ? (\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.fulltextNotConfigured', 'Full-text search driver not configured')}\n </p>\n <p className=\"text-xs text-status-warning-text mt-1\">\n {t('search.settings.fulltextNotConfiguredHint', 'Configure the required environment variables in the Configuration tab to enable indexing.')}\n </p>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n {/* Stats */}\n {fulltextStats ? (\n <div className=\"rounded-md border border-border p-4 max-w-xs\">\n <p className=\"text-sm text-muted-foreground\">{t('search.settings.documentsLabel', 'Documents')}</p>\n <p className=\"text-2xl font-bold\">{fulltextStats.numberOfDocuments.toLocaleString()}</p>\n </div>\n ) : (\n <div className=\"p-3 rounded-md bg-muted/50\">\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.noIndexMessage', \"No index found for this tenant. Click 'Full Reindex' to create one.\")}\n </p>\n </div>\n )}\n\n {/* Active reindex lock banner */}\n {fulltextReindexLock && (\n <div className=\"p-4 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: fulltextReindexLock.action,\n minutes: fulltextReindexLock.elapsedMinutes,\n })}\n </p>\n </div>\n </div>\n </div>\n )}\n\n {/* Actions */}\n <div className=\"flex flex-wrap gap-3 pt-2\">\n {fulltextStats && (\n <>\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleReindexClick('clear')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'clear' ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.clearIndexLabel', 'Clear Index')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.clearIndexDescription', 'Remove all documents but keep index settings')}\n </span>\n </div>\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => handleReindexClick('recreate')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'recreate' ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.recreateIndexLabel', 'Recreate Index')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.recreateIndexDescription', 'Delete and recreate the index with fresh settings')}\n </span>\n </div>\n </>\n )}\n <div className=\"flex flex-col\">\n <Button\n type=\"button\"\n variant=\"default\"\n size=\"sm\"\n onClick={() => handleReindexClick('reindex')}\n disabled={reindexing !== null || fulltextReindexLock !== null}\n >\n {reindexing === 'reindex' || fulltextReindexLock !== null ? (\n <>\n <Spinner size=\"sm\" className=\"mr-2\" />\n {t('search.settings.processingLabel', 'Processing...')}\n </>\n ) : (\n t('search.settings.fullReindexLabel', 'Full Reindex')\n )}\n </Button>\n <span className=\"text-xs text-muted-foreground mt-1\">\n {t('search.settings.fullReindexDescription', 'Recreate index and re-index all data from database')}\n </span>\n </div>\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 {/* Reindex Confirmation Dialog */}\n {showReindexDialog && (\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 <div className=\"flex items-start gap-3 mb-4\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-status-warning-bg\">\n <svg className=\"h-5 w-5 text-status-warning-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\" />\n </svg>\n </div>\n <div>\n <h3 className=\"text-lg font-semibold\">{getDialogContent(showReindexDialog).title}</h3>\n <p className=\"text-sm text-muted-foreground mt-1\">{getDialogContent(showReindexDialog).description}</p>\n </div>\n </div>\n\n <div className=\"mb-4 p-3 rounded-md bg-status-warning-bg\">\n <div className=\"flex items-start gap-2\">\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 <p className=\"text-sm text-status-warning-text\">{getDialogContent(showReindexDialog).warning}</p>\n </div>\n </div>\n\n <div className=\"flex justify-end gap-3\">\n <Button type=\"button\" variant=\"outline\" onClick={handleReindexCancel}>\n {t('search.settings.cancelLabel', 'Cancel')}\n </Button>\n <Button\n type=\"button\"\n variant={showReindexDialog === 'reindex' ? 'default' : 'destructive'}\n onClick={handleReindexConfirm}\n >\n {getDialogContent(showReindexDialog).confirmLabel}\n </Button>\n </div>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default FulltextSearchSection\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -30,7 +30,7 @@ function GlobalSearchSection({
30
30
  checked: strategies.has("fulltext"),
31
31
  onChange: () => onToggleStrategy("fulltext"),
32
32
  disabled: saving || strategies.has("fulltext") && strategies.size === 1,
33
- className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary"
33
+ className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring"
34
34
  }
35
35
  ),
36
36
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
@@ -55,7 +55,7 @@ function GlobalSearchSection({
55
55
  checked: strategies.has("vector"),
56
56
  onChange: () => onToggleStrategy("vector"),
57
57
  disabled: saving || strategies.has("vector") && strategies.size === 1,
58
- className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary"
58
+ className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring"
59
59
  }
60
60
  ),
61
61
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
@@ -80,7 +80,7 @@ function GlobalSearchSection({
80
80
  checked: strategies.has("tokens"),
81
81
  onChange: () => onToggleStrategy("tokens"),
82
82
  disabled: saving || strategies.has("tokens") && strategies.size === 1,
83
- className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary"
83
+ className: "mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring"
84
84
  }
85
85
  ),
86
86
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/search/frontend/components/sections/GlobalSearchSection.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\nexport type GlobalSearchSectionProps = {\n loading: boolean\n saving: boolean\n strategies: Set<string>\n fulltextConfigured: boolean\n vectorConfigured: boolean\n onToggleStrategy: (strategyId: string) => void\n}\n\nexport function GlobalSearchSection({\n loading,\n saving,\n strategies,\n fulltextConfigured,\n vectorConfigured,\n onToggleStrategy,\n}: GlobalSearchSectionProps) {\n const t = useT()\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.globalSearch.title', 'Global Search (Cmd+K)')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.globalSearch.description', 'Configure which search methods are used when searching with Cmd+K.')}\n </p>\n\n {loading ? (\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-3\">\n {/* Full-Text Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('fulltext')}\n onChange={() => onToggleStrategy('fulltext')}\n disabled={saving || (strategies.has('fulltext') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary\"\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.fulltext', 'Full-Text Search')}\n </span>\n {!fulltextConfigured && (\n <span className=\"text-xs text-amber-600 dark:text-amber-400\">\n {t('search.settings.globalSearch.notConfigured', '(Not configured)')}\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.fulltextDescription', 'Fast, typo-tolerant search across all text fields.')}\n </p>\n </div>\n </label>\n\n {/* Semantic Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('vector')}\n onChange={() => onToggleStrategy('vector')}\n disabled={saving || (strategies.has('vector') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary\"\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.vector', 'Semantic Search (AI)')}\n </span>\n {!vectorConfigured && (\n <span className=\"text-xs text-amber-600 dark:text-amber-400\">\n {t('search.settings.globalSearch.notConfigured', '(Not configured)')}\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.vectorDescription', 'AI-powered search that understands meaning and finds related content.')}\n </p>\n </div>\n </label>\n\n {/* Keyword Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('tokens')}\n onChange={() => onToggleStrategy('tokens')}\n disabled={saving || (strategies.has('tokens') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus:ring-primary\"\n />\n <div className=\"flex-1\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.tokens', 'Keyword Search')}\n </span>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.tokensDescription', 'Exact word matching in the database.')}\n </p>\n </div>\n </label>\n </div>\n )}\n </div>\n )\n}\n\nexport default GlobalSearchSection\n"],
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\nexport type GlobalSearchSectionProps = {\n loading: boolean\n saving: boolean\n strategies: Set<string>\n fulltextConfigured: boolean\n vectorConfigured: boolean\n onToggleStrategy: (strategyId: string) => void\n}\n\nexport function GlobalSearchSection({\n loading,\n saving,\n strategies,\n fulltextConfigured,\n vectorConfigured,\n onToggleStrategy,\n}: GlobalSearchSectionProps) {\n const t = useT()\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.globalSearch.title', 'Global Search (Cmd+K)')}\n </h2>\n <p className=\"text-sm text-muted-foreground mb-4\">\n {t('search.settings.globalSearch.description', 'Configure which search methods are used when searching with Cmd+K.')}\n </p>\n\n {loading ? (\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-3\">\n {/* Full-Text Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('fulltext')}\n onChange={() => onToggleStrategy('fulltext')}\n disabled={saving || (strategies.has('fulltext') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring\"\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.fulltext', 'Full-Text Search')}\n </span>\n {!fulltextConfigured && (\n <span className=\"text-xs text-amber-600 dark:text-amber-400\">\n {t('search.settings.globalSearch.notConfigured', '(Not configured)')}\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.fulltextDescription', 'Fast, typo-tolerant search across all text fields.')}\n </p>\n </div>\n </label>\n\n {/* Semantic Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('vector')}\n onChange={() => onToggleStrategy('vector')}\n disabled={saving || (strategies.has('vector') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring\"\n />\n <div className=\"flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.vector', 'Semantic Search (AI)')}\n </span>\n {!vectorConfigured && (\n <span className=\"text-xs text-amber-600 dark:text-amber-400\">\n {t('search.settings.globalSearch.notConfigured', '(Not configured)')}\n </span>\n )}\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.vectorDescription', 'AI-powered search that understands meaning and finds related content.')}\n </p>\n </div>\n </label>\n\n {/* Keyword Search Toggle */}\n <label\n className={`flex items-start gap-3 p-3 rounded-md border border-border hover:bg-muted/50 cursor-pointer transition-colors ${saving ? 'opacity-60' : ''}`}\n >\n <input\n type=\"checkbox\"\n checked={strategies.has('tokens')}\n onChange={() => onToggleStrategy('tokens')}\n disabled={saving || (strategies.has('tokens') && strategies.size === 1)}\n className=\"mt-1 h-4 w-4 rounded border-gray-300 text-primary focus-visible:ring-ring\"\n />\n <div className=\"flex-1\">\n <span className=\"font-medium\">\n {t('search.settings.globalSearch.tokens', 'Keyword Search')}\n </span>\n <p className=\"text-sm text-muted-foreground\">\n {t('search.settings.globalSearch.tokensDescription', 'Exact word matching in the database.')}\n </p>\n </div>\n </label>\n </div>\n )}\n </div>\n )\n}\n\nexport default GlobalSearchSection\n"],
5
5
  "mappings": ";AA2BM,cAQE,YARF;AAxBN,SAAS,YAAY;AACrB,SAAS,eAAe;AAWjB,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA6B;AAC3B,QAAM,IAAI,KAAK;AAEf,SACE,qBAAC,SAAI,WAAU,yDACb;AAAA,wBAAC,QAAG,WAAU,8BACX,YAAE,sCAAsC,uBAAuB,GAClE;AAAA,IACA,oBAAC,OAAE,WAAU,sCACV,YAAE,4CAA4C,oEAAoE,GACrH;AAAA,IAEC,UACC,qBAAC,SAAI,WAAU,iDACb;AAAA,0BAAC,WAAQ,MAAK,MAAK;AAAA,MACnB,oBAAC,UAAM,YAAE,gCAAgC,qBAAqB,GAAE;AAAA,OAClE,IAEA,qBAAC,SAAI,WAAU,aAEb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iHAAiH,SAAS,eAAe,EAAE;AAAA,UAEtJ;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,WAAW,IAAI,UAAU;AAAA,gBAClC,UAAU,MAAM,iBAAiB,UAAU;AAAA,gBAC3C,UAAU,UAAW,WAAW,IAAI,UAAU,KAAK,WAAW,SAAS;AAAA,gBACvE,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,qBAAC,SAAI,WAAU,UACb;AAAA,mCAAC,SAAI,WAAU,2BACb;AAAA,oCAAC,UAAK,WAAU,eACb,YAAE,yCAAyC,kBAAkB,GAChE;AAAA,gBACC,CAAC,sBACA,oBAAC,UAAK,WAAU,8CACb,YAAE,8CAA8C,kBAAkB,GACrE;AAAA,iBAEJ;AAAA,cACA,oBAAC,OAAE,WAAU,iCACV,YAAE,oDAAoD,oDAAoD,GAC7G;AAAA,eACF;AAAA;AAAA;AAAA,MACF;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iHAAiH,SAAS,eAAe,EAAE;AAAA,UAEtJ;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,WAAW,IAAI,QAAQ;AAAA,gBAChC,UAAU,MAAM,iBAAiB,QAAQ;AAAA,gBACzC,UAAU,UAAW,WAAW,IAAI,QAAQ,KAAK,WAAW,SAAS;AAAA,gBACrE,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,qBAAC,SAAI,WAAU,UACb;AAAA,mCAAC,SAAI,WAAU,2BACb;AAAA,oCAAC,UAAK,WAAU,eACb,YAAE,uCAAuC,sBAAsB,GAClE;AAAA,gBACC,CAAC,oBACA,oBAAC,UAAK,WAAU,8CACb,YAAE,8CAA8C,kBAAkB,GACrE;AAAA,iBAEJ;AAAA,cACA,oBAAC,OAAE,WAAU,iCACV,YAAE,kDAAkD,uEAAuE,GAC9H;AAAA,eACF;AAAA;AAAA;AAAA,MACF;AAAA,MAGA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iHAAiH,SAAS,eAAe,EAAE;AAAA,UAEtJ;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,WAAW,IAAI,QAAQ;AAAA,gBAChC,UAAU,MAAM,iBAAiB,QAAQ;AAAA,gBACzC,UAAU,UAAW,WAAW,IAAI,QAAQ,KAAK,WAAW,SAAS;AAAA,gBACrE,WAAU;AAAA;AAAA,YACZ;AAAA,YACA,qBAAC,SAAI,WAAU,UACb;AAAA,kCAAC,UAAK,WAAU,eACb,YAAE,uCAAuC,gBAAgB,GAC5D;AAAA,cACA,oBAAC,OAAE,WAAU,iCACV,YAAE,kDAAkD,sCAAsC,GAC7F;AAAA,eACF;AAAA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KAEJ;AAEJ;AAEA,IAAO,8BAAQ;",
6
6
  "names": []
7
7
  }
@@ -308,18 +308,18 @@ function VectorSearchSection({
308
308
  return /* @__PURE__ */ jsxs(
309
309
  "div",
310
310
  {
311
- className: `flex items-start gap-3 p-3 rounded-md border ${isCurrent && isReady ? "border-emerald-200 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-900/20" : !driver.implemented ? "border-border bg-muted/20 opacity-60" : "border-border bg-muted/30"}`,
311
+ className: `flex items-start gap-3 p-3 rounded-md border ${isCurrent && isReady ? "border-status-success-border bg-status-success-bg" : !driver.implemented ? "border-border bg-muted/30 opacity-60" : "border-border bg-muted/30"}`,
312
312
  children: [
313
- /* @__PURE__ */ jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${isCurrent && isReady ? "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400" : "bg-muted text-muted-foreground"}`, children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("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" }) }) }),
313
+ /* @__PURE__ */ jsx("div", { className: `flex h-8 w-8 items-center justify-center rounded-full flex-shrink-0 ${isCurrent && isReady ? "bg-status-success-bg text-status-success-icon" : "bg-muted text-muted-foreground"}`, children: /* @__PURE__ */ jsx("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("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" }) }) }),
314
314
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
315
315
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
316
- /* @__PURE__ */ jsx("p", { className: `text-sm font-medium ${isCurrent && isReady ? "text-emerald-700 dark:text-emerald-300" : ""}`, children: driver.name }),
317
- isCurrent && /* @__PURE__ */ jsx("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", children: t("search.settings.vector.active", "Active") }),
318
- !driver.implemented && /* @__PURE__ */ jsx("span", { className: "text-[10px] px-1.5 py-0.5 rounded bg-muted text-muted-foreground", children: t("search.settings.vector.comingSoon", "Coming soon") })
316
+ /* @__PURE__ */ jsx("p", { className: `text-sm font-medium ${isCurrent && isReady ? "text-status-success-text" : ""}`, children: driver.name }),
317
+ isCurrent && /* @__PURE__ */ jsx("span", { className: "text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text", children: t("search.settings.vector.active", "Active") }),
318
+ !driver.implemented && /* @__PURE__ */ jsx("span", { className: "text-overline px-1.5 py-0.5 rounded bg-muted text-muted-foreground", children: t("search.settings.vector.comingSoon", "Coming soon") })
319
319
  ] }),
320
320
  /* @__PURE__ */ jsx("div", { className: "mt-1 space-y-0.5", children: driver.envVars.map((envVar) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
321
- /* @__PURE__ */ jsx("div", { className: `h-1.5 w-1.5 rounded-full ${envVar.set ? "bg-emerald-500" : "bg-muted-foreground/40"}` }),
322
- /* @__PURE__ */ jsx("code", { className: "text-[10px] text-muted-foreground font-mono", children: envVar.name })
321
+ /* @__PURE__ */ jsx("div", { className: `h-1.5 w-1.5 rounded-full ${envVar.set ? "bg-status-success-icon" : "bg-muted-foreground/40"}` }),
322
+ /* @__PURE__ */ jsx("code", { className: "text-overline text-muted-foreground font-mono", children: envVar.name })
323
323
  ] }, envVar.name)) })
324
324
  ] })
325
325
  ]
@@ -342,13 +342,13 @@ function VectorSearchSection({
342
342
  type: "button",
343
343
  onClick: () => isConfigured && handleProviderChange(providerId),
344
344
  disabled: !isConfigured || embeddingLoading || embeddingSaving,
345
- className: `text-left p-3 rounded-lg border-2 transition-all ${isSelected ? "border-primary bg-primary/5 ring-1 ring-primary/20" : isConfigured ? "border-border hover:border-primary/50 hover:bg-muted/50 cursor-pointer" : "border-border bg-muted/20 opacity-50 cursor-not-allowed"}`,
345
+ className: `text-left p-3 rounded-lg border-2 transition-all ${isSelected ? "border-primary bg-primary/5 ring-1 ring-primary/20" : isConfigured ? "border-border hover:border-primary/50 hover:bg-muted/50 cursor-pointer" : "border-border bg-muted/30 opacity-50 cursor-not-allowed"}`,
346
346
  children: [
347
347
  /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
348
348
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
349
349
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
350
350
  /* @__PURE__ */ jsx("p", { className: `text-sm font-medium ${isSelected ? "text-primary" : isConfigured ? "" : "text-muted-foreground"}`, children: info.name }),
351
- isCurrentlySaved && isConfigured && /* @__PURE__ */ jsx("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", children: t("search.settings.vector.active", "Active") })
351
+ isCurrentlySaved && isConfigured && /* @__PURE__ */ jsx("span", { className: "text-overline px-1.5 py-0.5 rounded bg-status-success-bg text-status-success-text", children: t("search.settings.vector.active", "Active") })
352
352
  ] }),
353
353
  isConfigured ? /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [
354
354
  info.models.length,
@@ -357,10 +357,10 @@ function VectorSearchSection({
357
357
  ] }) : /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: [
358
358
  t("search.settings.vector.setEnvVar", "Set"),
359
359
  " ",
360
- /* @__PURE__ */ jsx("code", { className: "font-mono text-[10px] bg-muted px-1 rounded", children: info.envKeyRequired })
360
+ /* @__PURE__ */ jsx("code", { className: "font-mono text-overline bg-muted px-1 rounded", children: info.envKeyRequired })
361
361
  ] })
362
362
  ] }),
363
- /* @__PURE__ */ jsx("div", { className: `flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 ${isSelected ? "bg-primary text-primary-foreground" : isConfigured ? "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/40 dark:text-emerald-400" : "bg-muted text-muted-foreground"}`, children: isSelected ? /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) : isConfigured ? /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) : /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }) })
363
+ /* @__PURE__ */ jsx("div", { className: `flex h-5 w-5 items-center justify-center rounded-full flex-shrink-0 ${isSelected ? "bg-primary text-primary-foreground" : isConfigured ? "bg-status-success-bg text-status-success-icon" : "bg-muted text-muted-foreground"}`, children: isSelected ? /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 3, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) : isConfigured ? /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) : /* @__PURE__ */ jsx("svg", { className: "h-3 w-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 4v16m8-8H4" }) }) })
364
364
  ] }),
365
365
  isSelected && isConfigured && /* @__PURE__ */ jsxs("div", { className: "mt-3 pt-3 border-t border-border space-y-2", onClick: (e) => e.stopPropagation(), onKeyDown: (e) => e.stopPropagation(), role: "presentation", children: [
366
366
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
@@ -369,7 +369,7 @@ function VectorSearchSection({
369
369
  "select",
370
370
  {
371
371
  id: `model-${providerId}`,
372
- 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",
372
+ className: "w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50",
373
373
  value: displayModel,
374
374
  onChange: (e) => handleModelChange(e.target.value),
375
375
  disabled: embeddingLoading || embeddingSaving,
@@ -422,7 +422,7 @@ function VectorSearchSection({
422
422
  ": ",
423
423
  displayDimension
424
424
  ] }),
425
- embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && /* @__PURE__ */ jsxs("span", { className: "text-amber-600 dark:text-amber-400", children: [
425
+ embeddingSettings?.indexedDimension && embeddingSettings.indexedDimension !== displayDimension && /* @__PURE__ */ jsxs("span", { className: "text-status-warning-text", children: [
426
426
  t("search.settings.dimension.mismatch", "mismatch"),
427
427
  ": ",
428
428
  embeddingSettings.indexedDimension
@@ -442,9 +442,9 @@ function VectorSearchSection({
442
442
  );
443
443
  }) })
444
444
  ] }),
445
- /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
446
- /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("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" }) }),
447
- /* @__PURE__ */ jsxs("div", { className: "text-sm text-blue-800 dark:text-blue-200", children: [
445
+ /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md bg-status-info-bg border border-status-info-border", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
446
+ /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("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" }) }),
447
+ /* @__PURE__ */ jsxs("div", { className: "text-sm text-status-info-text", children: [
448
448
  /* @__PURE__ */ jsx("p", { className: "font-medium mb-1", children: t("search.settings.vector.howTo", "How to set up") }),
449
449
  /* @__PURE__ */ jsx("p", { className: "text-xs", children: 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.") })
450
450
  ] })
@@ -453,11 +453,11 @@ function VectorSearchSection({
453
453
  /* @__PURE__ */ jsx(TabsContent, { value: "index", children: embeddingLoading ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
454
454
  /* @__PURE__ */ jsx(Spinner, { size: "sm" }),
455
455
  /* @__PURE__ */ jsx("span", { children: t("search.settings.loadingLabel", "Loading settings...") })
456
- ] }) : !isEmbeddingConfigured ? /* @__PURE__ */ jsx("div", { className: "p-4 rounded-md bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
457
- /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("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" }) }),
456
+ ] }) : !isEmbeddingConfigured ? /* @__PURE__ */ jsx("div", { className: "p-4 rounded-md bg-status-warning-bg border border-status-warning-border", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
457
+ /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("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" }) }),
458
458
  /* @__PURE__ */ jsxs("div", { children: [
459
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-amber-800 dark:text-amber-200", children: t("search.settings.vectorNotConfigured", "No embedding provider configured") }),
460
- /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-700 dark:text-amber-300 mt-1", children: t("search.settings.vectorNotConfiguredHint", "Configure an embedding provider in the Configuration tab to enable indexing.") })
459
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-status-warning-text", children: t("search.settings.vectorNotConfigured", "No embedding provider configured") }),
460
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text mt-1", children: t("search.settings.vectorNotConfiguredHint", "Configure an embedding provider in the Configuration tab to enable indexing.") })
461
461
  ] })
462
462
  ] }) }) : /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
463
463
  embeddingSettings?.documentCount !== null && embeddingSettings?.documentCount !== void 0 && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border p-4 max-w-xs", children: [
@@ -486,19 +486,19 @@ function VectorSearchSection({
486
486
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
487
487
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("search.settings.vectorReindex.title", "Reindex Data") }),
488
488
  /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: t("search.settings.vectorReindex.description", "Rebuild vector embeddings for all indexed entities. This will purge existing data and regenerate all embeddings.") }),
489
- vectorReindexLock && /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
490
- /* @__PURE__ */ jsx(Spinner, { size: "sm", className: "flex-shrink-0 mt-0.5 text-blue-600 dark:text-blue-400" }),
489
+ vectorReindexLock && /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md bg-status-info-bg border border-status-info-border", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
490
+ /* @__PURE__ */ jsx(Spinner, { size: "sm", className: "flex-shrink-0 mt-0.5 text-status-info-icon" }),
491
491
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
492
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-blue-800 dark:text-blue-200", children: t("search.settings.reindexInProgress", "Reindex operation in progress") }),
493
- /* @__PURE__ */ jsx("p", { className: "text-xs text-blue-700 dark:text-blue-300 mt-1", children: t("search.settings.reindexInProgressDetails", "Action: {{action}} | Started {{minutes}} minutes ago", {
492
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-status-info-text", children: t("search.settings.reindexInProgress", "Reindex operation in progress") }),
493
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-status-info-text mt-1", children: t("search.settings.reindexInProgressDetails", "Action: {{action}} | Started {{minutes}} minutes ago", {
494
494
  action: vectorReindexLock.action,
495
495
  minutes: vectorReindexLock.elapsedMinutes
496
496
  }) })
497
497
  ] })
498
498
  ] }) }),
499
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 rounded bg-amber-50 dark:bg-amber-900/20", children: [
500
- /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("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" }) }),
501
- /* @__PURE__ */ jsx("p", { className: "text-xs text-amber-800 dark:text-amber-200", children: t("search.settings.vectorReindex.warning", "This may take a while for large datasets and will consume API credits.") })
499
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 rounded bg-status-warning-bg", children: [
500
+ /* @__PURE__ */ jsx("svg", { className: "h-4 w-4 text-status-warning-icon flex-shrink-0", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: /* @__PURE__ */ jsx("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" }) }),
501
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-status-warning-text", children: t("search.settings.vectorReindex.warning", "This may take a while for large datasets and will consume API credits.") })
502
502
  ] }),
503
503
  /* @__PURE__ */ jsx(
504
504
  Button,
@@ -523,11 +523,11 @@ function VectorSearchSection({
523
523
  ] }) : activityLogs.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 rounded-md bg-muted/50 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: t("search.settings.activity.noLogs", "No recent indexing activity") }) }) : /* @__PURE__ */ jsx("div", { className: "space-y-2 max-h-80 overflow-y-auto", children: activityLogs.map((log) => /* @__PURE__ */ jsx(
524
524
  "div",
525
525
  {
526
- className: `p-2 rounded-md text-sm ${log.level === "error" ? "bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800" : "bg-muted/50"}`,
526
+ className: `p-2 rounded-md text-sm ${log.level === "error" ? "bg-status-error-bg border border-status-error-border" : "bg-muted/50"}`,
527
527
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
528
- log.level === "error" && /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
528
+ log.level === "error" && /* @__PURE__ */ jsx("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", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
529
529
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
530
- /* @__PURE__ */ jsx("p", { className: `text-xs ${log.level === "error" ? "text-red-800 dark:text-red-200" : "text-foreground"}`, children: log.message }),
530
+ /* @__PURE__ */ jsx("p", { className: `text-xs ${log.level === "error" ? "text-status-error-text" : "text-foreground"}`, children: log.message }),
531
531
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-0.5", children: [
532
532
  (() => {
533
533
  const d = new Date(log.occurredAt);
@@ -557,7 +557,7 @@ function VectorSearchSection({
557
557
  ) })
558
558
  ] })
559
559
  ] }),
560
- showVectorReindexDialog && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg", children: [
560
+ showVectorReindexDialog && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-modal flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "mx-4 max-w-md rounded-lg border border-border bg-card p-6 shadow-lg", children: [
561
561
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: t("search.settings.reindex.confirmTitle", "Confirm Reindex") }),
562
562
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: t("search.settings.reindex.confirmDescription", "This will rebuild all vector embeddings. Existing data will be purged first.") }),
563
563
  /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3", children: [
@@ -565,7 +565,7 @@ function VectorSearchSection({
565
565
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "default", onClick: handleVectorReindexConfirm, children: t("search.settings.reindex.confirmButton", "Start Reindex") })
566
566
  ] })
567
567
  ] }) }),
568
- showEmbeddingConfirmDialog && pendingEmbeddingConfig && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg", children: [
568
+ showEmbeddingConfirmDialog && pendingEmbeddingConfig && /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-modal flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxs("div", { className: "mx-4 max-w-lg rounded-lg border border-border bg-card p-6 shadow-lg", children: [
569
569
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold mb-2", children: t("search.settings.change.title", "Confirm Provider Change") }),
570
570
  /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: t("search.settings.change.description", "Changing the embedding provider will require reindexing all data.") }),
571
571
  /* @__PURE__ */ jsxs("div", { className: "mb-4 p-3 rounded-md bg-muted/50 text-sm", children: [