fix(ui): Auto Run does not wait on the filter builder's resting picker

The builder reopens its field list after each condition, and live preview held
any open listbox for up to 5 s, so a PromQL label pick ran the chart about 5 s
late instead of right away as on main. The resting list is now marked and not
waited on; a list mid-edit still is.
This commit is contained in:
ktx-vaidehi
2026-11-03 15:01:09 +05:30
parent c53143162f
commit 227e7d4429
6 changed files with 45 additions and 2 deletions
@@ -123,6 +123,33 @@ async function addEq(field: string, value: string) {
}
describe("FilterBuilder", () => {
describe("resting list signal for live preview", () => {
const listbox = () => document.body.querySelector<HTMLElement>('[role="listbox"]');
const resting = () => listbox()?.hasAttribute("data-list-resting");
it("marks only the list reopened after a commit as resting, never one mid-edit", async () => {
mountBuilder("promql-builder", []);
await find("input").trigger("click");
await flushPromises();
expect(resting()).toBe(true);
await type("lev");
expect(resting()).toBe(false);
await type("level");
await press("Enter");
expect(listbox()).not.toBeNull();
expect(resting()).toBe(false);
await pickRow("eq");
expect(resting()).toBe(false);
await type("error");
await press("Enter");
expect(listbox()).not.toBeNull();
expect(resting()).toBe(true);
await find("chip-level-value").trigger("click");
await flushPromises();
expect(resting()).toBe(false);
});
});
describe("server switch for the extended engine operators", () => {
const EXTENDED = ["in", "not_in", "starts_with", "ends_with", "regex", "not_regex"];
@@ -202,6 +202,11 @@ const emptyText = computed(() => {
return t("filterBar.noOperators");
});
// Reopened for the next condition with nothing typed: offering a pick, not holding an edit.
const resting = computed(
() => step.value === "field" && !text.value && !editingId.value && !draft.value,
);
const multiStep = computed(() => step.value === "value" && editor.multiValue.value);
const selectedCount = computed(() => draft.value?.values.length ?? 0);
@@ -370,6 +375,7 @@ const draftOperator = computed(() => {
:loading="step === 'value' ? valuesLoading : step === 'field' && fieldsLoading"
:auto-highlight="autoHighlight"
:multiple="multiStep"
:resting="resting"
:placeholder="placeholderText"
:aria-label="t('filterBar.ariaLabel')"
:disabled="disabled"
@@ -185,6 +185,12 @@ describe("usePanelLivePreview", () => {
'<div data-reka-popper-content-wrapper><div role="listbox"></div></div>';
expect(isPopupOpen()).toBe(true);
});
it("does not hold for a resting list that only offers the next pick", () => {
document.body.innerHTML =
'<div data-reka-popper-content-wrapper><div role="listbox" data-list-resting></div></div>';
expect(isPopupOpen()).toBe(false);
});
});
describe("live runs", () => {
@@ -98,10 +98,10 @@ const withoutEditorMode = (panel: any) =>
queries: (panel.queries ?? []).map((query: any) => ({ ...query, customQuery: false })),
};
/** An open select list (field or function picker), but not menus, popovers or tooltips. */
/** An open select list mid-pick (field or function picker), but not a resting list, menus, popovers or tooltips. */
export const isPopupOpen = (): boolean =>
Array.from(document.querySelectorAll("[data-reka-popper-content-wrapper]")).some((wrapper) =>
wrapper.querySelector('[role="listbox"]'),
wrapper.querySelector('[role="listbox"]:not([data-list-resting])'),
);
/**
@@ -58,6 +58,8 @@ export interface ChipInputProps {
/** `plain` drops the input frame, for a field that sits inside an editor surface. */
appearance?: "field" | "plain";
ariaLabel?: I18nText;
/** The open list only offers a next pick and nothing is mid-edit; its listbox carries `data-list-resting` so watchers need not wait on it. */
resting?: boolean;
/** The default slot places the caret itself, by rendering its `caret` slot prop where typing should land. */
inlineCaret?: boolean;
/** Lines of chips shown before the field scrolls inside itself; it grows freely when unset. */
@@ -53,6 +53,7 @@ const props = withDefaults(defineProps<ChipInputProps>(), {
appearance: "field",
ariaLabel: undefined,
inlineCaret: false,
resting: false,
maxRows: undefined,
dataTest: undefined,
});
@@ -611,6 +612,7 @@ function onFieldFocusOut() {
ref="listRef"
role="listbox"
:aria-multiselectable="multiple || undefined"
:data-list-resting="resting ? '' : undefined"
:aria-label="searchPlaceholder ?? ariaLabel"
class="min-h-0 flex-1 overflow-y-auto p-1"
>