import { useState, useCallback, useEffect } from 'react' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/Popover' import Checkbox from '@/components/ui/Checkbox' import Button from '@/components/ui/Button' import Separator from '@/components/ui/Separator' import Input from '@/components/ui/Input' import { controlButtonVariant } from '@/lib/constants' import { useSettingsStore } from '@/stores/settings' import { useBackendState } from '@/stores/state' import { useGraphStore } from '@/stores/graph' import { SettingsIcon, RefreshCwIcon } from 'lucide-react' import { useTranslation } from 'react-i18next'; /** * Component that displays a checkbox with a label. */ const LabeledCheckBox = ({ checked, onCheckedChange, label }: { checked: boolean onCheckedChange: () => void label: string }) => { return (
) } /** * Component that displays a number input with a label. */ const LabeledNumberInput = ({ value, onEditFinished, label, min, max }: { value: number onEditFinished: (value: number) => void label: string min: number max?: number }) => { const [currentValue, setCurrentValue] = useState(value) const onValueChange = useCallback( (e: React.ChangeEvent) => { const text = e.target.value.trim() if (text.length === 0) { setCurrentValue(null) return } const newValue = Number.parseInt(text) if (!isNaN(newValue) && newValue !== currentValue) { if (min !== undefined && newValue < min) { return } if (max !== undefined && newValue > max) { return } setCurrentValue(newValue) } }, [currentValue, min, max] ) const onBlur = useCallback(() => { if (currentValue !== null && value !== currentValue) { onEditFinished(currentValue) } }, [value, currentValue, onEditFinished]) return (
{ if (e.key === 'Enter') { onBlur() } }} />
) } /** * Component that displays a popover with settings options. */ export default function Settings() { const [opened, setOpened] = useState(false) const [tempApiKey, setTempApiKey] = useState('') const refreshLayout = useGraphStore.use.refreshLayout() const showPropertyPanel = useSettingsStore.use.showPropertyPanel() const showNodeSearchBar = useSettingsStore.use.showNodeSearchBar() const showNodeLabel = useSettingsStore.use.showNodeLabel() const enableEdgeEvents = useSettingsStore.use.enableEdgeEvents() const enableNodeDrag = useSettingsStore.use.enableNodeDrag() const enableHideUnselectedEdges = useSettingsStore.use.enableHideUnselectedEdges() const showEdgeLabel = useSettingsStore.use.showEdgeLabel() const graphQueryMaxDepth = useSettingsStore.use.graphQueryMaxDepth() const graphMinDegree = useSettingsStore.use.graphMinDegree() const graphLayoutMaxIterations = useSettingsStore.use.graphLayoutMaxIterations() const enableHealthCheck = useSettingsStore.use.enableHealthCheck() const apiKey = useSettingsStore.use.apiKey() useEffect(() => { setTempApiKey(apiKey || '') }, [apiKey, opened]) const setEnableNodeDrag = useCallback( () => useSettingsStore.setState((pre) => ({ enableNodeDrag: !pre.enableNodeDrag })), [] ) const setEnableEdgeEvents = useCallback( () => useSettingsStore.setState((pre) => ({ enableEdgeEvents: !pre.enableEdgeEvents })), [] ) const setEnableHideUnselectedEdges = useCallback( () => useSettingsStore.setState((pre) => ({ enableHideUnselectedEdges: !pre.enableHideUnselectedEdges })), [] ) const setShowEdgeLabel = useCallback( () => useSettingsStore.setState((pre) => ({ showEdgeLabel: !pre.showEdgeLabel })), [] ) // const setShowPropertyPanel = useCallback( () => useSettingsStore.setState((pre) => ({ showPropertyPanel: !pre.showPropertyPanel })), [] ) const setShowNodeSearchBar = useCallback( () => useSettingsStore.setState((pre) => ({ showNodeSearchBar: !pre.showNodeSearchBar })), [] ) const setShowNodeLabel = useCallback( () => useSettingsStore.setState((pre) => ({ showNodeLabel: !pre.showNodeLabel })), [] ) const setEnableHealthCheck = useCallback( () => useSettingsStore.setState((pre) => ({ enableHealthCheck: !pre.enableHealthCheck })), [] ) const setGraphQueryMaxDepth = useCallback((depth: number) => { if (depth < 1) return useSettingsStore.setState({ graphQueryMaxDepth: depth }) }, []) const setGraphMinDegree = useCallback((degree: number) => { if (degree < 0) return useSettingsStore.setState({ graphMinDegree: degree }) }, []) const setGraphLayoutMaxIterations = useCallback((iterations: number) => { if (iterations < 1) return useSettingsStore.setState({ graphLayoutMaxIterations: iterations }) }, []) const setApiKey = useCallback(async () => { useSettingsStore.setState({ apiKey: tempApiKey || null }) await useBackendState.getState().check() setOpened(false) }, [tempApiKey]) const handleTempApiKeyChange = useCallback( (e: React.ChangeEvent) => { setTempApiKey(e.target.value) }, [setTempApiKey] ) const { t } = useTranslation(); return ( <> e.preventDefault()} >
e.preventDefault()}>
) }