Fix custom variable modal clearing when switching browser focus

Fixes #44805

Fixed a bug where the "Add custom variable" modal would clear entered
values when switching focus to another browser tab or application window
due to network refetches.
This commit is contained in:
Juan Fernandez
2026-06-05 16:11:30 -04:00
committed by GitHub
parent edd55f010e
commit eb42b22230
4 changed files with 40 additions and 2 deletions
@@ -0,0 +1 @@
* Fixed a bug where the "Add custom variable" modal would clear entered values when switching focus to another browser tab or application window.
+22
View File
@@ -154,6 +154,28 @@ describe("Modal", () => {
expect(onExit).toHaveBeenCalledTimes(1);
});
it("does not call onExit when a backdrop mousedown is interrupted by the window losing focus", () => {
const onExit = jest.fn();
const { container } = render(
<Modal title="Test" onExit={onExit}>
<div>content</div>
</Modal>
);
const background = container.querySelector(".modal__background");
if (!background) throw new Error("Background element not found");
// User presses down on the backdrop then the window loses focus (tab switch /
// app switch) before releasing — mouseup never fires on the page.
fireEvent.mouseDown(background);
fireEvent.blur(window);
// On return, the stale mousedown state must not close the modal.
fireEvent.mouseUp(background);
act(() => jest.runAllTimers());
expect(onExit).not.toHaveBeenCalled();
});
it("does not call onExit when clicking the background if disableClosingModal is true", async () => {
const onExit = jest.fn();
const { container } = render(
+10
View File
@@ -105,6 +105,16 @@ const Modal = ({
return undefined;
}, [onEnter]);
useEffect(() => {
const onWindowBlur = () => {
isDownOnBackgroundRef.current = false;
};
window.addEventListener("blur", onWindowBlur);
return () => {
window.removeEventListener("blur", onWindowBlur);
};
}, []);
const backgroundClasses = classnames(`${baseClass}__background`, {
[`${baseClass}__hidden`]: isHidden,
[`${baseClass}__closing`]: isClosing,
@@ -11,7 +11,10 @@ import { IVariable } from "interfaces/variables";
import { AppContext } from "context/app";
import { stringToClipboard } from "utilities/copy_text";
import { FLEET_WEBSITE_URL } from "utilities/constants";
import {
DEFAULT_USE_QUERY_OPTIONS,
FLEET_WEBSITE_URL,
} from "utilities/constants";
import CustomLink from "components/CustomLink";
import { HumanTimeDiffWithDateTip } from "components/HumanTimeDiffWithDateTip";
import ListItem from "components/ListItem/ListItem";
@@ -62,7 +65,9 @@ const Variables = ({ router, location }: IVariablesProps) => {
IListVariablesResponse,
Error,
IListVariablesResponse
>(["variables", apiParams], () => variablesAPI.getVariables(apiParams));
>(["variables", apiParams], () => variablesAPI.getVariables(apiParams), {
...DEFAULT_USE_QUERY_OPTIONS,
});
// Open the Add variable modal via deep-link (e.g. from the command
// palette). Gate on the same predicate the in-page button uses — the