pgkiln 0.49.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SECURITY.md CHANGED
@@ -96,6 +96,7 @@ first version (MVP). Every finding below has a regression test in
96
96
  | Output | Auto-escaping HTML templates, strict CSP (no inline scripts, no inline styles: the page's one `<style>` carries a per-response nonce), `X-Frame-Options`, `nosniff`, `no-store`. Images may also come from the map tile server (`MAP_TILE_URL`, an http(s) origin only); map data travels as JSON in a `<script type="application/json">` element with `<` escaped. A map area in a report URL (`r<id>_bb`) is parsed into four range-checked numbers before it reaches SQL; anything else is ignored. The browser fetches tiles from that server directly, so it sees users' IP addresses, map areas and the site's origin (sent as `Referer`, which OpenStreetMap requires; never the page's path or query): self-host tiles where that matters. |
97
97
  | Files | Uploads are size- and type-checked and stored per session (`meta.temp_files` shows only the session's own files). A posted text value can't point a file item at another file, and a "remove file" value only removes files of the form's own record. Downloads need a checksum bound to user, page, item and record, check page access and read as the app's role (RLS applies). They are sent as attachments with `nosniff` and a sandboxing CSP; only PNG, JPEG, GIF, WebP and PDF are shown inline. |
98
98
  | Data loading and PDFs | The `data_load` process loads as the app's role (grants, RLS, triggers apply) and shows only data errors and `RAISE` messages per row. Report PDFs run the report's own query with the same page, region and row checks as the screen. |
99
+ | SQL Worksheet transactions (sprint 107) | A worksheet's open transaction is held in server memory under the caller's builder session id plus the tab key and checked against the workspace: every lookup starts from the caller's own session, so another developer or another sign-in never reaches it. Its connection is a plain client built from the workspace's developer login (or the *Run as* application's), never returned to a pool, and closed at the end, so `SET ROLE` reaches only roles that login has and nothing leaks into the builder's pools; *Run as* can't change while it is open. Rolled back on idle timeout, sign-out, session expiry, workspace switch, tab close and server stop, with `idle_in_transaction_session_timeout` as a backstop; at most `WORKSHEET_TXN_MAX_PER_DEVELOPER` per developer and `WORKSHEET_TXN_MAX` per server, each one database connection outside the pools. CSRF and a developer sign-in on every endpoint. |
99
100
 
100
101
  ## Findings of the MVP review and their fixes
101
102
 
@@ -7,7 +7,7 @@ open item and open an issue or pull request; see [CONTRIBUTING.md](../CONTRIBUTI
7
7
  Legend: ✅ available · 🟡 partial (see notes) · ❌ not yet · ➖ not planned (a deliberate choice,
8
8
  or better served by the PostgreSQL ecosystem; see the notes and [extensions](guide/15-extensions.md))
9
9
 
10
- Last reviewed: 2026-10-16 (sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
10
+ Last reviewed: 2026-10-18 (sprint 108: the code editor's syntax colours in the builder's light and dark themes, read-only SQL highlighted, the Data Modeler in dark mode; sprint 107: a transaction mode in the SQL Worksheet with Commit and Rollback; DA-18: JavaScript (MLE) not planned, plv8 where installed; sprint 106: the change log of DDL change sets with Flyway, Liquibase and SQL downloads; sprint 104: RESTful Services modules, templates and handlers with PL/pgSQL and media handlers, privileges, OpenAPI and Try it; sprint 103: Schema Export / Import with pg_dump and pg_restore; sprint 102: the SQL Monitor with live sessions, Top SQL and a statement's plan; sprint 101: Scheduling of pg_cron jobs with a schedule builder, run now and run history; sprint 100: RESTful Services, tables and views published as REST endpoints with paging, filters, keys and OpenAPI; sprint 99: Administration → Database Users for PostgreSQL roles; sprint 98: the Data Modeler with relational diagrams, DDL and a data dictionary; sprint 97: charts of a query in the worksheet, saved charts and their dashboard; sprint 96: the SQL Workshop's Launchpad with pins and tool groups, the builder's search with Ctrl+K; sprint 95: Table Properties: create, edit or copy a table in a form with a DDL preview and Apply in one transaction; sprint 94: an object's menu with Open in a panel, Quick DDL, Add index / trigger / policy and Drop with dependents; sprint 93: worksheets saved as SQL Scripts with tabs and a Files list, Format, Convert case, find and replace, bind and substitution variables; sprint 92: the worksheet's Query Result with sort, value dialog, copy and downloads, plans as a tree with the slowest step and misestimates, SQL History with status, search and run again; sprint 91: the SQL Worksheet like Database Actions' SQL: navigator, Run Statement at the cursor and Run Script with a log per statement, Explain Plan, Autotrace, notices, history, Run as an application role; sprint 90: Comment Out in the page designer, gallery labels in title case; sprint 89: the Object Browser's schema, one row of tabs, blank NULLs, Modify column; sprint 88: home cards with colour bands and round icons, the hero on the page background, a page footer with the version and Back to top; sprint 87: the Create Application wizard reloads the page list for a schema, RLS badges, the alias from the name; sprint 86: the page designer by page number, HTML error pages in the builder; sprint 85: the Form Designer, beyond APEX; sprint 84: the date picker, facet menus; sprint 83: Component Settings and Component Groups; sprint 82: Report Queries; sprint 81: Application Computations and Shortcuts in Shared Components; sprint 80: the master grid's first row selected when the page opens and after a search; grid cells as text with their format mask until edited, with cell navigation by arrow keys, Enter, F2 and Escape; sprint 79: generated dashboards with sums, donuts and lines, leaving out charts that say nothing; applications open in their own light or dark mode until the user chooses, per application; a user menu with Appearance and Sign in when signed out; the developer toolbar's App and Page texts and debug state; the report search's column scope in the magnifier; sprint 78: generated faceted search reports with one column per foreign key, the faceted search's total row count, Show all and Yes/No values, one search field, friendly headings and number formats in generated grids and master-detail pages, friendly names in the Create Application wizard's page list; sprint 77: the Page Designer's layout and tree by display position, button positions, the tree's context menu with Duplicate and Copy to other page, Show Common / Show All, Go to group and the Template Options dialog; display positions, button positions and side-column page templates at runtime; sprint 76: the interactive report's menus and pagination, date items in the date format; sprint 75: the SQL Workshop's Object Browser and tabs; sprint 74: the builder's information architecture: Shared Components grid, Settings tabs, application home search and tasks; sprint 73: the Create Application wizard on one page with page types and features; sprint 72: the runtime chrome compared with APEX 26.2's: the developer toolbar, the Iris look, the navigation bar's Help menu and Install button; sprint 71: generated applications compared with APEX 26.2's: labels, foreign key names in reports, file columns, format masks, the Home page and the dashboard; sprint 70: treemap, sunburst and timeline charts; sprint 69: dragging tasks on a Gantt chart; sprint 68: the Data Reporter's welcome page, Find my workspace; sprint 67: REST source catalogs from OpenAPI documents, a workspace's export and import (two rows added); sprint 66: a blueprint from an existing application; sprint 65: facet charts; sprint 64: approval vacation rules and expiration policies; sprint 63: range, box plot and stock charts; sprint 62: workspace preferences (SQL Workshop and RESTful services per workspace), extension links, Manage backups across applications, SQL Workshop utilities with object reports, About Database and a database monitor; sprint 61: the builder's screens compared with APEX 26.1: the workspace sign-in page, the Administration menu with workspace message, environment banner and utilization, the SQL Workshop home, the App Gallery, application groups and cross application reports (four rows added); sprint 60: isolated workspaces with their own database logins, row-level security on pgkiln's tables and workspace database roles, workspace administrators; sprint 59: the Page Designer's help pane, Quick edit from the developer toolbar; sprint 58: page groups; sprint 57: region templates hero, title bar, buttons container, inline dialog and drawer, wizard with wizard progress, the carousel; sprint 56: Generate DDL and Schema Comparison in the SQL Workshop, `pgkiln ddl` and `pgkiln compare`; sprint 55: an editable login page with a Login region and the Minimal page template, Forgot password through the application's mail service; sprint 54: interactive grid views, the single row view, group by and chart; sprint 53: application settings, user preferences and items kept per user, dynamic translations, `meta.data_export` and data export downloads, display image and geocoded address items; sprint 52: every dynamic action event and action, Ajax callbacks, an error handling function, the session timeout warning; sprint 51: checked imports, application backups, availability and Run only, feedback, type-specific attribute help; sprint 50: lost update detection, warn on unsaved changes, the URL and search regions with search configurations, the developer toolbar with a session state viewer, and e-mail through SMTP with OAuth2, Microsoft Graph, Amazon SES and HTTP APIs; import checks, application availability, property help and e-mail compared again; 2026-10-06: pgkiln 0.31.0, in progress: static application files and the Execute JavaScript dynamic action; region, item, dynamic action and process plug-ins; conditional and dynamic theme styles; XML and Excel in `meta.parse_data`, zips in SQL, `meta.v_boolean`; file items in S3-compatible object storage; map layers by the visible area and as vector tiles; a graphical query builder; tenants for workflows and tasks; application files as YAML and region static IDs; Lucide icons and icon modifiers; PWA push notifications; 0.30.0: 136 icons and an icon picker; an axe-core accessibility audit; cropping pictures; session sharing between applications; twenty-two built-in languages; 0.29.0: workspaces; the Iris base style; drawers; built-in template components including the metric card; Theme Roller dark-mode colours, live preview and template options on items and report columns; report selection across pages; instance settings; fourteen built-in languages; 0.28.0: AI with Claude and OpenAI; 0.27.0: Data Reporter; sample data generator; create application from several sheets, pasted data or existing tables; 0.26.0: working copies with a three-way merge; theme, library and boilerplate applications with subscriptions; 0.25.0: Gantt, pyramid and polar charts; map layers, clustering and server-side spatial filters; REST data sources that write back from forms and grids and synchronise into tables, OAuth2 password and refresh-token grants; debug messages per request and an install/upgrade log; `meta.web_request()` and `meta.parse_data()`; Theme Roller style variants and template options; 0.24.0: automations with several actions, error handling per row and runs from SQL; invoke-API workflow steps; Unload Data in the Data Workshop; create page wizards for cards, calendar, chart, map, faceted search, form and master-detail; create an application from a file; 0.23.0: interactive grid aggregates, frozen/moved/resized columns, layouts and saved grid reports, master-detail, row actions and copy/paste; download processes, execution chains in the background, workflow processes, branches to a function's URL or another app, the Dialog Closed event; number format masks, automatic time zone, runtime messages in German, French and Spanish; SQL scripts, Quick SQL, a query builder, XML loading and data load definitions; custom authentication, lists, page and application locks with developer comments, supporting objects; 0.22.0: keyset paging, report PDFs and REST collections streamed from a cursor, database-account authentication; 0.21.0: HTTP-header authentication behind a reverse proxy; 0.20.0: a popup list of values with server-side search; 0.19.0: row-range pagination, maximum row counts and row limits, lazy loading and caching of regions, streamed CSV/Excel downloads; 0.18.0: calendar week/day/list views with drag and drop, bubble/gauge/funnel/radar charts and drill-down, smart filters, a region display selector and more facet types, computations, conditional branches, build options, menu buttons, REST data sources and web credentials, rich text/Markdown, rating, combobox, date range and QR code items; 0.17.0: an App Builder home, workspace dashboard and utilities like APEX's; 0.16.0: a Page Designer with drag-and-drop layout, a code editor with autocomplete, template components and plug-ins, parallel branches and versions of workflows, the `pgkiln` command line with one file per component; 0.15.0: drop and paste files, heat maps, filtering a report by the map area; 0.14.0: stacked, combo, scatter and pie charts, several files per upload item; 0.13.0: map and tree regions; 0.12.0: REST modules in the builder; 0.11.0: workflows and Progressive Web Apps; 0.10.0: LDAP, SAML, "Keep me signed in", document templates, JSON loading, approvals and the task list; pgkiln installs no application, HR is an example).
11
11
 
12
12
  ## At a glance
13
13
 
@@ -343,7 +343,7 @@ AI and row level security badges.
343
343
  | Database Actions | pgkiln | |
344
344
  |---|---|---|
345
345
  | SQL worksheet: navigator, editor, output tabs, status bar | SQL Workshop → SQL Worksheet (sprint 91): navigator by schema and object type with columns, drag and drop and SELECT / INSERT / UPDATE / DELETE; Query Result, Script Output, Notices (DBMS Output), Explain Plan, Autotrace, SQL History; resizable panes, fullscreen | ✅ |
346
- | Run Statement (Ctrl+Enter), Run Script (F5) | The statement at the cursor or the selection; a script with a log per statement (psql command tags, error line and column), stop or continue on error; Run as an application's role | ✅ |
346
+ | Run Statement (Ctrl+Enter), Run Script (F5) | The statement at the cursor or the selection; a script with a log per statement (psql command tags, error line and column), stop or continue on error; Run as an application's role. (sprint 107) Beyond Database Actions, which commits every statement: a worksheet tab in **Transaction** mode keeps its statements in one transaction until Commit or Rollback, with a badge for the open transaction; rolled back after an idle timeout, on sign-out, when the tab closes or the server stops | ✅ |
347
347
  | Explain Plan (F10), Autotrace (F6) | A tree of steps (sprint 92): cost, rows, conditions; with Autotrace (`EXPLAIN ANALYZE, BUFFERS`, rolled back) actual time, rows, loops, buffers, each step's own time, the slowest step and 10× misestimates; the text plan too | ✅ |
348
348
  | Query Result grid (paging, download, sharing) | 500 rows (All rows: 10,000) with row numbers, numbers right-aligned, sort, a value dialog, copy, Download as CSV, JSON, XML, Excel or SQL inserts (sprint 92); no sharing links | ✅ |
349
349
  | SQL History, DBMS Output | SQL History per developer with status, rows, time, search and run again; Notices with their time (sprint 92) | ✅ |
@@ -359,4 +359,4 @@ AI and row level security badges.
359
359
  | Launchpad, Search Database (Ctrl+K) | The SQL Workshop home as a Launchpad (sprint 96): pinned and recently visited, Development / Administration / Monitoring tabs; Search (Ctrl+K) for tools, applications, pages and database objects; no guided walk-through | ✅ |
360
360
  | Data Pump | Schema Export / Import (sprint 103): `pg_dump` of a schema (custom or plain format, definitions and / or data, include / exclude tables) and `pg_restore` of a one-schema archive into a new or existing schema (create schema as: renamed in one transaction), background jobs with status, size, duration and log, files kept N days; plus application backups and Unload Data. Plain dumps can't be imported here; one schema per job | ✅ |
361
361
  | Liquibase | Schema Comparison; (sprint 106) SQL Workshop → **Change Log**: DDL run from the SQL Worksheet, Table Properties and Schema Comparison (*Apply and record*) is recorded as change sets per schema (author, time, SQL, source, a stable number), downloaded as Flyway files (`V0001__add_bonus.sql`), a Liquibase formatted SQL changelog or a plain script, and marked against the latest export of an application. **Missing:** rollback blocks, preconditions and contexts; DDL run outside the SQL Workshop (psql, migrations) is not recorded | ✅ |
362
- | JavaScript (MLE) | ➖ Not planned: PostgreSQL has plv8 as an extension | ➖ |
362
+ | JavaScript (MLE) | ➖ Not planned: PostgreSQL has plv8 as an extension; where it is installed, plv8 functions are written in the SQL Worksheet like any other ([chapter 3](guide/03-builder.md#sql-workshop)) | ➖ |
@@ -169,6 +169,9 @@ which is read at startup; real environment variables take precedence.
169
169
  | `SAMPLE_DATA_STATEMENT_TIMEOUT` | `5min` | Statement timeout of SQL Workshop → Sample Data (each insert of a preview or a run) |
170
170
  | `SAMPLE_DATA_MAX_ROWS` | `100000` | Most rows one Sample Data run generates (all tables together) |
171
171
  | `UNLOAD_STATEMENT_TIMEOUT` | `5min` | Statement timeout of SQL Workshop → Unload Data (each statement: the cursor and every batch of rows) |
172
+ | `WORKSHEET_TXN_IDLE_SECONDS` | `300` | SQL Worksheet transaction mode: seconds without a run before an open transaction is rolled back (10 to 86400) |
173
+ | `WORKSHEET_TXN_MAX_PER_DEVELOPER` | `3` | Open worksheet transactions per developer (each holds a database connection) |
174
+ | `WORKSHEET_TXN_MAX` | `20` | Open worksheet transactions on the server |
172
175
  | `REGION_CACHE_MAX_ENTRIES` | `1000` | Most regions in the [region cache](04-pages-and-regions.md#large-tables) of one server process (`0` turns caching off) |
173
176
  | `REGION_CACHE_MAX_MB` | `64` | Memory for the region cache of one server process |
174
177
  | `AUTOMATIONS` | on | `off` stops this server from running [automations](06-processing.md#automations) |
@@ -235,7 +235,9 @@ On phones the rail gets narrower and the breadcrumb shows only the current page.
235
235
 
236
236
  The builder's look comes from design tokens at the top of `public/builder.css` (sprint 105): CSS custom properties
237
237
  for colours (a warm neutral palette with the kiln's ember for primary buttons, links, focus rings and selections),
238
- surfaces and their shadows, corner radii, the type scale and transitions, in a light and a dark set. The rail, the
238
+ surfaces and their shadows, corner radii, the type scale and transitions, in a light and a dark set; the code editor's syntax colours (`--ce-*`: keywords, strings, numbers, comments, binds,
239
+ quoted names, operators, the matching bracket, the current line, the selection and the line numbers) are tokens there
240
+ too (sprint 108). The rail, the
239
241
  toolbar and the status bar stay dark in both themes. Transitions are switched off when the operating system asks
240
242
  for reduced motion. The builder uses the system's fonts (Inter when it is installed); it loads nothing from
241
243
  other sites.
@@ -704,7 +706,13 @@ handlers, the SQL Workshop and the import box) opens in a small code editor:
704
706
  binds, `&ITEM.` substitutions, `$$` bodies), JSON and HTML (tags, attributes, `&ITEM.` and
705
707
  `{{tags}}`). The language follows the component type: a `static` region's source is HTML, a
706
708
  `regex` validation is plain text, an `execute_sql` dynamic action is PL/pgSQL.
707
- - **Line numbers**, the line and column of the cursor, and the **matching bracket** marked.
709
+ - **Line numbers**, the line and column of the cursor, the **current line** (a band and its number in bold
710
+ while the field has the focus) and the **matching bracket** marked.
711
+ - **Colours from the builder's theme** (sprint 108): keywords take the kiln's ember, types, functions, strings,
712
+ numbers, binds and quoted names cool hues, comments a muted grey, each at least 4.5:1 (WCAG AA) on the editor's
713
+ background in the light and the dark theme. Read-only SQL (the Object Browser's DDL and source tabs, the Data
714
+ Modeler's DDL, generated SQL in Quick SQL, Query Builder, Scheduling, Database Users and the table editor, the SQL
715
+ Monitor's text, a saved chart's query, the Change Log, a script's results) is highlighted the same way.
708
716
  - **Tab / Shift+Tab** indent and outdent (the selected lines, too); **Enter** keeps the
709
717
  indentation and indents after `(`, `begin`, `loop`, `then`; brackets and quotes are closed for
710
718
  you and typing the closer steps over it. Press **Escape, then Tab** to move on to the next field.
@@ -1381,11 +1389,41 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
1381
1389
  (**Ctrl + F**, **Ctrl + H**) with a regular expression or exact case, **Go to line** (**Ctrl + G**), and
1382
1390
  **Ctrl + /** comments the selected lines out or in. The **?** menu lists every key; **F1** opens this help. The
1383
1391
  upload button opens Load Data for the navigator's schema.
1384
- - Each statement commits on its own. Statements run as the **owner connection** (an isolated workspace's
1392
+ - Each statement commits on its own (**Autocommit**, like Database Actions). Statements run as the **owner connection** (an isolated workspace's
1385
1393
  developer login for its developers), on a connection of their own that is closed afterwards, so `SET ROLE` or
1386
1394
  `SET search_path` doesn't leak. **Run as** picks an application of your workspace instead: the statements then
1387
1395
  run as its database role, with `pgkiln.app_id` set, so its grants and row level security policies apply. Use
1388
- it to test policies; it is no security boundary, since the SQL could `RESET ROLE`.
1396
+ it to test policies; it is no security boundary, since the SQL could `RESET ROLE`. A `BEGIN` typed in
1397
+ Autocommit lasts for the run only: `begin; …; commit;` in one Run Script works, but a transaction still open at
1398
+ the end of the run is rolled back, with a warning under *Notices*.
1399
+ - (sprint 107) **Transaction mode** (more than Database Actions, which always autocommits): the toolbar's
1400
+ **Commit** menu switches a worksheet tab between *Autocommit* and *Transaction*. In Transaction mode the tab's
1401
+ statements (Run Statement and Run Script) stay in one transaction on a connection of its own until you press
1402
+ **Commit** or **Rollback**: a SELECT in the same tab sees the changes, other sessions (and your other tabs) don't
1403
+ until you commit. A badge shows *Transaction open*, the number of statements and its age; after a reload it shows
1404
+ the server's real state, and leaving the page with an open transaction asks first.
1405
+ - `COMMIT` or `ROLLBACK` typed in the editor end the transaction too (the next run starts a new one); a `BEGIN`
1406
+ typed inside it only warns. Statements PostgreSQL refuses inside a transaction (`VACUUM`, `CREATE INDEX
1407
+ CONCURRENTLY`, `ALTER SYSTEM`, `CREATE DATABASE`, …) are refused before they run, so they can't abort it.
1408
+ - A statement that fails leaves the transaction **aborted** (*Transaction failed*): every later statement fails
1409
+ until **Rollback**; Commit then rolls back as well, and says so.
1410
+ - **Explain Plan** and **Autotrace** run inside the open transaction behind a savepoint: the plan sees its changes,
1411
+ Autotrace's own changes are undone and the transaction stays as it was.
1412
+ - **Run as**: the transaction keeps the role it started with. Changing *Run as* while it is open is refused:
1413
+ commit or roll back first. `SET ROLE` typed in the editor reaches only the roles of the connection's login, as
1414
+ in Autocommit.
1415
+ - DDL reaches the **Change Log** when the transaction commits, never when it is rolled back. SQL History records
1416
+ each statement as it runs.
1417
+ - The transaction is **rolled back** when it is left without a run for `WORKSHEET_TXN_IDLE_SECONDS` (default
1418
+ 300, five minutes; the badge and the next run say so), when you close its worksheet tab or switch it to
1419
+ Autocommit (after asking), sign out, switch workspaces, and when the server stops. The database ends the
1420
+ connection itself a minute later (`idle_in_transaction_session_timeout`) should the server not.
1421
+ - Each open transaction holds a database connection outside the pools: a developer has at most
1422
+ `WORKSHEET_TXN_MAX_PER_DEVELOPER` (default 3) and the server `WORKSHEET_TXN_MAX` (default 20); past that a run in
1423
+ Transaction mode is refused. A transaction belongs to the builder session, workspace and worksheet tab that
1424
+ started it: another developer, or another sign-in of yours, never reaches it. It lives in the server's memory,
1425
+ so with several pgkiln servers behind a load balancer the browser must stay on one (sticky sessions).
1426
+ - Without JavaScript the worksheet runs in Autocommit only.
1389
1427
  - With script, the panes fill the window. Drag the splitters (or focus one and use the arrow keys) to resize
1390
1428
  them, hide the navigator, or use **Fullscreen** to see only the editor (**Escape** leaves). Sizes are
1391
1429
  remembered in the browser. Without script, the buttons post the form and the panes stack; Run Statement then
@@ -1453,8 +1491,9 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
1453
1491
  when the foreign key may be empty. A box's name opens **Table Properties** (a view: the Object
1454
1492
  Browser). The toolbar: **Save** (Ctrl+S), **Undo** / **Redo** (Ctrl+Z, Ctrl+Y), **Zoom out** / **Zoom
1455
1493
  in** (or Ctrl+wheel), **Fit**, **Auto layout** (referenced tables to the left of the tables that
1456
- reference them; undoable), a **Mini-map** (click or drag in it to move around), **SVG** and **PNG**
1457
- exports of the diagram as shown, **Print**, **Generate DDL** (the CREATE statements of the shown
1494
+ reference them; undoable), a **Mini-map** (click or drag in it to move around; the button shows when it is on),
1495
+ **SVG** and **PNG** exports of the diagram as shown (in light colours, whichever theme the builder uses; on screen the
1496
+ boxes, lines and mini-map follow the light or dark theme), **Print**, **Generate DDL** (the CREATE statements of the shown
1458
1497
  objects with their keys, indexes, triggers, row level security, policies, comments and grants: to
1459
1498
  download or open in the SQL Worksheet) and **Data dictionary** (each object's columns with type,
1460
1499
  nullability, default, keys and comments, its constraints and what references it; to print, save as
@@ -1526,6 +1565,10 @@ the SQL Workshop's connection may use. Without JavaScript the header's field ope
1526
1565
  **Flyway** versioned migrations (`V0001__add_bonus.sql`; several in a zip), a **Liquibase** formatted SQL changelog
1527
1566
  (`--liquibase formatted sql`, `--changeset author:0001-add_bonus`) or one plain SQL script; each change set also
1528
1567
  has its own Flyway file. Change sets belong to the workspace and are not part of an application export.
1568
+ - **JavaScript (MLE)**: not planned. Database Actions has a JavaScript tool for Oracle's Multilingual Engine;
1569
+ PostgreSQL runs JavaScript in the database only through the [plv8](15-extensions.md) extension. Where plv8 is
1570
+ installed, write `create function … language plv8` in the SQL Worksheet like any other function: the navigator,
1571
+ the Object Browser and Quick DDL show it. pgkiln adds no JavaScript editor of its own.
1529
1572
  - **Utilities** (`/builder/sql/utilities`; APEX: SQL Workshop → Utilities): tiles for Load and Unload Data, Sample
1530
1573
  Data, the Query Builder, DDL and Compare, and three pages of their own. Each runs in a read-only transaction with a
1531
1574
  15-second statement timeout, on the SQL Workshop's connection (an isolated workspace's developers see only the
@@ -68,7 +68,12 @@ src/
68
68
  xml.ts safe XML reader (no DTDs or entities, limits) and xmlTable(): rows from a repeating element (unit tested)
69
69
  sqlscript.ts SQL scripts: splitScript() (statements, line numbers and offsets, psql commands), runScript() (stop/continue, transaction, savepoints)
70
70
  sqlworksheet.ts (sprint 91) the worksheet's runs: pickStatements() (at the cursor, a selection, all), runStatements() (a log per
71
- statement, psql command tags, notices, error line and column), explainStatement() (EXPLAIN / rolled-back ANALYZE)
71
+ statement, psql command tags, notices, error line and column), explainStatement() (EXPLAIN / rolled-back ANALYZE;
72
+ a savepoint inside a worksheet transaction)
73
+ worksheet-txn.ts (sprint 107) the worksheet's transaction mode: an in-memory registry of pinned pg.Clients per (builder session,
74
+ worksheet tab), beginTxn() / endTxn() (caps per developer and server), accountRun() (statement count, DDL kept for
75
+ the Change Log until COMMIT), outsideTxnOnly(), sweepTxns() (idle timeout, ended sessions); onSessionEnd and
76
+ onClosePools roll back; WORKSHEET_TXN_IDLE_SECONDS / _MAX_PER_DEVELOPER / _MAX
72
77
  datamodel.ts (sprint 98) Data Modeler diagrams: readModel() (catalog), boxSize(), fkPath() (crow's feet), autoLayout(), diagramSvg()
73
78
  changelog.ts (sprint 106, migration 118) the change log: isSchemaDdl(), ddlTarget() (schema and object), changeName()
74
79
  (add_bonus, create_index_x), recordChanges() (grouped per schema), Flyway / Liquibase / plain SQL writers
@@ -249,7 +254,8 @@ src/
249
254
  worksheet's Chart tab, SQL Workshop → Charts (meta.sql_chart, 110; read-only runs)
250
255
  sql-tools.ts (sprint 96) SQL_TOOLS: every SQL Workshop tool with its group, tab and description (home, More menu, search)
251
256
  worksheet.ts (sprint 91) the SQL Worksheet (Database Actions' SQL; /sql/commands too): navigator (pickSchema, objects with
252
- columns, objectStatements), toolbar, output tabs, history (meta.sql_history, 108), plan trees, Run as an app's role, (sprint 93) Save / Rename / Download as SQL Scripts, bind and substitution values, POST /sql/worksheet/format; GET /sql/worksheet/navigator
257
+ columns, objectStatements), toolbar, output tabs, history (meta.sql_history, 108), plan trees, Run as an app's role, (sprint 93) Save / Rename / Download as SQL Scripts, bind and substitution values, POST /sql/worksheet/format; GET /sql/worksheet/navigator;
258
+ (sprint 107) transaction mode: the txn field, Commit / Rollback (mode=commit|rollback), txnBadge(), GET/POST /sql/worksheet/txn (JSON)
253
259
  object-browser.ts (sprint 75) the Object Browser: objects by type, system objects hidden, a table in tabs, column actions as SQL to review
254
260
  table-editor.ts (sprint 95) Table Properties: GET/POST /sql/objects/table (create, edit ?o=, ?template=), fromForm(), Preview / Apply
255
261
  (one transaction) / Open in the worksheet
@@ -339,14 +345,18 @@ src/
339
345
  public/
340
346
  app.css theme (light/dark, responsive; --font, --font-size, --radius for style variants; template option classes to-*)
341
347
  app.js client runtime: dialogs (dialog_closed actions), popup LOVs, dynamic actions (focus, classes, messages), grids (add/duplicate rows, master-detail refresh, move/resize columns, copy/paste of cell ranges), menus, lazy regions, maps (Leaflet layers, marker clusters, heat layer, layer legend, area/distance filter) (no inline JS)
342
- code-editor.js, .css builder code editor: enhances <textarea data-code>, highlighting, suggestions (no dependencies)
348
+ code-editor.js, .css builder code editor: enhances <textarea data-code>, highlighting, suggestions (no dependencies);
349
+ (sprint 108) the current line, and read-only <pre data-code-view="sql|plpgsql|json|html"> highlighted;
350
+ its colours are the --ce-* tokens in builder.css
343
351
  palette.js (sprint 96) the builder's search dialog (Ctrl+K), recently visited SQL Workshop pages, the Launchpad's tabs
344
352
  sql-monitor.js (sprint 102) the SQL Monitor: reloads the sessions' live part every 5 / 15 / 60 s, Pause (localStorage pgkiln.sqlMonitor)
345
353
  data-modeler.js, .css (sprint 98) the Data Modeler: drag boxes, undo/redo, save, zoom/fit, auto layout, mini-map, SVG/PNG export, print
346
354
  worksheet.js, .css (sprint 91) the SQL Worksheet: run keys with the cursor, output tabs, navigator swap and search, drag and drop, splitters;
347
- (92) grid sort, value dialog, history filter; (93) worksheet tabs in localStorage, Files, binds dialog, format, find, case
355
+ (92) grid sort, value dialog, history filter; (93) worksheet tabs in localStorage, Files, binds dialog, format, find, case;
356
+ (107) Autocommit / Transaction per tab, the badge from the server, beforeunload, rollback on closing a tab
348
357
  builder.css builder only: IDE look (dark chrome, icon rail, panes); design tokens at the top (colour,
349
- elevation, radius, type, motion; light and dark sets, sprint 105), then the shared controls
358
+ elevation, radius, type, motion; light and dark sets, sprint 105; code editor --ce-*, sprint 108),
359
+ then the shared controls
350
360
  builder.js builder only: tabs, component tree, property filter, drag and drop on the layout
351
361
  builder-icons.svg builder only: icons of the rail, toolbar and designer (b-*); b-kiln is the brand mark (brandMark() in ui.ts)
352
362
  test/
@@ -377,6 +387,8 @@ test/
377
387
  object-actions.test.ts (sprint 94) object menus: Quick DDL, Drop with dependents, Add index / trigger / policy, the panel, not-found
378
388
  data-modeler.test.ts (sprint 98) Data Modeler: "hr core" with its FK lines, saved positions, SVG, objects, DDL, dictionary, geometry
379
389
  worksheet.test.ts (sprint 91) the SQL Worksheet: statement at the cursor, Run Script log, plans, notices, history, navigator, Run as
390
+ worksheet-txn.test.ts (sprint 107) transaction mode: the tab's transaction, Commit / Rollback, typed COMMIT, aborted, idle timeout, refusals,
391
+ Explain in it, Change Log at COMMIT, the JSON endpoint, sign-out
380
392
  quicksql.test.ts Quick SQL parser and DDL generator
381
393
  xml.test.ts XML reader: rows, attributes, paths, refused DTDs and entities, limits
382
394
  printing.test.ts report PDFs
@@ -422,9 +434,10 @@ test/
422
434
  ai-mock.ts a local mock of the Claude Messages API (SSE stream) and OpenAI Chat Completions
423
435
  helpers.ts a cookie-keeping test browser
424
436
  e2e/responsive.test.ts browser tests at phone/tablet/desktop widths (Playwright)
425
- e2e/code-editor.test.ts the code editor in a browser: highlighting, keys, suggestions, touch, screen readers
437
+ e2e/code-editor.test.ts the code editor in a browser: highlighting, keys, suggestions, touch, screen readers, syntax colours at AA in both themes (sprint 108)
426
438
  e2e/data-modeler.test.ts (sprint 98) the Data Modeler in a browser: drag, save, reload, undo/redo, zoom, mini-map, exports, phone
427
- e2e/worksheet.test.ts (sprint 91) the SQL Worksheet in a browser: run keys, tabs, navigator, drag and drop, splitters, phone, no JavaScript
439
+ e2e/worksheet.test.ts (sprint 91) the SQL Worksheet in a browser: run keys, tabs, navigator, drag and drop, splitters, phone, no JavaScript;
440
+ (107) transaction mode: badge, reload, Rollback, closing a tab, Autocommit switch, beforeunload
428
441
  e2e/items.test.ts sprint 26 item types in a browser: editors, tags, stars, dates, reveal; without JavaScript
429
442
  e2e/designer.test.ts page designer: panes per width, drag and drop, keyboard, Arrange buttons, builder theme
430
443
  e2e/calendar.test.ts calendar drag and drop and create on click, view switching, chart drill-down
@@ -475,7 +488,7 @@ CI (`.github/workflows/ci.yml`) runs these jobs against PostgreSQL 17:
475
488
  - **test**: typecheck and `npm test` on a fresh database;
476
489
  - **e2e**: the browser tests, uploading the screenshots as an artifact; `test/e2e/accessibility.test.ts` runs
477
490
  axe-core (WCAG 2.1 A and AA rules) on every page of the HR example (light, dark, Iris) and the builder's main pages
478
- and allows no violation;
491
+ (in both builder themes, with the SQL Workshop and the wizards, since sprint 108) and allows no violation;
479
492
  - **docker**: builds the image and starts the compose stack as a user would.
480
493
 
481
494
  - **upgrade**: installs each earlier release (`v0.31.0` …) with its HR example (`git archive <tag> | tar -x`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.49.0",
3
+ "version": "0.50.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
@@ -9,6 +9,8 @@
9
9
  --accent ≥ 4.8:1 on every surface, --muted ≥ 5.6:1, in both themes
10
10
  - elevation: --shadow-xs … --shadow-lg; radius: --radius-sm / --radius / --radius-lg
11
11
  - type: --fs-xs … --fs-xl; motion: --ease and --dur (none under prefers-reduced-motion)
12
+ - code (sprint 108): --ce-* for public/code-editor.js and read-only <pre data-code-view>; every
13
+ syntax colour ≥ 4.5:1 on --ce-bg in both themes (test/e2e/code-editor.test.ts checks it)
12
14
  The light set first, the dark set for data-theme="dark" and for "System" when
13
15
  the OS prefers dark. The chrome (rail, toolbar, status bar) is dark in both
14
16
  themes (the same colours), a shade deeper than the page in the dark one. */
@@ -59,10 +61,31 @@
59
61
  --block: #ffffff;
60
62
  --block-head: #f7f5f2;
61
63
  --code-bg: #fbfaf8;
64
+ --field-border: var(--border-strong);
65
+
66
+ /* code editor (sprint 108, public/code-editor.js): every token colour is at least 4.5:1 on --ce-bg
67
+ (keywords take the ember; the others cool hues so they stay apart) */
62
68
  --ce-bg: #fdfcfb;
63
69
  --ce-gutter: #f5f3f0;
64
70
  --ce-gutter-text: #6b645d;
65
- --field-border: var(--border-strong);
71
+ --ce-gutter-active: #1c1917;
72
+ --ce-text: #1c1917;
73
+ --ce-kw: #b23a0a;
74
+ --ce-type: #0e6b66;
75
+ --ce-fn: #2457a6;
76
+ --ce-str: #3a7516;
77
+ --ce-num: #8a3ea0;
78
+ --ce-com: #736c66;
79
+ --ce-bind: #b02a5c;
80
+ --ce-qid: #80590a;
81
+ --ce-op: #5c5650;
82
+ --ce-tag: #2457a6;
83
+ --ce-attr: #b23a0a;
84
+ --ce-err: #c0262d;
85
+ --ce-match: rgb(234 88 12 / 16%);
86
+ --ce-match-ring: rgb(194 65 12 / 55%);
87
+ --ce-line: rgb(28 25 23 / 4.5%);
88
+ --ce-select: rgb(234 88 12 / 20%);
66
89
 
67
90
  /* shape, elevation, type, motion */
68
91
  --radius-sm: 6px;
@@ -91,7 +114,10 @@
91
114
  --bg: #181715; --surface: #1f1d1b; --surface-2: #242220; --surface-3: #2d2b28; --text: #edebe8; --muted: #a8a19a;
92
115
  --border: #312e2b; --border-strong: #423e39; --accent: #ff9152; --accent-text: #1a0b03; --accent-soft: #3a1f12; --ring: rgb(255 145 82 / 30%); --sel-bg: #4a2816; --sel-bar: #ff9152;
93
116
  --gold: #ff9152; --canvas: #151412; --canvas-dot: #2a2825; --block: #222120; --block-head: #292725; --code-bg: #1a1917; --warn: #e0a740;
94
- --ce-bg: #1a1917; --ce-gutter: #1f1d1b; --ce-gutter-text: #8f8880;
117
+ --ce-bg: #1a1917; --ce-gutter: #1f1d1b; --ce-gutter-text: #8f8880; --ce-gutter-active: #e9e6e3; --ce-text: #e9e6e3;
118
+ --ce-kw: #ff9152; --ce-type: #5cc8bd; --ce-fn: #8ab4ff; --ce-str: #a5d68a; --ce-num: #d4a8ff; --ce-com: #938b83; --ce-bind: #ff8fb8;
119
+ --ce-qid: #e6c26a; --ce-op: #b8b0a8; --ce-tag: #8ab4ff; --ce-attr: #ff9152; --ce-err: #ff7a70;
120
+ --ce-match: rgb(255 145 82 / 22%); --ce-match-ring: rgb(255 145 82 / 60%); --ce-line: rgb(255 255 255 / 4.5%); --ce-select: rgb(255 145 82 / 28%);
95
121
  --shadow-xs: 0 1px 1px rgb(0 0 0 / 30%);
96
122
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%), inset 0 1px 0 rgb(255 255 255 / 3%);
97
123
  --shadow-md: 0 4px 16px -2px rgb(0 0 0 / 50%), inset 0 1px 0 rgb(255 255 255 / 4%);
@@ -105,7 +131,10 @@
105
131
  --bg: #181715; --surface: #1f1d1b; --surface-2: #242220; --surface-3: #2d2b28; --text: #edebe8; --muted: #a8a19a;
106
132
  --border: #312e2b; --border-strong: #423e39; --accent: #ff9152; --accent-text: #1a0b03; --accent-soft: #3a1f12; --ring: rgb(255 145 82 / 30%); --sel-bg: #4a2816; --sel-bar: #ff9152;
107
133
  --gold: #ff9152; --canvas: #151412; --canvas-dot: #2a2825; --block: #222120; --block-head: #292725; --code-bg: #1a1917; --warn: #e0a740;
108
- --ce-bg: #1a1917; --ce-gutter: #1f1d1b; --ce-gutter-text: #8f8880;
134
+ --ce-bg: #1a1917; --ce-gutter: #1f1d1b; --ce-gutter-text: #8f8880; --ce-gutter-active: #e9e6e3; --ce-text: #e9e6e3;
135
+ --ce-kw: #ff9152; --ce-type: #5cc8bd; --ce-fn: #8ab4ff; --ce-str: #a5d68a; --ce-num: #d4a8ff; --ce-com: #938b83; --ce-bind: #ff8fb8;
136
+ --ce-qid: #e6c26a; --ce-op: #b8b0a8; --ce-tag: #8ab4ff; --ce-attr: #ff9152; --ce-err: #ff7a70;
137
+ --ce-match: rgb(255 145 82 / 22%); --ce-match-ring: rgb(255 145 82 / 60%); --ce-line: rgb(255 255 255 / 4.5%); --ce-select: rgb(255 145 82 / 28%);
109
138
  --shadow-xs: 0 1px 1px rgb(0 0 0 / 30%);
110
139
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%), inset 0 1px 0 rgb(255 255 255 / 3%);
111
140
  --shadow-md: 0 4px 16px -2px rgb(0 0 0 / 50%), inset 0 1px 0 rgb(255 255 255 / 4%);
@@ -1301,3 +1330,32 @@ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
1301
1330
  .rm-main { display: grid; gap: 1rem; min-width: 0; }
1302
1331
  .rm-tree .tree code { font-size: 0.75rem; min-width: 3.4rem; }
1303
1332
  @media (max-width: 760px) { .rm-layout { grid-template-columns: minmax(0, 1fr); } }
1333
+
1334
+ /* ------------------------------------------------------------ page polish (sprint 108): Object Browser, wizards, SQL Monitor */
1335
+ /* Object Browser: the tree in the builder's type scale, the selected object with the ember bar */
1336
+ .ob-folder .tree { font-size: var(--fs-base); }
1337
+ .ob-folder .tree a { padding-block: 0.28rem; }
1338
+ .ob-folder .tree a[aria-current="page"] { background: var(--sel-bg); color: var(--sel-text); box-shadow: inset 2px 0 0 var(--sel-bar); font-weight: 600; }
1339
+ .ob-folder > summary { border-radius: var(--radius-sm); }
1340
+ .ob-folder > summary:hover { background: var(--surface-3); }
1341
+ .ob-folder > summary .icon { color: var(--muted); }
1342
+ /* wizards: the icon picker looks like a select; a colour field is a swatch, not a bar */
1343
+ .ide .icon-picker > summary { border-color: var(--field-border); border-radius: var(--radius-sm); box-shadow: var(--shadow-xs); transition: border-color var(--dur) var(--ease); }
1344
+ .ide .icon-picker > summary:hover { border-color: color-mix(in srgb, var(--text) 22%, var(--border-strong)); }
1345
+ .ide .icon-picker > summary::after {
1346
+ content: ""; width: 14px; height: 14px; margin-left: 0.15rem;
1347
+ background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23857d75' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E") center / 14px no-repeat;
1348
+ }
1349
+ .ide .icon-picker[open] > summary { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring); }
1350
+ .ide .icon-picker-panel { border-color: var(--border-strong); border-radius: var(--radius); box-shadow: var(--shadow-md); background: var(--surface); }
1351
+ .ide .field input[type=color]:not(.swatch) {
1352
+ width: 4.5rem; height: 34px; min-height: 0; padding: 3px; cursor: pointer;
1353
+ border: 1px solid var(--field-border); border-radius: var(--radius-sm); background: var(--surface); box-shadow: var(--shadow-xs);
1354
+ }
1355
+ .ide .field input[type=color]::-webkit-color-swatch-wrapper { padding: 0; }
1356
+ .ide .field input[type=color]::-webkit-color-swatch { border: 0; border-radius: 4px; }
1357
+ .ide .field input[type=color]::-moz-color-swatch { border: 0; border-radius: 4px; }
1358
+ /* SQL Monitor: the refresh controls on one row */
1359
+ .sm-toolbar:not([hidden]) { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin: 0.25rem 0 0.75rem; }
1360
+ .sm-toolbar select { width: auto; }
1361
+ .sm-toolbar [aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); }
@@ -2,79 +2,23 @@
2
2
  transparent and lies exactly over the highlighted copy (.ce-code), so both
3
3
  must share font, size, line height, padding and tab size. */
4
4
  :root {
5
- --ce-bg: #fbfcfd;
6
- --ce-gutter: #f1f3f6;
7
- --ce-gutter-text: #5d6876;
8
- --ce-text: #1b2330;
9
- --ce-kw: #8b2bb9;
10
- --ce-type: #0b6e8a;
11
- --ce-fn: #1d5fc4;
12
- --ce-str: #1d7a3a;
13
- --ce-num: #b35400;
14
- --ce-com: #6b7685;
15
- --ce-bind: #b0306a;
16
- --ce-qid: #7a5b00;
17
- --ce-tag: #1d5fc4;
18
- --ce-attr: #8b2bb9;
19
- --ce-err: #c23028;
20
- --ce-match: rgb(11 99 197 / 18%);
21
- --ce-select: rgb(11 99 197 / 22%);
5
+ /* the colours (--ce-bg, --ce-kw, …, --ce-line, --ce-select) are tokens in builder.css, light and dark */
22
6
  --ce-font: 0.84rem;
23
7
  --ce-lh: 20px; /* whole pixels: fractional line heights drift apart over thousands of lines */
24
8
  }
25
- @media (prefers-color-scheme: dark) {
26
- :root:not([data-theme="light"]) {
27
- --ce-bg: #12161d;
28
- --ce-gutter: #171c24;
29
- --ce-gutter-text: #8f99a8;
30
- --ce-text: #e3e7ed;
31
- --ce-kw: #d39bff;
32
- --ce-type: #5fd0e6;
33
- --ce-fn: #82b6ff;
34
- --ce-str: #8fd694;
35
- --ce-num: #ffb46b;
36
- --ce-com: #8591a3;
37
- --ce-bind: #ff8cc0;
38
- --ce-qid: #e8c66a;
39
- --ce-tag: #82b6ff;
40
- --ce-attr: #d39bff;
41
- --ce-err: #ff7a70;
42
- --ce-match: rgb(105 164 255 / 25%);
43
- --ce-select: rgb(105 164 255 / 30%);
44
- }
45
- }
46
- :root[data-theme="dark"] {
47
- --ce-bg: #12161d;
48
- --ce-gutter: #171c24;
49
- --ce-gutter-text: #8f99a8;
50
- --ce-text: #e3e7ed;
51
- --ce-kw: #d39bff;
52
- --ce-type: #5fd0e6;
53
- --ce-fn: #82b6ff;
54
- --ce-str: #8fd694;
55
- --ce-num: #ffb46b;
56
- --ce-com: #8591a3;
57
- --ce-bind: #ff8cc0;
58
- --ce-qid: #e8c66a;
59
- --ce-tag: #82b6ff;
60
- --ce-attr: #d39bff;
61
- --ce-err: #ff7a70;
62
- --ce-match: rgb(105 164 255 / 25%);
63
- --ce-select: rgb(105 164 255 / 30%);
64
- }
65
9
  @media (pointer: coarse) {
66
10
  :root { --ce-font: 16px; --ce-lh: 24px; } /* the same as other fields: no zoom on focus in iOS */
67
11
  }
68
12
 
69
13
  .ce {
70
14
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr);
71
- min-width: 0; max-width: 100%; border: 1px solid var(--border); border-radius: 6px; background: var(--ce-bg);
15
+ min-width: 0; max-width: 100%; border: 1px solid var(--field-border, var(--border)); border-radius: var(--radius-sm, 6px); background: var(--ce-bg);
72
16
  }
73
- .ce:focus-within { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
17
+ .ce:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring, transparent); }
74
18
  .ce-gutter {
75
19
  --ce-digits: 2;
76
20
  width: calc(var(--ce-digits) * 1ch + 1.1rem); overflow: hidden; position: relative;
77
- background: var(--ce-gutter); border-right: 1px solid var(--border); border-radius: 6px 0 0 0;
21
+ background: var(--ce-gutter); border-right: 1px solid var(--border); border-radius: var(--radius-sm, 6px) 0 0 0;
78
22
  color: var(--ce-gutter-text); user-select: none;
79
23
  }
80
24
  .ce-gutter, .ce .ce-code, .ce textarea.ce-input {
@@ -82,6 +26,11 @@
82
26
  font-variant-ligatures: none; letter-spacing: 0; font-kerning: none;
83
27
  }
84
28
  .ce-nums { position: absolute; top: 0; left: 0; right: 0; white-space: pre; text-align: right; padding: 0.5rem 0.45rem 0 0; will-change: transform; }
29
+ /* the caret's line (sprint 108): a band behind the text and its number in the gutter, while the editor has the focus */
30
+ .ce-cur, .ce-cur-num { position: absolute; left: 0; right: 0; top: 0; height: var(--ce-lh); will-change: transform; display: none; }
31
+ .ce-cur { background: var(--ce-line); }
32
+ .ce-cur-num { padding-right: 0.45rem; text-align: right; color: var(--ce-gutter-active); background: var(--ce-gutter); font-weight: 650; }
33
+ .ce:focus-within :is(.ce-cur, .ce-cur-num):not([hidden]) { display: block; }
85
34
  .ce-main { position: relative; min-width: 0; }
86
35
  .ce .ce-hl { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
87
36
  .ce .ce-code {
@@ -99,29 +48,33 @@
99
48
  .ce textarea.ce-input:focus-visible { outline: none; }
100
49
  .ce textarea.sql-editor { min-height: 18rem; }
101
50
 
102
- /* tokens */
103
- .ce-code .t-kw { color: var(--ce-kw); font-weight: 600; }
104
- .ce-code .t-type { color: var(--ce-type); }
105
- .ce-code .t-fn { color: var(--ce-fn); }
106
- .ce-code .t-str { color: var(--ce-str); }
107
- .ce-code .t-key { color: var(--ce-fn); }
108
- .ce-code .t-num { color: var(--ce-num); }
109
- .ce-code .t-com { color: var(--ce-com); font-style: italic; }
110
- .ce-code .t-bind, .ce-code .t-sub { color: var(--ce-bind); font-weight: 600; }
111
- .ce-code .t-qid { color: var(--ce-qid); }
112
- .ce-code .t-dol { color: var(--ce-str); font-weight: 600; }
113
- .ce-code .t-tag { color: var(--ce-tag); }
114
- .ce-code .t-attr { color: var(--ce-attr); }
115
- .ce-code .t-ent { color: var(--ce-num); }
116
- .ce-code .t-err { color: var(--ce-err); text-decoration: wavy underline; }
117
- .ce-code .t-op, .ce-code .t-pun, .ce-code .t-br, .ce-code .t-id { color: var(--ce-text); }
118
- .ce-code .t-match { background: var(--ce-match); border-radius: 2px; outline: 1px solid var(--ce-match); }
51
+ /* tokens: in the editor and in read-only code (<pre data-code-view>, sprint 108) */
52
+ :is(.ce-code, .ce-view) .t-kw { color: var(--ce-kw); font-weight: 600; }
53
+ :is(.ce-code, .ce-view) .t-type { color: var(--ce-type); }
54
+ :is(.ce-code, .ce-view) .t-fn { color: var(--ce-fn); }
55
+ :is(.ce-code, .ce-view) .t-str { color: var(--ce-str); }
56
+ :is(.ce-code, .ce-view) .t-key { color: var(--ce-fn); }
57
+ :is(.ce-code, .ce-view) .t-num { color: var(--ce-num); }
58
+ :is(.ce-code, .ce-view) .t-com { color: var(--ce-com); font-style: italic; }
59
+ :is(.ce-code, .ce-view) .t-bind, :is(.ce-code, .ce-view) .t-sub { color: var(--ce-bind); font-weight: 600; }
60
+ :is(.ce-code, .ce-view) .t-qid { color: var(--ce-qid); }
61
+ :is(.ce-code, .ce-view) .t-dol { color: var(--ce-str); font-weight: 600; }
62
+ :is(.ce-code, .ce-view) .t-tag { color: var(--ce-tag); }
63
+ :is(.ce-code, .ce-view) .t-attr { color: var(--ce-attr); }
64
+ :is(.ce-code, .ce-view) .t-ent { color: var(--ce-num); }
65
+ :is(.ce-code, .ce-view) .t-err { color: var(--ce-err); text-decoration: wavy underline; }
66
+ :is(.ce-code, .ce-view) .t-op { color: var(--ce-op); }
67
+ :is(.ce-code, .ce-view) .t-pun, :is(.ce-code, .ce-view) .t-br, :is(.ce-code, .ce-view) .t-id { color: var(--ce-text); }
68
+ .ce-code .t-match { background: var(--ce-match); border-radius: 2px; outline: 1px solid var(--ce-match-ring); }
69
+
70
+ pre.ce-view { background: var(--ce-bg); color: var(--ce-text); border-color: var(--border); }
71
+ pre.ce-view::selection, pre.ce-view ::selection { background: var(--ce-select); }
119
72
 
120
73
  /* status bar: language, hint, caret position, check */
121
74
  .ce-bar {
122
75
  grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem 0.75rem;
123
76
  padding: 0.2rem 0.5rem; border-top: 1px solid var(--border); background: var(--ce-gutter);
124
- border-radius: 0 0 6px 6px; font-size: 0.75rem; color: var(--muted); min-width: 0;
77
+ border-radius: 0 0 var(--radius-sm, 6px) var(--radius-sm, 6px); font-size: 0.75rem; color: var(--muted); min-width: 0;
125
78
  }
126
79
  .ce-lang { font-weight: 650; letter-spacing: 0.02em; }
127
80
  .ce-hint { flex: 1 1 12rem; min-width: 0; }
@@ -138,7 +91,7 @@
138
91
  position: absolute; z-index: 30; left: 0; top: 0; margin: 0; padding: 0.25rem 0; list-style: none;
139
92
  width: max-content; min-width: 14rem; max-width: min(34rem, calc(100% - 0.5rem)); max-height: 15rem; overflow: auto;
140
93
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: 6px;
141
- box-shadow: 0 8px 24px rgb(16 24 40 / 18%); font-size: 0.82rem;
94
+ box-shadow: var(--shadow-lg, 0 8px 24px rgb(16 24 40 / 18%)); font-size: 0.82rem;
142
95
  }
143
96
  .ce-opt { display: flex; align-items: baseline; gap: 0.75rem; padding: 0.2rem 0.6rem 0.2rem 0.4rem; cursor: pointer; white-space: nowrap; }
144
97
  .ce-opt::before {