Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bright-bears-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@prisma/studio-core': patch
---

Keep the SQL editor content-sized until results are shown, then cap its height so long scripts scroll internally and the result grid can use the remaining space.
2 changes: 2 additions & 0 deletions Architecture/sql-view.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ SQL result visualization is governed by:
- SQL result grid MUST keep column pinning enabled and URL-backed using existing `pin` navigation state.
- SQL execution MUST remain cancellable via `AbortController`.
- SQL editor lines MUST soft-wrap within the available editor width instead of forcing page-level horizontal overflow while typing long queries.
- When SQL results are visible, the editor pane MUST stay content-sized up to a bounded height and then scroll internally, rather than splitting the viewport evenly with the result grid.

## Result Rendering Contract

Expand Down Expand Up @@ -97,3 +98,4 @@ Changes to SQL view MUST include tests for:
- read-only grid rendering (pin control present, sorting controls disabled)
- absence of history UI
- absence of pagination controls in SQL result grid
- bounded editor height when results are visible
1 change: 1 addition & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ The same lint transport also validates saved table-level SQL filter pills in the
Keyboard execution supports `Cmd/Ctrl+Enter`, and in multi-statement scripts it runs only the top-level statement at the current cursor.
Large SQL result sets stay responsive while you keep editing the query because result-grid rendering is isolated from editor keystrokes unless the executed result itself changes.
Long SQL lines wrap inside the editor instead of stretching the overall page wider, so writing large queries stays readable on narrow viewports.
When a query returns results, the editor keeps its content-sized height until it reaches a viewport cap, then scrolls internally so the result grid can use the remaining space.

## AI SQL Generation

Expand Down
82 changes: 82 additions & 0 deletions ui/studio/views/sql/SqlView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const setPinnedColumnIdsMock = vi.fn();
let mockEditorCursorHead = 0;
let mockEditorDocLength = 0;
let mockEditorDocText = "";
let mockCodeMirrorProps:
| { height?: string; maxHeight?: string; minHeight?: string }
| undefined;
let mockCodeMirrorOnChange: ((value: string) => void) | undefined;
let mockCodeMirrorExtensions: unknown[] = [];
const mockEditorDispatch = vi.fn((transaction: unknown) => {
Expand Down Expand Up @@ -106,7 +109,10 @@ vi.mock("../../../hooks/use-navigation", () => ({
vi.mock("@uiw/react-codemirror", () => ({
default: (props: {
"aria-label"?: string;
height?: string;
extensions?: unknown[];
maxHeight?: string;
minHeight?: string;
onCreateEditor?: (view: {
dispatch: (transaction: unknown) => void;
focus: () => void;
Expand All @@ -118,6 +124,11 @@ vi.mock("@uiw/react-codemirror", () => ({
onChange?: (value: string) => void;
value?: string;
}) => {
mockCodeMirrorProps = {
height: props.height,
maxHeight: props.maxHeight,
minHeight: props.minHeight,
};
mockCodeMirrorOnChange = props.onChange;
mockCodeMirrorExtensions = props.extensions ?? [];
mockEditorDocLength = (props.value ?? "").length;
Expand Down Expand Up @@ -398,6 +409,7 @@ afterEach(() => {
mockEditorDocText = "";
mockCodeMirrorOnChange = undefined;
mockCodeMirrorExtensions = [];
mockCodeMirrorProps = undefined;
});

beforeEach(() => {
Expand Down Expand Up @@ -1259,6 +1271,76 @@ describe("SqlView", () => {
harness.cleanup();
});

it("keeps the SQL editor in a bounded scroll region for long scripts", () => {
const { adapter } = createAdapterMock();
const studio = createStudioMock(adapter);
useStudioMock.mockReturnValue(studio);

const harness = renderSqlView();

const scrollRegion = harness.container.querySelector(
'[data-testid="sql-editor-scroll-container"]',
);
expect(scrollRegion).toBeTruthy();
expect(scrollRegion?.className).toContain("min-h-0");
expect(scrollRegion?.className).toContain("overflow-hidden");

harness.cleanup();
});
Comment thread
shaishab316 marked this conversation as resolved.

it("keeps the editor content-sized until results are shown, then caps it", async () => {
const { adapter } = createAdapterMock();
const studio = createStudioMock(adapter);
useStudioMock.mockReturnValue(studio);

const harness = renderSqlView();

expect(
harness.container
.querySelector('[data-testid="sql-editor-scroll-container"]')
?.className,
).toContain("flex-1");
expect(mockCodeMirrorProps).toMatchObject({
height: "100%",
maxHeight: undefined,
});

const runButton = [...harness.container.querySelectorAll("button")].find(
(button) => button.textContent?.includes("Run SQL"),
);

if (!runButton) {
throw new Error("SQL view run control not rendered");
}

act(() => {
runButton.dispatchEvent(new MouseEvent("click", { bubbles: true }));
});

await waitFor(() => {
return (
harness.container.textContent?.includes("1 row(s) returned") ?? false
);
});

expect(
harness.container
.querySelector('[data-testid="sql-editor-scroll-container"]')
?.className,
).toContain("flex-none");
expect(
harness.container
.querySelector('[data-testid="sql-result-grid-container"]')
?.className,
).toContain("flex-1");
expect(mockCodeMirrorProps).toMatchObject({
height: undefined,
maxHeight: "40vh",
});

harness.cleanup();
});

it("supports cancelling a running query", async () => {
const raw: Adapter["raw"] = async (_details, options) => {
return await new Promise((resolve) => {
Expand Down
Loading