feat(grid): add stop button to loading and refresh overlay

This commit is contained in:
zipg authored and GitHub committed 2026-09-24 19:13:32 +08:00
1 parent 124d7ae6cc
commit 05a72de255
6 files changed
+225 -29

No files matched your search

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { isActiveResultLoading, type QueryResultLoadingStateLike } from "@/lib/sql/queryExecutionState";
import { canCancelQueryExecution, isActiveResultLoading, shouldShowCancelAction, type QueryResultLoadingStateLike } from "@/lib/sql/queryExecutionState";
function state(overrides: Partial<QueryResultLoadingStateLike> = {}): QueryResultLoadingStateLike {
return {
@@ -33,3 +33,26 @@ describe("active query result loading", () => {
expect(isActiveResultLoading(state({ isExecuting: true, activeResultRunId: "run-a" }))).toBe(true);
});
});
describe("stop action visibility", () => {
it("hides the action when nothing is running", () => {
expect(shouldShowCancelAction(state())).toBe(false);
expect(shouldShowCancelAction(state({ executionId: "exec-1" }))).toBe(false);
});
it("hides the action while an execution has no cancellable id yet", () => {
expect(shouldShowCancelAction(state({ isExecuting: true }))).toBe(false);
});
it("keeps the action visible while a cancel request is in flight", () => {
const cancelling = state({ isExecuting: true, executionId: "exec-1", isCancelling: true });
expect(shouldShowCancelAction(cancelling)).toBe(true);
// The button must switch to its cancelling state instead of being pressable again.
expect(canCancelQueryExecution(cancelling)).toBe(false);
});
it("allows only one cancel request for an idle execution", () => {
expect(shouldShowCancelAction(state({ isExecuting: true, executionId: "exec-1" }))).toBe(true);
expect(canCancelQueryExecution(state({ isExecuting: true, executionId: "exec-1" }))).toBe(true);
});
});
@@ -26,3 +26,16 @@ export function isActiveResultLoading(state: QueryResultLoadingStateLike): boole
export function queryExecutionLabelKey(state: Pick<QueryExecutionStateLike, "isCancelling">): "common.loading" | "common.stopping" {
return state.isCancelling ? "common.stopping" : "common.loading";
}
/**
* Whether the stop action should be visible for a running execution.
*
* Unlike `canCancelQueryExecution` this stays true while a cancel request is in
* flight, so the control keeps its place and only switches to the cancelling
* state instead of disappearing. Executions without an id (for example the
* metadata/preparation window of a data-tab reload) have nothing to cancel, so
* the caller must not offer the action there.
*/
export function shouldShowCancelAction(state: QueryExecutionStateLike): boolean {
return state.isExecuting && !!state.executionId;
}