feat: glass box SQL console, tooltips, interpretations, UI polish#51
Conversation
- Show actual SQL queries in console for every button click (glass box) - Add contextual interpretation below JSON results explaining scalability implications - Fix tooltips: JS-driven fixed positioning instead of CSS pseudo- elements (no clipping by overflow:hidden parents) - Event log: distinct dark card container with visible border and empty state placeholder - Animations: smoother arrow glow, tab hover transform - Draggable resize: VS Code-style split pane (main area shrinks as bottom panel grows) - Fresh Playwright screenshots for all 9 tasks
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (12)
📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe PR adds a SQL Glass Box feature to log query steps with SQL statements, introduces result interpretation messages, and enhances the visualizer UI with interactive tooltips and a draggable console resize handle. Changes span backend SQL collection and frontend display across app.js, index.html, server.py, and style.css. Changes
Sequence DiagramsequenceDiagram
participant User
participant Frontend as Client (app.js)
participant Backend as Server (server.py)
participant Display as Display Layer
User->>Frontend: Trigger action (e.g., INSERT, SELECT)
Frontend->>Backend: Send request with query parameters
Backend->>Backend: Process query, collect steps with SQL
Backend-->>Frontend: Return result {steps[{sql, action, ...}], interpretation}
Frontend->>Display: showResult(status, latency, data, cls, apiResult)
Display->>Display: Remove old interpretation element
Display->>Display: Append new interpretation (if present)
Frontend->>Frontend: logSqlToConsole(apiResult)
Frontend->>Frontend: Iterate steps, extract sql field
Frontend->>Display: Append SQL/metadata lines to console output
Display->>Display: Auto-scroll console to bottom
User->>User: View SQL steps and interpretation in UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
Adds “glass box” visibility and UI polish to the Lab 10 database visualizer by surfacing executed SQL per step, adding contextual explanations, and improving interaction affordances (tooltips, event log, resizable panels).
Changes:
- Extend API step traces to include
sqland addinterpretationstrings for multiple patterns. - Update frontend to auto-log step SQL to the console, render interpretations in the result panel, add JS-driven tooltips, and add a draggable bottom-bar resize handle.
- Update styling/layout for the new UI elements and add refreshed screenshots.
Reviewed changes
Copilot reviewed 4 out of 16 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| 10-databases/visualizer/style.css | Layout tweaks (full-height app), tooltip styling, bottom bar/event log styling, resize handle visuals |
| 10-databases/visualizer/server.py | Adds sql fields to step traces and interpretation fields to responses; adds logged SQL strings for multiple operations |
| 10-databases/visualizer/index.html | Adds data-tooltip attributes, resize handle element, tooltip popup container, and event log header text |
| 10-databases/visualizer/app.js | Implements SQL console auto-logging, interpretation rendering, draggable resize, and JS-driven tooltips |
| 10-databases/visualizer/screenshots/01-replication-tab.png | Updated screenshot asset |
| 10-databases/visualizer/screenshots/02-sidebar-state.png | Updated screenshot asset |
| bench_sql = ("SELECT * FROM access_log WHERE student_id = ? " | ||
| f"AND resource = ? (x{count})") |
There was a problem hiding this comment.
bench_sql uses ? placeholders and appends (x{count}), which isn’t valid MySQL syntax and doesn’t match the actual executed query format (%s placeholders). Since this is shown to users as the “glass box” query, consider logging a syntactically correct MySQL statement and representing the loop count separately (e.g., in metadata).
| document.addEventListener('mouseover', (e) => { | ||
| const el = e.target.closest('[data-tooltip]'); | ||
| if (!el) { | ||
| popup.classList.remove('visible'); | ||
| return; | ||
| } | ||
| popup.textContent = el.dataset.tooltip; | ||
| popup.classList.add('visible'); | ||
|
|
There was a problem hiding this comment.
Tooltips are only wired to mouseover/mouseout, so keyboard users (tabbing) won’t see them, and touch devices may not trigger them consistently. Consider adding focusin/focusout handling (and possibly aria-describedby or title fallback) so tooltips are accessible beyond mouse hover.
| height: 100vh; | ||
| display: flex; | ||
| flex-direction: column; | ||
| overflow: hidden; |
There was a problem hiding this comment.
body { height: 100vh; overflow: hidden; } can prevent the page from scrolling when content exceeds the viewport (especially on small screens/mobile), potentially cutting off UI. Consider keeping min-height: 100vh (or using dynamic viewport units like 100dvh) and avoiding global overflow: hidden unless all content is guaranteed to fit with internal scroll regions.
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| min-height: 100vh; | |
| min-height: 100dvh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow-y: auto; |
| pointer-events: none; | ||
| opacity: 0; | ||
| transition: opacity 0.15s ease; | ||
| white-space: nowrap; |
There was a problem hiding this comment.
In .tooltip-popup, white-space: nowrap effectively disables wrapping, so max-width: 300px won’t prevent long tooltips from overflowing the viewport. Consider allowing wrapping (white-space: normal/pre-wrap) and adding overflow-wrap: anywhere (or similar) so long tooltip text stays on-screen.
| white-space: nowrap; | |
| white-space: normal; | |
| overflow-wrap: anywhere; |
| .travel-dot { | ||
| transition: opacity 0.15s ease; | ||
| } | ||
|
|
There was a problem hiding this comment.
There are now two .travel-dot rules (this new one and another later in the file), which can make the actual transition behavior hard to reason about (later rules will override earlier ones). Consider consolidating into a single .travel-dot declaration to avoid accidental overrides.
| .travel-dot { | |
| transition: opacity 0.15s ease; | |
| } |
| seq = 1 | ||
|
|
||
| # Write to primary | ||
| insert_sql = f"INSERT INTO students (name, email, major) VALUES ('{name}', '{email}', '{major}')" |
There was a problem hiding this comment.
insert_sql is built via string interpolation with raw name/email/major. Even though the executed query is parameterized, the displayed SQL will become syntactically invalid (and misleading for students) if inputs contain quotes/newlines. Consider logging a parameterized form (e.g., VALUES (%s, %s, %s)) and/or escaping values for display.
| insert_sql = f"INSERT INTO students (name, email, major) VALUES ('{name}', '{email}', '{major}')" | |
| insert_sql = "INSERT INTO students (name, email, major) VALUES (%s, %s, %s)" |
| explain_sql = (f"EXPLAIN SELECT * FROM access_log WHERE student_id = {student_id} " | ||
| f"AND resource = '{resource}'") | ||
| count_sql = (f"SELECT COUNT(*) AS cnt FROM access_log WHERE student_id = {student_id} " | ||
| f"AND resource = '{resource}'") |
There was a problem hiding this comment.
explain_sql / count_sql embed resource directly into a quoted SQL string for display. If resource contains a quote, the logged SQL becomes invalid and can look like injection despite the actual query being parameterized. Consider logging the parameterized query text (with placeholders) and/or escaping the value for display.
| explain_sql = (f"EXPLAIN SELECT * FROM access_log WHERE student_id = {student_id} " | |
| f"AND resource = '{resource}'") | |
| count_sql = (f"SELECT COUNT(*) AS cnt FROM access_log WHERE student_id = {student_id} " | |
| f"AND resource = '{resource}'") | |
| explain_sql = "EXPLAIN SELECT * FROM access_log WHERE student_id = %s AND resource = %s" | |
| count_sql = "SELECT COUNT(*) AS cnt FROM access_log WHERE student_id = %s AND resource = %s" |
| cur.execute(f"SET GLOBAL innodb_buffer_pool_size = {size}") | ||
| t1 = time.perf_counter() | ||
| return {"action": "SET BUFFER POOL", "size": size, | ||
| "latency_ms": round((t1 - t0) * 1000, 2)} | ||
| "latency_ms": round((t1 - t0) * 1000, 2), | ||
| "sql": f"SET GLOBAL innodb_buffer_pool_size = {size}", | ||
| "interpretation": ( |
There was a problem hiding this comment.
vertical_set_buffer executes SET GLOBAL innodb_buffer_pool_size = {size} using direct string interpolation from the request body. This allows SQL injection if the endpoint is called with crafted input (e.g., size containing ; ...). Consider validating/whitelisting allowed sizes and constructing the statement safely (e.g., enforce size as an integer and append a fixed unit).
Glass box SQL queries, contextual interpretations, JS tooltips, event log card, VS Code-style resize, fresh screenshots.
Summary by CodeRabbit