ArnoChen
commited on
Commit
Β·
0ef8cba
1
Parent(s):
a2251a6
implement API key alert
Browse files- lightrag_webui/README.md +1 -1
- lightrag_webui/bun.lock +3 -0
- lightrag_webui/package.json +1 -0
- lightrag_webui/src/App.tsx +15 -3
- lightrag_webui/src/components/ApiKeyAlert.tsx +79 -0
- lightrag_webui/src/components/{FocusOnNode.tsx β graph/FocusOnNode.tsx} +0 -0
- lightrag_webui/src/components/{FullScreenControl.tsx β graph/FullScreenControl.tsx} +0 -0
- lightrag_webui/src/components/{GraphControl.tsx β graph/GraphControl.tsx} +0 -0
- lightrag_webui/src/components/{GraphLabels.tsx β graph/GraphLabels.tsx} +0 -0
- lightrag_webui/src/components/{GraphSearch.tsx β graph/GraphSearch.tsx} +0 -0
- lightrag_webui/src/components/{LayoutsControl.tsx β graph/LayoutsControl.tsx} +0 -0
- lightrag_webui/src/components/{PropertiesView.tsx β graph/PropertiesView.tsx} +0 -0
- lightrag_webui/src/components/{Settings.tsx β graph/Settings.tsx} +1 -1
- lightrag_webui/src/components/{StatusCard.tsx β graph/StatusCard.tsx} +0 -0
- lightrag_webui/src/components/{StatusIndicator.tsx β graph/StatusIndicator.tsx} +1 -1
- lightrag_webui/src/components/{ThemeProvider.tsx β graph/ThemeProvider.tsx} +0 -0
- lightrag_webui/src/components/{ThemeToggle.tsx β graph/ThemeToggle.tsx} +0 -0
- lightrag_webui/src/components/{ZoomControl.tsx β graph/ZoomControl.tsx} +0 -0
- lightrag_webui/src/components/ui/AlertDialog.tsx +115 -0
- lightrag_webui/src/components/ui/Button.tsx +2 -1
- lightrag_webui/src/features/GraphViewer.tsx +9 -9
- lightrag_webui/src/features/SiteHeader.tsx +1 -1
- lightrag_webui/src/hooks/useTheme.tsx +1 -1
lightrag_webui/README.md
CHANGED
@@ -21,7 +21,7 @@ LightRAG WebUI is a React-based web interface for interacting with the LightRAG
|
|
21 |
Run the following command to build the project:
|
22 |
|
23 |
```bash
|
24 |
-
bun run build
|
25 |
```
|
26 |
|
27 |
This command will bundle the project and output the built files to the `lightrag/api/webui` directory.
|
|
|
21 |
Run the following command to build the project:
|
22 |
|
23 |
```bash
|
24 |
+
bun run build --emptyOutDir
|
25 |
```
|
26 |
|
27 |
This command will bundle the project and output the built files to the `lightrag/api/webui` directory.
|
lightrag_webui/bun.lock
CHANGED
@@ -5,6 +5,7 @@
|
|
5 |
"name": "lightrag-webui",
|
6 |
"dependencies": {
|
7 |
"@faker-js/faker": "^9.5.0",
|
|
|
8 |
"@radix-ui/react-checkbox": "^1.1.4",
|
9 |
"@radix-ui/react-dialog": "^1.1.6",
|
10 |
"@radix-ui/react-popover": "^1.1.6",
|
@@ -220,6 +221,8 @@
|
|
220 |
|
221 |
"@radix-ui/primitive": ["@radix-ui/[email protected]", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
|
222 |
|
|
|
|
|
223 |
"@radix-ui/react-arrow": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg=="],
|
224 |
|
225 |
"@radix-ui/react-checkbox": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw=="],
|
|
|
5 |
"name": "lightrag-webui",
|
6 |
"dependencies": {
|
7 |
"@faker-js/faker": "^9.5.0",
|
8 |
+
"@radix-ui/react-alert-dialog": "^1.1.6",
|
9 |
"@radix-ui/react-checkbox": "^1.1.4",
|
10 |
"@radix-ui/react-dialog": "^1.1.6",
|
11 |
"@radix-ui/react-popover": "^1.1.6",
|
|
|
221 |
|
222 |
"@radix-ui/primitive": ["@radix-ui/[email protected]", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
|
223 |
|
224 |
+
"@radix-ui/react-alert-dialog": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dialog": "1.1.6", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-p4XnPqgej8sZAAReCAKgz1REYZEBLR8hU9Pg27wFnCWIMc8g1ccCs0FjBcy05V15VTu8pAePw/VDYeOm/uZ6yQ=="],
|
225 |
+
|
226 |
"@radix-ui/react-arrow": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg=="],
|
227 |
|
228 |
"@radix-ui/react-checkbox": ["@radix-ui/[email protected]", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.0", "@radix-ui/react-use-previous": "1.1.0", "@radix-ui/react-use-size": "1.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw=="],
|
lightrag_webui/package.json
CHANGED
@@ -11,6 +11,7 @@
|
|
11 |
},
|
12 |
"dependencies": {
|
13 |
"@faker-js/faker": "^9.5.0",
|
|
|
14 |
"@radix-ui/react-checkbox": "^1.1.4",
|
15 |
"@radix-ui/react-dialog": "^1.1.6",
|
16 |
"@radix-ui/react-popover": "^1.1.6",
|
|
|
11 |
},
|
12 |
"dependencies": {
|
13 |
"@faker-js/faker": "^9.5.0",
|
14 |
+
"@radix-ui/react-alert-dialog": "^1.1.6",
|
15 |
"@radix-ui/react-checkbox": "^1.1.4",
|
16 |
"@radix-ui/react-dialog": "^1.1.6",
|
17 |
"@radix-ui/react-popover": "^1.1.6",
|
lightrag_webui/src/App.tsx
CHANGED
@@ -1,13 +1,15 @@
|
|
1 |
import { useState, useCallback } from 'react'
|
2 |
-
import ThemeProvider from '@/components/ThemeProvider'
|
3 |
import MessageAlert from '@/components/MessageAlert'
|
4 |
-
import
|
|
|
5 |
import { healthCheckInterval } from '@/lib/constants'
|
6 |
import { useBackendState } from '@/stores/state'
|
7 |
import { useSettingsStore } from '@/stores/settings'
|
8 |
import { useEffect } from 'react'
|
9 |
import { Toaster } from 'sonner'
|
10 |
import SiteHeader from '@/features/SiteHeader'
|
|
|
11 |
|
12 |
import GraphViewer from '@/features/GraphViewer'
|
13 |
import DocumentManager from '@/features/DocumentManager'
|
@@ -20,6 +22,7 @@ function App() {
|
|
20 |
const message = useBackendState.use.message()
|
21 |
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
22 |
const [currentTab] = useState(() => useSettingsStore.getState().currentTab)
|
|
|
23 |
|
24 |
// Health check
|
25 |
useEffect(() => {
|
@@ -39,6 +42,14 @@ function App() {
|
|
39 |
[]
|
40 |
)
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
return (
|
43 |
<ThemeProvider>
|
44 |
<main className="flex h-screen w-screen overflow-x-hidden">
|
@@ -64,7 +75,8 @@ function App() {
|
|
64 |
</div>
|
65 |
</Tabs>
|
66 |
{enableHealthCheck && <StatusIndicator />}
|
67 |
-
{message !== null && <MessageAlert />}
|
|
|
68 |
<Toaster />
|
69 |
</main>
|
70 |
</ThemeProvider>
|
|
|
1 |
import { useState, useCallback } from 'react'
|
2 |
+
import ThemeProvider from '@/components/graph/ThemeProvider'
|
3 |
import MessageAlert from '@/components/MessageAlert'
|
4 |
+
import ApiKeyAlert from '@/components/ApiKeyAlert'
|
5 |
+
import StatusIndicator from '@/components/graph/StatusIndicator'
|
6 |
import { healthCheckInterval } from '@/lib/constants'
|
7 |
import { useBackendState } from '@/stores/state'
|
8 |
import { useSettingsStore } from '@/stores/settings'
|
9 |
import { useEffect } from 'react'
|
10 |
import { Toaster } from 'sonner'
|
11 |
import SiteHeader from '@/features/SiteHeader'
|
12 |
+
import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
|
13 |
|
14 |
import GraphViewer from '@/features/GraphViewer'
|
15 |
import DocumentManager from '@/features/DocumentManager'
|
|
|
22 |
const message = useBackendState.use.message()
|
23 |
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
24 |
const [currentTab] = useState(() => useSettingsStore.getState().currentTab)
|
25 |
+
const [apiKeyInvalid, setApiKeyInvalid] = useState(false)
|
26 |
|
27 |
// Health check
|
28 |
useEffect(() => {
|
|
|
42 |
[]
|
43 |
)
|
44 |
|
45 |
+
useEffect(() => {
|
46 |
+
if (message) {
|
47 |
+
if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) {
|
48 |
+
setApiKeyInvalid(true)
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}, [message, setApiKeyInvalid])
|
52 |
+
|
53 |
return (
|
54 |
<ThemeProvider>
|
55 |
<main className="flex h-screen w-screen overflow-x-hidden">
|
|
|
75 |
</div>
|
76 |
</Tabs>
|
77 |
{enableHealthCheck && <StatusIndicator />}
|
78 |
+
{message !== null && !apiKeyInvalid && <MessageAlert />}
|
79 |
+
{apiKeyInvalid && <ApiKeyAlert />}
|
80 |
<Toaster />
|
81 |
</main>
|
82 |
</ThemeProvider>
|
lightrag_webui/src/components/ApiKeyAlert.tsx
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useState, useCallback, useEffect } from 'react'
|
2 |
+
import {
|
3 |
+
AlertDialog,
|
4 |
+
AlertDialogContent,
|
5 |
+
AlertDialogDescription,
|
6 |
+
AlertDialogHeader,
|
7 |
+
AlertDialogTitle,
|
8 |
+
AlertDialogTrigger
|
9 |
+
} from '@/components/ui/AlertDialog'
|
10 |
+
import Button from '@/components/ui/Button'
|
11 |
+
import Input from '@/components/ui/Input'
|
12 |
+
import { useSettingsStore } from '@/stores/settings'
|
13 |
+
import { useBackendState } from '@/stores/state'
|
14 |
+
import { InvalidApiKeyError, RequireApiKeError } from '@/api/lightrag'
|
15 |
+
|
16 |
+
import { toast } from 'sonner'
|
17 |
+
|
18 |
+
const ApiKeyAlert = () => {
|
19 |
+
const [opened, setOpened] = useState<boolean>(true)
|
20 |
+
const apiKey = useSettingsStore.use.apiKey()
|
21 |
+
const [tempApiKey, setTempApiKey] = useState<string>('')
|
22 |
+
const message = useBackendState.use.message()
|
23 |
+
|
24 |
+
useEffect(() => {
|
25 |
+
setTempApiKey(apiKey || '')
|
26 |
+
}, [apiKey, opened])
|
27 |
+
|
28 |
+
useEffect(() => {
|
29 |
+
if (message) {
|
30 |
+
if (message.includes(InvalidApiKeyError) || message.includes(RequireApiKeError)) {
|
31 |
+
setOpened(true)
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}, [message, setOpened])
|
35 |
+
|
36 |
+
const setApiKey = useCallback(async () => {
|
37 |
+
useSettingsStore.setState({ apiKey: tempApiKey || null })
|
38 |
+
if (await useBackendState.getState().check()) {
|
39 |
+
setOpened(false)
|
40 |
+
return
|
41 |
+
}
|
42 |
+
toast.error('API Key is invalid')
|
43 |
+
}, [tempApiKey])
|
44 |
+
|
45 |
+
const handleTempApiKeyChange = useCallback(
|
46 |
+
(e: React.ChangeEvent<HTMLInputElement>) => {
|
47 |
+
setTempApiKey(e.target.value)
|
48 |
+
},
|
49 |
+
[setTempApiKey]
|
50 |
+
)
|
51 |
+
|
52 |
+
return (
|
53 |
+
<AlertDialog open={opened} onOpenChange={setOpened}>
|
54 |
+
<AlertDialogTrigger>Open</AlertDialogTrigger>
|
55 |
+
<AlertDialogContent>
|
56 |
+
<AlertDialogHeader>
|
57 |
+
<AlertDialogTitle>API Key is required</AlertDialogTitle>
|
58 |
+
<AlertDialogDescription>Please enter your API key</AlertDialogDescription>
|
59 |
+
</AlertDialogHeader>
|
60 |
+
<form className="flex gap-2" onSubmit={(e) => e.preventDefault()}>
|
61 |
+
<Input
|
62 |
+
type="password"
|
63 |
+
value={tempApiKey}
|
64 |
+
onChange={handleTempApiKeyChange}
|
65 |
+
placeholder="Enter your API key"
|
66 |
+
className="max-h-full w-full min-w-0"
|
67 |
+
autoComplete="off"
|
68 |
+
/>
|
69 |
+
|
70 |
+
<Button onClick={setApiKey} variant="outline" size="sm">
|
71 |
+
Save
|
72 |
+
</Button>
|
73 |
+
</form>
|
74 |
+
</AlertDialogContent>
|
75 |
+
</AlertDialog>
|
76 |
+
)
|
77 |
+
}
|
78 |
+
|
79 |
+
export default ApiKeyAlert
|
lightrag_webui/src/components/{FocusOnNode.tsx β graph/FocusOnNode.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{FullScreenControl.tsx β graph/FullScreenControl.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{GraphControl.tsx β graph/GraphControl.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{GraphLabels.tsx β graph/GraphLabels.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{GraphSearch.tsx β graph/GraphSearch.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{LayoutsControl.tsx β graph/LayoutsControl.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{PropertiesView.tsx β graph/PropertiesView.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{Settings.tsx β graph/Settings.tsx}
RENAMED
@@ -40,7 +40,7 @@ const LabeledCheckBox = ({
|
|
40 |
*/
|
41 |
export default function Settings() {
|
42 |
const [opened, setOpened] = useState<boolean>(false)
|
43 |
-
const [tempApiKey, setTempApiKey] = useState<string>('')
|
44 |
|
45 |
const showPropertyPanel = useSettingsStore.use.showPropertyPanel()
|
46 |
const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar()
|
|
|
40 |
*/
|
41 |
export default function Settings() {
|
42 |
const [opened, setOpened] = useState<boolean>(false)
|
43 |
+
const [tempApiKey, setTempApiKey] = useState<string>('')
|
44 |
|
45 |
const showPropertyPanel = useSettingsStore.use.showPropertyPanel()
|
46 |
const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar()
|
lightrag_webui/src/components/{StatusCard.tsx β graph/StatusCard.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{StatusIndicator.tsx β graph/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/StatusCard'
|
6 |
|
7 |
const StatusIndicator = () => {
|
8 |
const health = useBackendState.use.health()
|
|
|
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/graph/StatusCard'
|
6 |
|
7 |
const StatusIndicator = () => {
|
8 |
const health = useBackendState.use.health()
|
lightrag_webui/src/components/{ThemeProvider.tsx β graph/ThemeProvider.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{ThemeToggle.tsx β graph/ThemeToggle.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/{ZoomControl.tsx β graph/ZoomControl.tsx}
RENAMED
File without changes
|
lightrag_webui/src/components/ui/AlertDialog.tsx
ADDED
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import * as React from 'react'
|
2 |
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
|
3 |
+
|
4 |
+
import { cn } from '@/lib/utils'
|
5 |
+
import { buttonVariants } from '@/components/ui/Button'
|
6 |
+
|
7 |
+
const AlertDialog = AlertDialogPrimitive.Root
|
8 |
+
|
9 |
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
10 |
+
|
11 |
+
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
12 |
+
|
13 |
+
const AlertDialogOverlay = React.forwardRef<
|
14 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Overlay>,
|
15 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
16 |
+
>(({ className, ...props }, ref) => (
|
17 |
+
<AlertDialogPrimitive.Overlay
|
18 |
+
className={cn(
|
19 |
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
20 |
+
className
|
21 |
+
)}
|
22 |
+
{...props}
|
23 |
+
ref={ref}
|
24 |
+
/>
|
25 |
+
))
|
26 |
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
27 |
+
|
28 |
+
const AlertDialogContent = React.forwardRef<
|
29 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Content>,
|
30 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
31 |
+
>(({ className, ...props }, ref) => (
|
32 |
+
<AlertDialogPortal>
|
33 |
+
<AlertDialogOverlay />
|
34 |
+
<AlertDialogPrimitive.Content
|
35 |
+
ref={ref}
|
36 |
+
className={cn(
|
37 |
+
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
|
38 |
+
className
|
39 |
+
)}
|
40 |
+
{...props}
|
41 |
+
/>
|
42 |
+
</AlertDialogPortal>
|
43 |
+
))
|
44 |
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
45 |
+
|
46 |
+
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
47 |
+
<div className={cn('flex flex-col space-y-2 text-center sm:text-left', className)} {...props} />
|
48 |
+
)
|
49 |
+
AlertDialogHeader.displayName = 'AlertDialogHeader'
|
50 |
+
|
51 |
+
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
52 |
+
<div
|
53 |
+
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
|
54 |
+
{...props}
|
55 |
+
/>
|
56 |
+
)
|
57 |
+
AlertDialogFooter.displayName = 'AlertDialogFooter'
|
58 |
+
|
59 |
+
const AlertDialogTitle = React.forwardRef<
|
60 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Title>,
|
61 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
62 |
+
>(({ className, ...props }, ref) => (
|
63 |
+
<AlertDialogPrimitive.Title
|
64 |
+
ref={ref}
|
65 |
+
className={cn('text-lg font-semibold', className)}
|
66 |
+
{...props}
|
67 |
+
/>
|
68 |
+
))
|
69 |
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
70 |
+
|
71 |
+
const AlertDialogDescription = React.forwardRef<
|
72 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Description>,
|
73 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
74 |
+
>(({ className, ...props }, ref) => (
|
75 |
+
<AlertDialogPrimitive.Description
|
76 |
+
ref={ref}
|
77 |
+
className={cn('text-muted-foreground text-sm', className)}
|
78 |
+
{...props}
|
79 |
+
/>
|
80 |
+
))
|
81 |
+
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
|
82 |
+
|
83 |
+
const AlertDialogAction = React.forwardRef<
|
84 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Action>,
|
85 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
86 |
+
>(({ className, ...props }, ref) => (
|
87 |
+
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
|
88 |
+
))
|
89 |
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
90 |
+
|
91 |
+
const AlertDialogCancel = React.forwardRef<
|
92 |
+
React.ComponentRef<typeof AlertDialogPrimitive.Cancel>,
|
93 |
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
94 |
+
>(({ className, ...props }, ref) => (
|
95 |
+
<AlertDialogPrimitive.Cancel
|
96 |
+
ref={ref}
|
97 |
+
className={cn(buttonVariants({ variant: 'outline' }), 'mt-2 sm:mt-0', className)}
|
98 |
+
{...props}
|
99 |
+
/>
|
100 |
+
))
|
101 |
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
102 |
+
|
103 |
+
export {
|
104 |
+
AlertDialog,
|
105 |
+
AlertDialogPortal,
|
106 |
+
AlertDialogOverlay,
|
107 |
+
AlertDialogTrigger,
|
108 |
+
AlertDialogContent,
|
109 |
+
AlertDialogHeader,
|
110 |
+
AlertDialogFooter,
|
111 |
+
AlertDialogTitle,
|
112 |
+
AlertDialogDescription,
|
113 |
+
AlertDialogAction,
|
114 |
+
AlertDialogCancel
|
115 |
+
}
|
lightrag_webui/src/components/ui/Button.tsx
CHANGED
@@ -4,7 +4,8 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|
4 |
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/Tooltip'
|
5 |
import { cn } from '@/lib/utils'
|
6 |
|
7 |
-
|
|
|
8 |
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
9 |
{
|
10 |
variants: {
|
|
|
4 |
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/Tooltip'
|
5 |
import { cn } from '@/lib/utils'
|
6 |
|
7 |
+
// eslint-disable-next-line react-refresh/only-export-components
|
8 |
+
export const buttonVariants = cva(
|
9 |
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
|
10 |
{
|
11 |
variants: {
|
lightrag_webui/src/features/GraphViewer.tsx
CHANGED
@@ -7,16 +7,16 @@ import { EdgeArrowProgram, NodePointProgram, NodeCircleProgram } from 'sigma/ren
|
|
7 |
import { NodeBorderProgram } from '@sigma/node-border'
|
8 |
import EdgeCurveProgram, { EdgeCurvedArrowProgram } from '@sigma/edge-curve'
|
9 |
|
10 |
-
import FocusOnNode from '@/components/FocusOnNode'
|
11 |
-
import LayoutsControl from '@/components/LayoutsControl'
|
12 |
-
import GraphControl from '@/components/GraphControl'
|
13 |
// import ThemeToggle from '@/components/ThemeToggle'
|
14 |
-
import ZoomControl from '@/components/ZoomControl'
|
15 |
-
import FullScreenControl from '@/components/FullScreenControl'
|
16 |
-
import Settings from '@/components/Settings'
|
17 |
-
import GraphSearch from '@/components/GraphSearch'
|
18 |
-
import GraphLabels from '@/components/GraphLabels'
|
19 |
-
import PropertiesView from '@/components/PropertiesView'
|
20 |
|
21 |
import { useSettingsStore } from '@/stores/settings'
|
22 |
import { useGraphStore } from '@/stores/graph'
|
|
|
7 |
import { NodeBorderProgram } from '@sigma/node-border'
|
8 |
import EdgeCurveProgram, { EdgeCurvedArrowProgram } from '@sigma/edge-curve'
|
9 |
|
10 |
+
import FocusOnNode from '@/components/graph/FocusOnNode'
|
11 |
+
import LayoutsControl from '@/components/graph/LayoutsControl'
|
12 |
+
import GraphControl from '@/components/graph/GraphControl'
|
13 |
// import ThemeToggle from '@/components/ThemeToggle'
|
14 |
+
import ZoomControl from '@/components/graph/ZoomControl'
|
15 |
+
import FullScreenControl from '@/components/graph/FullScreenControl'
|
16 |
+
import Settings from '@/components/graph/Settings'
|
17 |
+
import GraphSearch from '@/components/graph/GraphSearch'
|
18 |
+
import GraphLabels from '@/components/graph/GraphLabels'
|
19 |
+
import PropertiesView from '@/components/graph/PropertiesView'
|
20 |
|
21 |
import { useSettingsStore } from '@/stores/settings'
|
22 |
import { useGraphStore } from '@/stores/graph'
|
lightrag_webui/src/features/SiteHeader.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
import Button from '@/components/ui/Button'
|
2 |
import { SiteInfo } from '@/lib/constants'
|
3 |
-
import ThemeToggle from '@/components/ThemeToggle'
|
4 |
import { TabsList, TabsTrigger } from '@/components/ui/Tabs'
|
5 |
import { useSettingsStore } from '@/stores/settings'
|
6 |
import { cn } from '@/lib/utils'
|
|
|
1 |
import Button from '@/components/ui/Button'
|
2 |
import { SiteInfo } from '@/lib/constants'
|
3 |
+
import ThemeToggle from '@/components/graph/ThemeToggle'
|
4 |
import { TabsList, TabsTrigger } from '@/components/ui/Tabs'
|
5 |
import { useSettingsStore } from '@/stores/settings'
|
6 |
import { cn } from '@/lib/utils'
|
lightrag_webui/src/hooks/useTheme.tsx
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
import { useContext } from 'react'
|
2 |
-
import { ThemeProviderContext } from '@/components/ThemeProvider'
|
3 |
|
4 |
const useTheme = () => {
|
5 |
const context = useContext(ThemeProviderContext)
|
|
|
1 |
import { useContext } from 'react'
|
2 |
+
import { ThemeProviderContext } from '@/components/graph/ThemeProvider'
|
3 |
|
4 |
const useTheme = () => {
|
5 |
const context = useContext(ThemeProviderContext)
|