Skip to content

Commit d3b8f2f

Browse files
authored
Merge branch 'main' into fix/pg-get-table-columns-schema
2 parents f15eaff + e1064e0 commit d3b8f2f

40 files changed

Lines changed: 3433 additions & 256 deletions

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
77
for product tags (`vMAJOR.MINOR.PATCH`).
88

9+
Product releases follow a **weekly cadence** (Saturday 09:00 America/Los_Angeles). See `docs/oss-ux/RELEASE.md`.
10+
11+
## [1.1.0] — 2026-08-15
12+
13+
### Added
14+
15+
- Progressive dashboard builds (`dashboard-shell` / `dashboard-widget` SSE chunks) with live Preview mounting.
16+
- Dashboard organization: clone, folders, favorites, search.
17+
- Dashboard version history (`dashboard_versions`, restore) and AI-evaluated alerts (`dashboard_alerts`).
18+
- Dashboard refresh / auto-refresh and public TV kiosk mode.
19+
- Centered dashboard intro and editable breadcrumb title.
20+
- Server-owned dashboard generation persistence (`generation_status`, optimistic locking).
21+
22+
### Changed
23+
24+
- Multi-schema awareness across Editor, Brain, and Advisor UI (#55).
25+
- Slow Queries and Workload Analysis merged into a single Performance area (#52).
26+
27+
### Fixed
28+
29+
- CI: remove CodeQL visibility guard that blocked merges (#56).
30+
- Cloud agent ops notes for Hermes MCP restart and multi-schema fixtures (#53).
31+
32+
### Notes
33+
34+
- `@deepsql/mcp` remains `0.27.0` for this cut (no MCP API changes required).
35+
- Hand-apply SQL changelog `V111``V114` when not using `ddl-auto=update`.
36+
937
## [1.0.0] — 2026-08-13
1038

1139
First public OSS release.
@@ -31,4 +59,5 @@ First public OSS release.
3159
- Residual high-severity items tracked in `docs/oss-ux/OSS_SECURITY_REVIEW.md` (IDOR sweep, SET preamble allowlist, SSRF hardening, share-password defaults) are deferred past this cut.
3260
- Primary distribution path remains `docker compose up --build` (no pre-built container registry in this release).
3361

62+
[1.1.0]: https://github.com/DeepSQLAI/deepsql/releases/tag/v1.1.0
3463
[1.0.0]: https://github.com/DeepSQLAI/deepsql/releases/tag/v1.0.0

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ Dashboards are **generated by the embedded DeepSQL Agent acting as a coding agen
141141
- **Rendering + data access**: `DashboardArtifact.jsx` renders the HTML in a **sandboxed iframe** (`sandbox="allow-scripts"`, opaque origin + a strict CSP — no external network). The artifact fetches data only through an injected `deepsql.query(sql)` bridge that `postMessage`s to the parent; the parent calls **`POST /api/dashboards/query`** (`DashboardQueryController`), which is **read-only twice over** (`McpSqlGuardService.validateReadOnlySql` + `QueryExecutionContext.api` = `READ_ONLY_ONLY`) and access-scoped via `assertCanReadConnectionContent`. So the agent's code has full creative freedom while every query stays guarded and sandboxed. The bridge also auto-sizes the iframe and forwards runtime errors.
142142
- Generation endpoints unchanged (`POST /api/dashboards/generate` + `/generate/stream`). `DashboardBuilder.js`/`DashboardInputs.js` remain only because `tabs/Core/PreviewTab.js` still uses them — the dashboard *creation* path no longer touches them.
143143
- **Sharing**: both share types render a standalone read-only `DashboardViewer` (title + `DashboardArtifact` with an injected `queryFn`). Internal link `/dashboard-view/:id` (auth) uses the authed broker; public link `/share/dashboard/:token` (permitAll) uses `PublicDashboardController` (`GET /api/public/dashboards/{token}` + `/query`), which resolves only while `saved_dashboards.is_public` is true (revoke = flip it) and runs read-only + connection-scoped. `share_token`/`is_public` are set only via `POST|DELETE /api/saved-dashboards/{id}/share` (access-checked), never a general update. `ShareMenu.jsx` drives the UI. The public query path has its own nginx `dashq` limiter.
144+
- **Organization** (search/folders/favorites): `SavedDashboardController`'s search/folder/favorite endpoints existed for a while with no UI consumer. `DashboardsHome.jsx` now wires all of it — a search box (client-side filter over name/description), folder chips derived from `GET /connection/{id}/folders` with a per-card "move to folder" popover (`PUT /saved-dashboards/{id}` with `folder: ""` to clear — `updateDashboard` treats `null` as "field omitted" so blank is the explicit clear signal, same convention as `setSharePassword`), and a favorite star toggle (`POST /{id}/favorite`) with optimistic UI update.
145+
- **Clone**: `POST /saved-dashboards/{id}/clone` (`SavedDashboardService.cloneDashboard`) duplicates a dashboard's config/chat/tags/folder into a fresh row — not shared, not favorited. Exposed as a copy icon on each `DashboardsHome.jsx` card.
146+
- **Version history**: every real overwrite of `dashboardConfig` (agent build via `completeBuildTurn`, manual Source-tab edit via `updateDashboard`, or a restore) snapshots the *previous* config into `dashboard_versions` (`V113__create_dashboard_versions.sql`) before overwriting, tagged with a trigger (`AGENT_BUILD`/`MANUAL_EDIT`/`RESTORE`) — capped at 50 snapshots per dashboard, oldest pruned first. `GET /{id}/versions` lists them newest-first; `POST /{id}/versions/{versionId}/restore` swaps a snapshot back in as current (itself snapshotting whatever was live, so a restore is undoable too) and **dedupes**: after a restore, the restored row plus any other row with byte-identical `dashboard_config` are deleted, since that content is now "Current," not history — otherwise a restore-edit-restore cycle piles up an alternating chain of duplicate snapshots. `DashboardWorkspace.jsx`'s History panel shows a lightweight diff summary per entry (title/widget-count/size delta computed client-side, not a real line diff — the agent rewrites large chunks even for small logical changes) plus a Preview modal that renders that version's HTML live via `DashboardArtifact`.
147+
- **Refresh**: `DashboardArtifact`'s `useImperativeHandle` exposes `reload()`, which bumps an internal `reloadEpoch` state used as the `<iframe>`'s `key` — forcing a genuine remount (and re-running every widget's `deepsql.query()` call) even when `html` is referentially unchanged, which changing `html`/`srcDoc` alone can't guarantee. `DashboardWorkspace.jsx`'s canvas toolbar has a manual Refresh button plus an auto-refresh interval dropdown (Off/30s/5m/1h) that calls it on a timer, paused while a build is in flight (a completing build already replaces the iframe). `DashboardViewer.jsx` (both share surfaces) takes the same `autoRefreshMs` optionally, plus `hideChrome` for kiosk mode.
148+
- **TV/kiosk mode**: `PublicDashboardPage.jsx` reads `?kiosk=1&refresh=<seconds>` (chrome-less + auto-refresh, floor 10s) and `?tokens=tokA,tokB&advance=<seconds>` (cycles through multiple public share tokens, dwelling `advance` seconds each — the route's own `:token` is always the first slide). A password-protected dashboard mid-cycle is skipped (there's no one there to type a password) rather than parking the whole kiosk on a gate. `ShareMenu.jsx` surfaces a ready-made kiosk link (`?kiosk=1&refresh=60`) once a dashboard is public and unprotected.
149+
- **Alerts**: `dashboard_alerts` (`V114__create_dashboard_alerts.sql`) holds a natural-language condition per dashboard (e.g. "alert if the error rate exceeds 5% in the last hour"), evaluated on a schedule by `DashboardAlertService.evaluate()` — a **bounded agent session** (fresh `ensureSession`, no tools beyond `execute_sql`/schema lookups, a short task prompt asking for exactly `YES`/`NO` + a one-sentence reason grounded in a real query result) reusing the same agent plumbing as dashboard generation, just for a one-line answer instead of a whole HTML document. `DashboardAlertTaskConfig` registers one db-scheduler recurring task (`dashboard-alert-tick`, every minute) that evaluates whichever alerts are actually due per `DashboardAlertRepository.findDue` (each alert has its own `checkIntervalMinutes`) rather than one scheduled task per alert. A fired alert dispatches through `EmailService.sendDashboardAlert`/`WebhookService.sendDashboardAlert` (new methods, same pattern as the existing growth/slow-query alert methods) gated by a per-alert `cooldownMinutes` so a condition that stays true doesn't re-fire every tick. The alert runs **as whoever created it** (`createdByUsername`, captured at creation time) — there's no ambient "system" identity for a background job, and running every alert as an arbitrary admin would let one user's alert read data through someone else's access grant. `DashboardAlertController` is the CRUD surface (`/saved-dashboards/{id}/alerts`); `DashboardWorkspace.jsx`'s toolbar has an Alerts panel (composer + per-alert enable/disable/delete, last-check verdict shown inline).
144150

145151
## LLM Providers
146152

0 commit comments

Comments
 (0)