DataLinks: suggestions menu improvements (#19396)

* Deduplicate series labels in datalinks variables suggestions

* Allways show all variables available in datalinks suggestions
This commit is contained in:
Dominik Prokop 2019-09-25 12:46:37 +02:00 committed by GitHub
parent c60882b497
commit 97beb26f0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 31 deletions

View File

@ -8,7 +8,6 @@ import { Editor } from '@grafana/slate-react';
import { Value, Editor as CoreEditor } from 'slate'; import { Value, Editor as CoreEditor } from 'slate';
import Plain from 'slate-plain-serializer'; import Plain from 'slate-plain-serializer';
import { Popper as ReactPopper } from 'react-popper'; import { Popper as ReactPopper } from 'react-popper';
import useDebounce from 'react-use/lib/useDebounce';
import { css, cx } from 'emotion'; import { css, cx } from 'emotion';
import { SlatePrism } from '../../slate-plugins'; import { SlatePrism } from '../../slate-plugins';
@ -33,12 +32,7 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = ({ value, onChange, s
const editorRef = useRef<Editor>() as RefObject<Editor>; const editorRef = useRef<Editor>() as RefObject<Editor>;
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
const [showingSuggestions, setShowingSuggestions] = useState(false); const [showingSuggestions, setShowingSuggestions] = useState(false);
const [suggestionsIndex, setSuggestionsIndex] = useState(0); const [suggestionsIndex, setSuggestionsIndex] = useState(0);
const [usedSuggestions, setUsedSuggestions] = useState(
suggestions.filter(suggestion => value.includes(suggestion.value))
);
const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value)); const [linkUrl, setLinkUrl] = useState<Value>(makeValue(value));
const getStyles = useCallback(() => { const getStyles = useCallback(() => {
@ -54,29 +48,13 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = ({ value, onChange, s
}; };
}, [theme]); }, [theme]);
const currentSuggestions = useMemo(
() => suggestions.filter(suggestion => !usedSuggestions.map(s => s.value).includes(suggestion.value)),
[usedSuggestions, suggestions]
);
// Workaround for https://github.com/ianstormtaylor/slate/issues/2927 // Workaround for https://github.com/ianstormtaylor/slate/issues/2927
const stateRef = useRef({ showingSuggestions, currentSuggestions, suggestionsIndex, linkUrl, onChange }); const stateRef = useRef({ showingSuggestions, suggestions, suggestionsIndex, linkUrl, onChange });
stateRef.current = { showingSuggestions, currentSuggestions, suggestionsIndex, linkUrl, onChange }; stateRef.current = { showingSuggestions, suggestions, suggestionsIndex, linkUrl, onChange };
// SelectionReference is used to position the variables suggestion relatively to current DOM selection // SelectionReference is used to position the variables suggestion relatively to current DOM selection
const selectionRef = useMemo(() => new SelectionReference(), [setShowingSuggestions, linkUrl]); const selectionRef = useMemo(() => new SelectionReference(), [setShowingSuggestions, linkUrl]);
// Keep track of variables that has been used already
const updateUsedSuggestions = () => {
const currentLink = Plain.serialize(linkUrl);
const next = usedSuggestions.filter(suggestion => currentLink.includes(suggestion.value));
if (next.length !== usedSuggestions.length) {
setUsedSuggestions(next);
}
};
useDebounce(updateUsedSuggestions, 250, [linkUrl]);
const onKeyDown = React.useCallback((event: KeyboardEvent, next: () => any) => { const onKeyDown = React.useCallback((event: KeyboardEvent, next: () => any) => {
if (!stateRef.current.showingSuggestions) { if (!stateRef.current.showingSuggestions) {
if (event.key === '=' || event.key === '$' || (event.keyCode === 32 && event.ctrlKey)) { if (event.key === '=' || event.key === '$' || (event.keyCode === 32 && event.ctrlKey)) {
@ -93,13 +71,13 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = ({ value, onChange, s
case 'Enter': case 'Enter':
event.preventDefault(); event.preventDefault();
return onVariableSelect(stateRef.current.currentSuggestions[stateRef.current.suggestionsIndex]); return onVariableSelect(stateRef.current.suggestions[stateRef.current.suggestionsIndex]);
case 'ArrowDown': case 'ArrowDown':
case 'ArrowUp': case 'ArrowUp':
event.preventDefault(); event.preventDefault();
const direction = event.key === 'ArrowDown' ? 1 : -1; const direction = event.key === 'ArrowDown' ? 1 : -1;
return setSuggestionsIndex(index => modulo(index + direction, stateRef.current.currentSuggestions.length)); return setSuggestionsIndex(index => modulo(index + direction, stateRef.current.suggestions.length));
default: default:
return next(); return next();
} }
@ -126,9 +104,7 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = ({ value, onChange, s
setLinkUrl(editor.value); setLinkUrl(editor.value);
setShowingSuggestions(false); setShowingSuggestions(false);
setUsedSuggestions((previous: VariableSuggestion[]) => {
return [...previous, item];
});
setSuggestionsIndex(0); setSuggestionsIndex(0);
onChange(Plain.serialize(editor.value)); onChange(Plain.serialize(editor.value));
}; };
@ -159,7 +135,7 @@ export const DataLinkInput: React.FC<DataLinkInputProps> = ({ value, onChange, s
return ( return (
<div ref={ref} style={style} data-placement={placement}> <div ref={ref} style={style} data-placement={placement}>
<DataLinkSuggestions <DataLinkSuggestions
suggestions={currentSuggestions} suggestions={stateRef.current.suggestions}
onSuggestionSelect={onVariableSelect} onSuggestionSelect={onVariableSelect}
onClose={() => setShowingSuggestions(false)} onClose={() => setShowingSuggestions(false)}
activeIndex={suggestionsIndex} activeIndex={suggestionsIndex}

View File

@ -77,7 +77,10 @@ export const getPanelLinksVariableSuggestions = (): VariableSuggestion[] => [
]; ];
const getSeriesVars = (dataFrames: DataFrame[]) => { const getSeriesVars = (dataFrames: DataFrame[]) => {
const labels = _.flatten(dataFrames.map(df => Object.keys(df.labels || {}))); const labels = _.chain(dataFrames.map(df => Object.keys(df.labels || {})))
.flatten()
.uniq()
.value();
return [ return [
{ {