pgkiln 0.46.0 → 0.48.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.
Files changed (50) hide show
  1. package/db/migrations/108_sql_history.sql +25 -0
  2. package/db/migrations/109_builder_pins.sql +19 -0
  3. package/db/migrations/110_sql_charts.sql +23 -0
  4. package/db/migrations/111_sql_diagram.sql +24 -0
  5. package/db/migrations/113_rest_objects.sql +49 -0
  6. package/docs/apex-feature-parity.md +28 -2
  7. package/docs/guide/03-builder.md +178 -21
  8. package/docs/guide/08-security.md +19 -1
  9. package/docs/guide/10-tutorial.md +1 -1
  10. package/docs/guide/12-development.md +46 -2
  11. package/docs/guide/13-rest-api.md +74 -9
  12. package/docs/guide/16-files.md +2 -2
  13. package/package.json +1 -1
  14. package/public/builder.css +22 -0
  15. package/public/data-modeler.css +56 -0
  16. package/public/data-modeler.js +367 -0
  17. package/public/palette.js +133 -0
  18. package/public/worksheet.css +293 -0
  19. package/public/worksheet.js +669 -0
  20. package/src/app.ts +4 -0
  21. package/src/builder/ai-builder.ts +3 -3
  22. package/src/builder/autorest.ts +362 -0
  23. package/src/builder/data-modeler.ts +382 -0
  24. package/src/builder/db-users.ts +472 -0
  25. package/src/builder/launchpad.ts +140 -0
  26. package/src/builder/object-actions.ts +167 -0
  27. package/src/builder/object-browser.ts +47 -26
  28. package/src/builder/querybuilder.ts +1 -1
  29. package/src/builder/sampledata.ts +2 -2
  30. package/src/builder/scripts.ts +3 -3
  31. package/src/builder/sql-charts.ts +203 -0
  32. package/src/builder/sql-tools.ts +49 -0
  33. package/src/builder/sql.ts +28 -81
  34. package/src/builder/table-editor.ts +219 -0
  35. package/src/builder/ui.ts +21 -15
  36. package/src/builder/unload.ts +8 -4
  37. package/src/builder/worksheet.ts +592 -0
  38. package/src/builder/workspaces.ts +5 -3
  39. package/src/cli/replace.ts +3 -1
  40. package/src/datamodel.ts +324 -0
  41. package/src/dbroles.ts +215 -0
  42. package/src/runtime/autorest.ts +336 -0
  43. package/src/runtime/rest.ts +4 -4
  44. package/src/session.ts +2 -0
  45. package/src/sqlformat.ts +208 -0
  46. package/src/sqlplan.ts +133 -0
  47. package/src/sqlscript.ts +6 -2
  48. package/src/sqlworksheet.ts +278 -0
  49. package/src/tabledef.ts +226 -0
  50. package/src/unload.ts +14 -3
@@ -66,7 +66,13 @@ src/
66
66
  sampledata-words.ts built-in name, city, company and word lists of Sample Data
67
67
  unload.ts Unload Data: unloadStatement() (one SELECT), openUnload() (cursor, batches, CSV/JSON/XLSX/XML encoders on Postgres text values)
68
68
  xml.ts safe XML reader (no DTDs or entities, limits) and xmlTable(): rows from a repeating element (unit tested)
69
- sqlscript.ts SQL scripts: splitScript() (statements, line numbers, psql commands), runScript() (stop/continue, transaction, savepoints)
69
+ sqlscript.ts SQL scripts: splitScript() (statements, line numbers and offsets, psql commands), runScript() (stop/continue, transaction, savepoints)
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)
72
+ datamodel.ts (sprint 98) Data Modeler diagrams: readModel() (catalog), boxSize(), fkPath() (crow's feet), autoLayout(), diagramSvg()
73
+ tabledef.ts (sprint 95) a table as a definition: readTable(), checkTable(), tableSql() (CREATE, or ALTER from the catalog's version)
74
+ sqlformat.ts (sprint 93) formatSql(): the worksheet's Format (clauses per line, keyword case; strings and comments kept)
75
+ sqlplan.ts (sprint 92) EXPLAIN (FORMAT JSON) as a tree: parsePlan() (self time, slowest step, misestimates), planText()
70
76
  quicksql.ts Quick SQL: shorthand parser and PostgreSQL DDL generator (unit tested)
71
77
  xlsx.ts Excel writer for report downloads and Unload Data (typed cells, streamed through fflate's Zip)
72
78
  automations.ts cron parser, next run in a time zone, scheduler (also meta.task_expire_tick, 094), running automations (the actions run
@@ -81,6 +87,9 @@ src/
81
87
  mvt.ts Mapbox Vector Tile encoding for map layers served as tiles
82
88
  yamltext.ts the text style of the directory export: a strict YAML subset, written and read
83
89
  webclient.ts outgoing HTTP to web services: allow-list, address checks at connect time (SSRF), redirects, limits
90
+ dbroles.ts (sprint 99, DA-13) Database Users' SQL: roleSql (CREATE/ALTER ROLE, memberships, search path, schema
91
+ and default privileges: only what differs from the catalog), dropSql, checkRole/checkPassword,
92
+ scramVerifier (SCRAM-SHA-256, SASLprep) and the password slot (maskSql for review and log, withVerifier to run)
84
93
  secrets.ts secrets at rest (web credentials): AES-256-GCM with PGKILN_SECRET_KEY
85
94
  websources.ts web credentials (OAuth2 client credentials/password/refresh token grants, token cache, stored refresh
86
95
  tokens) and REST data sources: requests, JSON paths, typed rows, response cache, write-back operations
@@ -144,6 +153,9 @@ src/
144
153
  spatial.ts spatial filtering on the server: map area and distance parsing, PostGIS detection and SQL (ST_Intersects, ST_DWithin), lat/lng fallback (bounding box, haversine)
145
154
  pwa.ts Progressive Web App: manifest, service worker route, icons (PNG encoder), offline page
146
155
  rest.ts REST modules: handler checks, matching, bearer tokens, execution (collections stream from a cursor), OpenAPI
156
+ autorest.ts (sprint 100, migration 113) AutoREST: /a/:alias/autorest/<object>/ for the tables and views SQL Workshop →
157
+ RESTful Services published (meta.rest_object): caller() of rest.ts, SET ROLE to the app role, owner/BYPASSRLS
158
+ check, columns from the catalog (column grants), filters/q/order/paging, POST/PUT/DELETE by primary key, OpenAPI
147
159
  rest-sources.ts REST data sources in apps: regions and LOVs as SQL over "rest", the invoke_api process (items; the call is websources.ts invoke()),
148
160
  write-back of forms (fetch, form_dml) and grids (grid_dml) through the source's operations
149
161
  tree.ts tree region
@@ -215,12 +227,28 @@ src/
215
227
  (sprint 86) GET /builder/apps/:app/pages/:no, /builder/pages/:id redirects browsers there (designerUrl in ui.ts)
216
228
  errors.ts (sprint 86) the builder's HTML 404 and 500 pages for browsers (wantsHtml, a not-found handler and an onSend hook)
217
229
  arrange.ts page designer layout changes: move, column span, create from the gallery, undo / redo
218
- sql.ts SQL Workshop: the home and SQL commands (templates and drafts to review)
230
+ sql.ts SQL Workshop: the home and the session's schema
231
+ launchpad.ts (sprint 96) the SQL Workshop home's Launchpad (pins in meta.builder_pin, 109; tool groups), POST /builder/pins,
232
+ GET /builder/palette (the builder's search: JSON for Ctrl+K, a results page without JavaScript)
233
+ sql-charts.ts (sprint 97) charts of a query: chartSpec(), drawChart() (runtime/charts.ts, a PageCss in a nonce'd <style>), the
234
+ worksheet's Chart tab, SQL Workshop → Charts (meta.sql_chart, 110; read-only runs)
235
+ sql-tools.ts (sprint 96) SQL_TOOLS: every SQL Workshop tool with its group, tab and description (home, More menu, search)
236
+ worksheet.ts (sprint 91) the SQL Worksheet (Database Actions' SQL; /sql/commands too): navigator (pickSchema, objects with
237
+ 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
219
238
  object-browser.ts (sprint 75) the Object Browser: objects by type, system objects hidden, a table in tabs, column actions as SQL to review
239
+ table-editor.ts (sprint 95) Table Properties: GET/POST /sql/objects/table (create, edit ?o=, ?template=), fromForm(), Preview / Apply
240
+ (one transaction) / Open in the worksheet
241
+ object-actions.ts (sprint 94) an object's ⋯ menu (objectMenu) in the worksheet and the Object Browser: Quick DDL (objectDdl), Drop with
242
+ dependents, Add index / trigger / policy as drafts; GET /sql/objects/action, /sql/objects/panel (Open in a panel)
243
+ data-modeler.ts (sprint 98) SQL Workshop → Data Modeler: /sql/modeler (diagrams, meta.sql_diagram, 111), /:id (SVG), /:id/objects, /layout,
244
+ /rename, /delete, /svg (export), /ddl (diagramDdl), /dictionary (data dictionary, ?download=1)
220
245
  scripts.ts SQL Workshop → SQL Scripts: editor, upload/download, run, results per statement, run history
221
246
  quicksql.ts SQL Workshop → Quick SQL page (preview, save as script, run)
222
247
  querybuilder.ts SQL Workshop → Query Builder: catalog, joins by foreign key or drawn, functions/group by, buildQuery() from the URL; the canvas is in builder.js
223
248
  users.ts user directory and identity providers
249
+ db-users.ts (sprint 99, DA-13) Administration → Database Users (/builder/db-users, administrators only): PostgreSQL
250
+ roles with highlights, create/edit (review the masked SQL, then Apply in one transaction), drop with
251
+ reassigning; pgkiln's own roles read-only, roles of applications and workspaces not dropped
224
252
  api.ts per-app REST API page (API role, tokens)
225
253
  globalization.ts translations, XLIFF/CSV, text messages
226
254
  dataload.ts SQL Workshop → Load Data (with definitions, save a mapping as one); data load definition spec (Shared Components)
@@ -248,6 +276,9 @@ src/
248
276
  form-designer.ts page designer: Form Designer settings (designers' scheme; sources: key, actions, offered columns, labels, lists of values)
249
277
  workingcopies.ts Working copies: list and create, compare with differences, merge or refresh with conflict choices, delete
250
278
  rest.ts REST module endpoints list and curl example (Shared Components)
279
+ autorest.ts (sprint 100) SQL Workshop → RESTful Services (/builder/sql/rest): publish a table or view through an
280
+ application of the workspace (checks: schema the workshop may use, app role not the owner), its page
281
+ (grants per method, RLS, security_invoker, endpoints, cURL/fetch, OpenAPI link), settings, disable
251
282
  workflows.ts workflow versions, diagram and instances (Shared Components)
252
283
  process-jobs.ts page designer: the Jobs tab of a background chain process
253
284
  template-spec.ts template component property form (Shared Components)
@@ -279,6 +310,10 @@ public/
279
310
  app.css theme (light/dark, responsive; --font, --font-size, --radius for style variants; template option classes to-*)
280
311
  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)
281
312
  code-editor.js, .css builder code editor: enhances <textarea data-code>, highlighting, suggestions (no dependencies)
313
+ palette.js (sprint 96) the builder's search dialog (Ctrl+K), recently visited SQL Workshop pages, the Launchpad's tabs
314
+ data-modeler.js, .css (sprint 98) the Data Modeler: drag boxes, undo/redo, save, zoom/fit, auto layout, mini-map, SVG/PNG export, print
315
+ worksheet.js, .css (sprint 91) the SQL Worksheet: run keys with the cursor, output tabs, navigator swap and search, drag and drop, splitters;
316
+ (92) grid sort, value dialog, history filter; (93) worksheet tabs in localStorage, Files, binds dialog, format, find, case
282
317
  builder.css builder only: IDE look (dark chrome, icon rail, panes), builder light/dark tokens
283
318
  builder.js builder only: tabs, component tree, property filter, drag and drop on the layout
284
319
  builder-icons.svg builder only: icons of the rail, toolbar and designer (b-*)
@@ -298,6 +333,13 @@ test/
298
333
  unload.test.ts Unload Data: CSV/JSON/XLSX/XML output, read back with Load Data, read-only and one-statement checks, streaming
299
334
  app-from-file.test.ts Create → From a file: proposed names and types, app + table + rows + pages, row errors, login, validation
300
335
  workshop.test.ts SQL scripts, Quick SQL pages, query builder, data load definitions (Load Data, the process, export)
336
+ sql-charts.test.ts (sprint 97) the worksheet's Chart tab, saving a chart, the Charts dashboard, a chart's page, read-only runs
337
+ launchpad.test.ts (sprint 96) Launchpad groups, pins (builder pages only, at most 24), the search (JSON and page)
338
+ tabledef.test.ts (sprint 95) table definitions round trip: CREATE, read, ALTER, read again; mistakes
339
+ table-editor.test.ts (sprint 95) the Table Properties page: preview, apply, a failing apply rolls back, template, worksheet
340
+ object-actions.test.ts (sprint 94) object menus: Quick DDL, Drop with dependents, Add index / trigger / policy, the panel, not-found
341
+ data-modeler.test.ts (sprint 98) Data Modeler: "hr core" with its FK lines, saved positions, SVG, objects, DDL, dictionary, geometry
342
+ worksheet.test.ts (sprint 91) the SQL Worksheet: statement at the cursor, Run Script log, plans, notices, history, navigator, Run as
301
343
  quicksql.test.ts Quick SQL parser and DDL generator
302
344
  xml.test.ts XML reader: rows, attributes, paths, refused DTDs and entities, limits
303
345
  printing.test.ts report PDFs
@@ -343,6 +385,8 @@ test/
343
385
  helpers.ts a cookie-keeping test browser
344
386
  e2e/responsive.test.ts browser tests at phone/tablet/desktop widths (Playwright)
345
387
  e2e/code-editor.test.ts the code editor in a browser: highlighting, keys, suggestions, touch, screen readers
388
+ e2e/data-modeler.test.ts (sprint 98) the Data Modeler in a browser: drag, save, reload, undo/redo, zoom, mini-map, exports, phone
389
+ e2e/worksheet.test.ts (sprint 91) the SQL Worksheet in a browser: run keys, tabs, navigator, drag and drop, splitters, phone, no JavaScript
346
390
  e2e/items.test.ts sprint 26 item types in a browser: editors, tags, stars, dates, reveal; without JavaScript
347
391
  e2e/designer.test.ts page designer: panes per width, drag and drop, keyboard, Arrange buttons, builder theme
348
392
  e2e/calendar.test.ts calendar drag and drop and create on click, view switching, chart drill-down
@@ -1,17 +1,17 @@
1
1
  # 13. REST APIs
2
2
 
3
- pgkiln offers two ways to expose data securely over REST (mobile apps, integrations, scripts),
3
+ pgkiln offers three ways to expose data securely over REST (mobile apps, integrations, scripts),
4
4
  which can be combined:
5
5
 
6
- | | [REST modules](#rest-modules-in-the-builder) | [PostgREST](#how-it-works) |
7
- |---|---|---|
8
- | What | Endpoints you define in the builder: a method, a path and the SQL | A separate service that turns a schema of views and functions into an API |
9
- | Served by | pgkiln itself, under `/a/<alias>/rest/<module>/` | PostgREST, next to pgkiln |
10
- | Runs as | the application's database role (like its pages) | a dedicated API role |
11
- | Good for | a handful of tailored endpoints, field apps, integrations | broad data access with filtering, sorting and embedding |
6
+ | | [REST modules](#rest-modules-in-the-builder) | [AutoREST](#autorest-tables-and-views-from-the-sql-workshop) | [PostgREST](#how-it-works) |
7
+ |---|---|---|---|
8
+ | What | Endpoints you define in the builder: a method, a path and the SQL | A table or view published as it is: rows, one row, insert, update, delete | A separate service that turns a schema of views and functions into an API |
9
+ | Served by | pgkiln itself, under `/a/<alias>/rest/<module>/` | pgkiln itself, under `/a/<alias>/autorest/<object>/` | PostgREST, next to pgkiln |
10
+ | Runs as | the application's database role (like its pages) | the application's database role | a dedicated API role |
11
+ | Good for | a handful of tailored endpoints, field apps, integrations | quick CRUD access to a table, prototypes, simple integrations | broad data access with filtering, sorting and embedding |
12
12
 
13
- Both use the same tokens (App → REST API: tokens and OAuth clients), the same accounts and the
14
- same row level security, and both publish an OpenAPI description.
13
+ All three use the same tokens (App → REST API: tokens and OAuth clients), the same accounts and the
14
+ same row level security, and all publish an OpenAPI description.
15
15
 
16
16
  ## REST modules in the builder
17
17
 
@@ -63,6 +63,71 @@ curl -X POST http://127.0.0.1:3100/a/hr/rest/v1/leave -H "Authorization: Bearer
63
63
  -H "Content-Type: application/json" -d '{"start_date": "2027-05-03", "end_date": "2027-05-04", "reason": "dentist"}'
64
64
  ```
65
65
 
66
+ ## AutoREST: tables and views from the SQL Workshop
67
+
68
+ **SQL Workshop → RESTful Services** (`/builder/sql/rest`; Database Actions: a table's *REST › Enable*, ORDS
69
+ AutoREST), or **REST › Enable / Disable** in a table's or view's ⋯ menu (SQL Worksheet navigator, Object Browser).
70
+ Choose:
71
+
72
+ | Setting | Meaning |
73
+ |---|---|
74
+ | Table or view | Any table, partitioned table, view, materialized view or foreign table of a schema the SQL Workshop may use (not `meta`) |
75
+ | Application | An application of the current workspace with a database role. It decides how requests run (below) and gives the URL |
76
+ | URL name | The segment in `/a/<alias>/autorest/<name>/`: lower case letters, digits, `_` and `-`; the object's name by default |
77
+ | Methods | `GET` (rows and one row), `POST` (insert), `PUT` (update), `DELETE`. `PUT` and `DELETE` need a primary key; a materialized view answers `GET` only |
78
+ | Who may call it | **A bearer token of the application** (the default), or **public**: anyone, without a token. Public is never implied: it is a choice on the form |
79
+ | Roles | Optional application roles; the caller needs one of them (`meta.has_role()`), else 403 |
80
+ | Page size | Rows per page without `?limit=` (1–500, default 25) |
81
+
82
+ The object's page shows the checks (the role is not the owner and doesn't bypass row level security; its grants per
83
+ method; row level security on or off; for a view whether it is `security_invoker`; the primary key; columns the role
84
+ may not read), the endpoints with their URLs, cURL and `fetch` examples, and the OpenAPI link. Its settings can be
85
+ changed, the object disabled (404) or removed (*Disable REST*). The table itself is never changed.
86
+
87
+ **Endpoints** (`/a/hr/autorest/dept/` for `hr.dept` published through `hr`):
88
+
89
+ | Request | Answer |
90
+ |---|---|
91
+ | `GET …/dept/` | `{"items": […], "offset": 0, "limit": 25, "has_more": true}`. `?limit=` (1–500) and `?offset=` page; `?<column>=<value>` keeps rows whose column equals the value (several are combined with AND); `?q=<text>` keeps rows where a text column contains the text (case-insensitive; `%` and `_` are literal); `?order=dname,deptno.desc` sorts (default: the primary key). An unknown parameter or column is a 400 |
92
+ | `GET …/dept/10` | The row as an object, or 404. A composite key is comma separated: `…/pair/1,x` (URL-encode a comma inside a value) |
93
+ | `POST …/dept/` | A JSON object of column values → 201 with the new row and a `Location` header. Columns left out get their defaults; an unknown column is a 400 |
94
+ | `PUT …/dept/10` | A JSON object of the columns to change → 200 with the row, or 404 (also when row level security hides it). Columns left out keep their values |
95
+ | `DELETE …/dept/10` | 204, or 404 |
96
+ | `GET /a/hr/autorest/openapi.json` | OpenAPI 3 of the application's published objects: without a token the public ones, with a valid token all of them; column types as JSON Schema |
97
+
98
+ A method that isn't enabled answers 405 with an `Allow` header. Errors are JSON `{"error": "…"}`, as for REST modules:
99
+ 400 for invalid input, a check or unique constraint, or a `raise exception`; 403 for a missing role or grant
100
+ (including column grants and a row level security `with check`).
101
+
102
+ **How a request runs.** As for [REST modules](#rest-modules-in-the-builder): the token is checked (signature, expiry,
103
+ the application, an active account with access or a client that isn't revoked) at every request; a browser session is
104
+ not accepted. The statement then runs in a transaction **as the application's database role**, with
105
+ `meta.app_user()` = the caller (`nobody` for a public object without a token), `meta.has_role()` reading the caller's
106
+ roles, and a 30-second statement timeout. So the role's grants, column grants and the table's row level security
107
+ apply exactly as on the application's pages. Columns the role may not select are left out of every answer and can't
108
+ be filtered or sorted on. AutoREST refuses, when the object is enabled and again at every request (after `SET ROLE`),
109
+ a role that owns the object or is a member of its owner (row level security doesn't apply to the owner), a superuser
110
+ and a role with `BYPASSRLS`. An application without a database role can't publish objects. Names come from the
111
+ catalog and are quoted; filter values, keys and bodies are query parameters, never SQL text.
112
+
113
+ The workspace preference *Enable RESTful services* turns AutoREST off with the REST modules (404), and the
114
+ application's availability applies too.
115
+
116
+ ```bash
117
+ TOKEN=… # App → REST API → Issue a token for king
118
+ curl "http://127.0.0.1:3100/a/hr/autorest/dept/?limit=2" -H "Authorization: Bearer $TOKEN"
119
+ # {"items":[{"deptno":10,"dname":"ACCOUNTING",…},{"deptno":20,…}],"offset":0,"limit":2,"has_more":true}
120
+ curl "http://127.0.0.1:3100/a/hr/autorest/dept/?limit=2" # 401: no token
121
+ ```
122
+
123
+ **Views.** A view without `security_invoker = true` runs with its owner's rights, so the row level security of the
124
+ tables beneath it does not apply to the caller; the page warns about it. Views have no primary key: they publish the
125
+ collection (`GET`, and `POST` when PostgreSQL can insert into the view).
126
+
127
+ **Export.** The published objects are installation data, like OAuth clients: they name objects of this database and
128
+ are not part of an application export; an in-place import (`pgkiln import --replace`) keeps them. Tailored endpoints
129
+ that travel with the application are [REST modules](#rest-modules-in-the-builder).
130
+
66
131
  ## PostgREST
67
132
 
68
133
  [PostgREST](https://postgrest.org) runs as a separate service **next to** pgkiln and turns
@@ -265,7 +265,7 @@ parsing, type inference and limits.)
265
265
  3. The result shows the rows inserted, updated and skipped, with a link to the table in the
266
266
  Object Browser.
267
267
 
268
- Load Data runs as the builder's owner connection, like SQL Commands.
268
+ Load Data runs as the builder's owner connection, like the SQL Worksheet.
269
269
 
270
270
  ### SQL Workshop → Unload Data
271
271
 
@@ -352,7 +352,7 @@ Rows to develop and test with (APEX 26.1's Data Generator / "sample data for dev
352
352
  Definitions are shared by the developers of the installation, like SQL scripts, and not part of
353
353
  an application export (they describe tables, not an application).
354
354
 
355
- Sample Data runs as the builder's owner connection (like SQL Commands: triggers run, row level
355
+ Sample Data runs as the builder's owner connection (like the SQL Worksheet: triggers run, row level
356
356
  security doesn't apply to the owner), on a connection of its own that is closed afterwards, with a
357
357
  statement timeout (`SAMPLE_DATA_STATEMENT_TIMEOUT`, default `5min`) and at most
358
358
  `SAMPLE_DATA_MAX_ROWS` rows per run (default 100,000). Table and column names come from the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.46.0",
3
+ "version": "0.48.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
@@ -1032,3 +1032,25 @@ details.prop-group-more[open] > summary { margin-bottom: 8px; }
1032
1032
 
1033
1033
  /* (sprint 90, PD-4) a commented-out component in the tree (APEX: Comment Out): struck through and muted */
1034
1034
  .pd-node[data-commented] .pd-label { text-decoration: line-through; color: var(--muted); }
1035
+
1036
+ /* (sprint 99, DA-13) Administration → Database Users */
1037
+ .dbu-stats { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.6rem; }
1038
+ .dbu-stats a.stat { color: inherit; text-decoration: none; }
1039
+ .dbu-stats a.stat:hover, .dbu-stats a.stat:focus-visible { border-color: var(--accent); }
1040
+ .dbu-stats a.stat[aria-current="page"] { border-color: var(--accent); background: var(--accent-soft); }
1041
+ .dbu-search { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
1042
+ .dbu-search input { flex: 1 1 12rem; max-width: 24rem; }
1043
+ .dbu-members { max-height: 16rem; overflow: auto; }
1044
+ .dbu-schemas .te-c { text-align: center; width: 1%; white-space: nowrap; }
1045
+ .dbu-sql { white-space: pre-wrap; overflow-wrap: anywhere; }
1046
+ .dbu-list td { white-space: normal; overflow: visible; max-width: 24rem; }
1047
+ .dbu-list td .tag { margin: 0.1rem 0; }
1048
+ .dbu-facts { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1rem; margin: 0; }
1049
+ .dbu-facts dt { color: var(--muted); }
1050
+ .dbu-facts dd { margin: 0; min-width: 0; }
1051
+ @media (max-width: 640px) {
1052
+ .dbu-facts { grid-template-columns: 1fr; } .dbu-facts dd { margin-bottom: 0.4rem; }
1053
+ .dbu-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } .dbu-stats a.stat { padding: 0.5rem 0.7rem; } .dbu-stats .stat b { font-size: 1.15rem; }
1054
+ }
1055
+ /* (sprint 100) RESTful Services: examples wrap instead of scrolling sideways */
1056
+ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
@@ -0,0 +1,56 @@
1
+ /* pgkiln builder: the SQL Workshop's Data Modeler (sprint 98, src/builder/data-modeler.ts, public/data-modeler.js).
2
+ The diagram is an SVG with presentation attributes (light colours: an exported file); here the builder's theme
3
+ overrides them. The canvas scrolls inside the page, so a wide diagram never widens the page. */
4
+ .dm-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; margin-bottom: 8px; }
5
+ .dm-name { margin: 0; font-size: 1.25rem; overflow-wrap: anywhere; }
6
+ .dm-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 8px; }
7
+ .dm-toolbar form { display: contents; }
8
+ .dm-toolbar .btn[disabled] { opacity: 0.5; }
9
+ .dm-status { min-width: 0; }
10
+ .dm-stage { position: relative; }
11
+ .dm-canvas { overflow: auto; max-width: 100%; height: 65vh; min-height: 18rem; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); }
12
+ .dm-canvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
13
+ .dm-svg { display: block; }
14
+ .dm-svg .dm-bg { fill: var(--bg); }
15
+ .dm-svg .dm-frame { fill: var(--surface); stroke: var(--border); }
16
+ .dm-svg .dm-view .dm-frame { fill: var(--surface-2); }
17
+ .dm-svg .dm-head { fill: var(--accent-soft); stroke: var(--border); }
18
+ .dm-svg .dm-title { fill: var(--text); }
19
+ .dm-svg .dm-col { fill: var(--text); }
20
+ .dm-svg .dm-type, .dm-svg .dm-kind, .dm-svg .dm-more { fill: var(--muted); }
21
+ .dm-svg .dm-key { fill: var(--gold, #b45309); }
22
+ .dm-svg .dm-line, .dm-svg .dm-end { stroke: var(--muted); }
23
+ .dm-svg .dm-opt { fill: var(--bg); stroke: var(--muted); }
24
+ .dm-svg .dm-fk:hover .dm-line, .dm-svg .dm-fk:hover .dm-end { stroke: var(--accent); stroke-width: 2.5; }
25
+ .dm-svg .dm-link:hover .dm-title, .dm-svg .dm-link:focus .dm-title { fill: var(--accent); text-decoration: underline; }
26
+ .dm-live .dm-box { cursor: grab; touch-action: none; }
27
+ .dm-live .dm-box.dm-dragging { cursor: grabbing; }
28
+ .dm-svg .dm-box:focus { outline: none; }
29
+ .dm-svg .dm-box:focus-visible .dm-frame { stroke: var(--accent); stroke-width: 2.5; }
30
+ .dm-svg .dm-dragging .dm-frame { stroke: var(--accent); }
31
+ .dm-svg text { user-select: none; }
32
+ .dm-minimap { position: absolute; right: 12px; bottom: 12px; width: 200px; height: 140px; border: 1px solid var(--border); border-radius: var(--radius);
33
+ background: var(--surface); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); cursor: pointer; touch-action: none; }
34
+ .dm-minimap-bg { fill: var(--surface); }
35
+ .dm-minimap-view { fill: var(--accent); fill-opacity: 0.15; stroke: var(--accent); stroke-width: 4; vector-effect: non-scaling-stroke; }
36
+ .dm-legend { margin: 6px 0 12px; }
37
+ .dm-search-row { display: flex; gap: 6px; flex-wrap: wrap; }
38
+ .dm-search-row input { flex: 1 1 12rem; min-width: 0; }
39
+ .dm-settings { margin-bottom: 16px; }
40
+ .dm-settings > summary { cursor: pointer; margin-bottom: 8px; }
41
+ .dm-settings form { margin-bottom: 8px; }
42
+ .dm-dict-actions { margin-bottom: 12px; }
43
+ .dm-dict-toc { columns: 3 14rem; }
44
+ .dm-dict-table { margin-top: 1.5rem; }
45
+ .dm-dict-table h2 { border-bottom: 1px solid var(--border); padding-bottom: 4px; overflow-wrap: anywhere; }
46
+ @media (max-width: 640px) {
47
+ .dm-btn-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
48
+ .dm-canvas { height: 55vh; }
49
+ .dm-minimap { width: 130px; height: 90px; }
50
+ }
51
+ @media print {
52
+ .sw-tabs, .dm-toolbar, .dm-legend, #dm-objects, #dm-add, .dm-settings, .dm-minimap, .dm-dict-actions, .ide-alerts { display: none !important; }
53
+ .dm-canvas { height: auto; overflow: visible; border: 0; }
54
+ .dm-svg { max-width: 100%; height: auto; }
55
+ .dm-dict-table { break-inside: avoid-page; }
56
+ }