yangdx
commited on
Commit
Β·
402ce00
1
Parent(s):
7b96a33
Refactor API key alert and remove message alert component
Browse files- Move StatusIndicator to status directory
- Remove obsolete MessageAlert component
- Enhance ApiKeyAlert with open state control
- Improve health check logic with alert state
- Add error message display in ApiKeyAlert
lightrag_webui/src/App.tsx
CHANGED
@@ -1,9 +1,8 @@
|
|
1 |
import { useState, useCallback, useEffect, useRef } from 'react'
|
2 |
import ThemeProvider from '@/components/ThemeProvider'
|
3 |
import TabVisibilityProvider from '@/contexts/TabVisibilityProvider'
|
4 |
-
import MessageAlert from '@/components/MessageAlert'
|
5 |
import ApiKeyAlert from '@/components/ApiKeyAlert'
|
6 |
-
import StatusIndicator from '@/components/
|
7 |
import { healthCheckInterval } from '@/lib/constants'
|
8 |
import { useBackendState, useAuthStore } from '@/stores/state'
|
9 |
import { useSettingsStore } from '@/stores/settings'
|
@@ -22,26 +21,30 @@ function App() {
|
|
22 |
const message = useBackendState.use.message()
|
23 |
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
24 |
const currentTab = useSettingsStore.use.currentTab()
|
25 |
-
const [
|
26 |
const versionCheckRef = useRef(false); // Prevent duplicate calls in Vite dev mode
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
// Health check - can be disabled
|
29 |
useEffect(() => {
|
30 |
-
// Only execute if health check is enabled
|
31 |
-
if (!enableHealthCheck) return;
|
32 |
|
33 |
// Health check function
|
34 |
const performHealthCheck = async () => {
|
35 |
await useBackendState.getState().check();
|
36 |
};
|
37 |
|
38 |
-
// Execute immediately
|
39 |
-
performHealthCheck();
|
40 |
-
|
41 |
// Set interval for periodic execution
|
42 |
const interval = setInterval(performHealthCheck, healthCheckInterval * 1000);
|
43 |
return () => clearInterval(interval);
|
44 |
-
}, [enableHealthCheck]);
|
45 |
|
46 |
// Version check - independent and executed only once
|
47 |
useEffect(() => {
|
@@ -90,12 +93,10 @@ function App() {
|
|
90 |
useEffect(() => {
|
91 |
if (message) {
|
92 |
if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) {
|
93 |
-
|
94 |
-
return
|
95 |
}
|
96 |
}
|
97 |
-
|
98 |
-
}, [message, setApiKeyInvalid])
|
99 |
|
100 |
return (
|
101 |
<ThemeProvider>
|
@@ -123,8 +124,7 @@ function App() {
|
|
123 |
</div>
|
124 |
</Tabs>
|
125 |
{enableHealthCheck && <StatusIndicator />}
|
126 |
-
{
|
127 |
-
{apiKeyInvalid && <ApiKeyAlert />}
|
128 |
</main>
|
129 |
</TabVisibilityProvider>
|
130 |
</ThemeProvider>
|
|
|
1 |
import { useState, useCallback, useEffect, useRef } from 'react'
|
2 |
import ThemeProvider from '@/components/ThemeProvider'
|
3 |
import TabVisibilityProvider from '@/contexts/TabVisibilityProvider'
|
|
|
4 |
import ApiKeyAlert from '@/components/ApiKeyAlert'
|
5 |
+
import StatusIndicator from '@/components/status/StatusIndicator'
|
6 |
import { healthCheckInterval } from '@/lib/constants'
|
7 |
import { useBackendState, useAuthStore } from '@/stores/state'
|
8 |
import { useSettingsStore } from '@/stores/settings'
|
|
|
21 |
const message = useBackendState.use.message()
|
22 |
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
23 |
const currentTab = useSettingsStore.use.currentTab()
|
24 |
+
const [apiKeyAlertOpen, setApiKeyAlertOpen] = useState(false)
|
25 |
const versionCheckRef = useRef(false); // Prevent duplicate calls in Vite dev mode
|
26 |
|
27 |
+
const handleApiKeyAlertOpenChange = useCallback((open: boolean) => {
|
28 |
+
setApiKeyAlertOpen(open)
|
29 |
+
if (!open) {
|
30 |
+
useBackendState.getState().clear()
|
31 |
+
}
|
32 |
+
}, [])
|
33 |
+
|
34 |
// Health check - can be disabled
|
35 |
useEffect(() => {
|
36 |
+
// Only execute if health check is enabled and ApiKeyAlert is closed
|
37 |
+
if (!enableHealthCheck || apiKeyAlertOpen) return;
|
38 |
|
39 |
// Health check function
|
40 |
const performHealthCheck = async () => {
|
41 |
await useBackendState.getState().check();
|
42 |
};
|
43 |
|
|
|
|
|
|
|
44 |
// Set interval for periodic execution
|
45 |
const interval = setInterval(performHealthCheck, healthCheckInterval * 1000);
|
46 |
return () => clearInterval(interval);
|
47 |
+
}, [enableHealthCheck, apiKeyAlertOpen]);
|
48 |
|
49 |
// Version check - independent and executed only once
|
50 |
useEffect(() => {
|
|
|
93 |
useEffect(() => {
|
94 |
if (message) {
|
95 |
if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) {
|
96 |
+
setApiKeyAlertOpen(true)
|
|
|
97 |
}
|
98 |
}
|
99 |
+
}, [message])
|
|
|
100 |
|
101 |
return (
|
102 |
<ThemeProvider>
|
|
|
124 |
</div>
|
125 |
</Tabs>
|
126 |
{enableHealthCheck && <StatusIndicator />}
|
127 |
+
<ApiKeyAlert open={apiKeyAlertOpen} onOpenChange={handleApiKeyAlertOpenChange} />
|
|
|
128 |
</main>
|
129 |
</TabVisibilityProvider>
|
130 |
</ThemeProvider>
|
lightrag_webui/src/components/ApiKeyAlert.tsx
CHANGED
@@ -12,10 +12,12 @@ import { useSettingsStore } from '@/stores/settings'
|
|
12 |
import { useBackendState } from '@/stores/state'
|
13 |
import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
|
14 |
|
15 |
-
|
|
|
|
|
|
|
16 |
|
17 |
-
const ApiKeyAlert = () => {
|
18 |
-
const [opened, setOpened] = useState<boolean>(true)
|
19 |
const apiKey = useSettingsStore.use.apiKey()
|
20 |
const [tempApiKey, setTempApiKey] = useState<string>('')
|
21 |
const message = useBackendState.use.message()
|
@@ -32,14 +34,10 @@ const ApiKeyAlert = () => {
|
|
32 |
}
|
33 |
}, [message, setOpened])
|
34 |
|
35 |
-
const setApiKey = useCallback(
|
36 |
useSettingsStore.setState({ apiKey: tempApiKey || null })
|
37 |
-
|
38 |
-
|
39 |
-
return
|
40 |
-
}
|
41 |
-
toast.error('API Key is invalid')
|
42 |
-
}, [tempApiKey])
|
43 |
|
44 |
const handleTempApiKeyChange = useCallback(
|
45 |
(e: React.ChangeEvent<HTMLInputElement>) => {
|
@@ -53,22 +51,31 @@ const ApiKeyAlert = () => {
|
|
53 |
<AlertDialogContent>
|
54 |
<AlertDialogHeader>
|
55 |
<AlertDialogTitle>API Key is required</AlertDialogTitle>
|
56 |
-
<AlertDialogDescription>
|
|
|
|
|
57 |
</AlertDialogHeader>
|
58 |
-
<
|
59 |
-
<
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
|
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
</AlertDialogContent>
|
73 |
</AlertDialog>
|
74 |
)
|
|
|
12 |
import { useBackendState } from '@/stores/state'
|
13 |
import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
|
14 |
|
15 |
+
interface ApiKeyAlertProps {
|
16 |
+
open: boolean;
|
17 |
+
onOpenChange: (open: boolean) => void;
|
18 |
+
}
|
19 |
|
20 |
+
const ApiKeyAlert = ({ open: opened, onOpenChange: setOpened }: ApiKeyAlertProps) => {
|
|
|
21 |
const apiKey = useSettingsStore.use.apiKey()
|
22 |
const [tempApiKey, setTempApiKey] = useState<string>('')
|
23 |
const message = useBackendState.use.message()
|
|
|
34 |
}
|
35 |
}, [message, setOpened])
|
36 |
|
37 |
+
const setApiKey = useCallback(() => {
|
38 |
useSettingsStore.setState({ apiKey: tempApiKey || null })
|
39 |
+
setOpened(false)
|
40 |
+
}, [tempApiKey, setOpened])
|
|
|
|
|
|
|
|
|
41 |
|
42 |
const handleTempApiKeyChange = useCallback(
|
43 |
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
51 |
<AlertDialogContent>
|
52 |
<AlertDialogHeader>
|
53 |
<AlertDialogTitle>API Key is required</AlertDialogTitle>
|
54 |
+
<AlertDialogDescription>
|
55 |
+
Please enter your API key to access the service
|
56 |
+
</AlertDialogDescription>
|
57 |
</AlertDialogHeader>
|
58 |
+
<div className="flex flex-col gap-4">
|
59 |
+
<form className="flex gap-2" onSubmit={(e) => e.preventDefault()}>
|
60 |
+
<Input
|
61 |
+
type="password"
|
62 |
+
value={tempApiKey}
|
63 |
+
onChange={handleTempApiKeyChange}
|
64 |
+
placeholder="Enter your API key"
|
65 |
+
className="max-h-full w-full min-w-0"
|
66 |
+
autoComplete="off"
|
67 |
+
/>
|
68 |
|
69 |
+
<Button onClick={setApiKey} variant="outline" size="sm">
|
70 |
+
Save
|
71 |
+
</Button>
|
72 |
+
</form>
|
73 |
+
{message && (
|
74 |
+
<div className="text-sm text-red-500">
|
75 |
+
{message}
|
76 |
+
</div>
|
77 |
+
)}
|
78 |
+
</div>
|
79 |
</AlertDialogContent>
|
80 |
</AlertDialog>
|
81 |
)
|
lightrag_webui/src/components/MessageAlert.tsx
DELETED
@@ -1,56 +0,0 @@
|
|
1 |
-
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/Alert'
|
2 |
-
import { useBackendState } from '@/stores/state'
|
3 |
-
import { useEffect, useState } from 'react'
|
4 |
-
import { cn } from '@/lib/utils'
|
5 |
-
|
6 |
-
// import Button from '@/components/ui/Button'
|
7 |
-
// import { controlButtonVariant } from '@/lib/constants'
|
8 |
-
|
9 |
-
import { AlertCircle } from 'lucide-react'
|
10 |
-
|
11 |
-
const MessageAlert = () => {
|
12 |
-
const health = useBackendState.use.health()
|
13 |
-
const message = useBackendState.use.message()
|
14 |
-
const messageTitle = useBackendState.use.messageTitle()
|
15 |
-
const [isMounted, setIsMounted] = useState(false)
|
16 |
-
|
17 |
-
useEffect(() => {
|
18 |
-
setTimeout(() => {
|
19 |
-
setIsMounted(true)
|
20 |
-
}, 50)
|
21 |
-
}, [])
|
22 |
-
|
23 |
-
return (
|
24 |
-
<Alert
|
25 |
-
// variant={health ? 'default' : 'destructive'}
|
26 |
-
className={cn(
|
27 |
-
'bg-background/90 absolute top-12 left-1/2 flex w-auto max-w-lg -translate-x-1/2 transform items-center gap-4 shadow-md backdrop-blur-lg transition-all duration-500 ease-in-out',
|
28 |
-
isMounted ? 'translate-y-0 opacity-100' : '-translate-y-20 opacity-0',
|
29 |
-
!health && 'bg-red-700 text-white'
|
30 |
-
)}
|
31 |
-
>
|
32 |
-
{!health && (
|
33 |
-
<div>
|
34 |
-
<AlertCircle className="size-4" />
|
35 |
-
</div>
|
36 |
-
)}
|
37 |
-
<div>
|
38 |
-
<AlertTitle className="font-bold">{messageTitle}</AlertTitle>
|
39 |
-
<AlertDescription>{message}</AlertDescription>
|
40 |
-
</div>
|
41 |
-
{/* <div className="flex">
|
42 |
-
<div className="flex-auto" />
|
43 |
-
<Button
|
44 |
-
size="sm"
|
45 |
-
variant={controlButtonVariant}
|
46 |
-
className="border-primary max-h-8 border !p-2 text-xs"
|
47 |
-
onClick={() => useBackendState.getState().clear()}
|
48 |
-
>
|
49 |
-
Close
|
50 |
-
</Button>
|
51 |
-
</div> */}
|
52 |
-
</Alert>
|
53 |
-
)
|
54 |
-
}
|
55 |
-
|
56 |
-
export default MessageAlert
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lightrag_webui/src/components/{graph β status}/StatusCard.tsx
RENAMED
File without changes
|
lightrag_webui/src/components/{graph β status}/StatusIndicator.tsx
RENAMED
@@ -2,7 +2,7 @@ import { cn } from '@/lib/utils'
|
|
2 |
import { useBackendState } from '@/stores/state'
|
3 |
import { useEffect, useState } from 'react'
|
4 |
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover'
|
5 |
-
import StatusCard from '@/components/
|
6 |
import { useTranslation } from 'react-i18next'
|
7 |
|
8 |
const StatusIndicator = () => {
|
|
|
2 |
import { useBackendState } from '@/stores/state'
|
3 |
import { useEffect, useState } from 'react'
|
4 |
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover'
|
5 |
+
import StatusCard from '@/components/status/StatusCard'
|
6 |
import { useTranslation } from 'react-i18next'
|
7 |
|
8 |
const StatusIndicator = () => {
|