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 => { 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 ( className="ml-2" triggerClassName="max-h-8" searchInputClassName="max-h-8" triggerTooltip={t('graphPanel.graphLabels.selectTooltip')} fetcher={fetchData} renderOption={(item) =>
{item}
} getOptionValue={(item) => item} getDisplayValue={(item) =>
{item}
} notFound={
No labels found
} 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