mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
c60882b497
commit
97beb26f0c
@ -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}
|
||||||
|
@ -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 [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user