mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
fix(ui): use active alerts to populate grid dropdown
This commit is contained in:
committed by
Łukasz Mierzwa
parent
caec5bee3a
commit
98f70108cd
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## [unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Multi-grid label dropdown will only show label names from visible alerts.
|
||||
|
||||
## v0.80
|
||||
|
||||
### Added
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user