cherry-pick 7297ca1d
This commit is contained in:
parent
93acccf818
commit
c96bc06153
5 changed files with 125 additions and 108 deletions
|
|
@ -8,105 +8,98 @@
|
||||||
"build": "bunx --bun vite build",
|
"build": "bunx --bun vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "bunx --bun vite preview",
|
"preview": "bunx --bun vite preview",
|
||||||
"test": "bun test",
|
|
||||||
"test:watch": "bun test --watch",
|
|
||||||
"test:coverage": "bun test --coverage",
|
|
||||||
"dev-no-bun": "vite",
|
"dev-no-bun": "vite",
|
||||||
"build-no-bun": "vite build --emptyOutDir",
|
"build-no-bun": "vite build --emptyOutDir",
|
||||||
"preview-no-bun": "vite preview"
|
"preview-no-bun": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^9.9.0",
|
"@faker-js/faker": "^9.5.0",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-checkbox": "^1.3.3",
|
"@radix-ui/react-checkbox": "^1.1.4",
|
||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.6",
|
||||||
"@radix-ui/react-popover": "^1.1.15",
|
"@radix-ui/react-popover": "^1.1.6",
|
||||||
"@radix-ui/react-progress": "^1.1.8",
|
"@radix-ui/react-progress": "^1.1.2",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.1.6",
|
||||||
"@radix-ui/react-separator": "^1.1.8",
|
"@radix-ui/react-separator": "^1.1.2",
|
||||||
"@radix-ui/react-slot": "^1.2.4",
|
"@radix-ui/react-slot": "^1.1.2",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
"@radix-ui/react-use-controllable-state": "^1.2.2",
|
"@radix-ui/react-use-controllable-state": "^1.1.0",
|
||||||
"@react-sigma/core": "^5.0.4",
|
"@react-sigma/core": "^5.0.2",
|
||||||
"@react-sigma/graph-search": "^5.0.4",
|
"@react-sigma/graph-search": "^5.0.3",
|
||||||
"@react-sigma/layout-circlepack": "^5.0.4",
|
"@react-sigma/layout-circlepack": "^5.0.2",
|
||||||
"@react-sigma/layout-circular": "^5.0.4",
|
"@react-sigma/layout-circular": "^5.0.2",
|
||||||
"@react-sigma/layout-force": "^5.0.4",
|
"@react-sigma/layout-force": "^5.0.2",
|
||||||
"@react-sigma/layout-forceatlas2": "^5.0.4",
|
"@react-sigma/layout-forceatlas2": "^5.0.2",
|
||||||
"@react-sigma/layout-noverlap": "^5.0.4",
|
"@react-sigma/layout-noverlap": "^5.0.2",
|
||||||
"@react-sigma/layout-random": "^5.0.4",
|
"@react-sigma/layout-random": "^5.0.2",
|
||||||
"@react-sigma/minimap": "^5.0.5",
|
"@react-sigma/minimap": "^5.0.2",
|
||||||
"@sigma/edge-curve": "^3.1.0",
|
"@sigma/edge-curve": "^3.1.0",
|
||||||
"@sigma/node-border": "^3.0.0",
|
"@sigma/node-border": "^3.0.0",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"axios": "^1.7.9",
|
||||||
"axios": "^1.13.2",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.0.4",
|
||||||
"graphology": "^0.26.0",
|
"graphology": "^0.26.0",
|
||||||
"graphology-generators": "^0.11.2",
|
"graphology-generators": "^0.11.2",
|
||||||
"graphology-layout": "^0.6.1",
|
"graphology-layout": "^0.6.1",
|
||||||
"graphology-layout-force": "^0.2.4",
|
"graphology-layout-force": "^0.2.4",
|
||||||
"graphology-layout-forceatlas2": "^0.10.1",
|
"graphology-layout-forceatlas2": "^0.10.1",
|
||||||
"graphology-layout-noverlap": "^0.4.2",
|
"graphology-layout-noverlap": "^0.4.2",
|
||||||
"i18next": "^25.6.3",
|
"i18next": "^24.2.2",
|
||||||
"katex": "^0.16.25",
|
"katex": "^0.16.22",
|
||||||
"mermaid": "^11.12.1",
|
"lucide-react": "^0.475.0",
|
||||||
"lucide-react": "^0.554.0",
|
"mermaid": "^11.9.0",
|
||||||
"minisearch": "^7.2.0",
|
"minisearch": "^7.1.2",
|
||||||
"react": "^19.2.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.2.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.6",
|
||||||
"react-error-boundary": "^6.0.0",
|
"react-error-boundary": "^5.0.0",
|
||||||
"react-i18next": "^16.2.3",
|
"react-i18next": "^15.4.1",
|
||||||
"react-markdown": "^9.1.0",
|
"react-markdown": "^9.1.0",
|
||||||
"react-number-format": "^5.4.4",
|
"react-number-format": "^5.4.3",
|
||||||
"react-router-dom": "^7.9.6",
|
"react-router-dom": "^7.3.0",
|
||||||
"react-select": "^5.10.2",
|
"react-select": "^5.10.2",
|
||||||
"react-syntax-highlighter": "^15.6.6",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"rehype-katex": "^7.0.1",
|
"rehype-katex": "^7.0.1",
|
||||||
"rehype-raw": "^7.0.0",
|
|
||||||
"rehype-react": "^8.0.0",
|
"rehype-react": "^8.0.0",
|
||||||
"remark-gfm": "^4.0.1",
|
"remark-gfm": "^4.0.1",
|
||||||
"remark-math": "^6.0.0",
|
"remark-math": "^6.0.0",
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"sigma": "^3.0.2",
|
"sigma": "^3.0.1",
|
||||||
"sonner": "^1.7.4",
|
"sonner": "^1.7.4",
|
||||||
"tailwind-merge": "^3.4.0",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.1",
|
||||||
"typography": "^0.16.24",
|
"typography": "^0.16.24",
|
||||||
"unist-util-visit": "^5.0.0",
|
"zustand": "^5.0.3"
|
||||||
"zustand": "^5.0.8"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.21.0",
|
||||||
"@stylistic/eslint-plugin-js": "^4.4.1",
|
"@stylistic/eslint-plugin-js": "^3.1.0",
|
||||||
"@types/bun": "^1.3.3",
|
"@tailwindcss/vite": "^4.0.8",
|
||||||
"@tailwindcss/vite": "^4.1.17",
|
"@types/bun": "^1.2.3",
|
||||||
"@types/katex": "^0.16.7",
|
"@types/katex": "^0.16.7",
|
||||||
"@types/node": "^22.18.9",
|
"@types/node": "^22.13.5",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react": "^19.2.7",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@types/react-dom": "^19.2.3",
|
|
||||||
"@types/react-i18next": "^8.1.0",
|
"@types/react-i18next": "^8.1.0",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/seedrandom": "^3.0.8",
|
"@types/seedrandom": "^3.0.8",
|
||||||
"@vitejs/plugin-react-swc": "^4.2.2",
|
"@vitejs/plugin-react-swc": "^3.8.0",
|
||||||
"eslint": "^9.39.1",
|
"eslint": "^9.21.0",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.0.1",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.4",
|
||||||
"eslint-plugin-react-hooks": "^7.0.1",
|
"eslint-plugin-react-hooks": "^5.1.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.24",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.5.0",
|
"globals": "^15.15.0",
|
||||||
"graphology-types": "^0.24.8",
|
"graphology-types": "^0.24.8",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.5.2",
|
||||||
"prettier-plugin-tailwindcss": "^0.7.1",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"typescript-eslint": "^8.48.0",
|
"tailwindcss": "^4.0.8",
|
||||||
"tailwindcss": "^4.1.17",
|
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"typescript": "~5.9.3",
|
"typescript": "~5.7.3",
|
||||||
"vite": "^7.1.12"
|
"typescript-eslint": "^8.24.1",
|
||||||
|
"vite": "^6.1.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useRegisterEvents, useSetSettings, useSigma } from '@react-sigma/core'
|
||||||
import { AbstractGraph } from 'graphology-types'
|
import { AbstractGraph } from 'graphology-types'
|
||||||
// import { useLayoutCircular } from '@react-sigma/layout-circular'
|
// import { useLayoutCircular } from '@react-sigma/layout-circular'
|
||||||
import { useLayoutForceAtlas2 } from '@react-sigma/layout-forceatlas2'
|
import { useLayoutForceAtlas2 } from '@react-sigma/layout-forceatlas2'
|
||||||
import { useEffect } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
// import useRandomGraph, { EdgeType, NodeType } from '@/hooks/useRandomGraph'
|
// import useRandomGraph, { EdgeType, NodeType } from '@/hooks/useRandomGraph'
|
||||||
import { EdgeType, NodeType } from '@/hooks/useLightragGraph'
|
import { EdgeType, NodeType } from '@/hooks/useLightragGraph'
|
||||||
|
|
@ -44,6 +44,20 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
|
||||||
const focusedEdge = useGraphStore.use.focusedEdge()
|
const focusedEdge = useGraphStore.use.focusedEdge()
|
||||||
const sigmaGraph = useGraphStore.use.sigmaGraph()
|
const sigmaGraph = useGraphStore.use.sigmaGraph()
|
||||||
|
|
||||||
|
// Track system theme changes when theme is set to 'system'
|
||||||
|
const [systemThemeIsDark, setSystemThemeIsDark] = useState(() =>
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (theme === 'system') {
|
||||||
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
|
const handler = (e: MediaQueryListEvent) => setSystemThemeIsDark(e.matches)
|
||||||
|
mediaQuery.addEventListener('change', handler)
|
||||||
|
return () => mediaQuery.removeEventListener('change', handler)
|
||||||
|
}
|
||||||
|
}, [theme])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When component mount or maxIterations changes
|
* When component mount or maxIterations changes
|
||||||
* => ensure graph reference and apply layout
|
* => ensure graph reference and apply layout
|
||||||
|
|
@ -204,7 +218,9 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
|
||||||
* => Setting the sigma reducers
|
* => Setting the sigma reducers
|
||||||
*/
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isDarkTheme = theme === 'dark'
|
// Check if dark mode is actually applied (handles both 'dark' theme and 'system' theme when OS is dark)
|
||||||
|
const isDarkTheme = theme === 'dark' ||
|
||||||
|
(theme === 'system' && window.document.documentElement.classList.contains('dark'))
|
||||||
const labelColor = isDarkTheme ? Constants.labelColorDarkTheme : undefined
|
const labelColor = isDarkTheme ? Constants.labelColorDarkTheme : undefined
|
||||||
const edgeColor = isDarkTheme ? Constants.edgeColorDarkTheme : undefined
|
const edgeColor = isDarkTheme ? Constants.edgeColorDarkTheme : undefined
|
||||||
|
|
||||||
|
|
@ -329,6 +345,7 @@ const GraphControl = ({ disableHoverEffect }: { disableHoverEffect?: boolean })
|
||||||
sigma,
|
sigma,
|
||||||
disableHoverEffect,
|
disableHoverEffect,
|
||||||
theme,
|
theme,
|
||||||
|
systemThemeIsDark,
|
||||||
hideUnselectedEdges,
|
hideUnselectedEdges,
|
||||||
enableEdgeEvents,
|
enableEdgeEvents,
|
||||||
renderEdgeLabels,
|
renderEdgeLabels,
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,10 @@ import Input from '@/components/ui/Input'
|
||||||
|
|
||||||
import { controlButtonVariant } from '@/lib/constants'
|
import { controlButtonVariant } from '@/lib/constants'
|
||||||
import { useSettingsStore } from '@/stores/settings'
|
import { useSettingsStore } from '@/stores/settings'
|
||||||
|
import { useGraphStore } from '@/stores/graph'
|
||||||
|
import useRandomGraph from '@/hooks/useRandomGraph'
|
||||||
|
|
||||||
import { SettingsIcon, Undo2 } from 'lucide-react'
|
import { SettingsIcon, Undo2, Shuffle } from 'lucide-react'
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -163,6 +165,9 @@ export default function Settings() {
|
||||||
|
|
||||||
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
const enableHealthCheck = useSettingsStore.use.enableHealthCheck()
|
||||||
|
|
||||||
|
// Random graph functionality for development/testing
|
||||||
|
const { randomGraph } = useRandomGraph()
|
||||||
|
|
||||||
const setEnableNodeDrag = useCallback(
|
const setEnableNodeDrag = useCallback(
|
||||||
() => useSettingsStore.setState((pre) => ({ enableNodeDrag: !pre.enableNodeDrag })),
|
() => useSettingsStore.setState((pre) => ({ enableNodeDrag: !pre.enableNodeDrag })),
|
||||||
[]
|
[]
|
||||||
|
|
@ -228,6 +233,11 @@ export default function Settings() {
|
||||||
useSettingsStore.setState({ graphLayoutMaxIterations: iterations })
|
useSettingsStore.setState({ graphLayoutMaxIterations: iterations })
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const handleGenerateRandomGraph = useCallback(() => {
|
||||||
|
const graph = randomGraph()
|
||||||
|
useGraphStore.getState().setSigmaGraph(graph)
|
||||||
|
}, [randomGraph])
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const saveSettings = () => setOpened(false);
|
const saveSettings = () => setOpened(false);
|
||||||
|
|
@ -376,6 +386,24 @@ export default function Settings() {
|
||||||
defaultValue={15}
|
defaultValue={15}
|
||||||
onEditFinished={setGraphLayoutMaxIterations}
|
onEditFinished={setGraphLayoutMaxIterations}
|
||||||
/>
|
/>
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
{/* Development/Testing Section */}
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<label className="text-sm leading-none font-medium text-muted-foreground">
|
||||||
|
Development
|
||||||
|
</label>
|
||||||
|
<Button
|
||||||
|
onClick={handleGenerateRandomGraph}
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<Shuffle className="h-3.5 w-3.5" />
|
||||||
|
Generate Random Graph
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Separator />
|
<Separator />
|
||||||
<Button
|
<Button
|
||||||
onClick={saveSettings}
|
onClick={saveSettings}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,16 @@ const useRandomGraph = () => {
|
||||||
image: faker.image.urlLoremFlickr()
|
image: faker.image.urlLoremFlickr()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Add edge attributes
|
||||||
|
graph.edges().forEach((edge: string) => {
|
||||||
|
graph.mergeEdgeAttributes(edge, {
|
||||||
|
label: faker.lorem.words(faker.number.int({ min: 1, max: 3 })),
|
||||||
|
size: faker.number.float({ min: 1, max: 5 }),
|
||||||
|
color: randomColor()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
return graph as Graph<NodeType, EdgeType>
|
return graph as Graph<NodeType, EdgeType>
|
||||||
}, [faker])
|
}, [faker])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,24 @@
|
||||||
import { ButtonVariantType } from '@/components/ui/Button'
|
import { ButtonVariantType } from '@/components/ui/Button'
|
||||||
|
|
||||||
// Get backend URL from environment variable, or construct it from window location
|
export const backendBaseUrl = ''
|
||||||
const getBackendUrl = (): string => {
|
export const webuiPrefix = '/webui/'
|
||||||
// First try environment variable
|
|
||||||
if (import.meta.env.VITE_API_BASE_URL) {
|
|
||||||
return import.meta.env.VITE_API_BASE_URL
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to construct from current location if we're behind a reverse proxy
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
const protocol = window.location.protocol
|
|
||||||
const host = window.location.host
|
|
||||||
// Assume API is at :9621 on same host (standard dev port), or check if specified in environment
|
|
||||||
return `${protocol}//${host.split(':')[0]}:9621`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to localhost on port 9621 (standard development port)
|
|
||||||
return 'http://localhost:9621'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const backendBaseUrl = getBackendUrl()
|
|
||||||
export const webuiPrefix = '/'
|
|
||||||
|
|
||||||
export const controlButtonVariant: ButtonVariantType = 'ghost'
|
export const controlButtonVariant: ButtonVariantType = 'ghost'
|
||||||
|
|
||||||
export const labelColorDarkTheme = '#B2EBF2'
|
export const labelColorDarkTheme = '#FFFFFF'
|
||||||
export const labelColorLightTheme = '#000'
|
export const LabelColorHighlightedDarkTheme = '#000000'
|
||||||
export const LabelColorHighlightedDarkTheme = '#000'
|
|
||||||
|
|
||||||
export const nodeColorDisabled = '#E2E2E2'
|
export const nodeColorDisabled = '#E2E2E2'
|
||||||
export const nodeBorderColor = '#EEEEEE'
|
export const nodeBorderColor = '#EEEEEE'
|
||||||
export const nodeBorderColorSelected = '#F57F17'
|
export const nodeBorderColorSelected = '#F57F17'
|
||||||
|
|
||||||
export const edgeColorDarkTheme = '#969696'
|
export const edgeColorDarkTheme = '#888888'
|
||||||
export const edgeColorSelected = '#F57F17'
|
export const edgeColorSelected = '#F57F17'
|
||||||
export const edgeColorHighlighted = '#B2EBF2'
|
export const edgeColorHighlighted = '#FFFFFF'
|
||||||
|
|
||||||
export const searchResultLimit = 50
|
export const searchResultLimit = 50
|
||||||
export const labelListLimit = 100
|
export const labelListLimit = 100
|
||||||
|
|
||||||
// Search History Configuration
|
|
||||||
export const searchHistoryMaxItems = 500
|
|
||||||
export const searchHistoryVersion = '1.0'
|
|
||||||
|
|
||||||
// API Request Limits
|
|
||||||
export const popularLabelsDefaultLimit = 300
|
|
||||||
export const searchLabelsDefaultLimit = 50
|
|
||||||
|
|
||||||
// UI Display Limits
|
|
||||||
export const dropdownDisplayLimit = 300
|
|
||||||
|
|
||||||
export const minNodeSize = 4
|
export const minNodeSize = 4
|
||||||
export const maxNodeSize = 20
|
export const maxNodeSize = 20
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue