Merge pull request #6364 from menloresearch/feat/local-api-server
feat: allow see Apikey when server local status running
This commit is contained in:
commit
b2c4e89402
@ -3,15 +3,18 @@ import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
|||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
import { Eye, EyeOff } from 'lucide-react'
|
import { Eye, EyeOff } from 'lucide-react'
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
interface ApiKeyInputProps {
|
interface ApiKeyInputProps {
|
||||||
showError?: boolean
|
showError?: boolean
|
||||||
onValidationChange?: (isValid: boolean) => void
|
onValidationChange?: (isValid: boolean) => void
|
||||||
|
isServerRunning?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ApiKeyInput({
|
export function ApiKeyInput({
|
||||||
showError = false,
|
showError = false,
|
||||||
onValidationChange,
|
onValidationChange,
|
||||||
|
isServerRunning,
|
||||||
}: ApiKeyInputProps) {
|
}: ApiKeyInputProps) {
|
||||||
const { apiKey, setApiKey } = useLocalApiServer()
|
const { apiKey, setApiKey } = useLocalApiServer()
|
||||||
const [inputValue, setInputValue] = useState(apiKey.toString())
|
const [inputValue, setInputValue] = useState(apiKey.toString())
|
||||||
@ -19,16 +22,19 @@ export function ApiKeyInput({
|
|||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const validateApiKey = useCallback((value: string) => {
|
const validateApiKey = useCallback(
|
||||||
if (!value || value.trim().length === 0) {
|
(value: string) => {
|
||||||
setError(t('common:apiKeyRequired'))
|
if (!value || value.trim().length === 0) {
|
||||||
onValidationChange?.(false)
|
setError(t('common:apiKeyRequired'))
|
||||||
return false
|
onValidationChange?.(false)
|
||||||
}
|
return false
|
||||||
setError('')
|
}
|
||||||
onValidationChange?.(true)
|
setError('')
|
||||||
return true
|
onValidationChange?.(true)
|
||||||
}, [onValidationChange, t])
|
return true
|
||||||
|
},
|
||||||
|
[onValidationChange, t]
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showError) {
|
if (showError) {
|
||||||
@ -64,11 +70,12 @@ export function ApiKeyInput({
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
className={`w-full text-sm pr-10 ${
|
className={cn(
|
||||||
hasError
|
'w-full text-sm pr-10',
|
||||||
? 'border-1 border-destructive focus:border-destructive focus:ring-destructive'
|
hasError &&
|
||||||
: ''
|
'border-1 border-destructive focus:border-destructive focus:ring-destructive',
|
||||||
}`}
|
isServerRunning && 'opacity-50 pointer-events-none'
|
||||||
|
)}
|
||||||
placeholder={t('common:enterApiKey')}
|
placeholder={t('common:enterApiKey')}
|
||||||
/>
|
/>
|
||||||
<div className="absolute right-2 top-1/2 transform -translate-y-1/2 flex items-center gap-1">
|
<div className="absolute right-2 top-1/2 transform -translate-y-1/2 flex items-center gap-1">
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
export function ApiPrefixInput() {
|
export function ApiPrefixInput({
|
||||||
|
isServerRunning,
|
||||||
|
}: {
|
||||||
|
isServerRunning?: boolean
|
||||||
|
}) {
|
||||||
const { apiPrefix, setApiPrefix } = useLocalApiServer()
|
const { apiPrefix, setApiPrefix } = useLocalApiServer()
|
||||||
const [inputValue, setInputValue] = useState(apiPrefix)
|
const [inputValue, setInputValue] = useState(apiPrefix)
|
||||||
|
|
||||||
@ -27,7 +32,10 @@ export function ApiPrefixInput() {
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
className="w-24 h-8 text-sm"
|
className={cn(
|
||||||
|
'w-24 h-8 text-sm',
|
||||||
|
isServerRunning && 'opacity-50 pointer-events-none'
|
||||||
|
)}
|
||||||
placeholder="/v1"
|
placeholder="/v1"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { Input } from '@/components/ui/input'
|
import { Input } from '@/components/ui/input'
|
||||||
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
export function PortInput() {
|
export function PortInput({ isServerRunning }: { isServerRunning?: boolean }) {
|
||||||
const { serverPort, setServerPort } = useLocalApiServer()
|
const { serverPort, setServerPort } = useLocalApiServer()
|
||||||
const [inputValue, setInputValue] = useState(serverPort.toString())
|
const [inputValue, setInputValue] = useState(serverPort.toString())
|
||||||
|
|
||||||
@ -29,7 +30,10 @@ export function PortInput() {
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
className="w-24 h-8 text-sm"
|
className={cn(
|
||||||
|
'w-24 h-8 text-sm',
|
||||||
|
isServerRunning && 'opacity-50 pointer-events-none'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
|
|
||||||
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
@ -12,12 +13,19 @@ const hostOptions = [
|
|||||||
{ value: '0.0.0.0', label: '0.0.0.0' },
|
{ value: '0.0.0.0', label: '0.0.0.0' },
|
||||||
]
|
]
|
||||||
|
|
||||||
export function ServerHostSwitcher() {
|
export function ServerHostSwitcher({
|
||||||
|
isServerRunning,
|
||||||
|
}: {
|
||||||
|
isServerRunning?: boolean
|
||||||
|
}) {
|
||||||
const { serverHost, setServerHost } = useLocalApiServer()
|
const { serverHost, setServerHost } = useLocalApiServer()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger
|
||||||
|
asChild
|
||||||
|
className={cn(isServerRunning && 'opacity-50 pointer-events-none')}
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
title="Edit Server Host"
|
title="Edit Server Host"
|
||||||
className="flex cursor-pointer items-center gap-1 px-2 py-1 rounded-sm bg-main-view-fg/15 text-sm outline-none text-main-view-fg font-medium"
|
className="flex cursor-pointer items-center gap-1 px-2 py-1 rounded-sm bg-main-view-fg/15 text-sm outline-none text-main-view-fg font-medium"
|
||||||
|
|||||||
@ -2,8 +2,13 @@ import { Input } from '@/components/ui/input'
|
|||||||
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useTranslation } from '@/i18n/react-i18next-compat'
|
import { useTranslation } from '@/i18n/react-i18next-compat'
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
export function TrustedHostsInput() {
|
export function TrustedHostsInput({
|
||||||
|
isServerRunning,
|
||||||
|
}: {
|
||||||
|
isServerRunning?: boolean
|
||||||
|
}) {
|
||||||
const { trustedHosts, setTrustedHosts } = useLocalApiServer()
|
const { trustedHosts, setTrustedHosts } = useLocalApiServer()
|
||||||
const [inputValue, setInputValue] = useState(trustedHosts.join(', '))
|
const [inputValue, setInputValue] = useState(trustedHosts.join(', '))
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -38,8 +43,11 @@ export function TrustedHostsInput() {
|
|||||||
value={inputValue}
|
value={inputValue}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={handleBlur}
|
onBlur={handleBlur}
|
||||||
className="w-full h-8 text-sm"
|
|
||||||
placeholder={t('common:enterTrustedHosts')}
|
placeholder={t('common:enterTrustedHosts')}
|
||||||
|
className={cn(
|
||||||
|
'w-24 h-8 text-sm',
|
||||||
|
isServerRunning && 'opacity-50 pointer-events-none'
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,7 +45,8 @@ function LocalAPIServer() {
|
|||||||
} = useLocalApiServer()
|
} = useLocalApiServer()
|
||||||
|
|
||||||
const { serverStatus, setServerStatus } = useAppState()
|
const { serverStatus, setServerStatus } = useAppState()
|
||||||
const { selectedModel, selectedProvider, getProviderByName } = useModelProvider()
|
const { selectedModel, selectedProvider, getProviderByName } =
|
||||||
|
useModelProvider()
|
||||||
const [showApiKeyError, setShowApiKeyError] = useState(false)
|
const [showApiKeyError, setShowApiKeyError] = useState(false)
|
||||||
const [isApiKeyEmpty, setIsApiKeyEmpty] = useState(
|
const [isApiKeyEmpty, setIsApiKeyEmpty] = useState(
|
||||||
!apiKey || apiKey.toString().trim().length === 0
|
!apiKey || apiKey.toString().trim().length === 0
|
||||||
@ -293,38 +294,31 @@ function LocalAPIServer() {
|
|||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:localApiServer.serverHost')}
|
title={t('settings:localApiServer.serverHost')}
|
||||||
description={t('settings:localApiServer.serverHostDesc')}
|
description={t('settings:localApiServer.serverHostDesc')}
|
||||||
className={cn(
|
actions={
|
||||||
isServerRunning && 'opacity-50 pointer-events-none'
|
<ServerHostSwitcher isServerRunning={isServerRunning} />
|
||||||
)}
|
}
|
||||||
actions={<ServerHostSwitcher />}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:localApiServer.serverPort')}
|
title={t('settings:localApiServer.serverPort')}
|
||||||
description={t('settings:localApiServer.serverPortDesc')}
|
description={t('settings:localApiServer.serverPortDesc')}
|
||||||
className={cn(
|
actions={<PortInput isServerRunning={isServerRunning} />}
|
||||||
isServerRunning && 'opacity-50 pointer-events-none'
|
|
||||||
)}
|
|
||||||
actions={<PortInput />}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:localApiServer.apiPrefix')}
|
title={t('settings:localApiServer.apiPrefix')}
|
||||||
description={t('settings:localApiServer.apiPrefixDesc')}
|
description={t('settings:localApiServer.apiPrefixDesc')}
|
||||||
className={cn(
|
actions={<ApiPrefixInput isServerRunning={isServerRunning} />}
|
||||||
isServerRunning && 'opacity-50 pointer-events-none'
|
|
||||||
)}
|
|
||||||
actions={<ApiPrefixInput />}
|
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
title={t('settings:localApiServer.apiKey')}
|
title={t('settings:localApiServer.apiKey')}
|
||||||
description={t('settings:localApiServer.apiKeyDesc')}
|
description={t('settings:localApiServer.apiKeyDesc')}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex-col sm:flex-row items-start sm:items-center sm:justify-between gap-y-2',
|
'flex-col sm:flex-row items-start sm:items-center sm:justify-between gap-y-2',
|
||||||
isServerRunning && 'opacity-50 pointer-events-none',
|
|
||||||
isApiKeyEmpty && showApiKeyError && 'pb-6'
|
isApiKeyEmpty && showApiKeyError && 'pb-6'
|
||||||
)}
|
)}
|
||||||
classNameWrapperAction="w-full sm:w-auto"
|
classNameWrapperAction="w-full sm:w-auto"
|
||||||
actions={
|
actions={
|
||||||
<ApiKeyInput
|
<ApiKeyInput
|
||||||
|
isServerRunning={isServerRunning}
|
||||||
showError={showApiKeyError}
|
showError={showApiKeyError}
|
||||||
onValidationChange={handleApiKeyValidation}
|
onValidationChange={handleApiKeyValidation}
|
||||||
/>
|
/>
|
||||||
@ -334,11 +328,12 @@ function LocalAPIServer() {
|
|||||||
title={t('settings:localApiServer.trustedHosts')}
|
title={t('settings:localApiServer.trustedHosts')}
|
||||||
description={t('settings:localApiServer.trustedHostsDesc')}
|
description={t('settings:localApiServer.trustedHostsDesc')}
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex-col sm:flex-row items-start sm:items-center sm:justify-between gap-y-2',
|
'flex-col sm:flex-row items-start sm:items-center sm:justify-between gap-y-2'
|
||||||
isServerRunning && 'opacity-50 pointer-events-none'
|
|
||||||
)}
|
)}
|
||||||
classNameWrapperAction="w-full sm:w-auto"
|
classNameWrapperAction="w-full sm:w-auto"
|
||||||
actions={<TrustedHostsInput />}
|
actions={
|
||||||
|
<TrustedHostsInput isServerRunning={isServerRunning} />
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user