@samanhappy/mcphub 0.12.15 → 0.12.17

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 (73) hide show
  1. package/dist/config/index.js +9 -9
  2. package/dist/config/index.js.map +1 -1
  3. package/dist/controllers/oauthCallbackController.js +10 -5
  4. package/dist/controllers/oauthCallbackController.js.map +1 -1
  5. package/dist/middlewares/userContext.js +17 -2
  6. package/dist/middlewares/userContext.js.map +1 -1
  7. package/dist/server.js +2 -4
  8. package/dist/server.js.map +1 -1
  9. package/dist/services/mcpService.js +7 -2
  10. package/dist/services/mcpService.js.map +1 -1
  11. package/dist/services/sseService.js +14 -1
  12. package/dist/services/sseService.js.map +1 -1
  13. package/dist/services/vectorSearchService.js +5 -1
  14. package/dist/services/vectorSearchService.js.map +1 -1
  15. package/dist/utils/proxyTrust.js +20 -0
  16. package/dist/utils/proxyTrust.js.map +1 -0
  17. package/frontend/dist/assets/ActivityPage-ClgKeihP.js +2 -0
  18. package/frontend/dist/assets/ActivityPage-ClgKeihP.js.map +1 -0
  19. package/frontend/dist/assets/Badge-Ck2fhRdl.js +2 -0
  20. package/frontend/dist/assets/Badge-Ck2fhRdl.js.map +1 -0
  21. package/frontend/dist/assets/ConfirmDialog-uYjffH4V.js +2 -0
  22. package/frontend/dist/assets/ConfirmDialog-uYjffH4V.js.map +1 -0
  23. package/frontend/dist/assets/Dashboard-BIXrLobn.js +2 -0
  24. package/frontend/dist/assets/Dashboard-BIXrLobn.js.map +1 -0
  25. package/frontend/dist/assets/DeleteDialog-BAfrV8EB.js +2 -0
  26. package/frontend/dist/assets/DeleteDialog-BAfrV8EB.js.map +1 -0
  27. package/frontend/dist/assets/GroupsPage-BjrvyHwu.js +33 -0
  28. package/frontend/dist/assets/GroupsPage-BjrvyHwu.js.map +1 -0
  29. package/frontend/dist/assets/LoginPage-BBHt_TfF.js +2 -0
  30. package/frontend/dist/assets/LoginPage-BBHt_TfF.js.map +1 -0
  31. package/frontend/dist/assets/LogsPage-D8Znq5NB.js +2 -0
  32. package/frontend/dist/assets/LogsPage-D8Znq5NB.js.map +1 -0
  33. package/frontend/dist/assets/MarketPage-haRuzjCw.js +3 -0
  34. package/frontend/dist/assets/MarketPage-haRuzjCw.js.map +1 -0
  35. package/frontend/dist/assets/Pagination-y-gVO8ms.js +2 -0
  36. package/frontend/dist/assets/Pagination-y-gVO8ms.js.map +1 -0
  37. package/frontend/dist/assets/PromptsPage-ByHWPyGe.js +2 -0
  38. package/frontend/dist/assets/PromptsPage-ByHWPyGe.js.map +1 -0
  39. package/frontend/dist/assets/ResourcesPage-Bodw5OY9.js +2 -0
  40. package/frontend/dist/assets/ResourcesPage-Bodw5OY9.js.map +1 -0
  41. package/frontend/dist/assets/ServersPage-CtS1I4yS.js +37 -0
  42. package/frontend/dist/assets/ServersPage-CtS1I4yS.js.map +1 -0
  43. package/frontend/dist/assets/SettingsPage-DxVigf7p.js +12 -0
  44. package/frontend/dist/assets/SettingsPage-DxVigf7p.js.map +1 -0
  45. package/frontend/dist/assets/ToggleGroup-HfxdlkGi.js +2 -0
  46. package/frontend/dist/assets/ToggleGroup-HfxdlkGi.js.map +1 -0
  47. package/frontend/dist/assets/UsersPage-Bipw33cS.js +2 -0
  48. package/frontend/dist/assets/UsersPage-Bipw33cS.js.map +1 -0
  49. package/frontend/dist/assets/framework-vendor-_OBebcuv.js +61 -0
  50. package/frontend/dist/assets/framework-vendor-_OBebcuv.js.map +1 -0
  51. package/frontend/dist/assets/i18n-vendor-MQ921plD.js +2 -0
  52. package/frontend/dist/assets/i18n-vendor-MQ921plD.js.map +1 -0
  53. package/frontend/dist/assets/icons-vendor-B67NtVuR.js +172 -0
  54. package/frontend/dist/assets/icons-vendor-B67NtVuR.js.map +1 -0
  55. package/frontend/dist/assets/index-CmnA4an8.js +5 -0
  56. package/frontend/dist/assets/index-CmnA4an8.js.map +1 -0
  57. package/frontend/dist/assets/index-DfFHVARX.css +1 -0
  58. package/frontend/dist/assets/resourceService-BfCTSBsr.js +2 -0
  59. package/frontend/dist/assets/{resourceService-C3LGHhTi.js.map → resourceService-BfCTSBsr.js.map} +1 -1
  60. package/frontend/dist/assets/useGroupData-DLhbP6zd.js +2 -0
  61. package/frontend/dist/assets/useGroupData-DLhbP6zd.js.map +1 -0
  62. package/frontend/dist/assets/useServerData-QZqQTYcv.js +2 -0
  63. package/frontend/dist/assets/useServerData-QZqQTYcv.js.map +1 -0
  64. package/frontend/dist/assets/useSettingsData-D3VROqS7.js +2 -0
  65. package/frontend/dist/assets/useSettingsData-D3VROqS7.js.map +1 -0
  66. package/frontend/dist/assets/variableDetection-C3Xi21av.js +16 -0
  67. package/frontend/dist/assets/variableDetection-C3Xi21av.js.map +1 -0
  68. package/frontend/dist/index.html +5 -2
  69. package/package.json +2 -2
  70. package/frontend/dist/assets/index-CebeneXS.js +0 -323
  71. package/frontend/dist/assets/index-CebeneXS.js.map +0 -1
  72. package/frontend/dist/assets/index-PEyR1nSL.css +0 -1
  73. package/frontend/dist/assets/resourceService-C3LGHhTi.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SettingsPage-DxVigf7p.js","sources":["../../src/utils/passwordValidation.ts","../../src/components/ChangePasswordForm.tsx","../../src/components/ui/MultiSelect.tsx","../../src/utils/key.ts","../../src/constants/permissions.ts","../../src/pages/SettingsPage.tsx"],"sourcesContent":["/**\n * Frontend password strength validation utility\n * Should match backend validation rules\n */\n\nexport interface PasswordValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\nexport const validatePasswordStrength = (password: string): PasswordValidationResult => {\n const errors: string[] = [];\n\n // Check minimum length\n if (password.length < 8) {\n errors.push('passwordMinLength');\n }\n\n // Check for at least one letter\n if (!/[a-zA-Z]/.test(password)) {\n errors.push('passwordRequireLetter');\n }\n\n // Check for at least one number\n if (!/\\d/.test(password)) {\n errors.push('passwordRequireNumber');\n }\n\n // Check for at least one special character\n if (!/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) {\n errors.push('passwordRequireSpecial');\n }\n\n return {\n isValid: errors.length === 0,\n errors,\n };\n};\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { ChangePasswordCredentials } from '../types';\nimport { changePassword } from '../services/authService';\nimport { validatePasswordStrength } from '../utils/passwordValidation';\n\ninterface ChangePasswordFormProps {\n onSuccess?: () => void;\n onCancel?: () => void;\n}\n\nconst ChangePasswordForm: React.FC<ChangePasswordFormProps> = ({ onSuccess, onCancel }) => {\n const { t } = useTranslation();\n const [formData, setFormData] = useState<ChangePasswordCredentials>({\n currentPassword: '',\n newPassword: '',\n });\n const [confirmPassword, setConfirmPassword] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const [passwordErrors, setPasswordErrors] = useState<string[]>([]);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value } = e.target;\n if (name === 'confirmPassword') {\n setConfirmPassword(value);\n } else {\n setFormData(prev => ({ ...prev, [name]: value }));\n \n // Validate password strength on change for new password\n if (name === 'newPassword') {\n const validation = validatePasswordStrength(value);\n setPasswordErrors(validation.errors);\n }\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validate password strength\n const validation = validatePasswordStrength(formData.newPassword);\n if (!validation.isValid) {\n setError(t('auth.passwordStrengthError'));\n setPasswordErrors(validation.errors);\n return;\n }\n\n // Validate passwords match\n if (formData.newPassword !== confirmPassword) {\n setError(t('auth.passwordsNotMatch'));\n return;\n }\n\n setIsLoading(true);\n try {\n const response = await changePassword(formData);\n\n if (response.success) {\n setSuccess(true);\n if (onSuccess) {\n onSuccess();\n }\n } else {\n setError(response.message || t('auth.changePasswordError'));\n }\n } catch (err) {\n setError(t('auth.changePasswordError'));\n } finally {\n setIsLoading(false);\n }\n };\n\n return (\n <div className=\"p-6 bg-white dark:bg-gray-800 rounded-lg shadow-md\">\n <h2 className=\"text-xl font-bold mb-4\">{t('auth.changePassword')}</h2>\n\n {success ? (\n <div className=\"bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4\">\n {t('auth.changePasswordSuccess')}\n </div>\n ) : (\n <form onSubmit={handleSubmit}>\n {error && (\n <div className=\"bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4\">\n {error}\n </div>\n )}\n\n <div className=\"mb-4\">\n <label className=\"block text-gray-700 text-sm font-bold mb-2\" htmlFor=\"currentPassword\">\n {t('auth.currentPassword')}\n </label>\n <input\n type=\"password\"\n id=\"currentPassword\"\n name=\"currentPassword\"\n className=\"w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500 form-input\"\n value={formData.currentPassword}\n onChange={handleChange}\n required\n />\n </div>\n\n <div className=\"mb-4\">\n <label className=\"block text-gray-700 text-sm font-bold mb-2\" htmlFor=\"newPassword\">\n {t('auth.newPassword')}\n </label>\n <input\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n className=\"w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500 form-input\"\n value={formData.newPassword}\n onChange={handleChange}\n required\n minLength={8}\n />\n {/* Password strength hints */}\n {formData.newPassword && passwordErrors.length > 0 && (\n <div className=\"mt-2 text-sm text-gray-600\">\n <p className=\"font-semibold mb-1\">{t('auth.passwordStrengthHint')}</p>\n <ul className=\"list-disc list-inside space-y-1\">\n {passwordErrors.map((errorKey) => (\n <li key={errorKey} className=\"text-red-600\">\n {t(`auth.${errorKey}`)}\n </li>\n ))}\n </ul>\n </div>\n )}\n {formData.newPassword && passwordErrors.length === 0 && (\n <p className=\"mt-2 text-sm text-green-600\">✓ {t('auth.passwordStrengthHint')}</p>\n )}\n </div>\n\n <div className=\"mb-6\">\n <label className=\"block text-gray-700 text-sm font-bold mb-2\" htmlFor=\"confirmPassword\">\n {t('auth.confirmPassword')}\n </label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n className=\"w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500 form-input\"\n value={confirmPassword}\n onChange={handleChange}\n required\n minLength={8}\n />\n </div>\n\n <div className=\"flex justify-end space-x-2\">\n {onCancel && (\n <button\n type=\"button\"\n onClick={onCancel}\n disabled={isLoading}\n className=\"py-2 px-4 border border-gray-300 rounded-md text-sm font-medium text-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500\"\n >\n {t('common.cancel')}\n </button>\n )}\n <button\n type=\"submit\"\n disabled={isLoading}\n className=\"py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 btn-primary\"\n >\n {isLoading ? (\n <span className=\"flex items-center\">\n <svg className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\"></circle>\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n {t('common.save')}\n </span>\n ) : (\n t('common.save')\n )}\n </button>\n </div>\n </form>\n )}\n </div>\n );\n};\n\nexport default ChangePasswordForm;","import React, { useState, useRef, useEffect } from 'react';\nimport { Check, ChevronDown, X } from 'lucide-react';\n\ninterface MultiSelectProps {\n options: { value: string; label: string }[];\n selected: string[];\n onChange: (selected: string[]) => void;\n placeholder?: string;\n disabled?: boolean;\n className?: string;\n}\n\nexport const MultiSelect: React.FC<MultiSelectProps> = ({\n options,\n selected,\n onChange,\n placeholder = 'Select items...',\n disabled = false,\n className = '',\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [searchTerm, setSearchTerm] = useState('');\n const dropdownRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n setSearchTerm('');\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n const filteredOptions = options.filter((option) =>\n option.label.toLowerCase().includes(searchTerm.toLowerCase()),\n );\n\n const handleToggleOption = (value: string) => {\n if (disabled) return;\n\n const newSelected = selected.includes(value)\n ? selected.filter((item) => item !== value)\n : [...selected, value];\n\n onChange(newSelected);\n };\n\n const handleRemoveItem = (value: string, e: React.MouseEvent) => {\n e.stopPropagation();\n if (disabled) return;\n onChange(selected.filter((item) => item !== value));\n };\n\n const handleToggleDropdown = () => {\n if (disabled) return;\n setIsOpen(!isOpen);\n if (!isOpen) {\n setTimeout(() => inputRef.current?.focus(), 0);\n }\n };\n\n const getSelectedLabels = () => {\n return selected\n .map((value) => options.find((opt) => opt.value === value)?.label || value)\n .filter(Boolean);\n };\n\n return (\n <div ref={dropdownRef} className={`relative ${className}`}>\n {/* Selected items display */}\n <div\n onClick={handleToggleDropdown}\n className={`\n min-h-[38px] w-full px-3 py-1.5 border rounded-md shadow-sm\n flex flex-wrap items-center gap-1.5 cursor-pointer\n transition-all duration-200\n ${disabled ? 'bg-gray-100 cursor-not-allowed' : 'bg-white hover:border-blue-400'}\n ${isOpen ? 'border-blue-500 ring-1 ring-blue-500' : 'border-gray-300'}\n `}\n >\n {selected.length > 0 ? (\n <>\n {getSelectedLabels().map((label, index) => (\n <span\n key={selected[index]}\n className=\"inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300\"\n >\n {label}\n {!disabled && (\n <button\n type=\"button\"\n onClick={(e) => handleRemoveItem(selected[index], e)}\n className=\"ml-1 hover:bg-blue-200 rounded-full p-0.5 transition-colors\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </span>\n ))}\n </>\n ) : (\n <span className=\"text-gray-400 text-sm\">{placeholder}</span>\n )}\n <div className=\"flex-1\"></div>\n <ChevronDown\n className={`h-4 w-4 text-gray-400 transition-transform duration-200 ${isOpen ? 'transform rotate-180' : ''}`}\n />\n </div>\n\n {/* Dropdown menu */}\n {isOpen && !disabled && (\n <div className=\"absolute z-50 w-full mt-1 bg-white dark:bg-gray-800 border border-gray-300 rounded-md shadow-lg max-h-60 overflow-hidden\">\n {/* Search input */}\n <div className=\"p-2 border-b border-gray-200 dark:border-gray-700\">\n <input\n ref={inputRef}\n type=\"text\"\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n placeholder=\"Search...\"\n className=\"w-full px-3 py-1.5 text-sm border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500\"\n onClick={(e) => e.stopPropagation()}\n />\n </div>\n\n {/* Options list */}\n <div className=\"max-h-48 overflow-y-auto\">\n {filteredOptions.length > 0 ? (\n filteredOptions.map((option) => {\n const isSelected = selected.includes(option.value);\n return (\n <div\n key={option.value}\n onClick={() => handleToggleOption(option.value)}\n className={`\n px-3 py-2 cursor-pointer flex items-center justify-between\n transition-colors duration-150\n ${isSelected ? 'bg-blue-50 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' : 'hover:bg-gray-100 dark:hover:bg-gray-700'}\n `}\n >\n <span className=\"text-sm\">{option.label}</span>\n {isSelected && <Check className=\"h-4 w-4 text-blue-600\" />}\n </div>\n );\n })\n ) : (\n <div className=\"px-3 py-2 text-sm text-gray-500 text-center\">\n {searchTerm ? 'No results found' : 'No options available'}\n </div>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n","export function generateRandomKey(length: number = 32): string {\n const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n const array = new Uint8Array(length);\n crypto.getRandomValues(array);\n return Array.from(array)\n .map((x) => characters.charAt(x % characters.length))\n .join('');\n}\n","// Predefined permission constants\nexport const PERMISSIONS = {\n // Settings page permissions\n SETTINGS_SMART_ROUTING: 'settings:smart_routing',\n SETTINGS_ROUTE_CONFIG: 'settings:route_config',\n SETTINGS_INSTALL_CONFIG: 'settings:install_config',\n SETTINGS_SYSTEM_CONFIG: 'settings:system_config',\n SETTINGS_OAUTH_SERVER: 'settings:oauth_server',\n SETTINGS_EXPORT_CONFIG: 'settings:export_config',\n} as const;\n\nexport default PERMISSIONS;\n","import React, { useState, useEffect } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router-dom';\nimport ChangePasswordForm from '@/components/ChangePasswordForm';\nimport { Switch } from '@/components/ui/ToggleGroup';\nimport { MultiSelect } from '@/components/ui/MultiSelect';\nimport { useSettingsData } from '@/hooks/useSettingsData';\nimport { useToast } from '@/contexts/ToastContext';\nimport { generateRandomKey } from '@/utils/key';\nimport { PermissionChecker } from '@/components/PermissionChecker';\nimport { PERMISSIONS } from '@/constants/permissions';\nimport { Copy, Check, Download, Edit, Trash2 } from 'lucide-react';\nimport type { BearerKey } from '@/types';\nimport { useServerContext } from '@/contexts/ServerContext';\nimport { useGroupData } from '@/hooks/useGroupData';\n\ninterface BearerKeyRowProps {\n keyData: BearerKey;\n loading: boolean;\n availableServers: { value: string; label: string }[];\n availableGroups: { value: string; label: string }[];\n onSave: (\n id: string,\n payload: {\n name: string;\n token: string;\n enabled: boolean;\n accessType: 'all' | 'groups' | 'servers' | 'custom';\n allowedGroups: string;\n allowedServers: string;\n },\n ) => Promise<void>;\n onDelete: (id: string) => Promise<void>;\n}\n\nconst BearerKeyRow: React.FC<BearerKeyRowProps> = ({\n keyData,\n loading,\n availableServers,\n availableGroups,\n onSave,\n onDelete,\n}) => {\n const { t } = useTranslation();\n const { showToast } = useToast();\n const [isEditing, setIsEditing] = useState(false);\n const [name, setName] = useState(keyData.name);\n const [token, setToken] = useState(keyData.token);\n const [enabled, setEnabled] = useState<boolean>(keyData.enabled);\n const [accessType, setAccessType] = useState<'all' | 'groups' | 'servers' | 'custom'>(\n keyData.accessType || 'all',\n );\n const [selectedGroups, setSelectedGroups] = useState<string[]>(keyData.allowedGroups || []);\n const [selectedServers, setSelectedServers] = useState<string[]>(keyData.allowedServers || []);\n const [saving, setSaving] = useState(false);\n const [deleting, setDeleting] = useState(false);\n\n useEffect(() => {\n if (!isEditing) {\n setName(keyData.name);\n setToken(keyData.token);\n setEnabled(keyData.enabled);\n setAccessType(keyData.accessType || 'all');\n setSelectedGroups(keyData.allowedGroups || []);\n setSelectedServers(keyData.allowedServers || []);\n }\n }, [keyData, isEditing]);\n\n const handleCopyToken = async () => {\n try {\n if (navigator.clipboard && window.isSecureContext) {\n await navigator.clipboard.writeText(keyData.token);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n } else {\n const textArea = document.createElement('textarea');\n textArea.value = keyData.token;\n textArea.style.position = 'fixed';\n textArea.style.left = '-9999px';\n document.body.appendChild(textArea);\n textArea.focus();\n textArea.select();\n try {\n document.execCommand('copy');\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n } catch (err) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n }\n document.body.removeChild(textArea);\n }\n } catch (error) {\n console.error('Failed to copy', error);\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n }\n };\n\n const handleSave = async () => {\n if (accessType === 'groups' && selectedGroups.length === 0) {\n showToast(t('settings.selectAtLeastOneGroup') || 'Please select at least one group', 'error');\n return;\n }\n if (accessType === 'servers' && selectedServers.length === 0) {\n showToast(\n t('settings.selectAtLeastOneServer') || 'Please select at least one server',\n 'error',\n );\n return;\n }\n if (accessType === 'custom' && selectedGroups.length === 0 && selectedServers.length === 0) {\n showToast(\n t('settings.selectAtLeastOneGroupOrServer') || 'Please select at least one group or server',\n 'error',\n );\n return;\n }\n\n setSaving(true);\n try {\n await onSave(keyData.id, {\n name,\n token,\n enabled,\n accessType,\n allowedGroups: selectedGroups.join(', '),\n allowedServers: selectedServers.join(', '),\n });\n setIsEditing(false);\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async () => {\n if (!window.confirm(t('settings.deleteBearerKeyConfirm') || 'Delete this key?')) {\n return;\n }\n setDeleting(true);\n try {\n await onDelete(keyData.id);\n } finally {\n setDeleting(false);\n }\n };\n\n const isGroupsMode = accessType === 'groups';\n const isCustomMode = accessType === 'custom';\n\n // Helper function to format access type display text\n const formatAccessTypeDisplay = (key: BearerKey): string => {\n if (key.accessType === 'all') {\n return t('settings.bearerKeyAccessAll') || 'All Resources';\n }\n if (key.accessType === 'groups') {\n return `${t('settings.bearerKeyAccessGroups') || 'Groups'}: ${key.allowedGroups}`;\n }\n if (key.accessType === 'servers') {\n return `${t('settings.bearerKeyAccessServers') || 'Servers'}: ${key.allowedServers}`;\n }\n if (key.accessType === 'custom') {\n const parts: string[] = [];\n if (key.allowedGroups && key.allowedGroups.length > 0) {\n parts.push(`${t('settings.bearerKeyAccessGroups') || 'Groups'}: ${key.allowedGroups}`);\n }\n if (key.allowedServers && key.allowedServers.length > 0) {\n parts.push(`${t('settings.bearerKeyAccessServers') || 'Servers'}: ${key.allowedServers}`);\n }\n return `${t('settings.bearerKeyAccessCustom') || 'Custom'}: ${parts.join('; ')}`;\n }\n return '';\n };\n\n if (isEditing) {\n return (\n <tr>\n <td colSpan={5} className=\"p-0 border-b border-gray-200 dark:border-gray-700\">\n <div className=\"bg-gray-50 dark:bg-gray-800 p-5\">\n <div className=\"grid grid-cols-1 md:grid-cols-12 gap-4 mb-4\">\n <div className=\"md:col-span-3\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyName') || 'Name'}\n </label>\n <input\n type=\"text\"\n className=\"block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input transition-shadow duration-200\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n disabled={loading}\n />\n </div>\n <div className=\"md:col-span-9\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyToken') || 'Token'}\n </label>\n <input\n type=\"text\"\n className=\"block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input transition-shadow duration-200\"\n value={token}\n onChange={(e) => setToken(e.target.value)}\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-end gap-4\">\n <div className=\"w-40\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyEnabled') || 'Status'}\n </label>\n <div className=\"flex items-center h-[38px] px-3 bg-white dark:bg-gray-800 border border-gray-300 rounded-md\">\n <span\n className={`text-sm mr-3 ${enabled ? 'text-green-600 font-medium' : 'text-gray-500'}`}\n >\n {enabled ? 'Active' : 'Inactive'}\n </span>\n <Switch\n disabled={loading}\n checked={enabled}\n onCheckedChange={(checked) => setEnabled(checked)}\n />\n </div>\n </div>\n\n <div className=\"w-48\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAccessType') || 'Access scope'}\n </label>\n <select\n className=\"block w-full py-2 px-3 border border-gray-300 bg-white dark:bg-gray-800 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-select transition-shadow duration-200\"\n value={accessType}\n onChange={(e) =>\n setAccessType(e.target.value as 'all' | 'groups' | 'servers' | 'custom')\n }\n disabled={loading}\n >\n <option value=\"all\">{t('settings.bearerKeyAccessAll') || 'All Resources'}</option>\n <option value=\"groups\">\n {t('settings.bearerKeyAccessGroups') || 'Specific Groups'}\n </option>\n <option value=\"servers\">\n {t('settings.bearerKeyAccessServers') || 'Specific Servers'}\n </option>\n <option value=\"custom\">\n {t('settings.bearerKeyAccessCustom') || 'Custom (Groups & Servers)'}\n </option>\n </select>\n </div>\n\n {/* Show single selector for groups or servers mode */}\n {!isCustomMode && (\n <div className=\"flex-1 min-w-[200px]\">\n <label\n className={`block text-sm font-medium mb-1 ${accessType === 'all' ? 'text-gray-400' : 'text-gray-700'}`}\n >\n {isGroupsMode\n ? t('settings.bearerKeyAllowedGroups') || 'Allowed groups'\n : t('settings.bearerKeyAllowedServers') || 'Allowed servers'}\n </label>\n <MultiSelect\n options={isGroupsMode ? availableGroups : availableServers}\n selected={isGroupsMode ? selectedGroups : selectedServers}\n onChange={isGroupsMode ? setSelectedGroups : setSelectedServers}\n placeholder={\n isGroupsMode\n ? t('settings.selectGroups') || 'Select groups...'\n : t('settings.selectServers') || 'Select servers...'\n }\n disabled={loading || accessType === 'all'}\n />\n </div>\n )}\n\n {/* Show both selectors for custom mode */}\n {isCustomMode && (\n <>\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAllowedGroups') || 'Allowed groups'}\n </label>\n <MultiSelect\n options={availableGroups}\n selected={selectedGroups}\n onChange={setSelectedGroups}\n placeholder={t('settings.selectGroups') || 'Select groups...'}\n disabled={loading}\n />\n </div>\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAllowedServers') || 'Allowed servers'}\n </label>\n <MultiSelect\n options={availableServers}\n selected={selectedServers}\n onChange={setSelectedServers}\n placeholder={t('settings.selectServers') || 'Select servers...'}\n disabled={loading}\n />\n </div>\n </>\n )}\n\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setIsEditing(false)}\n className=\"px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 text-gray-700 rounded-md text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 h-[38px]\"\n >\n {t('common.cancel') || 'Cancel'}\n </button>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={loading || saving}\n className=\"px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary h-[38px]\"\n >\n {saving ? t('common.saving') || 'Saving...' : t('common.save') || 'Save'}\n </button>\n </div>\n </div>\n </div>\n </td>\n </tr>\n );\n }\n\n return (\n <tr className=\"hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700\">\n <td className=\"px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900\">\n {keyData.name}\n </td>\n <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500 font-mono\">\n <div className=\"flex items-center gap-2\">\n <span>\n {keyData.token.length > 12\n ? `${keyData.token.substring(0, 8)}...${keyData.token.substring(keyData.token.length - 4)}`\n : keyData.token}\n </span>\n <button\n onClick={handleCopyToken}\n className=\"text-gray-400 hover:text-gray-600 transition-colors\"\n title={t('common.copy') || 'Copy'}\n >\n <Copy className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </td>\n <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\">\n <span\n className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${keyData.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}`}\n >\n {keyData.enabled ? t('common.active') || 'Active' : t('common.inactive') || 'Inactive'}\n </span>\n </td>\n <td className=\"px-6 py-4 whitespace-nowrap text-sm text-gray-500\">\n {formatAccessTypeDisplay(keyData)}\n </td>\n <td className=\"px-6 py-4 whitespace-nowrap text-right text-sm font-medium\">\n <button\n onClick={() => setIsEditing(true)}\n className=\"text-blue-600 hover:text-blue-900 mr-4 inline-flex items-center\"\n title={t('common.edit') || 'Edit'}\n >\n <Edit className=\"h-4 w-4\" />\n </button>\n <button\n onClick={handleDelete}\n disabled={deleting}\n className=\"text-red-600 hover:text-red-900 inline-flex items-center\"\n title={t('common.delete') || 'Delete'}\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </td>\n </tr>\n );\n};\n\n/**\n * Returns the default token limit for a given embedding model name.\n * Mirrors the backend getModelDefaultTokenLimit() function.\n * Used to display a contextual hint in the embeddingMaxTokens field.\n */\nfunction getDefaultTokenLimitForUI(model: string): number {\n const lower = model.toLowerCase();\n const MODEL_LIMITS: Array<[string, number]> = [\n ['text-embedding-3-small', 8191],\n ['text-embedding-3-large', 8191],\n ['text-embedding-ada-002', 8191],\n ['gemini-embedding-001', 2048],\n ['bge-m3', 8192],\n ];\n for (const [pattern, limit] of MODEL_LIMITS) {\n if (lower.includes(pattern)) return limit;\n }\n if (lower.includes('bge')) return 512;\n return 512;\n}\n\n/**\n * Parses embeddingMaxTokens from form input string.\n * Returns the parsed value if it differs from current value, otherwise undefined (no update needed).\n * - Empty string or whitespace → null (clear override)\n * - Valid number string → parsed number\n * - Invalid input or unchanged value → undefined\n */\nfunction parseEmbeddingMaxTokensForUpdate(\n rawValue: string,\n currentValue: number | null | undefined,\n): number | null | undefined {\n const trimmed = rawValue.trim();\n const parsed = trimmed ? parseInt(trimmed, 10) : NaN;\n const result = trimmed && !isNaN(parsed) ? parsed : null;\n const current = currentValue ?? null;\n return result !== current ? result : undefined;\n}\n\nfunction parseBasePacingDelayForUpdate(\n rawValue: string,\n currentValue: number | null | undefined,\n): number | null | undefined {\n const trimmed = rawValue.trim();\n const parsed = trimmed ? parseInt(trimmed, 10) : NaN;\n const result = trimmed && !isNaN(parsed) && parsed >= 0 ? parsed : null;\n const current = currentValue ?? null;\n return result !== current ? result : undefined;\n}\n\nconst SettingsPage: React.FC = () => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n const { showToast } = useToast();\n const { allServers: servers } = useServerContext(); // Use allServers for settings (not paginated)\n const { groups } = useGroupData();\n\n const [installConfig, setInstallConfig] = useState<{\n pythonIndexUrl: string;\n npmRegistry: string;\n baseUrl: string;\n }>({\n pythonIndexUrl: '',\n npmRegistry: '',\n baseUrl: 'http://localhost:3000',\n });\n\n const [tempSmartRoutingConfig, setTempSmartRoutingConfig] = useState<{\n dbUrl: string;\n basePacingDelayMs: string;\n embeddingProvider: 'openai' | 'azure_openai';\n embeddingEncodingFormat: 'auto' | 'base64' | 'float';\n openaiApiBaseUrl: string;\n openaiApiKey: string;\n openaiApiEmbeddingModel: string;\n azureOpenaiEndpoint: string;\n azureOpenaiApiKey: string;\n azureOpenaiApiVersion: string;\n azureOpenaiEmbeddingDeployment: string;\n azureOpenaiEmbeddingModel: string;\n // Empty string = use model default; numeric string = explicit override\n embeddingMaxTokens: string;\n }>({\n dbUrl: '',\n basePacingDelayMs: '',\n embeddingProvider: 'openai',\n embeddingEncodingFormat: 'auto',\n openaiApiBaseUrl: '',\n openaiApiKey: '',\n openaiApiEmbeddingModel: '',\n azureOpenaiEndpoint: '',\n azureOpenaiApiKey: '',\n azureOpenaiApiVersion: '2024-02-15-preview',\n azureOpenaiEmbeddingDeployment: '',\n azureOpenaiEmbeddingModel: '',\n embeddingMaxTokens: '',\n });\n\n const [tempMCPRouterConfig, setTempMCPRouterConfig] = useState<{\n apiKey: string;\n referer: string;\n title: string;\n baseUrl: string;\n }>({\n apiKey: '',\n referer: 'https://www.mcphub.app',\n title: 'MCPHub',\n baseUrl: 'https://api.mcprouter.to/v1',\n });\n\n const [tempOAuthServerConfig, setTempOAuthServerConfig] = useState<{\n accessTokenLifetime: string;\n refreshTokenLifetime: string;\n authorizationCodeLifetime: string;\n allowedScopes: string;\n dynamicRegistrationAllowedGrantTypes: string;\n }>({\n accessTokenLifetime: '3600',\n refreshTokenLifetime: '1209600',\n authorizationCodeLifetime: '300',\n allowedScopes: 'read, write',\n dynamicRegistrationAllowedGrantTypes: 'authorization_code, refresh_token',\n });\n\n const [tempNameSeparator, setTempNameSeparator] = useState<string>('-');\n const [showAddBearerKeyForm, setShowAddBearerKeyForm] = useState(false);\n\n const {\n routingConfig,\n tempRoutingConfig,\n setTempRoutingConfig,\n installConfig: savedInstallConfig,\n smartRoutingConfig,\n mcpRouterConfig,\n oauthServerConfig,\n nameSeparator,\n enableSessionRebuild,\n loading,\n bearerKeys,\n updateRoutingConfig,\n updateInstallConfig,\n updateSmartRoutingConfig,\n updateSmartRoutingConfigBatch,\n updateMCPRouterConfig,\n updateOAuthServerConfig,\n updateNameSeparator,\n updateSessionRebuild,\n exportMCPSettings,\n createBearerKey,\n updateBearerKey,\n deleteBearerKey,\n refreshBearerKeys,\n } = useSettingsData();\n\n // Update local installConfig when savedInstallConfig changes\n useEffect(() => {\n if (savedInstallConfig) {\n setInstallConfig(savedInstallConfig);\n }\n }, [savedInstallConfig]);\n\n // Update local tempSmartRoutingConfig when smartRoutingConfig changes\n useEffect(() => {\n if (smartRoutingConfig) {\n setTempSmartRoutingConfig({\n dbUrl: smartRoutingConfig.dbUrl || '',\n basePacingDelayMs:\n smartRoutingConfig.basePacingDelayMs != null\n ? String(smartRoutingConfig.basePacingDelayMs)\n : '',\n embeddingProvider:\n smartRoutingConfig.embeddingProvider === 'azure_openai' ? 'azure_openai' : 'openai',\n embeddingEncodingFormat:\n smartRoutingConfig.embeddingEncodingFormat === 'base64'\n ? 'base64'\n : smartRoutingConfig.embeddingEncodingFormat === 'float'\n ? 'float'\n : 'auto',\n openaiApiBaseUrl: smartRoutingConfig.openaiApiBaseUrl || '',\n openaiApiKey: smartRoutingConfig.openaiApiKey || '',\n openaiApiEmbeddingModel: smartRoutingConfig.openaiApiEmbeddingModel || '',\n azureOpenaiEndpoint: smartRoutingConfig.azureOpenaiEndpoint || '',\n azureOpenaiApiKey: smartRoutingConfig.azureOpenaiApiKey || '',\n azureOpenaiApiVersion: smartRoutingConfig.azureOpenaiApiVersion || '2024-02-15-preview',\n azureOpenaiEmbeddingDeployment: smartRoutingConfig.azureOpenaiEmbeddingDeployment || '',\n azureOpenaiEmbeddingModel: smartRoutingConfig.azureOpenaiEmbeddingModel || '',\n embeddingMaxTokens:\n smartRoutingConfig.embeddingMaxTokens != null\n ? String(smartRoutingConfig.embeddingMaxTokens)\n : '',\n });\n }\n }, [smartRoutingConfig]);\n\n // Update local tempMCPRouterConfig when mcpRouterConfig changes\n useEffect(() => {\n if (mcpRouterConfig) {\n setTempMCPRouterConfig({\n apiKey: mcpRouterConfig.apiKey || '',\n referer: mcpRouterConfig.referer || 'https://www.mcphub.app',\n title: mcpRouterConfig.title || 'MCPHub',\n baseUrl: mcpRouterConfig.baseUrl || 'https://api.mcprouter.to/v1',\n });\n }\n }, [mcpRouterConfig]);\n\n useEffect(() => {\n if (oauthServerConfig) {\n setTempOAuthServerConfig({\n accessTokenLifetime:\n oauthServerConfig.accessTokenLifetime !== undefined\n ? String(oauthServerConfig.accessTokenLifetime)\n : '',\n refreshTokenLifetime:\n oauthServerConfig.refreshTokenLifetime !== undefined\n ? String(oauthServerConfig.refreshTokenLifetime)\n : '',\n authorizationCodeLifetime:\n oauthServerConfig.authorizationCodeLifetime !== undefined\n ? String(oauthServerConfig.authorizationCodeLifetime)\n : '',\n allowedScopes:\n oauthServerConfig.allowedScopes && oauthServerConfig.allowedScopes.length > 0\n ? oauthServerConfig.allowedScopes.join(', ')\n : '',\n dynamicRegistrationAllowedGrantTypes: oauthServerConfig.dynamicRegistration\n ?.allowedGrantTypes?.length\n ? oauthServerConfig.dynamicRegistration.allowedGrantTypes.join(', ')\n : '',\n });\n }\n }, [oauthServerConfig]);\n\n // Update local tempNameSeparator when nameSeparator changes\n useEffect(() => {\n setTempNameSeparator(nameSeparator);\n }, [nameSeparator]);\n\n // Refresh bearer keys when component mounts\n useEffect(() => {\n refreshBearerKeys();\n }, []);\n\n const [sectionsVisible, setSectionsVisible] = useState({\n routingConfig: false,\n installConfig: false,\n smartRoutingConfig: false,\n oauthServerConfig: false,\n mcpRouterConfig: false,\n nameSeparator: false,\n password: false,\n exportConfig: false,\n bearerKeys: false,\n });\n\n const toggleSection = (\n section:\n | 'routingConfig'\n | 'installConfig'\n | 'smartRoutingConfig'\n | 'oauthServerConfig'\n | 'mcpRouterConfig'\n | 'nameSeparator'\n | 'password'\n | 'exportConfig'\n | 'bearerKeys',\n ) => {\n setSectionsVisible((prev) => ({\n ...prev,\n [section]: !prev[section],\n }));\n };\n\n const handleRoutingConfigChange = async (\n key:\n | 'enableGlobalRoute'\n | 'enableGroupNameRoute'\n | 'enableBearerAuth'\n | 'bearerAuthKey'\n | 'bearerAuthHeaderName'\n | 'jsonBodyLimit'\n | 'skipAuth',\n value: boolean | string,\n ) => {\n await updateRoutingConfig(key, value);\n };\n\n const handleTempRoutingConfigChange = (\n key: 'bearerAuthHeaderName' | 'jsonBodyLimit',\n value: string,\n ) => {\n setTempRoutingConfig((prev) => ({\n ...prev,\n [key]: value,\n }));\n };\n\n const handleInstallConfigChange = (\n key: 'pythonIndexUrl' | 'npmRegistry' | 'baseUrl',\n value: string,\n ) => {\n setInstallConfig({\n ...installConfig,\n [key]: value,\n });\n };\n\n const saveInstallConfig = async (key: 'pythonIndexUrl' | 'npmRegistry' | 'baseUrl') => {\n await updateInstallConfig(key, installConfig[key]);\n };\n\n const handleSmartRoutingConfigChange = (\n key:\n | 'dbUrl'\n | 'basePacingDelayMs'\n | 'embeddingProvider'\n | 'embeddingEncodingFormat'\n | 'openaiApiBaseUrl'\n | 'openaiApiKey'\n | 'openaiApiEmbeddingModel'\n | 'azureOpenaiEndpoint'\n | 'azureOpenaiApiKey'\n | 'azureOpenaiApiVersion'\n | 'azureOpenaiEmbeddingDeployment'\n | 'azureOpenaiEmbeddingModel'\n | 'embeddingMaxTokens',\n value: string,\n ) => {\n setTempSmartRoutingConfig({\n ...tempSmartRoutingConfig,\n [key]: value,\n });\n };\n\n const handleMCPRouterConfigChange = (\n key: 'apiKey' | 'referer' | 'title' | 'baseUrl',\n value: string,\n ) => {\n setTempMCPRouterConfig({\n ...tempMCPRouterConfig,\n [key]: value,\n });\n };\n\n const saveMCPRouterConfig = async (key: 'apiKey' | 'referer' | 'title' | 'baseUrl') => {\n await updateMCPRouterConfig(key, tempMCPRouterConfig[key]);\n };\n\n type OAuthServerNumberField =\n | 'accessTokenLifetime'\n | 'refreshTokenLifetime'\n | 'authorizationCodeLifetime';\n\n const handleOAuthServerNumberChange = (key: OAuthServerNumberField, value: string) => {\n setTempOAuthServerConfig((prev) => ({\n ...prev,\n [key]: value,\n }));\n };\n\n const handleOAuthServerTextChange = (\n key: 'allowedScopes' | 'dynamicRegistrationAllowedGrantTypes',\n value: string,\n ) => {\n setTempOAuthServerConfig((prev) => ({\n ...prev,\n [key]: value,\n }));\n };\n\n const saveOAuthServerNumberConfig = async (key: OAuthServerNumberField) => {\n const rawValue = tempOAuthServerConfig[key];\n if (!rawValue || rawValue.trim() === '') {\n showToast(t('settings.invalidNumberInput') || 'Please enter a valid number', 'error');\n return;\n }\n\n const parsedValue = Number(rawValue);\n if (Number.isNaN(parsedValue) || parsedValue < 0) {\n showToast(t('settings.invalidNumberInput') || 'Please enter a valid number', 'error');\n return;\n }\n\n await updateOAuthServerConfig(key, parsedValue);\n };\n\n const saveOAuthServerAllowedScopes = async () => {\n const scopes = tempOAuthServerConfig.allowedScopes\n .split(',')\n .map((scope) => scope.trim())\n .filter((scope) => scope.length > 0);\n\n await updateOAuthServerConfig('allowedScopes', scopes);\n };\n\n const saveOAuthServerGrantTypes = async () => {\n const grantTypes = tempOAuthServerConfig.dynamicRegistrationAllowedGrantTypes\n .split(',')\n .map((grant) => grant.trim())\n .filter((grant) => grant.length > 0);\n\n await updateOAuthServerConfig('dynamicRegistration', {\n ...oauthServerConfig.dynamicRegistration,\n allowedGrantTypes: grantTypes,\n });\n };\n\n const handleOAuthServerToggle = async (\n key: 'enabled' | 'requireClientSecret' | 'requireState',\n value: boolean,\n ) => {\n await updateOAuthServerConfig(key, value);\n };\n\n const handleDynamicRegistrationToggle = async (\n updates: Partial<typeof oauthServerConfig.dynamicRegistration>,\n ) => {\n await updateOAuthServerConfig('dynamicRegistration', {\n ...oauthServerConfig.dynamicRegistration,\n ...updates,\n });\n };\n\n const saveNameSeparator = async () => {\n await updateNameSeparator(tempNameSeparator);\n };\n\n const handleSmartRoutingEnabledChange = async (value: boolean) => {\n // If enabling Smart Routing, validate required fields and save any unsaved changes\n if (value) {\n const currentDbUrl = tempSmartRoutingConfig.dbUrl || smartRoutingConfig.dbUrl;\n const missingFields: string[] = [];\n if (!currentDbUrl) missingFields.push(t('settings.dbUrl') || 'Database URL');\n\n if (tempSmartRoutingConfig.embeddingProvider === 'azure_openai') {\n const currentEndpoint =\n tempSmartRoutingConfig.azureOpenaiEndpoint || smartRoutingConfig.azureOpenaiEndpoint;\n const currentKey =\n tempSmartRoutingConfig.azureOpenaiApiKey || smartRoutingConfig.azureOpenaiApiKey;\n const currentApiVersion =\n tempSmartRoutingConfig.azureOpenaiApiVersion || smartRoutingConfig.azureOpenaiApiVersion;\n const currentDeployment =\n tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment ||\n smartRoutingConfig.azureOpenaiEmbeddingDeployment;\n\n if (!currentEndpoint || !currentKey || !currentApiVersion || !currentDeployment) {\n missingFields.push(\n t('settings.azureOpenaiEndpoint') || 'Azure OpenAI Endpoint',\n t('settings.azureOpenaiApiKey') || 'Azure OpenAI API Key',\n t('settings.azureOpenaiApiVersion') || 'Azure OpenAI API Version',\n t('settings.azureOpenaiEmbeddingDeployment') || 'Azure Embedding Deployment',\n );\n }\n } else {\n // Get current OpenAI config values with explicit type checking and trim\n const currentOpenaiApiKey = (typeof tempSmartRoutingConfig.openaiApiKey === 'string'\n ? tempSmartRoutingConfig.openaiApiKey\n : smartRoutingConfig.openaiApiKey || ''\n ).trim();\n const currentOpenaiApiBaseUrl = (typeof tempSmartRoutingConfig.openaiApiBaseUrl === 'string'\n ? tempSmartRoutingConfig.openaiApiBaseUrl\n : smartRoutingConfig.openaiApiBaseUrl || ''\n ).trim();\n const currentOpenaiApiEmbeddingModel = (typeof tempSmartRoutingConfig.openaiApiEmbeddingModel === 'string'\n ? tempSmartRoutingConfig.openaiApiEmbeddingModel\n : smartRoutingConfig.openaiApiEmbeddingModel || ''\n ).trim();\n\n if (!currentOpenaiApiKey) {\n missingFields.push(t('settings.openaiApiKey') || 'OpenAI API Key');\n }\n if (!currentOpenaiApiBaseUrl) {\n missingFields.push(t('settings.openaiApiBaseUrl') || 'OpenAI API Base URL');\n }\n if (!currentOpenaiApiEmbeddingModel) {\n missingFields.push(t('settings.openaiApiEmbeddingModel') || 'OpenAI Embedding Model');\n }\n }\n\n if (missingFields.length > 0) {\n showToast(\n t('settings.smartRoutingValidationError', {\n fields: missingFields.join(', '),\n }),\n );\n return;\n }\n\n // Prepare updates object with unsaved changes and enabled status\n const updates: any = { enabled: value };\n\n // Check for unsaved changes and include them in the batch update\n if (tempSmartRoutingConfig.dbUrl !== smartRoutingConfig.dbUrl) {\n updates.dbUrl = tempSmartRoutingConfig.dbUrl;\n }\n const parsedBasePacingDelay = parseBasePacingDelayForUpdate(\n tempSmartRoutingConfig.basePacingDelayMs,\n smartRoutingConfig.basePacingDelayMs,\n );\n if (parsedBasePacingDelay !== undefined) {\n updates.basePacingDelayMs = parsedBasePacingDelay;\n }\n if (tempSmartRoutingConfig.embeddingProvider !== smartRoutingConfig.embeddingProvider) {\n updates.embeddingProvider = tempSmartRoutingConfig.embeddingProvider;\n }\n if (\n tempSmartRoutingConfig.embeddingEncodingFormat !==\n smartRoutingConfig.embeddingEncodingFormat\n ) {\n updates.embeddingEncodingFormat = tempSmartRoutingConfig.embeddingEncodingFormat;\n }\n if (tempSmartRoutingConfig.openaiApiBaseUrl !== smartRoutingConfig.openaiApiBaseUrl) {\n updates.openaiApiBaseUrl = tempSmartRoutingConfig.openaiApiBaseUrl;\n }\n if (tempSmartRoutingConfig.openaiApiKey !== smartRoutingConfig.openaiApiKey) {\n updates.openaiApiKey = tempSmartRoutingConfig.openaiApiKey;\n }\n if (\n tempSmartRoutingConfig.openaiApiEmbeddingModel !==\n smartRoutingConfig.openaiApiEmbeddingModel\n ) {\n updates.openaiApiEmbeddingModel = tempSmartRoutingConfig.openaiApiEmbeddingModel;\n }\n\n if (tempSmartRoutingConfig.azureOpenaiEndpoint !== smartRoutingConfig.azureOpenaiEndpoint) {\n updates.azureOpenaiEndpoint = tempSmartRoutingConfig.azureOpenaiEndpoint;\n }\n if (tempSmartRoutingConfig.azureOpenaiApiKey !== smartRoutingConfig.azureOpenaiApiKey) {\n updates.azureOpenaiApiKey = tempSmartRoutingConfig.azureOpenaiApiKey;\n }\n if (\n tempSmartRoutingConfig.azureOpenaiApiVersion !== smartRoutingConfig.azureOpenaiApiVersion\n ) {\n updates.azureOpenaiApiVersion = tempSmartRoutingConfig.azureOpenaiApiVersion;\n }\n if (\n tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment !==\n smartRoutingConfig.azureOpenaiEmbeddingDeployment\n ) {\n updates.azureOpenaiEmbeddingDeployment =\n tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment;\n }\n if (\n tempSmartRoutingConfig.azureOpenaiEmbeddingModel !==\n smartRoutingConfig.azureOpenaiEmbeddingModel\n ) {\n updates.azureOpenaiEmbeddingModel = tempSmartRoutingConfig.azureOpenaiEmbeddingModel;\n }\n\n // embeddingMaxTokens: empty string → null (clear override), numeric string → number\n const parsedTokens = parseEmbeddingMaxTokensForUpdate(\n tempSmartRoutingConfig.embeddingMaxTokens,\n smartRoutingConfig.embeddingMaxTokens,\n );\n if (parsedTokens !== undefined) {\n updates.embeddingMaxTokens = parsedTokens;\n }\n\n // Save all changes in a single batch update\n await updateSmartRoutingConfigBatch(updates);\n } else {\n // If disabling, just update the enabled status\n await updateSmartRoutingConfig('enabled', value);\n }\n };\n\n const handleSaveSmartRoutingConfig = async () => {\n const updates: any = {};\n\n if (tempSmartRoutingConfig.dbUrl !== smartRoutingConfig.dbUrl) {\n updates.dbUrl = tempSmartRoutingConfig.dbUrl;\n }\n const parsedBasePacingDelay = parseBasePacingDelayForUpdate(\n tempSmartRoutingConfig.basePacingDelayMs,\n smartRoutingConfig.basePacingDelayMs,\n );\n if (parsedBasePacingDelay !== undefined) {\n updates.basePacingDelayMs = parsedBasePacingDelay;\n }\n if (tempSmartRoutingConfig.embeddingProvider !== smartRoutingConfig.embeddingProvider) {\n updates.embeddingProvider = tempSmartRoutingConfig.embeddingProvider;\n }\n if (\n tempSmartRoutingConfig.embeddingEncodingFormat !== smartRoutingConfig.embeddingEncodingFormat\n ) {\n updates.embeddingEncodingFormat = tempSmartRoutingConfig.embeddingEncodingFormat;\n }\n if (tempSmartRoutingConfig.openaiApiBaseUrl !== smartRoutingConfig.openaiApiBaseUrl) {\n updates.openaiApiBaseUrl = tempSmartRoutingConfig.openaiApiBaseUrl;\n }\n if (tempSmartRoutingConfig.openaiApiKey !== smartRoutingConfig.openaiApiKey) {\n updates.openaiApiKey = tempSmartRoutingConfig.openaiApiKey;\n }\n if (\n tempSmartRoutingConfig.openaiApiEmbeddingModel !== smartRoutingConfig.openaiApiEmbeddingModel\n ) {\n updates.openaiApiEmbeddingModel = tempSmartRoutingConfig.openaiApiEmbeddingModel;\n }\n\n if (tempSmartRoutingConfig.azureOpenaiEndpoint !== smartRoutingConfig.azureOpenaiEndpoint) {\n updates.azureOpenaiEndpoint = tempSmartRoutingConfig.azureOpenaiEndpoint;\n }\n if (tempSmartRoutingConfig.azureOpenaiApiKey !== smartRoutingConfig.azureOpenaiApiKey) {\n updates.azureOpenaiApiKey = tempSmartRoutingConfig.azureOpenaiApiKey;\n }\n if (tempSmartRoutingConfig.azureOpenaiApiVersion !== smartRoutingConfig.azureOpenaiApiVersion) {\n updates.azureOpenaiApiVersion = tempSmartRoutingConfig.azureOpenaiApiVersion;\n }\n if (\n tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment !==\n smartRoutingConfig.azureOpenaiEmbeddingDeployment\n ) {\n updates.azureOpenaiEmbeddingDeployment =\n tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment;\n }\n if (\n tempSmartRoutingConfig.azureOpenaiEmbeddingModel !==\n smartRoutingConfig.azureOpenaiEmbeddingModel\n ) {\n updates.azureOpenaiEmbeddingModel = tempSmartRoutingConfig.azureOpenaiEmbeddingModel;\n }\n\n // embeddingMaxTokens: empty string → null (clear override), numeric string → number\n const parsedEmbeddingMaxTokens = parseEmbeddingMaxTokensForUpdate(\n tempSmartRoutingConfig.embeddingMaxTokens,\n smartRoutingConfig.embeddingMaxTokens,\n );\n if (parsedEmbeddingMaxTokens !== undefined) {\n updates.embeddingMaxTokens = parsedEmbeddingMaxTokens;\n }\n\n if (Object.keys(updates).length > 0) {\n await updateSmartRoutingConfigBatch(updates);\n } else {\n showToast(t('settings.noChanges') || 'No changes to save', 'info');\n }\n };\n\n const handlePasswordChangeSuccess = () => {\n setTimeout(() => {\n navigate('/');\n }, 2000);\n };\n\n const [copiedConfig, setCopiedConfig] = useState(false);\n const [mcpSettingsJson, setMcpSettingsJson] = useState<string>('');\n\n const [newBearerKey, setNewBearerKey] = useState<{\n name: string;\n token: string;\n enabled: boolean;\n accessType: 'all' | 'groups' | 'servers' | 'custom';\n allowedGroups: string;\n allowedServers: string;\n }>({\n name: '',\n token: '',\n enabled: true,\n accessType: 'all',\n allowedGroups: '',\n allowedServers: '',\n });\n\n const [newSelectedGroups, setNewSelectedGroups] = useState<string[]>([]);\n const [newSelectedServers, setNewSelectedServers] = useState<string[]>([]);\n\n // Prepare options for MultiSelect\n const availableServers = servers.map((server) => ({\n value: server.name,\n label: server.name,\n }));\n\n const availableGroups = groups.map((group) => ({\n value: group.name,\n label: group.name,\n }));\n\n // Reset selected arrays when accessType changes\n useEffect(() => {\n if (newBearerKey.accessType !== 'groups' && newBearerKey.accessType !== 'custom') {\n setNewSelectedGroups([]);\n }\n if (newBearerKey.accessType !== 'servers' && newBearerKey.accessType !== 'custom') {\n setNewSelectedServers([]);\n }\n }, [newBearerKey.accessType]);\n\n const fetchMcpSettings = async () => {\n try {\n const result = await exportMCPSettings();\n console.log('Fetched MCP settings:', result);\n const configJson = JSON.stringify(result.data, null, 2);\n setMcpSettingsJson(configJson);\n } catch (error) {\n console.error('Error fetching MCP settings:', error);\n showToast(t('settings.exportError') || 'Failed to fetch settings', 'error');\n }\n };\n\n useEffect(() => {\n if (sectionsVisible.exportConfig && !mcpSettingsJson) {\n fetchMcpSettings();\n }\n }, [sectionsVisible.exportConfig]);\n\n const handleCopyConfig = async () => {\n if (!mcpSettingsJson) return;\n\n try {\n if (navigator.clipboard && window.isSecureContext) {\n await navigator.clipboard.writeText(mcpSettingsJson);\n setCopiedConfig(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopiedConfig(false), 2000);\n } else {\n // Fallback for HTTP or unsupported clipboard API\n const textArea = document.createElement('textarea');\n textArea.value = mcpSettingsJson;\n textArea.style.position = 'fixed';\n textArea.style.left = '-9999px';\n document.body.appendChild(textArea);\n textArea.focus();\n textArea.select();\n try {\n document.execCommand('copy');\n setCopiedConfig(true);\n showToast(t('common.copySuccess') || 'Copied to clipboard', 'success');\n setTimeout(() => setCopiedConfig(false), 2000);\n } catch (err) {\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n console.error('Copy to clipboard failed:', err);\n }\n document.body.removeChild(textArea);\n }\n } catch (error) {\n console.error('Error copying configuration:', error);\n showToast(t('common.copyFailed') || 'Copy failed', 'error');\n }\n };\n\n const handleDownloadConfig = () => {\n if (!mcpSettingsJson) return;\n\n const blob = new Blob([mcpSettingsJson], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = 'mcp_settings.json';\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n showToast(t('settings.exportSuccess') || 'Settings exported successfully', 'success');\n };\n\n const parseCommaSeparated = (value: string): string[] | undefined => {\n const parts = value\n .split(',')\n .map((item) => item.trim())\n .filter((item) => item.length > 0);\n return parts.length > 0 ? parts : undefined;\n };\n\n const handleCreateBearerKey = async () => {\n if (!newBearerKey.name || !newBearerKey.token) {\n showToast(t('settings.bearerKeyRequired') || 'Name and token are required', 'error');\n return;\n }\n\n if (newBearerKey.accessType === 'groups' && newSelectedGroups.length === 0) {\n showToast(t('settings.selectAtLeastOneGroup') || 'Please select at least one group', 'error');\n return;\n }\n if (newBearerKey.accessType === 'servers' && newSelectedServers.length === 0) {\n showToast(\n t('settings.selectAtLeastOneServer') || 'Please select at least one server',\n 'error',\n );\n return;\n }\n if (\n newBearerKey.accessType === 'custom' &&\n newSelectedGroups.length === 0 &&\n newSelectedServers.length === 0\n ) {\n showToast(\n t('settings.selectAtLeastOneGroupOrServer') || 'Please select at least one group or server',\n 'error',\n );\n return;\n }\n\n await createBearerKey({\n name: newBearerKey.name,\n token: newBearerKey.token,\n enabled: newBearerKey.enabled,\n accessType: newBearerKey.accessType,\n allowedGroups:\n (newBearerKey.accessType === 'groups' || newBearerKey.accessType === 'custom') &&\n newSelectedGroups.length > 0\n ? newSelectedGroups\n : undefined,\n allowedServers:\n (newBearerKey.accessType === 'servers' || newBearerKey.accessType === 'custom') &&\n newSelectedServers.length > 0\n ? newSelectedServers\n : undefined,\n } as any);\n\n setNewBearerKey({\n name: '',\n token: '',\n enabled: true,\n accessType: 'all',\n allowedGroups: '',\n allowedServers: '',\n });\n setNewSelectedGroups([]);\n setNewSelectedServers([]);\n await refreshBearerKeys();\n };\n\n const handleSaveExistingBearerKey = async (\n id: string,\n payload: {\n name: string;\n token: string;\n enabled: boolean;\n accessType: 'all' | 'groups' | 'servers' | 'custom';\n allowedGroups: string;\n allowedServers: string;\n },\n ) => {\n await updateBearerKey(id, {\n name: payload.name,\n token: payload.token,\n enabled: payload.enabled,\n accessType: payload.accessType,\n allowedGroups: parseCommaSeparated(payload.allowedGroups),\n allowedServers: parseCommaSeparated(payload.allowedServers),\n } as any);\n await refreshBearerKeys();\n };\n\n const handleDeleteExistingBearerKey = async (id: string) => {\n await deleteBearerKey(id);\n await refreshBearerKeys();\n };\n\n return (\n <div className=\"container mx-auto\">\n <h1 className=\"text-2xl font-bold text-gray-900 mb-8\">{t('pages.settings.title')}</h1>\n\n {/* Bearer Keys Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_ROUTE_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 page-card dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('bearerKeys')}\n >\n <h2 className=\"font-semibold text-gray-800\">\n {t('settings.bearerKeysSectionTitle') || 'Bearer authentication keys'}\n </h2>\n <span className=\"text-gray-500 transition-transform duration-200\">\n {sectionsVisible.bearerKeys ? '▼' : '►'}\n </span>\n </div>\n\n {sectionsVisible.bearerKeys && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.enableBearerAuth') || 'Enable Bearer Authentication'}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableBearerAuthDescription') ||\n 'Require bearer token authentication for MCP requests'}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={routingConfig.enableBearerAuth}\n onCheckedChange={(checked) =>\n handleRoutingConfigChange('enableBearerAuth', checked)\n }\n />\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.bearerAuthHeaderName')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.bearerAuthHeaderNameDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempRoutingConfig.bearerAuthHeaderName}\n onChange={(e) =>\n handleTempRoutingConfigChange('bearerAuthHeaderName', e.target.value)\n }\n placeholder={t('settings.bearerAuthHeaderNamePlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() =>\n handleRoutingConfigChange(\n 'bearerAuthHeaderName',\n tempRoutingConfig.bearerAuthHeaderName,\n )\n }\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"flex justify-between items-center\">\n <p className=\"text-sm text-gray-600\">\n {t('settings.bearerKeysSectionDescription') ||\n 'Manage multiple bearer authentication keys with different access scopes.'}\n </p>\n {!showAddBearerKeyForm && (\n <button\n type=\"button\"\n onClick={() => setShowAddBearerKeyForm(true)}\n className=\"flex items-center text-blue-600 hover:text-blue-800 font-medium transition-colors duration-200\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-5 w-5 mr-1\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n {t('settings.addBearerKey') || 'Add bearer key'}\n </button>\n )}\n </div>\n\n {/* Existing keys */}\n {bearerKeys.length === 0 ? (\n <p className=\"text-sm text-gray-500\">\n {t('settings.noBearerKeys') || 'No bearer keys configured yet.'}\n </p>\n ) : (\n <div className=\"mt-2 overflow-x-auto\">\n <table className=\"min-w-full divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-lg\">\n <thead className=\"bg-gray-50 dark:bg-gray-800\">\n <tr>\n <th\n scope=\"col\"\n className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\"\n >\n {t('settings.bearerKeyName') || 'Name'}\n </th>\n <th\n scope=\"col\"\n className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\"\n >\n {t('settings.bearerKeyToken') || 'Token'}\n </th>\n <th\n scope=\"col\"\n className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\"\n >\n {t('settings.bearerKeyEnabled') || 'Status'}\n </th>\n <th\n scope=\"col\"\n className=\"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider\"\n >\n {t('settings.bearerKeyAccessType') || 'Access Scope'}\n </th>\n <th\n scope=\"col\"\n className=\"px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider\"\n >\n {t('common.actions') || 'Actions'}\n </th>\n </tr>\n </thead>\n <tbody className=\"bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700\">\n {bearerKeys.map((key) => (\n <BearerKeyRow\n key={key.id}\n keyData={key}\n loading={loading}\n availableServers={availableServers}\n availableGroups={availableGroups}\n onSave={handleSaveExistingBearerKey}\n onDelete={handleDeleteExistingBearerKey}\n />\n ))}\n </tbody>\n </table>\n </div>\n )}\n\n {/* New key form */}\n {showAddBearerKeyForm && (\n <div className=\"mt-6 border-t border-gray-200 dark:border-gray-700 pt-6\">\n <div className=\"bg-gray-50 dark:bg-gray-800 rounded-lg p-5 border border-gray-200 dark:border-gray-700\">\n <h3 className=\"font-medium text-gray-900 mb-4 flex items-center gap-2\">\n <span className=\"bg-blue-100 text-blue-600 p-1 rounded\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"h-4 w-4\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path\n fillRule=\"evenodd\"\n d=\"M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z\"\n clipRule=\"evenodd\"\n />\n </svg>\n </span>\n {t('settings.addBearerKey') || 'Add bearer key'}\n </h3>\n\n <div className=\"grid grid-cols-1 md:grid-cols-12 gap-4 mb-4\">\n <div className=\"md:col-span-3\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyName') || 'Name'}\n </label>\n <input\n type=\"text\"\n className=\"block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input transition-shadow duration-200\"\n placeholder=\"e.g. My API Key\"\n value={newBearerKey.name}\n onChange={(e) =>\n setNewBearerKey((prev) => ({ ...prev, name: e.target.value }))\n }\n disabled={loading}\n />\n </div>\n <div className=\"md:col-span-9\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyToken') || 'Token'}\n </label>\n <div className=\"flex rounded-md shadow-sm\">\n <input\n type=\"text\"\n className=\"flex-1 block w-full py-2 px-3 border border-gray-300 rounded-l-md rounded-r-none border-r-0 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input transition-shadow duration-200\"\n placeholder=\"sk-...\"\n value={newBearerKey.token}\n onChange={(e) =>\n setNewBearerKey((prev) => ({ ...prev, token: e.target.value }))\n }\n disabled={loading}\n />\n <button\n type=\"button\"\n onClick={() =>\n setNewBearerKey((prev) => ({ ...prev, token: generateRandomKey() }))\n }\n disabled={loading}\n className=\"relative -ml-[5px] inline-flex items-center px-4 py-2 border border-gray-300 bg-gray-100 dark:bg-gray-800 text-gray-700 text-sm font-medium rounded-r-md rounded-l-none hover:bg-gray-200 focus:outline-none focus:ring-1 focus:ring-blue-500 focus:border-blue-500 transition-colors duration-200 z-10\"\n >\n {t('settings.generate') || 'Generate'}\n </button>\n </div>\n </div>\n </div>\n\n <div className=\"flex flex-wrap items-end gap-4 mb-2\">\n <div className=\"w-40\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyEnabled') || 'Status'}\n </label>\n <div className=\"flex items-center h-[38px] px-3 bg-white dark:bg-gray-800 border border-gray-300 rounded-md\">\n <span\n className={`text-sm mr-3 ${newBearerKey.enabled ? 'text-green-600 font-medium' : 'text-gray-500'}`}\n >\n {newBearerKey.enabled ? 'Active' : 'Inactive'}\n </span>\n <Switch\n disabled={loading}\n checked={newBearerKey.enabled}\n onCheckedChange={(checked) =>\n setNewBearerKey((prev) => ({ ...prev, enabled: checked }))\n }\n />\n </div>\n </div>\n\n <div className=\"w-48\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAccessType') || 'Access scope'}\n </label>\n <select\n className=\"block w-full py-2 px-3 border border-gray-300 bg-white dark:bg-gray-800 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-select transition-shadow duration-200\"\n value={newBearerKey.accessType}\n onChange={(e) =>\n setNewBearerKey((prev) => ({\n ...prev,\n accessType: e.target.value as 'all' | 'groups' | 'servers' | 'custom',\n }))\n }\n disabled={loading}\n >\n <option value=\"all\">\n {t('settings.bearerKeyAccessAll') || 'All Resources'}\n </option>\n <option value=\"groups\">\n {t('settings.bearerKeyAccessGroups') || 'Specific Groups'}\n </option>\n <option value=\"servers\">\n {t('settings.bearerKeyAccessServers') || 'Specific Servers'}\n </option>\n <option value=\"custom\">\n {t('settings.bearerKeyAccessCustom') || 'Custom (Groups & Servers)'}\n </option>\n </select>\n </div>\n\n {newBearerKey.accessType !== 'custom' && (\n <div className=\"flex-1 min-w-[200px]\">\n <label\n className={`block text-sm font-medium mb-1 ${newBearerKey.accessType === 'all' ? 'text-gray-400' : 'text-gray-700'}`}\n >\n {newBearerKey.accessType === 'groups'\n ? t('settings.bearerKeyAllowedGroups') || 'Allowed groups'\n : t('settings.bearerKeyAllowedServers') || 'Allowed servers'}\n </label>\n <MultiSelect\n options={\n newBearerKey.accessType === 'groups'\n ? availableGroups\n : availableServers\n }\n selected={\n newBearerKey.accessType === 'groups'\n ? newSelectedGroups\n : newSelectedServers\n }\n onChange={\n newBearerKey.accessType === 'groups'\n ? setNewSelectedGroups\n : setNewSelectedServers\n }\n placeholder={\n newBearerKey.accessType === 'groups'\n ? t('settings.selectGroups') || 'Select groups...'\n : t('settings.selectServers') || 'Select servers...'\n }\n disabled={loading || newBearerKey.accessType === 'all'}\n />\n </div>\n )}\n\n {newBearerKey.accessType === 'custom' && (\n <>\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAllowedGroups') || 'Allowed groups'}\n </label>\n <MultiSelect\n options={availableGroups}\n selected={newSelectedGroups}\n onChange={setNewSelectedGroups}\n placeholder={t('settings.selectGroups') || 'Select groups...'}\n disabled={loading}\n />\n </div>\n <div className=\"flex-1 min-w-[200px]\">\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('settings.bearerKeyAllowedServers') || 'Allowed servers'}\n </label>\n <MultiSelect\n options={availableServers}\n selected={newSelectedServers}\n onChange={setNewSelectedServers}\n placeholder={t('settings.selectServers') || 'Select servers...'}\n disabled={loading}\n />\n </div>\n </>\n )}\n\n <div className=\"flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => setShowAddBearerKeyForm(false)}\n className=\"px-4 py-2 bg-white dark:bg-gray-800 border border-gray-300 text-gray-700 rounded-md text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 h-[38px]\"\n >\n {t('common.cancel') || 'Cancel'}\n </button>\n <button\n type=\"button\"\n onClick={handleCreateBearerKey}\n disabled={loading}\n className=\"px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary h-[38px]\"\n >\n {t('settings.addBearerKeyButton') || 'Create Key'}\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* Smart Routing Configuration Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_SMART_ROUTING}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 page-card dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('smartRoutingConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('pages.settings.smartRouting')}</h2>\n <span className=\"text-gray-500 transition-transform duration-200\">\n {sectionsVisible.smartRoutingConfig ? '▼' : '►'}\n </span>\n </div>\n\n {sectionsVisible.smartRoutingConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.enableSmartRouting')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableSmartRoutingDescription')}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={smartRoutingConfig.enabled}\n onCheckedChange={(checked) => handleSmartRoutingEnabledChange(checked)}\n />\n </div>\n\n {/* Smart Routing Required Fields Information */}\n <div className=\"p-3 bg-blue-300 border border-blue-200 rounded-md\">\n <p className=\"text-sm text-blue-800\">\n {t('settings.smartRoutingRequiredFields')}\n </p>\n </div>\n\n {/* hide when DB_URL env is set */}\n {smartRoutingConfig.dbUrl !== '${DB_URL}' && (\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.dbUrl')}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.dbUrl}\n onChange={(e) => handleSmartRoutingConfigChange('dbUrl', e.target.value)}\n placeholder={t('settings.dbUrlPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm border-gray-300 form-input\"\n disabled={loading}\n />\n </div>\n </div>\n )}\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.embeddingProvider') || 'Embedding Provider'}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <select\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 bg-white dark:bg-gray-800 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-select\"\n value={tempSmartRoutingConfig.embeddingProvider}\n onChange={(e) =>\n handleSmartRoutingConfigChange(\n 'embeddingProvider',\n e.target.value as 'openai' | 'azure_openai',\n )\n }\n disabled={loading}\n >\n <option value=\"openai\">OpenAI (or compatible)</option>\n <option value=\"azure_openai\">Azure OpenAI</option>\n </select>\n </div>\n </div>\n\n {tempSmartRoutingConfig.embeddingProvider === 'openai' ? (\n <>\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.openaiApiKey')}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"password\"\n value={tempSmartRoutingConfig.openaiApiKey}\n onChange={(e) =>\n handleSmartRoutingConfigChange('openaiApiKey', e.target.value)\n }\n placeholder={t('settings.openaiApiKeyPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm border-gray-300\"\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.openaiApiBaseUrl')}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.openaiApiBaseUrl}\n onChange={(e) =>\n handleSmartRoutingConfigChange('openaiApiBaseUrl', e.target.value)\n }\n placeholder={t('settings.openaiApiBaseUrlPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n required\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.openaiApiEmbeddingModel')}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.openaiApiEmbeddingModel}\n onChange={(e) =>\n handleSmartRoutingConfigChange('openaiApiEmbeddingModel', e.target.value)\n }\n placeholder={t('settings.openaiApiEmbeddingModelPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n required\n />\n </div>\n </div>\n </>\n ) : (\n <>\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.azureOpenaiEndpoint') || 'Azure OpenAI Endpoint'}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.azureOpenaiEndpoint}\n onChange={(e) =>\n handleSmartRoutingConfigChange('azureOpenaiEndpoint', e.target.value)\n }\n placeholder={\n t('settings.azureOpenaiEndpointPlaceholder') ||\n 'https://YOUR_RESOURCE_NAME.openai.azure.com'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.azureOpenaiApiKey') || 'Azure OpenAI API Key'}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"password\"\n value={tempSmartRoutingConfig.azureOpenaiApiKey}\n onChange={(e) =>\n handleSmartRoutingConfigChange('azureOpenaiApiKey', e.target.value)\n }\n placeholder={t('settings.azureOpenaiApiKeyPlaceholder') || '***'}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm border-gray-300\"\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.azureOpenaiApiVersion') || 'Azure OpenAI API Version'}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.azureOpenaiApiVersion}\n onChange={(e) =>\n handleSmartRoutingConfigChange('azureOpenaiApiVersion', e.target.value)\n }\n placeholder={\n t('settings.azureOpenaiApiVersionPlaceholder') || '2024-02-15-preview'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.azureOpenaiEmbeddingDeployment') ||\n 'Azure Embedding Deployment'}\n </h3>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.azureOpenaiEmbeddingDeployment}\n onChange={(e) =>\n handleSmartRoutingConfigChange(\n 'azureOpenaiEmbeddingDeployment',\n e.target.value,\n )\n }\n placeholder={\n t('settings.azureOpenaiEmbeddingDeploymentPlaceholder') ||\n 'your-embedding-deployment-name'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n <span className=\"text-red-500 px-1\">*</span>\n {t('settings.azureOpenaiEmbeddingModel') || 'Azure Embedding Model Name'}\n </h3>\n <p className=\"text-xs text-gray-500 mt-1\">\n {t('settings.azureOpenaiEmbeddingModelDescription') ||\n 'The actual OpenAI model name deployed in Azure (e.g. text-embedding-3-small). Used for accurate token counting.'}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempSmartRoutingConfig.azureOpenaiEmbeddingModel}\n onChange={(e) =>\n handleSmartRoutingConfigChange(\n 'azureOpenaiEmbeddingModel',\n e.target.value,\n )\n }\n placeholder={\n t('settings.azureOpenaiEmbeddingModelPlaceholder') ||\n 'text-embedding-3-small'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n required\n />\n </div>\n </div>\n </>\n )}\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.basePacingDelayMs')}\n </h3>\n <p className=\"text-xs text-gray-500 mt-1\">\n {t('settings.basePacingDelayMsDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"number\"\n min=\"0\"\n step=\"1000\"\n value={tempSmartRoutingConfig.basePacingDelayMs}\n onChange={(e) =>\n handleSmartRoutingConfigChange('basePacingDelayMs', e.target.value)\n }\n placeholder={\n t('settings.basePacingDelayMsPlaceholder') || 'Empty = default 0 ms'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n </div>\n <p className=\"text-xs text-gray-500 mt-2\">\n {(() => {\n const trimmedValue = tempSmartRoutingConfig.basePacingDelayMs.trim();\n if (!trimmedValue) {\n return t('settings.basePacingDelayMsAuto', { value: 0 });\n }\n if (trimmedValue === '0') {\n return t('settings.basePacingDelayMsZero');\n }\n return t('settings.basePacingDelayMsOverride');\n })()}\n </p>\n\n\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.embeddingEncodingFormat')}\n </h3>\n <p className=\"text-xs text-gray-500 mt-1\">\n {t('settings.embeddingEncodingFormatDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <select\n value={tempSmartRoutingConfig.embeddingEncodingFormat}\n onChange={(e) =>\n handleSmartRoutingConfigChange(\n 'embeddingEncodingFormat',\n e.target.value as 'auto' | 'base64' | 'float',\n )\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-select\"\n disabled={loading}\n >\n <option value=\"auto\">\n {t('settings.embeddingEncodingFormatAuto') || 'Auto'}\n </option>\n <option value=\"base64\">Base64</option>\n <option value=\"float\">Float</option>\n </select>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.embeddingMaxTokens')}\n </h3>\n <p className=\"text-xs text-gray-500 mt-1\">\n {t('settings.embeddingMaxTokensDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"number\"\n min=\"1\"\n value={tempSmartRoutingConfig.embeddingMaxTokens}\n onChange={(e) =>\n handleSmartRoutingConfigChange('embeddingMaxTokens', e.target.value)\n }\n placeholder={\n t('settings.embeddingMaxTokensPlaceholder') || 'Empty = auto by model'\n }\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n </div>\n <p className=\"text-xs text-gray-500 mt-2\">\n {(() => {\n const embeddingModelName =\n (tempSmartRoutingConfig.embeddingProvider === 'azure_openai'\n ? tempSmartRoutingConfig.azureOpenaiEmbeddingModel ||\n smartRoutingConfig.azureOpenaiEmbeddingModel\n : tempSmartRoutingConfig.openaiApiEmbeddingModel ||\n smartRoutingConfig.openaiApiEmbeddingModel) ||\n 'text-embedding-3-small';\n\n return tempSmartRoutingConfig.embeddingMaxTokens.trim()\n ? t('settings.embeddingMaxTokensOverride')\n : t('settings.embeddingMaxTokensAuto', {\n limit: getDefaultTokenLimitForUI(embeddingModelName),\n model: embeddingModelName,\n });\n })()}\n </p>\n </div>\n \n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.progressiveDisclosure')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.progressiveDisclosureDescription')}\n </p>\n </div>\n <Switch\n disabled={loading || !smartRoutingConfig.enabled}\n checked={smartRoutingConfig.progressiveDisclosure}\n onCheckedChange={(checked) =>\n updateSmartRoutingConfig('progressiveDisclosure', checked)\n }\n />\n </div>\n\n <div className=\"flex justify-end pt-2\">\n <button\n onClick={handleSaveSmartRoutingConfig}\n disabled={loading}\n className=\"px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* OAuth Server Configuration Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_OAUTH_SERVER}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('oauthServerConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('pages.settings.oauthServer')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.oauthServerConfig ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.oauthServerConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.enableOauthServer')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableOauthServerDescription')}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={oauthServerConfig.enabled}\n onCheckedChange={(checked) => handleOAuthServerToggle('enabled', checked)}\n />\n </div>\n\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.requireClientSecret')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.requireClientSecretDescription')}\n </p>\n </div>\n <Switch\n disabled={loading || !oauthServerConfig.enabled}\n checked={oauthServerConfig.requireClientSecret}\n onCheckedChange={(checked) =>\n handleOAuthServerToggle('requireClientSecret', checked)\n }\n />\n </div>\n\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.requireState')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.requireStateDescription')}</p>\n </div>\n <Switch\n disabled={loading || !oauthServerConfig.enabled}\n checked={oauthServerConfig.requireState}\n onCheckedChange={(checked) => handleOAuthServerToggle('requireState', checked)}\n />\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.accessTokenLifetime')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.accessTokenLifetimeDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"number\"\n value={tempOAuthServerConfig.accessTokenLifetime}\n onChange={(e) =>\n handleOAuthServerNumberChange('accessTokenLifetime', e.target.value)\n }\n placeholder={t('settings.accessTokenLifetimePlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveOAuthServerNumberConfig('accessTokenLifetime')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.refreshTokenLifetime')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.refreshTokenLifetimeDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"number\"\n value={tempOAuthServerConfig.refreshTokenLifetime}\n onChange={(e) =>\n handleOAuthServerNumberChange('refreshTokenLifetime', e.target.value)\n }\n placeholder={t('settings.refreshTokenLifetimePlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveOAuthServerNumberConfig('refreshTokenLifetime')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.authorizationCodeLifetime')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.authorizationCodeLifetimeDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"number\"\n value={tempOAuthServerConfig.authorizationCodeLifetime}\n onChange={(e) =>\n handleOAuthServerNumberChange('authorizationCodeLifetime', e.target.value)\n }\n placeholder={t('settings.authorizationCodeLifetimePlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveOAuthServerNumberConfig('authorizationCodeLifetime')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.allowedScopes')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.allowedScopesDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempOAuthServerConfig.allowedScopes}\n onChange={(e) => handleOAuthServerTextChange('allowedScopes', e.target.value)}\n placeholder={t('settings.allowedScopesPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={saveOAuthServerAllowedScopes}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md space-y-4\">\n <div className=\"flex justify-between items-center\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.enableDynamicRegistration')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.dynamicRegistrationDescription')}\n </p>\n </div>\n <Switch\n disabled={loading || !oauthServerConfig.enabled}\n checked={oauthServerConfig.dynamicRegistration.enabled}\n onCheckedChange={(checked) =>\n handleDynamicRegistrationToggle({ enabled: checked })\n }\n />\n </div>\n\n <div>\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.dynamicRegistrationAllowedGrantTypes')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.dynamicRegistrationAllowedGrantTypesDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempOAuthServerConfig.dynamicRegistrationAllowedGrantTypes}\n onChange={(e) =>\n handleOAuthServerTextChange(\n 'dynamicRegistrationAllowedGrantTypes',\n e.target.value,\n )\n }\n placeholder={t('settings.dynamicRegistrationAllowedGrantTypesPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={\n loading ||\n !oauthServerConfig.enabled ||\n !oauthServerConfig.dynamicRegistration.enabled\n }\n />\n <button\n onClick={saveOAuthServerGrantTypes}\n disabled={\n loading ||\n !oauthServerConfig.enabled ||\n !oauthServerConfig.dynamicRegistration.enabled\n }\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.dynamicRegistrationAuth')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.dynamicRegistrationAuthDescription')}\n </p>\n </div>\n <Switch\n disabled={\n loading ||\n !oauthServerConfig.enabled ||\n !oauthServerConfig.dynamicRegistration.enabled\n }\n checked={oauthServerConfig.dynamicRegistration.requiresAuthentication}\n onCheckedChange={(checked) =>\n handleDynamicRegistrationToggle({ requiresAuthentication: checked })\n }\n />\n </div>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* MCPRouter Configuration Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_INSTALL_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 page-card dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('mcpRouterConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('settings.mcpRouterConfig')}</h2>\n <span className=\"text-gray-500 transition-transform duration-200\">\n {sectionsVisible.mcpRouterConfig ? '▼' : '►'}\n </span>\n </div>\n\n {sectionsVisible.mcpRouterConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.mcpRouterApiKey')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.mcpRouterApiKeyDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"password\"\n value={tempMCPRouterConfig.apiKey}\n onChange={(e) => handleMCPRouterConfigChange('apiKey', e.target.value)}\n placeholder={t('settings.mcpRouterApiKeyPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm border-gray-300 form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveMCPRouterConfig('apiKey')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.mcpRouterBaseUrl')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.mcpRouterBaseUrlDescription')}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempMCPRouterConfig.baseUrl}\n onChange={(e) => handleMCPRouterConfigChange('baseUrl', e.target.value)}\n placeholder={t('settings.mcpRouterBaseUrlPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveMCPRouterConfig('baseUrl')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* System Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_SYSTEM_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('nameSeparator')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('settings.systemSettings')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.nameSeparator ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.nameSeparator && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.nameSeparatorLabel')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.nameSeparatorDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempNameSeparator}\n onChange={(e) => setTempNameSeparator(e.target.value)}\n placeholder=\"-\"\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n maxLength={5}\n />\n <button\n onClick={saveNameSeparator}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.enableSessionRebuild')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableSessionRebuildDescription')}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={enableSessionRebuild}\n onCheckedChange={(checked) => updateSessionRebuild(checked)}\n />\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* Route Configuration Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_ROUTE_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('routingConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('pages.settings.routeConfig')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.routingConfig ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.routingConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.enableGlobalRoute')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableGlobalRouteDescription')}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={routingConfig.enableGlobalRoute}\n onCheckedChange={(checked) =>\n handleRoutingConfigChange('enableGlobalRoute', checked)\n }\n />\n </div>\n\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">\n {t('settings.enableGroupNameRoute')}\n </h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.enableGroupNameRouteDescription')}\n </p>\n </div>\n <Switch\n disabled={loading}\n checked={routingConfig.enableGroupNameRoute}\n onCheckedChange={(checked) =>\n handleRoutingConfigChange('enableGroupNameRoute', checked)\n }\n />\n </div>\n\n <div className=\"flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div>\n <h3 className=\"font-medium text-gray-700\">{t('settings.skipAuth')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.skipAuthDescription')}</p>\n </div>\n <Switch\n disabled={loading}\n checked={routingConfig.skipAuth}\n onCheckedChange={(checked) => handleRoutingConfigChange('skipAuth', checked)}\n />\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.jsonBodyLimit')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.jsonBodyLimitDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={tempRoutingConfig.jsonBodyLimit}\n onChange={(e) => handleTempRoutingConfigChange('jsonBodyLimit', e.target.value)}\n placeholder={t('settings.jsonBodyLimitPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => handleRoutingConfigChange('jsonBodyLimit', tempRoutingConfig.jsonBodyLimit)}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* Installation Configuration Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_INSTALL_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('installConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('settings.installConfig')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.installConfig ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.installConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.baseUrl')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.baseUrlDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={installConfig.baseUrl}\n onChange={(e) => handleInstallConfigChange('baseUrl', e.target.value)}\n placeholder={t('settings.baseUrlPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveInstallConfig('baseUrl')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.pythonIndexUrl')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.pythonIndexUrlDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={installConfig.pythonIndexUrl}\n onChange={(e) => handleInstallConfigChange('pythonIndexUrl', e.target.value)}\n placeholder={t('settings.pythonIndexUrlPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveInstallConfig('pythonIndexUrl')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-2\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.npmRegistry')}</h3>\n <p className=\"text-sm text-gray-500\">{t('settings.npmRegistryDescription')}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <input\n type=\"text\"\n value={installConfig.npmRegistry}\n onChange={(e) => handleInstallConfigChange('npmRegistry', e.target.value)}\n placeholder={t('settings.npmRegistryPlaceholder')}\n className=\"flex-1 mt-1 block w-full py-2 px-3 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm form-input\"\n disabled={loading}\n />\n <button\n onClick={() => saveInstallConfig('npmRegistry')}\n disabled={loading}\n className=\"mt-1 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {t('common.save')}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n\n {/* Change Password */}\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\" data-section=\"password\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('password')}\n role=\"button\"\n >\n <h2 className=\"font-semibold text-gray-800\">{t('auth.changePassword')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.password ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.password && (\n <div className=\"max-w-lg pb-4 px-6\">\n <ChangePasswordForm onSuccess={handlePasswordChangeSuccess} />\n </div>\n )}\n </div>\n\n {/* Export MCP Settings */}\n <PermissionChecker permissions={PERMISSIONS.SETTINGS_EXPORT_CONFIG}>\n <div className=\"bg-white dark:bg-gray-800 shadow rounded-lg mb-6 dashboard-card\">\n <div\n className=\"flex justify-between items-center cursor-pointer transition-colors duration-200 hover:text-blue-600 py-4 px-6\"\n onClick={() => toggleSection('exportConfig')}\n >\n <h2 className=\"font-semibold text-gray-800\">{t('settings.exportMcpSettings')}</h2>\n <span className=\"text-gray-500\">{sectionsVisible.exportConfig ? '▼' : '►'}</span>\n </div>\n\n {sectionsVisible.exportConfig && (\n <div className=\"space-y-4 pb-4 px-6\">\n <div className=\"p-3 bg-gray-50 dark:bg-gray-800 rounded-md\">\n <div className=\"mb-4\">\n <h3 className=\"font-medium text-gray-700\">{t('settings.mcpSettingsJson')}</h3>\n <p className=\"text-sm text-gray-500\">\n {t('settings.mcpSettingsJsonDescription')}\n </p>\n </div>\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-3\">\n <button\n onClick={handleCopyConfig}\n disabled={!mcpSettingsJson}\n className=\"flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n {copiedConfig ? <Check size={16} /> : <Copy size={16} />}\n {copiedConfig ? t('common.copied') : t('settings.copyToClipboard')}\n </button>\n <button\n onClick={handleDownloadConfig}\n disabled={!mcpSettingsJson}\n className=\"flex items-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white rounded-md text-sm font-medium disabled:opacity-50 btn-primary\"\n >\n <Download size={16} />\n {t('settings.downloadJson')}\n </button>\n </div>\n {mcpSettingsJson && (\n <div className=\"mt-3\">\n <pre className=\"bg-gray-900 text-gray-100 p-4 rounded-md overflow-x-auto text-xs max-h-96\">\n {mcpSettingsJson}\n </pre>\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n </div>\n </PermissionChecker>\n </div>\n );\n};\n\nexport default SettingsPage;\n"],"names":["validatePasswordStrength","password","errors","ChangePasswordForm","onSuccess","onCancel","t","useTranslation","formData","setFormData","useState","confirmPassword","setConfirmPassword","isLoading","setIsLoading","error","setError","success","setSuccess","passwordErrors","setPasswordErrors","handleChange","e","name","value","prev","validation","handleSubmit","response","changePassword","jsxs","jsx","errorKey","MultiSelect","options","selected","onChange","placeholder","disabled","className","isOpen","setIsOpen","searchTerm","setSearchTerm","dropdownRef","useRef","inputRef","useEffect","handleClickOutside","event","filteredOptions","option","handleToggleOption","newSelected","item","handleRemoveItem","handleToggleDropdown","_a","getSelectedLabels","opt","Fragment","label","index","X","ChevronDown","isSelected","Check","generateRandomKey","length","characters","array","x","PERMISSIONS","BearerKeyRow","keyData","loading","availableServers","availableGroups","onSave","onDelete","showToast","useToast","isEditing","setIsEditing","setName","token","setToken","enabled","setEnabled","accessType","setAccessType","selectedGroups","setSelectedGroups","selectedServers","setSelectedServers","saving","setSaving","deleting","setDeleting","handleCopyToken","textArea","handleSave","handleDelete","isGroupsMode","isCustomMode","formatAccessTypeDisplay","key","parts","Switch","checked","Copy","Edit","Trash2","getDefaultTokenLimitForUI","model","lower","MODEL_LIMITS","pattern","limit","parseEmbeddingMaxTokensForUpdate","rawValue","currentValue","trimmed","parsed","result","parseBasePacingDelayForUpdate","SettingsPage","navigate","useNavigate","servers","useServerContext","groups","useGroupData","installConfig","setInstallConfig","tempSmartRoutingConfig","setTempSmartRoutingConfig","tempMCPRouterConfig","setTempMCPRouterConfig","tempOAuthServerConfig","setTempOAuthServerConfig","tempNameSeparator","setTempNameSeparator","showAddBearerKeyForm","setShowAddBearerKeyForm","routingConfig","tempRoutingConfig","setTempRoutingConfig","savedInstallConfig","smartRoutingConfig","mcpRouterConfig","oauthServerConfig","nameSeparator","enableSessionRebuild","bearerKeys","updateRoutingConfig","updateInstallConfig","updateSmartRoutingConfig","updateSmartRoutingConfigBatch","updateMCPRouterConfig","updateOAuthServerConfig","updateNameSeparator","updateSessionRebuild","exportMCPSettings","createBearerKey","updateBearerKey","deleteBearerKey","refreshBearerKeys","useSettingsData","_b","sectionsVisible","setSectionsVisible","toggleSection","section","handleRoutingConfigChange","handleTempRoutingConfigChange","handleInstallConfigChange","saveInstallConfig","handleSmartRoutingConfigChange","handleMCPRouterConfigChange","saveMCPRouterConfig","handleOAuthServerNumberChange","handleOAuthServerTextChange","saveOAuthServerNumberConfig","parsedValue","saveOAuthServerAllowedScopes","scopes","scope","saveOAuthServerGrantTypes","grantTypes","grant","handleOAuthServerToggle","handleDynamicRegistrationToggle","updates","saveNameSeparator","handleSmartRoutingEnabledChange","currentDbUrl","missingFields","currentEndpoint","currentKey","currentApiVersion","currentDeployment","currentOpenaiApiKey","currentOpenaiApiBaseUrl","currentOpenaiApiEmbeddingModel","parsedBasePacingDelay","parsedTokens","handleSaveSmartRoutingConfig","parsedEmbeddingMaxTokens","handlePasswordChangeSuccess","copiedConfig","setCopiedConfig","mcpSettingsJson","setMcpSettingsJson","newBearerKey","setNewBearerKey","newSelectedGroups","setNewSelectedGroups","newSelectedServers","setNewSelectedServers","server","group","fetchMcpSettings","configJson","handleCopyConfig","err","handleDownloadConfig","blob","url","link","parseCommaSeparated","handleCreateBearerKey","handleSaveExistingBearerKey","id","payload","handleDeleteExistingBearerKey","PermissionChecker","trimmedValue","embeddingModelName","Download"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{j as s}from"./framework-vendor-_OBebcuv.js";import{l as i}from"./index-CmnA4an8.js";const l=({checked:t,onCheckedChange:n,disabled:o=!1})=>s.jsx("button",{type:"button",role:"switch","aria-checked":t,disabled:o,className:i("relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",t?"bg-blue-200":"bg-gray-100",o?"opacity-50 cursor-not-allowed":"cursor-pointer"),onClick:()=>!o&&n(!t),children:s.jsx("span",{className:i("inline-block h-4 w-4 transform rounded-full bg-white transition-transform",t?"translate-x-6":"translate-x-1")})});export{l as S};
2
+ //# sourceMappingURL=ToggleGroup-HfxdlkGi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleGroup-HfxdlkGi.js","sources":["../../src/components/ui/ToggleGroup.tsx"],"sourcesContent":["import React, { ReactNode } from 'react';\nimport { cn } from '@/utils/cn';\n\ninterface ToggleGroupItemProps {\n value: string;\n isSelected: boolean;\n onClick: () => void;\n children: ReactNode;\n}\n\nexport const ToggleGroupItem: React.FC<ToggleGroupItemProps> = ({\n isSelected,\n onClick,\n children\n}) => {\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={isSelected}\n className={cn(\n \"flex w-full items-center justify-between p-2 rounded transition-colors cursor-pointer\",\n isSelected\n ? \"bg-blue-50 text-blue-700 hover:bg-blue-100 border-l-4 border-blue-500\"\n : \"hover:bg-gray-50 text-gray-700\"\n )}\n onClick={onClick}\n >\n <span className=\"flex items-center\">\n {children}\n </span>\n {isSelected && (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" className=\"w-5 h-5 text-blue-500\">\n <path fillRule=\"evenodd\" d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </button>\n );\n};\n\ninterface ToggleGroupProps {\n label: string;\n helpText?: string;\n noOptionsText?: string;\n values: string[];\n options: { value: string; label: string }[];\n onChange: (values: string[]) => void;\n className?: string;\n}\n\nexport const ToggleGroup: React.FC<ToggleGroupProps> = ({\n label,\n helpText,\n noOptionsText = \"No options available\",\n values,\n options,\n onChange,\n className\n}) => {\n const handleToggle = (value: string) => {\n const isSelected = values.includes(value);\n if (isSelected) {\n onChange(values.filter(v => v !== value));\n } else {\n onChange([...values, value]);\n }\n };\n\n return (\n <div className={className}>\n <label className=\"block text-gray-700 text-sm font-bold mb-2\">\n {label}\n </label>\n <div className=\"border border-gray-200 dark:border-gray-700 rounded shadow max-h-60 overflow-y-auto\">\n {options.length === 0 ? (\n <p className=\"text-gray-500 text-sm p-3\">{noOptionsText}</p>\n ) : (\n <div className=\"space-y-1 p-1\">\n {options.map(option => (\n <ToggleGroupItem\n key={option.value}\n value={option.value}\n isSelected={values.includes(option.value)}\n onClick={() => handleToggle(option.value)}\n >\n {option.label}\n </ToggleGroupItem>\n ))}\n </div>\n )}\n </div>\n {helpText && (\n <p className=\"text-xs text-gray-500 mt-1\">\n {helpText}\n </p>\n )}\n </div>\n );\n};\n\ninterface SwitchProps {\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n disabled?: boolean;\n}\n\nexport const Switch: React.FC<SwitchProps> = ({\n checked,\n onCheckedChange,\n disabled = false\n}) => {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={cn(\n \"relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500\",\n checked ? \"bg-blue-200\" : \"bg-gray-100\",\n disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer\"\n )}\n onClick={() => !disabled && onCheckedChange(!checked)}\n >\n <span\n className={cn(\n \"inline-block h-4 w-4 transform rounded-full bg-white transition-transform\",\n checked ? \"translate-x-6\" : \"translate-x-1\"\n )}\n />\n </button>\n );\n};"],"names":["Switch","checked","onCheckedChange","disabled","jsx","cn"],"mappings":"2FA0GO,MAAMA,EAAgC,CAAC,CAC5C,QAAAC,EACA,gBAAAC,EACA,SAAAC,EAAW,EACb,IAEIC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,KAAK,SACL,eAAcH,EACd,SAAAE,EACA,UAAWE,EACT,wLACAJ,EAAU,cAAgB,cAC1BE,EAAW,gCAAkC,gBAAA,EAE/C,QAAS,IAAM,CAACA,GAAYD,EAAgB,CAACD,CAAO,EAEpD,SAAAG,EAAAA,IAAC,OAAA,CACC,UAAWC,EACT,4EACAJ,EAAU,gBAAkB,eAAA,CAC9B,CAAA,CACF,CAAA"}
@@ -0,0 +1,2 @@
1
+ import{r as c,j as e}from"./framework-vendor-_OBebcuv.js";import{i as A,e as E,f as S,d as U,u as F}from"./index-CmnA4an8.js";import{u as j}from"./i18n-vendor-MQ921plD.js";import{D}from"./DeleteDialog-BAfrV8EB.js";import{U as R,h as z,T as L}from"./icons-vendor-B67NtVuR.js";const N=()=>{const{t:n}=j(),[w,a]=c.useState([]),[l,p]=c.useState(!0),[m,t]=c.useState(null),[x,u]=c.useState(0),o=c.useCallback(async()=>{try{p(!0);const s=await A("/users");if(!s.success){t(s.message||n("users.fetchError"));return}s&&s.success&&Array.isArray(s.data)?a(s.data):(console.error("Invalid user data format:",s),a([])),t(null)}catch(s){console.error("Error fetching users:",s),t(s instanceof Error?s.message:"Failed to fetch users"),a([])}finally{p(!1)}},[]),h=c.useCallback(()=>{u(s=>s+1)},[]),f=async s=>{try{const r=await U("/users",s);return h(),r}catch(r){return t(r instanceof Error?r.message:"Failed to create user"),null}},b=async(s,r)=>{try{const g=await S(`/users/${s}`,r);return h(),g||null}catch(g){return t(g instanceof Error?g.message:"Failed to update user"),null}},d=async s=>{try{const r=await E(`/users/${s}`);return r!=null&&r.success?(h(),r):(t((r==null?void 0:r.message)||n("users.deleteError")),r)}catch(r){return t(r instanceof Error?r.message:"Failed to delete user"),!1}};return c.useEffect(()=>{o()},[o,x]),{users:w,loading:l,error:m,setError:t,triggerRefresh:h,createUser:f,updateUser:b,deleteUser:d}},T=({onAdd:n,onCancel:w})=>{const{t:a}=j(),{createUser:l}=N(),[p,m]=c.useState(null),[t,x]=c.useState(!1),[u,o]=c.useState({username:"",password:"",isAdmin:!1}),h=async b=>{if(b.preventDefault(),m(null),!u.username.trim()){m(a("users.usernameRequired"));return}if(!u.password.trim()){m(a("users.passwordRequired"));return}if(u.password.length<6){m(a("users.passwordTooShort"));return}x(!0);try{const d=await l(u);d!=null&&d.success?n():m((d==null?void 0:d.message)||a("users.createError"))}catch(d){m(d instanceof Error?d.message:a("users.createError"))}finally{x(!1)}},f=b=>{const{name:d,value:s,type:r,checked:g}=b.target;o(y=>({...y,[d]:r==="checkbox"?g:s}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:h,children:[e.jsx("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:a("users.addNew")}),p&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:p})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"username",className:"block text-sm font-medium text-gray-700 mb-1",children:[a("users.username")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"text",id:"username",name:"username",value:u.username,onChange:f,placeholder:a("users.usernamePlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:t})]}),e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"password",className:"block text-sm font-medium text-gray-700 mb-1",children:[a("users.password")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"password",id:"password",name:"password",value:u.password,onChange:f,placeholder:a("users.passwordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:t,minLength:6})]}),e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:u.isAdmin,onChange:f,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:t}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:a("users.adminRole")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-3 mt-8",children:[e.jsx("button",{type:"button",onClick:w,className:"px-5 py-2.5 text-gray-700 bg-white dark:bg-gray-800 border border-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200 font-medium btn-secondary shadow-sm",disabled:t,children:a("common.cancel")}),e.jsxs("button",{type:"submit",className:"px-5 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 font-medium btn-primary shadow-md disabled:opacity-70 disabled:cursor-not-allowed flex items-center",disabled:t,children:[t&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),a(t?"common.creating":"users.create")]})]})]})})})},q=({user:n,onEdit:w,onCancel:a})=>{const{t:l}=j(),{updateUser:p}=N(),[m,t]=c.useState(null),[x,u]=c.useState(!1),[o,h]=c.useState({isAdmin:n.isAdmin,newPassword:"",confirmPassword:""}),f=async d=>{if(d.preventDefault(),t(null),o.newPassword&&o.newPassword!==o.confirmPassword){t(l("users.passwordMismatch"));return}if(o.newPassword&&o.newPassword.length<6){t(l("users.passwordTooShort"));return}u(!0);try{const s={isAdmin:o.isAdmin};o.newPassword&&(s.newPassword=o.newPassword);const r=await p(n.username,s);r!=null&&r.success?w():t((r==null?void 0:r.message)||l("users.updateError"))}catch(s){t(s instanceof Error?s.message:l("users.updateError"))}finally{u(!1)}},b=d=>{const{name:s,value:r,type:g,checked:y}=d.target;h(v=>({...v,[s]:g==="checkbox"?y:r}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:f,children:[e.jsxs("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:[l("users.edit")," - ",e.jsx("span",{className:"text-blue-600",children:n.username})]}),m&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:m})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:o.isAdmin,onChange:b,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:x}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:l("users.adminRole")})]}),e.jsxs("div",{className:"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2",children:[e.jsx("p",{className:"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3",children:l("users.changePassword")}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"newPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.newPassword")}),e.jsx("input",{type:"password",id:"newPassword",name:"newPassword",value:o.newPassword,onChange:b,placeholder:l("users.newPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:x,minLength:6})]}),o.newPassword&&e.jsxs("div",{className:"animate-fadeIn",children:[e.jsx("label",{htmlFor:"confirmPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.confirmPassword")}),e.jsx("input",{type:"password",id:"confirmPassword",name:"confirmPassword",value:o.confirmPassword,onChange:b,placeholder:l("users.confirmPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:x,minLength:6})]})]})]})]}),e.jsxs("div",{className:"flex justify-end space-x-3 mt-8",children:[e.jsx("button",{type:"button",onClick:a,className:"px-5 py-2.5 text-gray-700 bg-white dark:bg-gray-800 border border-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-all duration-200 font-medium btn-secondary shadow-sm",disabled:x,children:l("common.cancel")}),e.jsxs("button",{type:"submit",className:"px-5 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-all duration-200 font-medium btn-primary shadow-md disabled:opacity-70 disabled:cursor-not-allowed flex items-center",disabled:x,children:[x&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),l(x?"common.updating":"users.update")]})]})]})})})},W=()=>{const{t:n}=j(),{auth:w}=F(),a=w.user,{users:l,loading:p,error:m,setError:t,deleteUser:x,triggerRefresh:u}=N(),[o,h]=c.useState(null),[f,b]=c.useState(!1),[d,s]=c.useState(null);if(!(a!=null&&a.isAdmin))return e.jsx("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 dashboard-card",children:e.jsx("p",{className:"text-red-600",children:n("users.adminRequired")})});const r=i=>{h(i)},g=()=>{h(null),u()},y=i=>{s(i)},v=async()=>{if(d){const i=await x(d);i!=null&&i.success||t((i==null?void 0:i.message)||n("users.deleteError")),s(null)}},k=()=>{b(!0)},C=()=>{b(!1),u()};return e.jsxs("div",{className:"container mx-auto",children:[e.jsxs("div",{className:"flex justify-between items-center mb-8",children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:n("pages.users.title")}),e.jsx("div",{className:"flex space-x-4",children:e.jsxs("button",{onClick:k,className:"px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 flex items-center btn-primary transition-all duration-200 shadow-sm",children:[e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 mr-2",viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("path",{fillRule:"evenodd",d:"M10 3a1 1 0 00-1 1v5H4a1 1 0 100 2h5v5a1 1 0 102 0v-5h5a1 1 0 100-2h-5V4a1 1 0 00-1-1z",clipRule:"evenodd"})}),n("users.add")]})})]}),m&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 error-box rounded-lg shadow-sm",children:e.jsxs("div",{className:"flex justify-between items-center",children:[e.jsx("p",{children:m}),e.jsx("button",{onClick:()=>t(null),className:"text-red-500 hover:text-red-700",children:e.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-5 w-5",viewBox:"0 0 20 20",fill:"currentColor",children:e.jsx("path",{fillRule:"evenodd",d:"M4.293 4.293a1 1 011.414 0L10 8.586l4.293-4.293a1 1 111.414 1.414L11.414 10l4.293 4.293a1 1 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 01-1.414-1.414L8.586 10 4.293 5.707a1 1 010-1.414z",clipRule:"evenodd"})})})]})}),p?e.jsx("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 loading-container flex justify-center items-center h-64",children:e.jsxs("div",{className:"flex flex-col items-center justify-center",children:[e.jsxs("svg",{className:"animate-spin h-10 w-10 text-blue-500 mb-4",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),e.jsx("p",{className:"text-gray-600",children:n("app.loading")})]})}):l.length===0?e.jsx("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg p-6 empty-state dashboard-card",children:e.jsxs("div",{className:"flex flex-col items-center justify-center py-12",children:[e.jsx("div",{className:"p-4 bg-gray-100 dark:bg-gray-800 rounded-full mb-4",children:e.jsx(R,{className:"h-8 w-8 text-gray-400"})}),e.jsx("p",{className:"text-gray-600 text-lg font-medium",children:n("users.noUsers")}),e.jsx("button",{onClick:k,className:"mt-4 text-blue-600 hover:text-blue-800 font-medium",children:n("users.addFirst")})]})}):e.jsx("div",{className:"bg-white dark:bg-gray-800 shadow rounded-lg overflow-hidden table-container dashboard-card",children:e.jsxs("table",{className:"min-w-full divide-y divide-gray-200 dark:divide-gray-700",children:[e.jsx("thead",{className:"bg-gray-50 dark:bg-gray-800",children:e.jsxs("tr",{children:[e.jsx("th",{scope:"col",className:"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider",children:n("users.username")}),e.jsx("th",{scope:"col",className:"px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider",children:n("users.role")}),e.jsx("th",{scope:"col",className:"px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider",children:n("users.actions")})]})}),e.jsx("tbody",{className:"bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700",children:l.map(i=>{const P=(a==null?void 0:a.username)===i.username;return e.jsxs("tr",{className:"hover:bg-gray-50 dark:bg-gray-800 dark:hover:bg-gray-700 transition-colors duration-150",children:[e.jsx("td",{className:"px-6 py-4 whitespace-nowrap",children:e.jsxs("div",{className:"flex items-center",children:[e.jsx("div",{className:"flex-shrink-0 h-10 w-10",children:e.jsx("div",{className:"h-10 w-10 rounded-full bg-blue-100 dark:bg-blue-900/40 flex items-center justify-center text-blue-600 dark:text-blue-300 font-bold text-lg",children:i.username.charAt(0).toUpperCase()})}),e.jsx("div",{className:"ml-4",children:e.jsxs("div",{className:"text-sm font-medium text-gray-900 flex items-center",children:[i.username,P&&e.jsx("span",{className:"ml-2 px-2 py-0.5 text-xs bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300 rounded-full border border-blue-200 dark:border-blue-800",children:n("users.currentUser")})]})})]})}),e.jsx("td",{className:"px-6 py-4 whitespace-nowrap",children:e.jsx("span",{className:`px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full ${i.isAdmin?"bg-purple-100 text-purple-800 border border-purple-200 dark:bg-purple-900/40 dark:text-purple-300 dark:border-purple-800":"bg-gray-100 text-gray-800 border border-gray-200 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-700"}`,children:i.isAdmin?n("users.admin"):n("users.user")})}),e.jsx("td",{className:"px-6 py-4 whitespace-nowrap text-right text-sm font-medium",children:e.jsxs("div",{className:"flex justify-end space-x-3",children:[e.jsx("button",{onClick:()=>r(i),className:"text-blue-600 dark:text-blue-400 hover:text-blue-900 dark:hover:text-blue-300 p-1 rounded hover:bg-blue-50 dark:hover:bg-blue-900/40 transition-colors",title:n("users.edit"),children:e.jsx(z,{size:18})}),!P&&e.jsx("button",{onClick:()=>y(i.username),className:"text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300 p-1 rounded hover:bg-red-50 dark:hover:bg-red-900/40 transition-colors",title:n("users.delete"),children:e.jsx(L,{size:18})})]})})]},i.username)})})]})}),f&&e.jsx(T,{onAdd:C,onCancel:C}),o&&e.jsx(q,{user:o,onEdit:g,onCancel:()=>h(null)}),e.jsx(D,{isOpen:!!d,onClose:()=>s(null),onConfirm:v,serverName:d||"",isGroup:!1,isUser:!0})]})};export{W as default};
2
+ //# sourceMappingURL=UsersPage-Bipw33cS.js.map