mirror of
https://github.com/prymitive/karma
synced 2026-08-28 11:17:28 +00:00
chore(ui): replace react-autosuggest with downshift
This commit is contained in:
committed by
Łukasz Mierzwa
parent
7e0b77193e
commit
e327da26b7
Generated
+4
-51
@@ -4539,14 +4539,6 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/react-autosuggest": {
|
||||
"version": "10.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-autosuggest/-/react-autosuggest-10.1.4.tgz",
|
||||
"integrity": "sha512-NdSUpRX6u1VsLpF63ss3yBGGcTFDJZg35D9XPTOgXPaUXZTJcfglcjyYgQwiMYRsbnz438dWt2gff/qIb7sWcw==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "17.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz",
|
||||
@@ -7338,8 +7330,7 @@
|
||||
"compute-scroll-into-view": {
|
||||
"version": "1.0.17",
|
||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz",
|
||||
"integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
@@ -8801,7 +8792,6 @@
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.2.tgz",
|
||||
"integrity": "sha512-WnPoQ6miic4+uEzPEfqgeen0t5YREOUabMopU/Juo/UYDMZl0ZACkO6ykWCRg48dlEUmEt6zfaJlj1x7kEy78g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"compute-scroll-into-view": "^1.0.17",
|
||||
@@ -8812,8 +8802,7 @@
|
||||
"react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9184,7 +9173,8 @@
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promise-pool": {
|
||||
"version": "2.5.0",
|
||||
@@ -16781,18 +16771,6 @@
|
||||
"whatwg-fetch": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"react-autosuggest": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-autosuggest/-/react-autosuggest-10.1.0.tgz",
|
||||
"integrity": "sha512-/azBHmc6z/31s/lBf6irxPf/7eejQdR0IqnZUzjdSibtlS8+Rw/R79pgDAo6Ft5QqCUTyEQ+f0FhL+1olDQ8OA==",
|
||||
"requires": {
|
||||
"es6-promise": "^4.2.8",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-themeable": "^1.1.0",
|
||||
"section-iterator": "^2.0.0",
|
||||
"shallow-equal": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"react-colorful": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.1.2.tgz",
|
||||
@@ -17370,21 +17348,6 @@
|
||||
"use-latest": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"react-themeable": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-themeable/-/react-themeable-1.1.0.tgz",
|
||||
"integrity": "sha1-fURm3ZsrX6dQWHJ4JenxUro3mg4=",
|
||||
"requires": {
|
||||
"object-assign": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"object-assign": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
|
||||
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
||||
@@ -18322,11 +18285,6 @@
|
||||
"lodash": "^4.17.4"
|
||||
}
|
||||
},
|
||||
"section-iterator": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz",
|
||||
"integrity": "sha1-v0RNev7rlK1Dw5rS+yYVFifMuio="
|
||||
},
|
||||
"select": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
|
||||
@@ -18544,11 +18502,6 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"shallow-equal": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
|
||||
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
|
||||
},
|
||||
"shallowequal": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
|
||||
|
||||
+1
-2
@@ -28,7 +28,6 @@
|
||||
"@types/promise-retry": "1.1.3",
|
||||
"@types/qs": "6.9.6",
|
||||
"@types/react": "17.0.3",
|
||||
"@types/react-autosuggest": "10.1.4",
|
||||
"@types/react-dom": "17.0.3",
|
||||
"@types/react-js-pagination": "3.0.3",
|
||||
"@types/react-select": "4.0.14",
|
||||
@@ -41,6 +40,7 @@
|
||||
"copy-to-clipboard": "3.3.1",
|
||||
"csshake": "1.5.3",
|
||||
"date-fns": "2.20.1",
|
||||
"downshift": "6.1.2",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"favico.js": "0.3.10",
|
||||
@@ -59,7 +59,6 @@
|
||||
"qs": "6.10.1",
|
||||
"react": "17.0.2",
|
||||
"react-app-polyfill": "2.0.0",
|
||||
"react-autosuggest": "10.1.0",
|
||||
"react-cool-dimensions": "2.0.1",
|
||||
"react-day-picker": "7.4.10",
|
||||
"react-dom": "17.0.2",
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const AutosuggestTheme = {
|
||||
container: "autosuggest d-inline-block mw-100",
|
||||
suggestionsContainer: "dropdown",
|
||||
suggestionsList: "dropdown-menu show shadow",
|
||||
suggestion: "dropdown-item cursor-pointer",
|
||||
suggestionFocused: "active",
|
||||
suggestionHighlighted: "active",
|
||||
};
|
||||
|
||||
export { AutosuggestTheme };
|
||||
@@ -4,11 +4,11 @@ exports[`<FilterInput /> matches snapshot with no filters 1`] = `
|
||||
"
|
||||
<div class=\\"input-group w-100 mr-2 components-filterinput-outer bg-transparent\\">
|
||||
<div class=\\"form-control components-filterinput border-0 rounded-0 bg-inherit\\">
|
||||
<div role=\\"combobox\\"
|
||||
<div class=\\"autosuggest d-inline-block mw-100\\"
|
||||
role=\\"combobox\\"
|
||||
aria-haspopup=\\"listbox\\"
|
||||
aria-owns=\\"react-autowhatever-1\\"
|
||||
aria-owns=\\"downshift-0-menu\\"
|
||||
aria-expanded=\\"false\\"
|
||||
class=\\"autosuggest d-inline-block mw-100\\"
|
||||
>
|
||||
<span class=\\"input-group-text d-inline-block mr-2 border-0 bg-inherit px-1\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
@@ -26,21 +26,22 @@ exports[`<FilterInput /> matches snapshot with no filters 1`] = `
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<input type=\\"text\\"
|
||||
class=\\"components-filterinput-wrapper text-white mw-100\\"
|
||||
placeholder
|
||||
<input class=\\"components-filterinput-wrapper text-white mw-100\\"
|
||||
size=\\"1\\"
|
||||
value
|
||||
autocomplete=\\"off\\"
|
||||
id=\\"downshift-0-input\\"
|
||||
aria-autocomplete=\\"list\\"
|
||||
aria-controls=\\"react-autowhatever-1\\"
|
||||
aria-controls=\\"downshift-0-menu\\"
|
||||
aria-labelledby=\\"downshift-0-label\\"
|
||||
autocomplete=\\"off\\"
|
||||
value
|
||||
>
|
||||
<div id=\\"react-autowhatever-1\\"
|
||||
role=\\"listbox\\"
|
||||
class=\\"dropdown\\"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<span class=\\"dropdown\\"
|
||||
id=\\"downshift-0-menu\\"
|
||||
role=\\"listbox\\"
|
||||
aria-labelledby=\\"downshift-0-label\\"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class=\\"input-group-append\\">
|
||||
<span class=\\"input-group-text border-0 rounded-0 bg-inherit px-0\\">
|
||||
@@ -153,27 +154,28 @@ exports[`<FilterInput /> matches snapshot with some filters 1`] = `
|
||||
</path>
|
||||
</svg>
|
||||
</button>
|
||||
<div role=\\"combobox\\"
|
||||
<div class=\\"autosuggest d-inline-block mw-100\\"
|
||||
role=\\"combobox\\"
|
||||
aria-haspopup=\\"listbox\\"
|
||||
aria-owns=\\"react-autowhatever-1\\"
|
||||
aria-owns=\\"downshift-1-menu\\"
|
||||
aria-expanded=\\"false\\"
|
||||
class=\\"autosuggest d-inline-block mw-100\\"
|
||||
>
|
||||
<input type=\\"text\\"
|
||||
class=\\"components-filterinput-wrapper text-white mw-100\\"
|
||||
placeholder
|
||||
<input class=\\"components-filterinput-wrapper text-white mw-100\\"
|
||||
size=\\"1\\"
|
||||
value
|
||||
autocomplete=\\"off\\"
|
||||
id=\\"downshift-1-input\\"
|
||||
aria-autocomplete=\\"list\\"
|
||||
aria-controls=\\"react-autowhatever-1\\"
|
||||
aria-controls=\\"downshift-1-menu\\"
|
||||
aria-labelledby=\\"downshift-1-label\\"
|
||||
autocomplete=\\"off\\"
|
||||
value
|
||||
>
|
||||
<div id=\\"react-autowhatever-1\\"
|
||||
role=\\"listbox\\"
|
||||
class=\\"dropdown\\"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<span class=\\"dropdown\\"
|
||||
id=\\"downshift-1-menu\\"
|
||||
role=\\"listbox\\"
|
||||
aria-labelledby=\\"downshift-1-label\\"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class=\\"input-group-append\\">
|
||||
<span class=\\"input-group-text border-0 rounded-0 bg-inherit px-0\\">
|
||||
|
||||
@@ -124,22 +124,39 @@ describe("<FilterInput />", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("clicking input changes background color", () => {
|
||||
const tree = MountedInput();
|
||||
tree.find("input").simulate("click");
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/bg-focused/);
|
||||
});
|
||||
|
||||
it("focusing input changes background color", () => {
|
||||
const tree = MountedInput();
|
||||
const input = tree.find("input");
|
||||
input.simulate("focus");
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/bg-focused/);
|
||||
});
|
||||
|
||||
it("focusing form changes background color", () => {
|
||||
const tree = MountedInput();
|
||||
const formControl = tree.find(".form-control");
|
||||
formControl.find("input").simulate("focus");
|
||||
expect(toDiffableHtml(tree.html())).toMatch(/bg-focused/);
|
||||
});
|
||||
|
||||
it("bluring input changes background color", () => {
|
||||
it("bluring input changes background color", async () => {
|
||||
const tree = MountedInput();
|
||||
const formControl = tree.find(".form-control");
|
||||
formControl
|
||||
.find("input")
|
||||
.simulate("change", { target: { value: "cluster" } });
|
||||
formControl.find("input").simulate("blur");
|
||||
expect(toDiffableHtml(tree.html())).not.toMatch(/bg-focused/);
|
||||
tree.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("<FilterInput Autosuggest />", () => {
|
||||
describe("<FilterInput autocomplete />", () => {
|
||||
it("fetches suggestions on input change", async () => {
|
||||
const tree = MountedInput();
|
||||
tree.find("input").simulate("change", { target: { value: "cluster" } });
|
||||
@@ -151,6 +168,7 @@ describe("<FilterInput Autosuggest />", () => {
|
||||
expect(useFetchGetMock.fetch.calls[0]).toContain(
|
||||
"./autocomplete.json?term=cluster"
|
||||
);
|
||||
tree.unmount();
|
||||
});
|
||||
|
||||
it("doesn't fetch any suggestion if the input value is empty", () => {
|
||||
@@ -160,6 +178,26 @@ describe("<FilterInput Autosuggest />", () => {
|
||||
jest.runOnlyPendingTimers();
|
||||
});
|
||||
expect(useFetchGetMock.fetch.calls).toHaveLength(0);
|
||||
tree.unmount();
|
||||
});
|
||||
|
||||
it("highliting a suggestion makes it active", async () => {
|
||||
const tree = MountedInput();
|
||||
tree.find("input").simulate("change", { target: { value: "cluster" } });
|
||||
act(() => {
|
||||
jest.runOnlyPendingTimers();
|
||||
});
|
||||
|
||||
// suggestions are rendered only when input is focused
|
||||
tree.find("input").simulate("focus");
|
||||
// find() doesn't pick up suggestions even when tree.html() shows them
|
||||
// forcing update seems to solve it
|
||||
// https://github.com/airbnb/enzyme/issues/1233#issuecomment-343449560
|
||||
tree.update();
|
||||
|
||||
tree.find("input").simulate("keydown", { keyCode: 40, key: "ArrowDown" });
|
||||
tree.update();
|
||||
expect(tree.find(".dropdown-item").at(0).html()).toMatch(/active/);
|
||||
});
|
||||
|
||||
it("clicking on a suggestion adds it to filters", async () => {
|
||||
@@ -176,8 +214,7 @@ describe("<FilterInput Autosuggest />", () => {
|
||||
// forcing update seems to solve it
|
||||
// https://github.com/airbnb/enzyme/issues/1233#issuecomment-343449560
|
||||
tree.update();
|
||||
// not sure why but suggestions are being found twice
|
||||
const suggestion = tree.find(".dropdown-item").at(2);
|
||||
const suggestion = tree.find(".dropdown-item").at(1);
|
||||
expect(suggestion.text()).toBe("cluster=prod");
|
||||
suggestion.simulate("click");
|
||||
expect(alertStore.filters.values).toHaveLength(1);
|
||||
|
||||
@@ -2,7 +2,11 @@ import { FC, useEffect, useState, useRef, useCallback } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import Autosuggest from "react-autosuggest";
|
||||
import {
|
||||
useCombobox,
|
||||
UseComboboxState,
|
||||
UseComboboxStateChangeOptions,
|
||||
} from "downshift";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons/faSearch";
|
||||
@@ -14,57 +18,25 @@ import { useFetchGet } from "Hooks/useFetchGet";
|
||||
import { useDebounce } from "Hooks/useDebounce";
|
||||
import { useOnClickOutside } from "Hooks/useOnClickOutside";
|
||||
import { FilterInputLabel } from "Components/Labels/FilterInputLabel";
|
||||
import { AutosuggestTheme } from "./Constants";
|
||||
import { History } from "./History";
|
||||
|
||||
const FilterInput: FC<{
|
||||
alertStore: AlertStore;
|
||||
settingsStore: Settings;
|
||||
}> = observer(({ alertStore, settingsStore }) => {
|
||||
const autosuggestRef = useRef<Autosuggest | null>(null);
|
||||
const inputRef = useRef<HTMLElement | null>(null);
|
||||
const formRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
const [value, setValue] = useState<string>("");
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [isFocused, setIsFocused] = useState<boolean>(false);
|
||||
|
||||
const onSuggestionsClearRequested = useCallback(() => setSuggestions([]), []);
|
||||
|
||||
const onSuggestionSelected = useCallback(
|
||||
(_, { suggestion }) => {
|
||||
setValue("");
|
||||
alertStore.filters.addFilter(suggestion);
|
||||
},
|
||||
[alertStore.filters]
|
||||
);
|
||||
|
||||
const onChange = useCallback((_, { newValue }) => setValue(newValue), []);
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(event) => {
|
||||
event.preventDefault();
|
||||
if (value !== "") {
|
||||
alertStore.filters.addFilter(value);
|
||||
setValue("");
|
||||
}
|
||||
},
|
||||
[alertStore.filters, value]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
inputRef.current = ((autosuggestRef.current as Autosuggest)
|
||||
.input as HTMLInputElement).parentElement;
|
||||
if (!IsMobile()) {
|
||||
((autosuggestRef.current as Autosuggest)
|
||||
.input as HTMLInputElement).focus();
|
||||
inputRef.current?.focus();
|
||||
setIsFocused(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onBlur = useCallback(() => setIsFocused(false), []);
|
||||
useOnClickOutside(formRef, onBlur, true);
|
||||
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
const [term, setTerm] = useState<string>("");
|
||||
const debouncedSearchTerm = useDebounce<string>(term, 300);
|
||||
|
||||
@@ -73,76 +45,84 @@ const FilterInput: FC<{
|
||||
{ autorun: false }
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (debouncedSearchTerm) {
|
||||
get();
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
const stateReducer = (
|
||||
state: UseComboboxState<string>,
|
||||
actionAndChanges: UseComboboxStateChangeOptions<string>
|
||||
) => {
|
||||
const { type, changes } = actionAndChanges;
|
||||
switch (type) {
|
||||
case useCombobox.stateChangeTypes.InputBlur: {
|
||||
onBlur();
|
||||
return changes;
|
||||
}
|
||||
default:
|
||||
return changes;
|
||||
}
|
||||
return () => cancelGet();
|
||||
}, [get, cancelGet, debouncedSearchTerm]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
onSuggestionsClearRequested();
|
||||
} else if (!isLoading && response !== null) {
|
||||
setSuggestions(response);
|
||||
}
|
||||
}, [response, error, isLoading, onSuggestionsClearRequested]);
|
||||
const {
|
||||
isOpen,
|
||||
getMenuProps,
|
||||
getInputProps,
|
||||
getComboboxProps,
|
||||
highlightedIndex,
|
||||
getItemProps,
|
||||
setInputValue,
|
||||
inputValue,
|
||||
} = useCombobox({
|
||||
stateReducer: stateReducer,
|
||||
items: suggestions,
|
||||
onInputValueChange: ({ inputValue }) => {
|
||||
if (inputValue) {
|
||||
setTerm(inputValue);
|
||||
} else {
|
||||
setTerm("");
|
||||
setSuggestions([]);
|
||||
}
|
||||
},
|
||||
onSelectedItemChange: ({ selectedItem }) => {
|
||||
applyFilter(selectedItem);
|
||||
},
|
||||
});
|
||||
|
||||
const applyFilter = useCallback(
|
||||
(inputValue: string | null | undefined) => {
|
||||
if (inputValue) {
|
||||
alertStore.filters.addFilter(inputValue);
|
||||
}
|
||||
setInputValue("");
|
||||
setSuggestions([]);
|
||||
},
|
||||
[alertStore.filters, setInputValue]
|
||||
);
|
||||
|
||||
const onInputClick = (className: string) => {
|
||||
if (
|
||||
typeof className === "string" &&
|
||||
className.split(" ").includes("form-control")
|
||||
) {
|
||||
((autosuggestRef.current as Autosuggest)
|
||||
.input as HTMLInputElement).focus();
|
||||
inputRef.current?.focus();
|
||||
setIsFocused(true);
|
||||
}
|
||||
};
|
||||
|
||||
const renderSuggestion = (
|
||||
suggestion: string,
|
||||
{ query }: { query: string }
|
||||
) => {
|
||||
const parts = suggestion.split(new RegExp(`(${query})`, "gi"));
|
||||
return (
|
||||
<span>
|
||||
{parts.map((part, i) => (
|
||||
<span
|
||||
key={i}
|
||||
style={
|
||||
part.toLowerCase() === query.toLowerCase()
|
||||
? { fontWeight: "bold" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{part}
|
||||
</span>
|
||||
))}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (debouncedSearchTerm) {
|
||||
get();
|
||||
} else {
|
||||
setSuggestions([]);
|
||||
}
|
||||
return () => cancelGet();
|
||||
}, [get, cancelGet, debouncedSearchTerm]);
|
||||
|
||||
const renderInputComponent: FC<{ value: string }> = ({
|
||||
value,
|
||||
...inputProps
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{alertStore.filters.values.length ? null : (
|
||||
<span className="input-group-text d-inline-block mr-2 border-0 bg-inherit px-1">
|
||||
<FontAwesomeIcon icon={faSearch} />
|
||||
</span>
|
||||
)}
|
||||
<input
|
||||
className="components-filterinput-wrapper text-white mw-100"
|
||||
placeholder=""
|
||||
size={value.length + 1}
|
||||
value={value}
|
||||
{...inputProps}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
setSuggestions([]);
|
||||
} else if (!isLoading && response !== null) {
|
||||
setSuggestions(response);
|
||||
}
|
||||
}, [response, error, isLoading]);
|
||||
|
||||
return (
|
||||
// data-filters is there to register filters for observation in mobx
|
||||
@@ -150,7 +130,10 @@ const FilterInput: FC<{
|
||||
<form
|
||||
className="form-inline flex-grow-1 flex-shrink-1 mr-auto"
|
||||
style={{ minWidth: "0px" }}
|
||||
onSubmit={onSubmit}
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
applyFilter(inputValue);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
ref={formRef}
|
||||
@@ -171,26 +154,52 @@ const FilterInput: FC<{
|
||||
filter={filter}
|
||||
/>
|
||||
))}
|
||||
<Autosuggest
|
||||
ref={autosuggestRef}
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={({ value }) => setTerm(value)}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
onSuggestionSelected={onSuggestionSelected}
|
||||
shouldRenderSuggestions={(value) =>
|
||||
value ? value.trim().length > 1 : false
|
||||
}
|
||||
getSuggestionValue={(suggestion) => suggestion}
|
||||
renderSuggestion={renderSuggestion}
|
||||
renderInputComponent={renderInputComponent}
|
||||
inputProps={{
|
||||
value: value,
|
||||
onChange: onChange,
|
||||
onFocus: () => setIsFocused(true),
|
||||
onBlur: onBlur,
|
||||
}}
|
||||
theme={AutosuggestTheme}
|
||||
/>
|
||||
<div
|
||||
className="autosuggest d-inline-block mw-100"
|
||||
{...getComboboxProps()}
|
||||
>
|
||||
{alertStore.filters.values.length ? null : (
|
||||
<span className="input-group-text d-inline-block mr-2 border-0 bg-inherit px-1">
|
||||
<FontAwesomeIcon icon={faSearch} />
|
||||
</span>
|
||||
)}
|
||||
<input
|
||||
className="components-filterinput-wrapper text-white mw-100"
|
||||
size={inputValue ? inputValue.length + 1 : 1}
|
||||
onClick={() => setIsFocused(true)}
|
||||
{...getInputProps({ ref: inputRef })}
|
||||
/>
|
||||
</div>
|
||||
<span className="dropdown" {...getMenuProps()}>
|
||||
{isOpen && inputValue && suggestions.length ? (
|
||||
<div className="dropdown-menu show shadow">
|
||||
{suggestions.slice(0, 10).map((item, index) => (
|
||||
<li
|
||||
className={`dropdown-item cursor-pointer ${
|
||||
highlightedIndex === index ? "active" : ""
|
||||
}`}
|
||||
key={`${item}${index}`}
|
||||
{...getItemProps({ item, index })}
|
||||
>
|
||||
{item
|
||||
.split(new RegExp(`(${inputValue})`, "gi"))
|
||||
.map((part, i) => (
|
||||
<span
|
||||
key={i}
|
||||
style={
|
||||
part.toLowerCase() === inputValue.toLowerCase()
|
||||
? { fontWeight: "bold" }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{part}
|
||||
</span>
|
||||
))}
|
||||
</li>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</span>
|
||||
</div>
|
||||
<div className="input-group-append">
|
||||
<History alertStore={alertStore} settingsStore={settingsStore} />
|
||||
|
||||
Reference in New Issue
Block a user