fix(ui): use active alerts to populate grid dropdown

This commit is contained in:
Łukasz Mierzwa
2021-03-01 20:12:31 +00:00
committed by Łukasz Mierzwa
parent caec5bee3a
commit 98f70108cd
5 changed files with 115 additions and 22 deletions

View File

@@ -1,5 +1,11 @@
# Changelog
## [unreleased]
### Changed
- Multi-grid label dropdown will only show label names from visible alerts.
## v0.80
### Added

View File

@@ -5,9 +5,12 @@ import { mount } from "enzyme";
import fetchMock from "fetch-mock";
import { MockGrid } from "__fixtures__/Stories";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { GridLabelSelect } from "./GridLabelSelect";
let alertStore: AlertStore;
let settingsStore: Settings;
beforeEach(() => {
@@ -16,13 +19,16 @@ beforeEach(() => {
body: JSON.stringify([]),
});
alertStore = new AlertStore([]);
settingsStore = new Settings(null);
jest.useFakeTimers();
});
const MountedGridLabelSelect = () => {
return mount(<GridLabelSelect settingsStore={settingsStore} />);
return mount(
<GridLabelSelect alertStore={alertStore} settingsStore={settingsStore} />
);
};
describe("<GridLabelSelect />", () => {
@@ -35,6 +41,7 @@ describe("<GridLabelSelect />", () => {
it("clicking toggle renders select dropdown", async () => {
const promise = Promise.resolve();
MockGrid(alertStore);
const tree = MountedGridLabelSelect();
const toggle = tree.find("span.components-grid-label-select-dropdown");
toggle.simulate("click");
@@ -42,6 +49,22 @@ describe("<GridLabelSelect />", () => {
await act(() => promise);
});
it("clicking an option updates grid settings", async () => {
const promise = Promise.resolve();
MockGrid(alertStore);
const tree = MountedGridLabelSelect();
const toggle = tree.find("span.components-grid-label-select-dropdown");
toggle.simulate("click");
expect(tree.find("div.components-grid-label-select-menu")).toHaveLength(1);
settingsStore.multiGridConfig.config.gridLabel = "foo";
const options = tree.find("div.react-select__option");
options.at(4).simulate("click");
expect(settingsStore.multiGridConfig.config.gridLabel).toBe("cluster");
await act(() => promise);
});
it("clicking toggle twice hides select dropdown", async () => {
const promise = Promise.resolve();
const tree = MountedGridLabelSelect();

View File

@@ -11,23 +11,96 @@ import { observer } from "mobx-react-lite";
import { Manager, Reference, Popper } from "react-popper";
import AsyncSelect from "react-select/async";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { CommonPopperModifiers } from "Common/Popper";
import { NewLabelName, StringToOption, OptionT } from "Common/Select";
import { DropdownSlide } from "Components/Animations/DropdownSlide";
import { ThemeContext } from "Components/Theme";
import { useOnClickOutside } from "Hooks/useOnClickOutside";
import { GridLabelName } from "Components/MainModal/Configuration/GridLabelName";
const NullContainer: FC = () => null;
const GridLabelNameSelect: FC<{
alertStore: AlertStore;
settingsStore: Settings;
}> = ({ alertStore, settingsStore }) => {
const loadOptions = (
inputValue: string,
callback: (options: OptionT[]) => void
) => {
const labelNames: { [key: string]: boolean } = {
"@alertmanager": true,
"@cluster": true,
"@receiver": true,
};
alertStore.data.grids.forEach((grid) => {
labelNames[grid.labelName] = true;
grid.alertGroups.forEach((group) => {
Object.keys(group.labels).forEach((name) => {
labelNames[name] = true;
});
Object.keys(group.shared.labels).forEach((name) => {
labelNames[name] = true;
});
group.alerts.forEach((alert) => {
Object.keys(alert.labels).forEach((name) => {
labelNames[name] = true;
});
});
});
});
callback(
Object.keys(labelNames)
.sort()
.map((key) => StringToOption(key))
);
};
const context = React.useContext(ThemeContext);
return (
<AsyncSelect
styles={context.reactSelectStyles}
classNamePrefix="react-select"
formatCreateLabel={NewLabelName}
loadOptions={loadOptions}
defaultOptions
onChange={(option) => {
settingsStore.multiGridConfig.config.gridLabel = (option as OptionT).value;
}}
menuIsOpen={true}
components={{
ClearIndicator: null,
IndicatorSeparator: null,
DropdownIndicator: null,
ValueContainer: NullContainer,
Control: NullContainer,
}}
/>
);
};
const Dropdown: FC<{
popperPlacement?: string;
popperRef?: Ref<HTMLDivElement>;
popperStyle?: CSSProperties;
alertStore: AlertStore;
settingsStore: Settings;
}> = ({ popperPlacement, popperRef, popperStyle, settingsStore }) => {
}> = ({
popperPlacement,
popperRef,
popperStyle,
alertStore,
settingsStore,
}) => {
return (
<div
className="dropdown-menu d-block shadow components-grid-label-select-menu border-0 p-0"
@@ -39,24 +112,18 @@ const Dropdown: FC<{
}}
data-placement={popperPlacement}
>
<GridLabelName
<GridLabelNameSelect
alertStore={alertStore}
settingsStore={settingsStore}
isOpen={true}
selectComponents={{
ClearIndicator: null,
IndicatorSeparator: null,
DropdownIndicator: null,
ValueContainer: NullContainer,
Control: NullContainer,
}}
/>
</div>
);
};
const GridLabelSelect: FC<{
alertStore: AlertStore;
settingsStore: Settings;
}> = observer(({ settingsStore }) => {
}> = observer(({ alertStore, settingsStore }) => {
const [isVisible, setIsVisible] = useState<boolean>(false);
const hide = useCallback(() => setIsVisible(false), []);
const toggle = useCallback(() => setIsVisible(!isVisible), [isVisible]);
@@ -86,6 +153,7 @@ const GridLabelSelect: FC<{
popperPlacement={placement}
popperRef={ref}
popperStyle={style}
alertStore={alertStore}
settingsStore={settingsStore}
/>
)}

View File

@@ -41,7 +41,10 @@ const Swimlane: FC<{
className="flex-shrink-0 flex-grow-1 px-0"
style={{ minWidth: "0px" }}
>
<GridLabelSelect settingsStore={settingsStore} />
<GridLabelSelect
alertStore={alertStore}
settingsStore={settingsStore}
/>
</span>
)}
<span className="flex-shrink-0 flex-grow-0 ml-2 mr-0">

View File

@@ -1,7 +1,6 @@
import React, { FC } from "react";
import Creatable from "react-select/creatable";
import { GroupTypeBase, SelectComponentsConfig } from "react-select";
import { useFetchGet } from "Hooks/useFetchGet";
import { FormatBackendURI } from "Stores/AlertStore";
@@ -25,11 +24,7 @@ const staticValues = [
const GridLabelName: FC<{
settingsStore: Settings;
isOpen?: boolean | undefined;
selectComponents?:
| Partial<SelectComponentsConfig<OptionT, false, GroupTypeBase<OptionT>>>
| undefined;
}> = ({ settingsStore, isOpen = undefined, selectComponents = undefined }) => {
}> = ({ settingsStore }) => {
const { response } = useFetchGet<string[]>(
FormatBackendURI(`labelNames.json`)
);
@@ -56,8 +51,6 @@ const GridLabelName: FC<{
onChange={(option) => {
settingsStore.multiGridConfig.config.gridLabel = (option as OptionT).value;
}}
menuIsOpen={isOpen}
components={selectComponents}
/>
);
};