pgkiln 0.82.0 → 0.83.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 (61) hide show
  1. package/db/migrations/153_component_events.sql +21 -0
  2. package/docs/apex-feature-parity.md +3 -3
  3. package/docs/guide/03-builder.md +8 -1
  4. package/docs/guide/04-pages-and-regions.md +2 -1
  5. package/docs/guide/07-dynamic-actions.md +27 -0
  6. package/docs/guide/11-from-apex.md +2 -1
  7. package/docs/guide/12-development.md +9 -1
  8. package/package.json +1 -1
  9. package/public/app.css +2 -0
  10. package/public/app.js +85 -4
  11. package/public/builder.css +25 -2
  12. package/public/data-modeler.js +8 -5
  13. package/public/sql-monitor.js +5 -2
  14. package/src/builder/ai-builder.ts +50 -46
  15. package/src/builder/api.ts +49 -49
  16. package/src/builder/autorest.ts +92 -87
  17. package/src/builder/changelog.ts +39 -37
  18. package/src/builder/components.ts +5 -4
  19. package/src/builder/data-modeler.ts +89 -84
  20. package/src/builder/data-security.ts +39 -37
  21. package/src/builder/dataload.ts +69 -65
  22. package/src/builder/datapump.ts +108 -97
  23. package/src/builder/ddl-tools.ts +38 -34
  24. package/src/builder/document-view.ts +11 -11
  25. package/src/builder/i18n/de.ts +1627 -0
  26. package/src/builder/i18n/en.ts +1627 -0
  27. package/src/builder/i18n/es.ts +1627 -0
  28. package/src/builder/i18n/fr.ts +1627 -0
  29. package/src/builder/i18n/it.ts +1627 -0
  30. package/src/builder/i18n/ja.ts +1627 -0
  31. package/src/builder/i18n/ko.ts +1627 -0
  32. package/src/builder/i18n/nl.ts +1627 -0
  33. package/src/builder/i18n/pt.ts +1627 -0
  34. package/src/builder/i18n/zh-cn.ts +1627 -0
  35. package/src/builder/i18n/zh-tw.ts +1627 -0
  36. package/src/builder/i18n.ts +18 -0
  37. package/src/builder/object-actions.ts +18 -16
  38. package/src/builder/object-browser.ts +2 -2
  39. package/src/builder/querybuilder.ts +42 -36
  40. package/src/builder/quicksql.ts +16 -18
  41. package/src/builder/region-settings.ts +201 -199
  42. package/src/builder/report-settings.ts +64 -60
  43. package/src/builder/rest-modules.ts +145 -143
  44. package/src/builder/sampledata.ts +59 -52
  45. package/src/builder/scheduling.ts +180 -159
  46. package/src/builder/scripts.ts +71 -65
  47. package/src/builder/sql-charts.ts +36 -30
  48. package/src/builder/sql-monitor.ts +95 -89
  49. package/src/builder/sql-utilities.ts +47 -40
  50. package/src/builder/top-sql.ts +21 -17
  51. package/src/builder/unload.ts +48 -44
  52. package/src/builder/worksheet.ts +3 -3
  53. package/src/cron-schedule.ts +47 -17
  54. package/src/metadata.ts +3 -1
  55. package/src/runtime/calendar.ts +3 -2
  56. package/src/runtime/context.ts +2 -0
  57. package/src/runtime/grid.ts +1 -0
  58. package/src/runtime/maps.ts +7 -4
  59. package/src/runtime/render.ts +6 -1
  60. package/src/runtime/routes.ts +4 -0
  61. package/src/runtime/tree.ts +4 -3
@@ -0,0 +1,21 @@
1
+ -- Sprint 161 (CD-3, part 2; APEX: component events of Interactive Grid, Calendar, Map and Tree).
2
+ --
3
+ -- Events (trigger: the component's region id or static id):
4
+ -- grid_row_init a row was added to an editable grid (Add row, Duplicate) (APEX: Row Initialization)
5
+ -- grid_save a grid's changes were saved; runs on the page that comes back (APEX: Save)
6
+ -- calendar_date_select an empty day or hour of a calendar was chosen; the condition sees the date
7
+ -- (YYYY-MM-DD or YYYY-MM-DDTHH:MM); a cancel_event keeps the Create link closed
8
+ -- (APEX: Date Select)
9
+ -- calendar_view_change a calendar showed another view or period; the condition sees the view
10
+ -- (month, week, day, list) (APEX: View Change)
11
+ -- map_object_click a marker or shape of a map was clicked; the condition sees its id column (else its
12
+ -- title) (APEX: Map Object Clicked)
13
+ -- map_change a map was moved or zoomed; the condition sees the zoom level (APEX: Map Changed)
14
+ -- tree_selection_change a node of a tree was chosen; the condition sees its id; a cancel_event keeps its link
15
+ -- closed (APEX: Selection Change [Tree])
16
+
17
+ alter table meta.dynamic_action drop constraint dynamic_action_event_check;
18
+ alter table meta.dynamic_action add constraint dynamic_action_event_check check (event in (
19
+ 'change', 'click', 'load', 'dialog_closed', 'after_refresh', 'selection_change', 'focus', 'blur', 'key_release', 'before_submit', 'custom', 'menu_entry',
20
+ 'double_click', 'key_down', 'key_press', 'mouse_enter', 'mouse_leave', 'select', 'resize', 'scroll', 'page_unload', 'before_refresh', 'facets_change',
21
+ 'grid_row_init', 'grid_save', 'calendar_date_select', 'calendar_view_change', 'map_object_click', 'map_change', 'tree_selection_change'));
@@ -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-11-05 against **APEX 26.2** (sprint 160: the Workflow Diagram region, an instance's steps with the reached, current and failed ones marked (CD-7); sprint 159: map layers Lines, Polygons and Extruded Polygons with fill and line styles per layer or per row (CD-6); sprint 158: the item types Image Upload, Text Field with autocomplete, Percent Graph and Display Map (CD-5); sprint 157: the process types Close Dialog, Clear Session State, Reset Pagination, User Preferences, Server Side Geocoding, Print Report, Human Task – Create / – Manage and Form – Initialization (CD-4); sprint 156: dynamic action events double click, key down / press, mouse enter / leave, select, resize, scroll, page unload, before refresh and facets change, greater / less and not-in-list conditions, and the actions Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding and Open report dialog (CD-3); sprint 155: APEX's validation types, with an authorization scheme, Always execute and the error's display location (CD-1); sprint 154: one catalogue of server-side condition types for every component, shown in words in the Page Designer (CD-2); sprint 153: Database users in the eleven builder languages (WS-7 leftover); sprint 152: Workspace utilities, the dashboard, Mail queue, Network access, Instance settings and LDAP directories in the eleven builder languages (WS-7 leftover); sprint 151: vector providers with a model in the database, PostgresML (APEX's ONNX models, AP-1 leftover); sprint 150: remote databases, another PostgreSQL database's tables as foreign tables the applications query (REST Enabled SQL, AP-7 leftover); sprint 149: running workflow instances inside parallel branches migrate to a newer version (WS-6 leftover); sprint 148: the AI assistant streams its answers as the model writes them (WS-4 leftover); sprint 147: `pgkiln advise --offline` checks an export's files without a database (AP-10 leftover); sprint 146: the Advisor checks JSON sources' views against their data profile (AP-8 leftover); sprint 145: the texts that offered AI with "Claude or OpenAI" name all four providers: Claude, OpenAI, Gemini and OpenAI-compatible services (AP-11); sprint 144: `pgkiln advise` for CI with text, JSON and SARIF output (APEXlang static analysis / SQLcl CodeScan), security checks in the Advisor, and working copies and locks from the command line and MCP (the Working Copy APIs) (AP-10); sprint 143: the interactive report's 26.2 dialogs: *is one of* / *is not one of* filters with the column's values and counts, *is between* two values (dates with the date picker in the application's format), relative periods on date columns, and the column order by drag and drop or arrow buttons, followed by downloads and the PDF (AP-9); sprint 142: JSON sources with a data profile and updatable views whose arrays are rows, document views of a table with its children (APEX's duality views), JSON path columns in reports (AP-8); sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; 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).
10
+ Last reviewed: 2026-11-06 against **APEX 26.2** (sprint 162: the SQL Workshop tools and the region and report settings in the eleven builder languages (CD-8); sprint 161: component events of grids, calendars, maps and trees (CD-3); sprint 160: the Workflow Diagram region, an instance's steps with the reached, current and failed ones marked (CD-7); sprint 159: map layers Lines, Polygons and Extruded Polygons with fill and line styles per layer or per row (CD-6); sprint 158: the item types Image Upload, Text Field with autocomplete, Percent Graph and Display Map (CD-5); sprint 157: the process types Close Dialog, Clear Session State, Reset Pagination, User Preferences, Server Side Geocoding, Print Report, Human Task – Create / – Manage and Form – Initialization (CD-4); sprint 156: dynamic action events double click, key down / press, mouse enter / leave, select, resize, scroll, page unload, before refresh and facets change, greater / less and not-in-list conditions, and the actions Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding and Open report dialog (CD-3); sprint 155: APEX's validation types, with an authorization scheme, Always execute and the error's display location (CD-1); sprint 154: one catalogue of server-side condition types for every component, shown in words in the Page Designer (CD-2); sprint 153: Database users in the eleven builder languages (WS-7 leftover); sprint 152: Workspace utilities, the dashboard, Mail queue, Network access, Instance settings and LDAP directories in the eleven builder languages (WS-7 leftover); sprint 151: vector providers with a model in the database, PostgresML (APEX's ONNX models, AP-1 leftover); sprint 150: remote databases, another PostgreSQL database's tables as foreign tables the applications query (REST Enabled SQL, AP-7 leftover); sprint 149: running workflow instances inside parallel branches migrate to a newer version (WS-6 leftover); sprint 148: the AI assistant streams its answers as the model writes them (WS-4 leftover); sprint 147: `pgkiln advise --offline` checks an export's files without a database (AP-10 leftover); sprint 146: the Advisor checks JSON sources' views against their data profile (AP-8 leftover); sprint 145: the texts that offered AI with "Claude or OpenAI" name all four providers: Claude, OpenAI, Gemini and OpenAI-compatible services (AP-11); sprint 144: `pgkiln advise` for CI with text, JSON and SARIF output (APEXlang static analysis / SQLcl CodeScan), security checks in the Advisor, and working copies and locks from the command line and MCP (the Working Copy APIs) (AP-10); sprint 143: the interactive report's 26.2 dialogs: *is one of* / *is not one of* filters with the column's values and counts, *is between* two values (dates with the date picker in the application's format), relative periods on date columns, and the column order by drag and drop or arrow buttons, followed by downloads and the PDF (AP-9); sprint 142: JSON sources with a data profile and updatable views whose arrays are rows, document views of a table with its children (APEX's duality views), JSON path columns in reports (AP-8); sprint 141: static workspace files (`#WORKSPACE_FILES#`), remote servers for REST data sources, catalogs and AI services (an environment variable per environment), and workspace-level web credentials (AP-7); sprint 140: the items Shuttle (ordered), Select One and Select Many, the regions Classic Report (report templates, pagination types), Breadcrumb and Help Text with a page help text, and a [mapping of every APEX item and region type](#item-and-region-types-one-by-one) (AP-4); sprint 139: OpenTelemetry, traces with a span per SQL statement, web call, AI request and tool call, logs, metrics and `/metrics` for Prometheus, browser spans relayed by pgkiln, per workspace off or its own collector (AP-6); sprint 138: an application's Utilities tab with a dashboard, database object dependencies, change history per component, Upgrade application, UI defaults (APEX's Attribute Dictionary), application and page checksums and an icon browser (AP-5); sprint 137: Create page as a grid of page types with previews, the page types interactive report, smart filters, search page, data loading, tree, timeline, media list, content row, comments, dashboard, wizard, unified task list and workflow console, a Feature tab with nine features that install once, and Create page as copy with shared components mapped or copied (AP-3); sprint 136: vector providers (an AI service with an embedding model or a SQL function), `meta.embed`, *Add vector column* in Table Properties with an HNSW index and a queue that keeps embeddings current, search types vector and hybrid (reciprocal rank fusion with full-text) and a Retrieve (RAG) tool for AI agents, all as the app's role through RLS, on pgvector (AP-1); sprint 135: full-text search configurations, APEX's Oracle Text search type on PostgreSQL full-text search with stemming, ranking, highlights, *Did you mean* and *Add full-text search* in Table Properties (AP-2); sprint 134: the builder also in Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어, APEX's ten builder languages plus Nederlands (SEC-5); sprints 121, 123–125: the builder in Deutsch, English, Español, Français, Nederlands and Português, step by step: the frame, sign-in, Workspace home, App Builder, Page Designer menus, the SQL Workshop's home, SQL Worksheet, Object Browser and Table Properties, Shared Components, application settings, users, identity providers, developers and workspaces (WS-7); sprint 122: *Ask in your own words* sets faceted search and smart filter facets, smart filters read a typed phrase (WS-5), and Sample Maps, Sample Approvals, Sample Data Loading and Sample Files in the App Gallery (WS-8); sprint 120: the App Gallery's single-topic sample apps (charts, cards, calendar, interactive grids, dynamic actions, reporting), the UX Pattern Catalog and a Utility Apps tab with Lookup Lists, Release Notes and Announcements (WS-8); sprint 119: data security per table, a roles × columns matrix and masked values per application role in a masking view, the same identity for pages, AI tools, REST, AutoREST and MCP (WS-13); sprint 118: Administration → Mail queue with delivery per hour and per workspace, the slowest provider calls and failures with Retry and Purge, a workspace's own mail service, and workspace network access lists that narrow the installation's allow-list (WS-9); sprint 117: Pillar Light and Pillar Dark navigation appearances with a header strip, clearer navigation tree states, subtle colour utilities, RTL; sprint 116: the comparison moved from 26.1 to 26.2, with a section for the 26.2 workspace items WS-1 … WS-13 and OCI managed identities; the App Builder list with Updated by, working copies and the lock; `pgkiln import --only`, a file-level import; stale rows on facet menus and blueprints fixed; sprint 115: popup LOVs that load on scroll, Wait Popup dynamic actions and dynamic actions on menu entries; sprint 114: Workflow 26.2 with custom task outcomes, task events and notifications, Send E-Mail and draft steps, migrating running instances and the diagram as SVG / PNG; sprint 113: Team Development with issues, labels, milestones, templates, a board and a set-up wizard; sprint 112: AI interactive reports with chips, Undo, computed columns and a phrase parser that needs no AI service; sprint 111: AI Agents with tools as a shared component, a Navigate tool with checksummed URLs, Gemini and OpenAI-compatible services; sprint 110: Data Reporter as a workspace tool with datasets, reporting applications, editors and viewers, published reports with stable URLs and pins; sprint 109: the Workspace home above the App Builder and SQL Workshop, with a summary, top applications, users and developers, and an optional release check; 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
 
@@ -200,7 +200,7 @@ review is a diff. Not counted in [At a glance](#at-a-glance): the rows above com
200
200
  | Computations | ✅ | Static, item, SQL query, SQL expression and PL/pgSQL function body; before header and after submit; with a condition, authorization and build option ([chapter 6](guide/06-processing.md#computations)); **application computations** (sprint 81) for every page: after authentication, before header, after submit ([chapter 6](guide/06-processing.md#application-computations)) |
201
201
  | Page processes | ✅ | SQL / PL/pgSQL, form DML, grid DML, data loading (`data_load`), **invoke API** (a REST data source or URL, response values into items), **download** (a file from a query; several rows become one zip; on submit or on load), **execution chains** (child processes with their own conditions, nested, optionally run in the background with a status view), **workflow** (start, terminate, retry), **Generate text with AI** (text or structured output into items); (sprint 157) **Close Dialog** with items to return, **Clear Session State**, **Reset Pagination**, **User Preferences**, **Server Side Geocoding**, **Print Report**, **Human Task – Create / – Manage**, **Form – Initialization** ([chapter 6](guide/06-processing.md#declarative-process-types)) |
202
202
  | Branches | ✅ | Before header and after processing, to a page (with items) or a URL inside the app, *When button pressed*, server-side conditions (the shared catalogue, sprint 154); the button's target page stays the fallback ([chapter 6](guide/06-processing.md#branches)); a PL/pgSQL function returning a path in the app, and a page of another application (with signed items) |
203
- | Dynamic actions | ✅ | Show, hide, enable, disable, set value (SQL), execute SQL, refresh region or item, alert, submit, set focus, add/remove class, show success/error message and clear errors (26.1); the **Dialog Closed** event (per dialog page, with the dialog's message). **Execute JavaScript**: calls a function a static application file registered with `pgkiln.actions.register` (no inline code: the CSP stays strict) ([chapter 7](guide/07-dynamic-actions.md#execute-javascript)); dynamic action plug-ins ; (sprint 156) events double click, key down / press, mouse enter / leave, select, resize, scroll, page unload, before refresh, facets change; conditions greater / less (or equal), not in list; Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding, Open report dialog. Not yet: grid, calendar, map and tree component events |
203
+ | Dynamic actions | ✅ | Show, hide, enable, disable, set value (SQL), execute SQL, refresh region or item, alert, submit, set focus, add/remove class, show success/error message and clear errors (26.1); the **Dialog Closed** event (per dialog page, with the dialog's message). **Execute JavaScript**: calls a function a static application file registered with `pgkiln.actions.register` (no inline code: the CSP stays strict) ([chapter 7](guide/07-dynamic-actions.md#execute-javascript)); dynamic action plug-ins ; (sprint 156) events double click, key down / press, mouse enter / leave, select, resize, scroll, page unload, before refresh, facets change; conditions greater / less (or equal), not in list; Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding, Open report dialog; component events (sprint 161) Row Initialization and Save of a grid, Date Select and View Change of a calendar, Map Object Clicked and Map Changed, Selection Change of a tree, each with its value for the condition and a Set Value without SQL |
204
204
  | Dynamic action events | ✅ | Change, click, page load, Dialog Closed and (sprint 52) Get/Lose Focus, Key Release, After Refresh (a refreshed, lazy or master-detail region), Selection Change (report row selection, a grid's master row), Before Page Submit and custom events (`pgkiln.trigger(name, value)`); the actions of one event run in sequence order ([chapter 7](guide/07-dynamic-actions.md#events)) |
205
205
  | Dynamic action actions: confirm, close/cancel dialog, clear, open/close region, download, print, current position, share | ✅ | (sprint 52) Confirm (No stops the actions after it, and a submit), Close and Cancel Dialog, Clear, Open/Close Region, Download (a download process of the page), Print, Get Current Position, Share (the share sheet, or the link copied) ([chapter 7](guide/07-dynamic-actions.md#actions)) |
206
206
  | Ajax callbacks (On Demand processes, `apex.server.process`) | ✅ | (sprint 52) Page and application processes with point *ajax*, called with `pgkiln.server.process(name, {items, x01 … x10})`: SQL as the app's role with its authorization and condition, JSON rows back, items it sets set on the page ([chapter 7](guide/07-dynamic-actions.md#ajax-callbacks)) |
@@ -335,7 +335,7 @@ row above where there is one.
335
335
  | WS-4 AI Agents with tools | ✅ | (sprint 111) AI Agents and AI Tools as shared components, a Navigate tool, Gemini and OpenAI-compatible services ([Workflow, automation and AI](#workflow-automation-and-ai)) |
336
336
  | WS-5 AI interactive reports: chips, computed columns | ✅ | (sprint 112) *Ask in your own words* with chips, Undo and computed columns; a phrase parser that needs no AI service; (sprint 122) phrases set faceted search and smart filter facets |
337
337
  | WS-6 Workflow 26.2: outcomes, migrating running instances, drafts, diagram export | ✅ | (sprint 114) Custom task outcomes, task events, Send E-Mail and draft steps, migrating running instances, the diagram as SVG / PNG ([Workflow, automation and AI](#workflow-automation-and-ai)) |
338
- | WS-7 The builder in more languages | ✅ | (sprint 121) The builder in Deutsch, English, Español, Français, Nederlands and Português, and (sprint 134, SEC-5) Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어 with CJK font stacks: links on the sign-in page, a language menu in the status bar, the choice stored per developer (migration 127); builder texts are keyed message files with a coverage check in CI, also for the builder's own JavaScript (sprint 123). Translated (sprints 121, 123–125): the builder's frame, sign-in page, Workspace home, App Builder home, an application's home and tabs, the Page Designer's toolbar, menus, tree and gallery, the SQL Workshop's home and tabs, the SQL Worksheet, Object Browser and Table Properties, Shared Components, an application's settings, Users, identity providers, Developers and Workspaces ([chapter 3](guide/03-builder.md#choosing-the-builder-language)). (sprint 152) Workspace utilities, the dashboard, Mail queue, Network access, Instance settings and LDAP directories; (sprint 153) Database users. Still English: the other SQL Workshop tools and the region and report settings, until they move over; by design the property editor's and component forms' field names and help |
338
+ | WS-7 The builder in more languages | ✅ | (sprint 121) The builder in Deutsch, English, Español, Français, Nederlands and Português, and (sprint 134, SEC-5) Italiano, 中文 (简体), 中文 (繁體), 日本語 and 한국어 with CJK font stacks: links on the sign-in page, a language menu in the status bar, the choice stored per developer (migration 127); builder texts are keyed message files with a coverage check in CI, also for the builder's own JavaScript (sprint 123). Translated (sprints 121, 123–125): the builder's frame, sign-in page, Workspace home, App Builder home, an application's home and tabs, the Page Designer's toolbar, menus, tree and gallery, the SQL Workshop's home and tabs, the SQL Worksheet, Object Browser and Table Properties, Shared Components, an application's settings, Users, identity providers, Developers and Workspaces ([chapter 3](guide/03-builder.md#choosing-the-builder-language)). (sprint 152) Workspace utilities, the dashboard, Mail queue, Network access, Instance settings and LDAP directories; (sprint 153) Database users; (sprint 162, CD-8) every SQL Workshop tool (SQL Monitor, Top SQL, Quick SQL, SQL Scripts, Generate DDL, Schema Comparison, Change Log, Charts, Load / Unload Data, Sample Data, Query Builder, Data Modeler, Utilities, Object Reports, AI, Schema Export / Import, Scheduling with schedules in words, RESTful Services, data security, document views) and the region and report settings. Still English: some App Builder screens (Team Development, mail, datasets, JSON sources, blueprints and a few more) until they move over; messages of checks shared with the command line; by design the property editor's and component forms' field names and help |
339
339
  | WS-8 App Gallery: more sample apps, Utility Apps | ✅ | (sprint 120) Four tabs with counts and a search that also works without JavaScript ([chapter 3](guide/03-builder.md#app-gallery)). *Sample Apps*: HR Demo, Tasks, ten single-topic apps (Sample Charts, Sample Cards, Sample Calendar, Sample Interactive Grids, Sample Dynamic Actions, Sample Reporting; sprint 122: Sample Maps, Sample Approvals, Sample Data Loading, Sample Files) and the **UX Pattern Catalog**, each with its own schema, data, demo account and explanatory texts, installed by administrators from one SQL file in one transaction; *Utility Apps*: Lookup Lists, Release Notes and Announcements as blueprints any developer installs into the workspace. APEX's 27 sample apps include topics pgkiln shows in HR Demo instead (REST, trees, collections); no remote catalogue |
340
340
  | WS-9 Mail queue reporting, workspace SMTP, workspace network ACLs | ✅ | (sprint 118) Administration → Mail queue (per hour and per workspace / application, the slowest provider calls, failures with the provider's answer, Retry and Purge), a workspace's own mail service, and a workspace's network access list that narrows the installation's allow-list for every outgoing call ([Administration](#administration)) |
341
341
  | WS-10 Universal Theme 26.2: Pillar appearances, navigation polish | ✅ | (sprint 117) Theme Roller → Navigation appearance Pillar Light / Pillar Dark per application or style, with a header strip colour for light and dark mode; the current page filled, its parents bold with an accent guide line; `u-color-*-subtle` utilities; a lighter processing indicator; RTL mirrored |
@@ -523,7 +523,14 @@ editor frame, access control, breadcrumbs, component settings) and an applicatio
523
523
  the administration screens: **Users** (accounts and identity providers), **Developers** and **Workspaces** (with
524
524
  utilization), and (sprint 152) **Workspace utilities**, the workspace **Dashboard**, **Mail queue**, **Network
525
525
  access**, **Instance settings** (its frame: each setting's own label and help, and the lockout checks' details, stay
526
- English) and **LDAP directories**, and (sprint 153) **Database users**. Other builder pages are still in English (they move over screen by screen); so are the
526
+ English) and **LDAP directories**, and (sprint 153) **Database users**, and (sprint 162) every **SQL Workshop tool**:
527
+ SQL Monitor, Top SQL, Quick SQL, SQL Scripts, Generate DDL, Schema Comparison, Change Log, Charts, Load and Unload
528
+ Data, Sample Data, Query Builder, Data Modeler, Utilities, Object Reports, the SQL Workshop's AI, Schema Export /
529
+ Import, Scheduling (schedules are described in your language), RESTful Services (modules and AutoREST) and the
530
+ Object Browser's data security and document view, and the Page Designer's **region and report settings** (cards,
531
+ charts, maps, calendars, facets, trees and the other region types, a report's columns). Messages that come from
532
+ the database or from checks shared with the command line (a policy check, a REST handler's validation) stay
533
+ English. Other builder pages are still in English (they move over screen by screen); so are the
527
534
  Page Designer's property names and their help (and, the same way, the field names and help of a shared component's
528
535
  form), the links to this guide, and any SQL the builder generates.
529
536
 
@@ -1068,7 +1068,8 @@ excludable job facet, salary ranges with from/to, a hire date range and a star r
1068
1068
 
1069
1069
  **Source**: a SELECT with one row per place. The position comes from `lat` and `lng` (or
1070
1070
  `latitude`/`longitude`), or from a `location` column holding `latitude,longitude` text (what a
1071
- [`location` item](05-items.md) stores). Optional columns: `title` and `body` (the popup), and
1071
+ [`location` item](05-items.md) stores). Optional columns: `title` and `body` (the popup), `id` (what a
1072
+ [`map_object_click`](07-dynamic-actions.md#component-events) dynamic action sees), and
1072
1073
  `geojson` (a GeoJSON geometry or feature, e.g. PostGIS `st_asgeojson(geom)`) to draw lines and areas;
1073
1074
  a GeoJSON point is a place like a row with `lat`/`lng`. With [PostGIS](#postgis) installed, a
1074
1075
  `geometry` or `geography` column (in WGS 84, SRID 4326) is enough: the server turns it into GeoJSON.
@@ -47,6 +47,13 @@ your own from a static application file.
47
47
  | `page_unload` | The page is left (APEX: Page Unload); only quick actions in the browser finish | – |
48
48
  | `before_refresh` | A region is about to be refreshed by a `refresh_region` action (APEX: Before Refresh); a `cancel_event` or declined `confirm` keeps it as it is | Region ids or static ids |
49
49
  | `facets_change` | A faceted search or smart filters region's facets were applied (APEX: Facets Change); runs on the page that comes back with the new filters | The facets region's id or static id |
50
+ | `grid_row_init` | A row was added to an editable grid by Add row or Duplicate (APEX: Row Initialization [Interactive Grid]); the condition sees the row's number among the new rows | The grid's id or static id |
51
+ | `grid_save` | A grid's changes were saved (APEX: Save [Interactive Grid]); runs on the page that comes back | The grid's id or static id |
52
+ | `calendar_date_select` | An empty day or hour of a calendar was clicked (APEX: Date Select); the condition sees `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM`; a `cancel_event` keeps the Create link closed | The calendar's id or static id |
53
+ | `calendar_view_change` | A calendar showed another view or period (APEX: View Change); the condition sees `month`, `week`, `day` or `list` | The calendar's id or static id |
54
+ | `map_object_click` | A marker or shape of a map was clicked (APEX: Map Object Clicked); the condition sees the row's `id` column, else its title | The map's id or static id |
55
+ | `map_change` | A map was moved or zoomed by the user (APEX: Map Changed); the condition sees the zoom level | The map's id or static id |
56
+ | `tree_selection_change` | A tree node was clicked (APEX: Selection Change [Tree]); the condition sees its `id`, the node is marked; a `cancel_event` keeps its link closed | The tree's id or static id |
50
57
 
51
58
  **The actions of one event and trigger run one after the other, in sequence order** (APEX: the true
52
59
  actions of a dynamic action), each waiting for the one before (a server action for its answer). A
@@ -58,6 +65,25 @@ actions of a dynamic action), each waiting for the one before (a server action f
58
65
  | 20 | `click` on `DELETE_ALL` | `execute_sql` | `delete from sales.order_line where id = any(string_to_array(:P5_SELECTED, ':')::int[])` |
59
66
  | 30 | `click` on `DELETE_ALL` | `refresh_region` | the order lines |
60
67
 
68
+ ### Component events
69
+
70
+ The last seven events above belong to a component region (sprint 161): the trigger is that region's
71
+ id or static id. Their value (the date, view, node id, map object id or zoom level) is what the
72
+ client-side condition compares, and an [Execute JavaScript](#execute-javascript) function gets it as
73
+ `value`, with the component's element (the grid row, calendar cell, map or tree node) as `element`.
74
+ Two of them can be cancelled: a `cancel_event` whose condition holds keeps the calendar's Create
75
+ link or the tree node's link closed, wherever it stands in the sequence; like every `cancel_event`
76
+ it also stops the actions after it, so put it last.
77
+
78
+ A **`set_value` without SQL** on a component event puts the event's value into its affected
79
+ items, in the browser. A tree of departments that filters an employee report, without JavaScript:
80
+
81
+ | Sequence | Event | Action | Affected / items to submit |
82
+ |---|---|---|---|
83
+ | 10 | `tree_selection_change` on the departments tree | `set_value` (no SQL) | `P5_DEPTNO` |
84
+ | 20 | `tree_selection_change` on the departments tree | `refresh_region` | the employees report; items to submit `P5_DEPTNO` |
85
+ | 30 | `tree_selection_change` on the departments tree | `cancel_event` | – (last, as it stops the actions after it; the node's link stays closed) |
86
+
61
87
  ## Actions
62
88
 
63
89
  | Action | Runs in | Effect |
@@ -185,6 +211,7 @@ The function gets one argument with the action's context:
185
211
  | `elements` | The affected items' fields and the affected region, as DOM elements |
186
212
  | `region` | The affected region's element, or `null` |
187
213
  | `message` | The action's message |
214
+ | `element` | A [component event](#component-events)'s element (grid row, calendar cell, map, tree node), else `null` |
188
215
 
189
216
  It may return a promise; an exception is shown as an error message. Besides `actions.register`,
190
217
  `window.pgkiln` offers `getValue(item)`, `setValue(item, value)`, `showSuccess(message)`,
@@ -39,7 +39,8 @@ What's missing is listed in the [feature parity matrix](../apex-feature-parity.m
39
39
  | Page computations (static, item, SQL query, SQL expression, PL/SQL function body) | Computations `before_header` / `after_submit`; function bodies are PL/pgSQL ([chapter 6](06-processing.md#computations)) |
40
40
  | Branches (page or URL, *When button pressed*, server-side condition), before header and after processing | Branches with `when_button` and a condition; URLs stay inside the application ([chapter 6](06-processing.md#branches)) |
41
41
  | Validation types (Rows returned, Expression, Function Body returning Boolean / Error Text, Item is NOT NULL / numeric / a valid date …, Item = Value, Item in Value, character checks, Regular Expression), Always Execute, Display Location | The same types as `type` (`exists`, `sql`, `function_body`, `function_error`, `not_null`, `numeric`, `valid_date`, `equals`, `in_list`, `chars_only`, `regex` …), `always_execute`, `display_location` ([chapter 6](06-processing.md#validations)). Interactive grid column validations aren't there yet: use a validation on the grid's process or a check constraint |
42
- | Dynamic action events (Double Click, Key Down / Press, Mouse Enter / Leave, Select, Resize, Scroll, Page Unload, Before Refresh, Facets Change), conditions (greater / less than, not in list) and actions (Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding, Invoke Interactive Report Dialog) | The same events, conditions and actions ([chapter 7](07-dynamic-actions.md)). Not yet: grid, calendar, map and tree component events; JavaScript expression conditions (use a registered function) |
42
+ | Dynamic action events (Double Click, Key Down / Press, Mouse Enter / Leave, Select, Resize, Scroll, Page Unload, Before Refresh, Facets Change), conditions (greater / less than, not in list) and actions (Cancel Event, Set Style, Collapse / Expand Tree, Show AI Assistant, Trigger Geocoding, Invoke Interactive Report Dialog) | The same events, conditions and actions ([chapter 7](07-dynamic-actions.md)). JavaScript expression conditions: use a registered function |
43
+ | Component events: Row Initialization and Save [Interactive Grid], Date Select and View Change [Calendar], Map Object Clicked and Map Changed, Selection Change [Tree] | `grid_row_init`, `grid_save`, `calendar_date_select`, `calendar_view_change`, `map_object_click`, `map_change`, `tree_selection_change`, triggered by the region ([chapter 7](07-dynamic-actions.md#component-events)) |
43
44
  | Workflow Diagram region | `workflow_diagram` with `{"instance_item": …}` ([chapter 6](06-processing.md#workflow-diagram-region)) |
44
45
  | Map layers Points, Lines, Polygons, Heat Map, Extruded Polygons | `"layer"`: `markers`, `lines`, `polygons`, `heat`, `extruded` (drawn flat, shaded by height), with fill and line colours, width and opacity per layer or per row ([chapter 4](04-pages-and-regions.md#map)) |
45
46
  | Items Image Upload, Text Field with autocomplete, Percent Graph, Display Map | `image_upload`, `autocomplete`, `percent_graph`, `display_map` ([chapter 5](05-items.md#item-types)) |
@@ -338,7 +338,8 @@ src/
338
338
  components.ts property spec of every component (drives the property editor)
339
339
  ui.ts IDE shell (icon rail, toolbar, breadcrumb, status bar), builder theme, form helpers, CSRF check, app tabs
340
340
  i18n.ts (sprint 121) the builder's own texts: BUILDER_LANGUAGES, tr(s) / translatorFor(lang) → tx(key, params),
341
- tx.rich (markup in a sentence), tx.dyn (keys made at run time), tx.label (known breadcrumb labels)
341
+ tx.rich (markup in a sentence), tx.dyn (keys made at run time), tx.label (known breadcrumb labels),
342
+ (sprint 162) tx.code (`backticks` become <code>), withTranslator / scopedTx (a request-scoped translator)
342
343
  i18n/ en.ts defines the builder's keys; de, es, fr, it, nl, pt, zh-cn, zh-tw, ja, ko (sprint 134) are Records of the same keys
343
344
  language.ts (migration 127) the status bar's language menu (POST /builder/language), the sign-in page's
344
345
  language links (?lang=, a cookie), meta.developer.language
@@ -704,8 +705,15 @@ const tx = tr(s); // the developer's language (
704
705
  html`<h2>${tx('wh.summary')}</h2><p>${tx('ab.count', { n: 3 })}</p>`; // plain text: html`` escapes it
705
706
  tx.rich('ab.none_yet', { create: html`<a href="…">${tx('ab.create_one')}</a>` }); // markup inside a sentence
706
707
  tx.dyn(`gallery.region.${type}`, REGION_LABELS[type][0]); // a key made at run time, with a fallback
708
+ tx.code('cr.schedule_help'); // (sprint 162) `backticked` parts become <code>: syntax help
707
709
  ```
708
710
 
711
+ (sprint 162) A long form built by many helpers (the region and report settings, RESTful Services' pages) doesn't
712
+ pass `tx` to each of them: its entry point runs inside `withTranslator(tr(s), () => …)`, and the helpers import
713
+ `scopedTx as tx`, which takes the translator of the request being rendered from an `AsyncLocalStorage` (so two
714
+ requests in different languages never mix; `test/builder-i18n.test.ts` renders German and French concurrently).
715
+ Outside `withTranslator` it is English.
716
+
709
717
  A missing text falls back to English, never to the raw key. Shared helpers that render chrome take the session as
710
718
  an optional last argument (`appHeader(a, 'pages', s)`, `workshopTabs('sql', s)`); `shell()` translates known English
711
719
  breadcrumb labels (`tx.label`) so pages that aren't moved yet still get a translated trail.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgkiln",
3
- "version": "0.82.0",
3
+ "version": "0.83.0",
4
4
  "description": "Open source low-code, SQL-driven application builder for PostgreSQL, inspired by Oracle APEX",
5
5
  "keywords": [
6
6
  "postgresql",
package/public/app.css CHANGED
@@ -1468,6 +1468,8 @@ path.map-near { stroke: #1f2733; stroke-dasharray: 6 4; fill: #1f2733; fill-opac
1468
1468
  .tree-view a, .tree-view summary > span, .tree-leaf > span { display: inline-flex; align-items: center; gap: 0.35rem; }
1469
1469
  .tree-leaf { padding-left: 1rem; }
1470
1470
  .tree-count { font-size: 0.75rem; color: var(--muted); }
1471
+ /* (161) the node a tree_selection_change dynamic action chose */
1472
+ .tree-view li.tree-selected > :is(a, span:not(.tree-count), .tree-row), .tree-view li.tree-selected > details > summary > span { background: var(--accent-soft); border-radius: 3px; outline: 1px solid var(--accent); outline-offset: 1px; }
1471
1473
  /* a linked branch: the disclosure triangle sits in front of the link's row */
1472
1474
  .tree-branch { position: relative; }
1473
1475
  .tree-branch > .tree-row { display: inline-flex; align-items: center; gap: 0.35rem; }
package/public/app.js CHANGED
@@ -507,6 +507,8 @@ const pgkilnUnsaved = (() => {
507
507
 
508
508
  /** (085) what runDa returns to stop the actions after it (a declined confirm) */
509
509
  const STOP = Symbol('stop');
510
+ /** (161) the element of a component event (a grid row, calendar cell, map, tree node): execute_javascript's `element` */
511
+ let componentElement = null;
510
512
  /** (156) does a Cancel Event in these actions hold its condition (decided at once, so the event's effect can be stopped)? */
511
513
  const cancels = (list) => list.some((da) => da.action === 'cancel_event' && conditionHolds(da));
512
514
  const text = (k) => (meta.texts && meta.texts[k]) || k;
@@ -634,6 +636,11 @@ const pgkilnUnsaved = (() => {
634
636
  case 'clear':
635
637
  for (const n of da.items) setItemValue(n, '');
636
638
  return;
639
+ // (161) set_value without SQL on a component event: the event's value, set in the browser
640
+ case 'set_value':
641
+ if (!da.eventValue) break;
642
+ for (const n of da.items) setItemValue(n, value == null ? '' : String(value));
643
+ return;
637
644
  case 'open_region':
638
645
  case 'close_region':
639
646
  for (const el of targets(da)) {
@@ -731,7 +738,7 @@ const pgkilnUnsaved = (() => {
731
738
  const fn = da.fn && actions.get(da.fn);
732
739
  if (!fn) return console.warn(`pgkiln: no function "${da.fn}" registered (pgkiln.actions.register) for dynamic action ${da.id}`);
733
740
  try {
734
- await fn({ value, items: da.items, region: da.region ? document.getElementById(`R${da.region}`) : null, elements: targets(da), message: da.message });
741
+ await fn({ value, items: da.items, region: da.region ? document.getElementById(`R${da.region}`) : null, elements: targets(da), message: da.message, element: componentElement });
735
742
  } catch (e) {
736
743
  console.error(e);
737
744
  showError(e.message);
@@ -920,6 +927,58 @@ const pgkilnUnsaved = (() => {
920
927
  runChain(regionRun('facets_change', document.getElementById(`R${changed.replace(/\D/g, '')}`)));
921
928
  }
922
929
  }
930
+ // (161) component events of grid, calendar, map and tree regions (trigger: the region). The component
931
+ // raises pgkiln:component {event, element, value}; detail.cancelled tells it a cancel_event holds
932
+ // (the calendar's Create link, the tree node's link) and detail.ran how many actions run.
933
+ document.addEventListener('pgkiln:component', (e) => {
934
+ const d = e.detail || {};
935
+ const region = d.element && d.element.closest && d.element.closest('section[id^="R"], div[id^="R"], dialog[id^="R"]');
936
+ const run = regionRun(d.event, region);
937
+ d.ran = run.length;
938
+ if (!run.length) return;
939
+ const value = d.value == null ? '' : String(d.value);
940
+ if (run.some((da) => da.action === 'cancel_event' && conditionHolds(da, value))) d.cancelled = true;
941
+ componentElement = d.element;
942
+ runChain(run, value).finally(() => (componentElement = null));
943
+ });
944
+ // grid_save: the page that comes back after a grid's Save
945
+ for (const id of meta.savedGrids || []) {
946
+ const run = regionRun('grid_save', document.getElementById(`R${id}`));
947
+ if (run.length) runChain(run);
948
+ }
949
+ // calendar_view_change: the page that comes back from a calendar's view or period link (cal_changed=<region>)
950
+ {
951
+ const params = new URLSearchParams(location.search);
952
+ const changed = params.get('cal_changed');
953
+ if (changed) {
954
+ params.delete('cal_changed');
955
+ history.replaceState(history.state, '', `${location.pathname}${params.size ? `?${params}` : ''}${location.hash}`);
956
+ const region = document.getElementById(`R${changed.replace(/\D/g, '')}`);
957
+ const run = regionRun('calendar_view_change', region);
958
+ if (run.length) runChain(run, region.querySelector('.calendar')?.dataset.view || '');
959
+ }
960
+ }
961
+ document.addEventListener('click', (e) => {
962
+ const a = e.target.closest?.('.calendar .cal-toolbar a[href]');
963
+ const region = a && a.closest('section[id^="R"], div[id^="R"]');
964
+ if (!region || !regionRun('calendar_view_change', region).length) return;
965
+ const url = new URL(a.href, location.href);
966
+ url.searchParams.set('cal_changed', region.id.slice(1));
967
+ a.href = url.pathname + url.search + url.hash;
968
+ }, true);
969
+ // tree_selection_change: a node's label chosen (not the disclosure of a linked branch); the node is marked
970
+ document.addEventListener('click', (e) => {
971
+ const node = e.target.closest?.('.tree-view li[data-node]');
972
+ if (!node) return;
973
+ const summary = e.target.closest('summary');
974
+ if (summary && !summary.querySelector(':scope > span:not(.sr-only), :scope > a')) return;
975
+ const d = { event: 'tree_selection_change', element: node, value: node.dataset.node };
976
+ document.dispatchEvent(new CustomEvent('pgkiln:component', { detail: d }));
977
+ if (!d.ran) return;
978
+ node.closest('.tree-view').querySelectorAll('li.tree-selected').forEach((li) => li.classList.remove('tree-selected'));
979
+ node.classList.add('tree-selected');
980
+ if (d.cancelled) e.preventDefault();
981
+ });
923
982
  // after_refresh: a region replaced by a refresh, a lazy load or a master row
924
983
  document.addEventListener('pgkiln:replaced', (e) => {
925
984
  const run = regionRun('after_refresh', e.detail);
@@ -1143,10 +1202,23 @@ const pgkilnUnsaved = (() => {
1143
1202
 
1144
1203
  // ------------------------------------------------------------ calendar
1145
1204
  // Create on click: a click on an empty day or hour slot follows its "+" link.
1205
+ // (161) a day or hour chosen (a click on the cell or its "+"): calendar_date_select; its cancel_event keeps the link closed
1206
+ let addClicked = false;
1146
1207
  document.addEventListener('click', (e) => {
1147
- const cell = e.target.closest?.('.calendar [data-add]');
1148
- if (!cell || e.target.closest('a, button')) return;
1149
- cell.querySelector(':scope > .cal-add')?.click();
1208
+ if (addClicked) return void (addClicked = false);
1209
+ const cell = e.target.closest?.('.calendar [data-date]');
1210
+ if (!cell) return;
1211
+ const add = e.target.closest('a.cal-add');
1212
+ if (!add && e.target.closest('a, button')) return;
1213
+ const d = { event: 'calendar_date_select', element: cell, value: cell.dataset.date };
1214
+ document.dispatchEvent(new CustomEvent('pgkiln:component', { detail: d }));
1215
+ if (d.cancelled) return void e.preventDefault();
1216
+ const link = !add && cell.hasAttribute('data-add') && cell.querySelector(':scope > .cal-add');
1217
+ if (link) {
1218
+ addClicked = true;
1219
+ link.click();
1220
+ addClicked = false;
1221
+ }
1150
1222
  });
1151
1223
  // Drag and drop (mouse): drop an event on a day or hour slot; the server moves it
1152
1224
  // and sends the calendar back. Without JS (and from the keyboard) the event's
@@ -1442,6 +1514,9 @@ const pgkilnUnsaved = (() => {
1442
1514
  return row;
1443
1515
  }
1444
1516
 
1517
+ /** (161) grid_row_init: a new row (Add row, Duplicate); the condition sees the row's number among the new rows */
1518
+ const rowInit = (row) => document.dispatchEvent(new CustomEvent('pgkiln:component', { detail: { event: 'grid_row_init', element: row, value: row.dataset.newRow } }));
1519
+
1445
1520
  /** The editable control of a cell, if any. */
1446
1521
  const control = (td) => td?.querySelector('input:not([type=hidden]), select');
1447
1522
 
@@ -1482,6 +1557,7 @@ const pgkilnUnsaved = (() => {
1482
1557
  if (add) {
1483
1558
  const row = addRow(add.closest('[data-grid]'));
1484
1559
  row?.querySelector('input:not([type=hidden]), select')?.focus();
1560
+ if (row) rowInit(row);
1485
1561
  return;
1486
1562
  }
1487
1563
  // Duplicate: the row's values in a new row (without JS a link does it on the server)
@@ -1498,6 +1574,7 @@ const pgkilnUnsaved = (() => {
1498
1574
  if (from && control(td) && control(from)) setCell(td, control(from).tagName === 'SELECT' ? control(from).value : cellText(from));
1499
1575
  }
1500
1576
  control(row.querySelector('td[data-col]:not([hidden])'))?.focus();
1577
+ rowInit(row);
1501
1578
  return;
1502
1579
  }
1503
1580
  if (e.target.closest('[data-grid-del]')) {
@@ -3247,6 +3324,8 @@ document.addEventListener('DOMContentLoaded', () => {
3247
3324
  // without a Referer: the tiles get the site's origin only (no paths or item values)
3248
3325
  window.L.tileLayer(data.tiles, { attribution: data.attribution, maxZoom: 19, referrerPolicy: 'strict-origin-when-cross-origin' }).addTo(map);
3249
3326
  const popup = (p) => {
3327
+ // (161) a marker or shape clicked (its popup opens): map_object_click sees its id, else its title
3328
+ el.dispatchEvent(new CustomEvent('pgkiln:component', { bubbles: true, detail: { event: 'map_object_click', element: el, value: p.id ?? p.title ?? '' } }));
3250
3329
  // built with the DOM, not HTML strings: titles and texts are data
3251
3330
  const box = document.createElement('div');
3252
3331
  const b = document.createElement('strong');
@@ -3290,6 +3369,8 @@ document.addEventListener('DOMContentLoaded', () => {
3290
3369
  if (data.layers.some((l) => l.kind === 'heat')) heatLegend(map, data.legend);
3291
3370
  if (several) layerSwitch(map, group, built, data.layersLabel);
3292
3371
  if (f) areaFilter(map, f);
3372
+ // (161) map_change: moved or zoomed by the user (after the first view); the condition sees the zoom level
3373
+ map.on('moveend', () => el.dispatchEvent(new CustomEvent('pgkiln:component', { bubbles: true, detail: { event: 'map_change', element: el, value: map.getZoom() } })));
3293
3374
  }
3294
3375
  });
3295
3376
 
@@ -401,6 +401,10 @@ body.ide {
401
401
  .ide-head-actions { margin-left: auto; }
402
402
  .ide-tabs { display: flex; gap: 4px; margin-top: 12px; overflow-x: auto; scrollbar-width: thin; }
403
403
  .ide-page > .ide-tabs { margin-top: 0; border-bottom: 1px solid var(--border); }
404
+ /* (sprint 163) regions and two-column rows stacked on a page always have a gap between them (pages used to rely on
405
+ an explicit .u-spacer, and the ones without one let a region touch the one above); not the regions side by side in a
406
+ grid, which have the grid's gap; :where() keeps it weaker than any page's own margin rule */
407
+ :where(.ide-page :is(.region, .columns, :has(> .region)) + :is(.region, .columns, :has(> .region)):not(:is(.columns, .qs-columns, .vec-columns, .ws-cols, .wh-top, [class*="grid"]) > *)) { margin-top: 1rem; }
404
408
  .ide-tab {
405
409
  position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 8px 11px 9px; color: var(--muted); text-decoration: none;
406
410
  border-bottom: 2px solid transparent; border-radius: var(--radius-sm) var(--radius-sm) 0 0; white-space: nowrap; font-weight: 550;
@@ -1340,7 +1344,7 @@ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
1340
1344
  .cron-field-grid input { width: 100%; font-family: var(--mono, monospace); }
1341
1345
  .cron-preview { border-left: 3px solid var(--accent); padding: 0.4rem 0.8rem; margin: 0.6rem 0; background: var(--accent-soft); border-radius: 0 4px 4px 0; }
1342
1346
  .cron-runs { margin: 0.25rem 0 0; padding-left: 1.4rem; font-variant-numeric: tabular-nums; }
1343
- .cron-error { color: var(--danger, #b42318); }
1347
+ .cron-error { color: var(--danger); }
1344
1348
  .cron-sql { white-space: pre-wrap; overflow-wrap: anywhere; }
1345
1349
  /* (sprint 102) SQL Monitor: refresh controls, session actions, bars in Top SQL */
1346
1350
  .sm-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; }
@@ -1526,7 +1530,7 @@ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
1526
1530
  .mail-queue-filters .field { min-width: 0; flex: 1 1 160px; max-width: 260px; }
1527
1531
  .mail-queue-stats { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
1528
1532
  .mail-queue-stats .stat b { font-size: 1.3rem; }
1529
- .stat.stat-bad b { color: var(--danger, #b42318); }
1533
+ .stat.stat-bad b { color: var(--danger); }
1530
1534
  .inline-form { display: inline; margin: 0; }
1531
1535
  .mail-failures .buttons { flex-wrap: wrap; gap: 6px; }
1532
1536
  .mail-answer { overflow-wrap: anywhere; font-family: var(--font-mono, monospace); font-size: 0.85em; }
@@ -1648,3 +1652,22 @@ a.cp-type:hover, a.cp-type:focus-visible { border-color: var(--accent); }
1648
1652
 
1649
1653
  /* (sprint 139, AP-6) OpenTelemetry */
1650
1654
  .otel-problem { color: var(--danger); overflow-wrap: anywhere; }
1655
+
1656
+ /* (sprint 163) an application's REST API page: status pills under the intro, the New client form behind a button */
1657
+ .api-intro { max-width: 80ch; margin: 0 0 0.6rem; }
1658
+ .api-status { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; padding: 0; margin: 0; }
1659
+ .api-status li { display: inline-block; border: 1px solid var(--border); border-radius: 14px; padding: 3px 12px; font-size: 0.875rem; overflow-wrap: anywhere; }
1660
+ .api-status li.is-ok > span:first-child { color: var(--success); }
1661
+ .api-status li.is-bad { border-color: var(--danger); }
1662
+ .api-status li.is-bad > span:first-child { color: var(--danger); font-weight: 700; }
1663
+ .api-top { align-items: start; }
1664
+ .api-top form > .field + .field { margin-top: 0.9rem; }
1665
+ .api-sub { font-size: 0.95rem; margin: 1.25rem 0 0.5rem; }
1666
+ .api-new > summary { list-style: none; display: inline-flex; }
1667
+ .api-new > summary::-webkit-details-marker { display: none; }
1668
+ .api-new[open] > summary { margin-bottom: 0.75rem; }
1669
+ .api-new-body { border-top: 1px solid var(--border); padding-top: 0.75rem; }
1670
+ .api-client-actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
1671
+ .api-client-actions select { width: auto; min-height: 0; padding-block: 0.2rem; font-size: 0.8125rem; }
1672
+ .api-client-actions .inline-form { display: flex; gap: 6px; align-items: center; }
1673
+ .api-clients td.actions { text-align: end; }
@@ -10,6 +10,9 @@
10
10
  // Strict CSP: no inline styles; geometry goes into SVG attributes, sizes through the CSSOM.
11
11
  (() => {
12
12
  'use strict';
13
+ // (sprint 162) texts in the builder's language: #builder-texts (shell(), keys js.*), English in en.ts
14
+ const TEXTS = (() => { try { return JSON.parse(document.getElementById('builder-texts')?.dataset.texts || '{}'); } catch { return {}; } })();
15
+ const msg = (key, params = {}) => (TEXTS[key] ?? key).replace(/\{(\w+)\}/g, (m, k) => (k in params ? String(params[k]) : m));
13
16
  // the data dictionary's Print button
14
17
  for (const b of document.querySelectorAll('.dm-dict-actions [data-dm=print]')) {
15
18
  b.hidden = false;
@@ -104,7 +107,7 @@
104
107
  btn('redo').disabled = !redo.length;
105
108
  const d = dirty();
106
109
  btn('save').classList.toggle('btn-hot', d);
107
- status.textContent = d ? 'Unsaved changes' : '';
110
+ status.textContent = d ? msg('js.dm.unsaved') : '';
108
111
  }
109
112
  function remember(before) {
110
113
  undo.push(before);
@@ -136,15 +139,15 @@
136
139
  format: 'json',
137
140
  positions: JSON.stringify([...boxes].map(([name, b]) => ({ name, x: Math.round(b.x), y: Math.round(b.y) }))),
138
141
  });
139
- status.textContent = 'Saving…';
142
+ status.textContent = msg('js.dm.saving');
140
143
  try {
141
144
  const res = await fetch(saveForm.action, { method: 'POST', body, credentials: 'same-origin', headers: { accept: 'application/json' } });
142
145
  if (!res.ok) throw new Error(String(res.status));
143
146
  saved = JSON.stringify(snapshot());
144
147
  changed();
145
- status.textContent = 'Saved';
148
+ status.textContent = msg('js.dm.saved');
146
149
  } catch (e) {
147
- status.textContent = `Not saved (${e.message}): try again`;
150
+ status.textContent = msg('js.dm.not_saved', { error: e.message });
148
151
  }
149
152
  }
150
153
  btn('save').addEventListener('click', save);
@@ -333,7 +336,7 @@
333
336
  ctx.drawImage(img, 0, 0, W, H);
334
337
  c.toBlob((blob) => blob && download(blob, `${fileName}.png`), 'image/png');
335
338
  };
336
- img.onerror = () => (status.textContent = 'The PNG could not be made: export SVG instead');
339
+ img.onerror = () => (status.textContent = msg('js.dm.no_png'));
337
340
  img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgText())}`;
338
341
  });
339
342
  btn('print').addEventListener('click', () => {
@@ -7,6 +7,9 @@
7
7
  // JavaScript the page's Refresh link reloads it.
8
8
  (() => {
9
9
  'use strict';
10
+ // (sprint 162) texts in the builder's language: #builder-texts (shell(), keys js.*), English in en.ts
11
+ const TEXTS = (() => { try { return JSON.parse(document.getElementById('builder-texts')?.dataset.texts || '{}'); } catch { return {}; } })();
12
+ const msg = (key, params = {}) => (TEXTS[key] ?? key).replace(/\{(\w+)\}/g, (m, k) => (k in params ? String(params[k]) : m));
10
13
  const live = document.querySelector('[data-sm-live]');
11
14
  const controls = document.querySelector('[data-sm-controls]');
12
15
  if (!live || !controls) return;
@@ -26,7 +29,7 @@
26
29
 
27
30
  const show = () => {
28
31
  pause.setAttribute('aria-pressed', paused ? 'true' : 'false');
29
- pause.textContent = paused ? 'Resume' : 'Pause';
32
+ pause.textContent = paused ? msg('js.sm.resume') : msg('js.sm.pause');
30
33
  live.classList.toggle('is-paused', paused);
31
34
  };
32
35
  const schedule = () => {
@@ -52,7 +55,7 @@
52
55
  paused = true;
53
56
  show();
54
57
  const note = live.querySelector('[data-sm-updated]');
55
- if (note) note.textContent = 'Refresh stopped: the monitor could not be reached (signed out?). Reload the page.';
58
+ if (note) note.textContent = msg('js.sm.stopped');
56
59
  }
57
60
  }
58
61
  select.addEventListener('change', () => {