- Optimize graph data fetching conditions - Add isFetching state to prevent duplicate requests - Improve label selection handling
91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import { useCallback } from 'react'
|
|
import { AsyncSelect } from '@/components/ui/AsyncSelect'
|
|
import { useSettingsStore } from '@/stores/settings'
|
|
import { useGraphStore } from '@/stores/graph'
|
|
import { labelListLimit } from '@/lib/constants'
|
|
import MiniSearch from 'minisearch'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
const GraphLabels = () => {
|
|
const { t } = useTranslation()
|
|
const label = useSettingsStore.use.queryLabel()
|
|
const graphLabels = useGraphStore.use.graphLabels()
|
|
|
|
const getSearchEngine = useCallback(() => {
|
|
// Create search engine
|
|
const searchEngine = new MiniSearch({
|
|
idField: 'id',
|
|
fields: ['value'],
|
|
searchOptions: {
|
|
prefix: true,
|
|
fuzzy: 0.2,
|
|
boost: {
|
|
label: 2
|
|
}
|
|
}
|
|
})
|
|
|
|
// Add documents
|
|
const documents = graphLabels.map((str, index) => ({ id: index, value: str }))
|
|
searchEngine.addAll(documents)
|
|
|
|
return {
|
|
labels: graphLabels,
|
|
searchEngine
|
|
}
|
|
}, [graphLabels])
|
|
|
|
const fetchData = useCallback(
|
|
async (query?: string): Promise<string[]> => {
|
|
const { labels, searchEngine } = getSearchEngine()
|
|
|
|
let result: string[] = labels
|
|
if (query) {
|
|
// Search labels
|
|
result = searchEngine.search(query).map((r: { id: number }) => labels[r.id])
|
|
}
|
|
|
|
return result.length <= labelListLimit
|
|
? result
|
|
: [...result.slice(0, labelListLimit), t('graphLabels.andOthers', { count: result.length - labelListLimit })]
|
|
},
|
|
[getSearchEngine]
|
|
)
|
|
|
|
const setQueryLabel = useCallback((newLabel: string) => {
|
|
if (newLabel.startsWith('And ') && newLabel.endsWith(' others')) return
|
|
|
|
const currentLabel = useSettingsStore.getState().queryLabel
|
|
|
|
if (newLabel === '*' && currentLabel === '*') {
|
|
// When reselecting '*', just set it again to trigger a new fetch
|
|
useSettingsStore.getState().setQueryLabel('*')
|
|
} else if (newLabel === currentLabel && newLabel !== '*') {
|
|
// When selecting the same label (except '*'), switch to '*'
|
|
useSettingsStore.getState().setQueryLabel('*')
|
|
} else {
|
|
useSettingsStore.getState().setQueryLabel(newLabel)
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<AsyncSelect<string>
|
|
className="ml-2"
|
|
triggerClassName="max-h-8"
|
|
searchInputClassName="max-h-8"
|
|
triggerTooltip={t('graphPanel.graphLabels.selectTooltip')}
|
|
fetcher={fetchData}
|
|
renderOption={(item) => <div>{item}</div>}
|
|
getOptionValue={(item) => item}
|
|
getDisplayValue={(item) => <div>{item}</div>}
|
|
notFound={<div className="py-6 text-center text-sm">No labels found</div>}
|
|
label={t('graphPanel.graphLabels.label')}
|
|
placeholder={t('graphPanel.graphLabels.placeholder')}
|
|
value={label !== null ? label : ''}
|
|
onChange={setQueryLabel}
|
|
clearable={false} // Prevent clearing value on reselect
|
|
/>
|
|
)
|
|
}
|
|
|
|
export default GraphLabels
|