pgkiln 0.52.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/SECURITY.md +6 -1
- package/db/migrations/125_app_change.sql +23 -0
- package/db/migrations/126_mail_queue_network_access.sql +119 -0
- package/docs/apex-feature-parity.md +41 -12
- package/docs/guide/01-installation.md +1 -1
- package/docs/guide/03-builder.md +116 -10
- package/docs/guide/06-processing.md +6 -1
- package/docs/guide/08-security.md +55 -0
- package/docs/guide/09-reference.md +3 -1
- package/docs/guide/11-from-apex.md +1 -0
- package/docs/guide/12-development.md +52 -11
- package/docs/guide/14-globalization.md +49 -1
- package/docs/guide/18-cli.md +21 -1
- package/docs/guide/19-rest-data-sources.md +12 -0
- package/docs/guide/20-ai-agents.md +8 -2
- package/examples/gallery/README.md +37 -6
- package/examples/gallery/gallery.json +23 -1
- package/examples/gallery/samples/sample-calendar.sql +172 -0
- package/examples/gallery/samples/sample-cards.sql +157 -0
- package/examples/gallery/samples/sample-charts.sql +265 -0
- package/examples/gallery/samples/sample-dynamic-actions.sql +177 -0
- package/examples/gallery/samples/sample-grids.sql +151 -0
- package/examples/gallery/samples/sample-reporting.sql +151 -0
- package/examples/gallery/samples/ux-patterns.sql +295 -0
- package/examples/gallery/utilities/announcements.json +24 -0
- package/examples/gallery/utilities/lookup-lists.json +28 -0
- package/examples/gallery/utilities/release-notes.json +41 -0
- package/examples/hr/hr_70_data_security.sql +79 -0
- package/package.json +1 -1
- package/public/app.css +99 -23
- package/public/builder.css +71 -1
- package/public/builder.js +4 -0
- package/src/app.ts +9 -0
- package/src/builder/app-updates.ts +55 -0
- package/src/builder/data-security.ts +182 -0
- package/src/builder/gallery.ts +94 -47
- package/src/builder/home.ts +16 -5
- package/src/builder/mail-queue.ts +212 -0
- package/src/builder/mail.ts +72 -45
- package/src/builder/network-access.ts +140 -0
- package/src/builder/object-actions.ts +1 -0
- package/src/builder/object-browser.ts +1 -1
- package/src/builder/rest-catalogs.ts +19 -4
- package/src/builder/sql.ts +2 -0
- package/src/builder/themeroller.ts +47 -6
- package/src/builder/ui.ts +5 -0
- package/src/builder/websources.ts +1 -1
- package/src/builder/workspace-mail.ts +121 -0
- package/src/builder/workspaces.ts +1 -0
- package/src/cli/main.ts +25 -3
- package/src/cli/mcp.ts +40 -4
- package/src/cli/only.ts +52 -0
- package/src/cli/replace.ts +5 -1
- package/src/datasec.ts +343 -0
- package/src/mail/mail.ts +50 -11
- package/src/mail/providers.ts +6 -3
- package/src/metadata.ts +2 -0
- package/src/network-acl.ts +126 -0
- package/src/objectstore.ts +3 -0
- package/src/runtime/charts.ts +4 -1
- package/src/runtime/engine.ts +3 -1
- package/src/runtime/regions.ts +8 -5
- package/src/runtime/render.ts +4 -2
- package/src/runtime/styles.ts +54 -12
- package/src/webclient.ts +45 -4
- package/src/webrequests.ts +5 -0
- package/src/websources.ts +30 -12
|
@@ -781,7 +781,12 @@ Microsoft retires basic authentication (a password) for SMTP in Exchange Online:
|
|
|
781
781
|
or the Graph provider. Secrets are stored encrypted with `PGKILN_SECRET_KEY`, are write-only in the
|
|
782
782
|
builder, never exported and never readable by applications. Each service lists the **From
|
|
783
783
|
addresses** it may send as (an address, or `@example.com` for a whole domain); an administrator
|
|
784
|
-
chooses each application's service, its From address and an optional **limit per day**.
|
|
784
|
+
chooses each application's service, its From address and an optional **limit per day**. A
|
|
785
|
+
workspace's administrators can also set up the [workspace's own mail
|
|
786
|
+
service](03-builder.md#a-workspaces-own-mail-service) (sprint 118): the workspace's applications that
|
|
787
|
+
an administrator gave no service send through it, with its default From address. Administration →
|
|
788
|
+
[Mail queue](03-builder.md#mail-queue) shows the delivery per hour and per application, the slowest
|
|
789
|
+
provider calls and the failures with the provider's answer, with Retry and Purge.
|
|
785
790
|
|
|
786
791
|
**How mail is sent.** `meta.send_mail` and the others only *queue* the mail, in the caller's
|
|
787
792
|
transaction: a transaction that rolls back sends nothing. After the commit, the server sends it at
|
|
@@ -540,6 +540,61 @@ quoted with `escapeIdentifier`, every value is checked (dates, numbers, schema n
|
|
|
540
540
|
The page is for administrators only (others get 403), every change needs the CSRF token, and pgkiln's own roles can't
|
|
541
541
|
be changed, dropped or granted from it, so the page can't take pgkiln's own connections away.
|
|
542
542
|
|
|
543
|
+
## Data security per table: rows, columns and values
|
|
544
|
+
|
|
545
|
+
(sprint 119) PostgreSQL has row level security but no column masking, so pgkiln puts a table's security in three
|
|
546
|
+
layers, all ordinary database objects, and shows them on one page: **SQL Workshop → Object Browser → a table →
|
|
547
|
+
Security** (also *Security…* in the table's ⋯ menu). It is pgkiln's answer to APEX 26.2's Deep Data Security.
|
|
548
|
+
|
|
549
|
+
- **Rows**: the table's row level security policies (above), listed with a link to Table Properties to switch row
|
|
550
|
+
level security on and to *Add policy*.
|
|
551
|
+
- **Columns**: a matrix of **database roles × columns** with *read* and *update* per cell. The rows are the roles
|
|
552
|
+
that have privileges on the table and the database roles of the workspace's applications (with the applications
|
|
553
|
+
that run as them). Apply writes `GRANT` / `REVOKE SELECT (c, …)` and `UPDATE (c, …)`. A column a role may not read
|
|
554
|
+
is refused by PostgreSQL ("permission denied") whoever sends the query. The table's owner, superusers and roles that
|
|
555
|
+
bypass row level security are listed apart: column privileges can't restrict them.
|
|
556
|
+
- **Values**: masked columns per **application role** (`meta.has_role()` of the signed-in user). A column's mask is
|
|
557
|
+
*empty (null)*, `***` or `***` plus the last four characters; tick the application roles that see the real value,
|
|
558
|
+
and *Everyone else* for users with none of the listed roles. The masks live in a **masking view** next to the table
|
|
559
|
+
(default name `<table>_masked`):
|
|
560
|
+
|
|
561
|
+
```sql
|
|
562
|
+
create view sales.orders_masked with (security_barrier) as
|
|
563
|
+
select t.id, t.customer,
|
|
564
|
+
case when (select meta.has_role('manager')) then t.amount end as amount,
|
|
565
|
+
case when false then t.iban::text else '***' || right(t.iban::text, 4) end as iban
|
|
566
|
+
from sales.orders t;
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
The view is owned by a role per schema, `<schema>_masking` (nologin), which pgkiln creates the first time. That
|
|
570
|
+
role is no owner, superuser or role that bypasses row level security (Apply checks it), so the table's policies
|
|
571
|
+
still apply inside the view; and it is a member of the database roles that read the table, so policies written
|
|
572
|
+
`to <role>` apply as well. The configuration is kept in the view's comment, so it travels with `pg_dump`,
|
|
573
|
+
Generate DDL and the change log; there is no `meta` table for it.
|
|
574
|
+
|
|
575
|
+
**Preview SQL** shows the statements, **Apply** runs them in one transaction (and records a change set in the
|
|
576
|
+
Change Log), **Open in the worksheet** puts them there. Nothing is changed when one statement fails.
|
|
577
|
+
|
|
578
|
+
**The mask holds only where the view is read.** As long as a role may still read the raw column on the table, its
|
|
579
|
+
queries on the table see the value; the preview warns about each such column. Point the application's pages,
|
|
580
|
+
REST handlers and AI tools at the view, then untick *read* of the masked columns for the role, and the value is
|
|
581
|
+
masked everywhere that role connects.
|
|
582
|
+
|
|
583
|
+
Every client meets the same rules because they all run as the application's database role with the same identity:
|
|
584
|
+
|
|
585
|
+
| Client | Runs as | `meta.app_user()` / `meta.has_role()` from |
|
|
586
|
+
|---|---|---|
|
|
587
|
+
| Pages, processes, dynamic actions, AI assistant and AI agent tools | the application's role (`appTx`) | the session |
|
|
588
|
+
| REST module handlers, AutoREST | the application's role | the bearer token (its user, the user's roles) |
|
|
589
|
+
| The MCP server's `run_query` with `alias` (and `user`) | the application's role | the user's roles in the application ([chapter 20](20-ai-agents.md#safety)) |
|
|
590
|
+
| psql, other tools | whatever role they log in as | — (only grants and policies apply) |
|
|
591
|
+
|
|
592
|
+
Policies and masks that use `meta.has_role()` can be combined: with a policy that shows a manager the rows of their
|
|
593
|
+
department, and `amount` masked for everyone but `manager`, a clerk reads their own rows with an empty amount.
|
|
594
|
+
Policies written per database role (`to sales_app`) apply to the masking role for every role it is a member of, so
|
|
595
|
+
prefer policies on `meta.app_user()` / `meta.has_role()` on tables with a masking view. The HR example's page 48
|
|
596
|
+
*Salaries (masked)* reads `hr.emp_masked` (`examples/hr/hr_70_data_security.sql`).
|
|
597
|
+
|
|
543
598
|
## Session state protection
|
|
544
599
|
|
|
545
600
|
- **URL items**: on pages with protection *Arguments must have checksum* (the default), item
|
|
@@ -81,7 +81,9 @@ select meta.web_request_source('EXCHANGE', '{"currency": "EUR"}');
|
|
|
81
81
|
must be on `PGKILN_REST_ALLOWED_HOSTS` (unset: no calls), private and loopback addresses are refused
|
|
82
82
|
when the connection is made unless the host is in `PGKILN_REST_PRIVATE_HOSTS`, redirects (at most 3)
|
|
83
83
|
go through the same checks, the response is cut off at `PGKILN_REST_MAX_BYTES` (default 5 MB) and
|
|
84
|
-
the time limit is 1–60 seconds.
|
|
84
|
+
the time limit is 1–60 seconds. A workspace's [network access list](03-builder.md#network-access)
|
|
85
|
+
(sprint 118) narrows the hosts for its applications: a refused request ends with `status` `error`
|
|
86
|
+
and the reason in `message`, and is logged (debug log, Refused calls).
|
|
85
87
|
- **Web credentials** are named, never passed: `p_credential => 'NAME'` signs the request with a
|
|
86
88
|
credential of the current application (basic, bearer, header, OAuth2), and only for the URLs it is
|
|
87
89
|
valid for. The secret is decrypted by the server for the request only and is never stored with it
|
|
@@ -65,6 +65,7 @@ What's missing is listed in the [feature parity matrix](../apex-feature-parity.m
|
|
|
65
65
|
| Automatic Time Zone | Settings → Globalization → Time zone and Automatic time zone; My account → Time zone ([chapter 14](14-globalization.md#time-zones)) |
|
|
66
66
|
| Universal Theme's default style (26.1: *Iris*) | Base style *Iris* (the default for new applications), *Lavender* or *Standard* ([chapter 14](14-globalization.md#base-styles-iris-lavender-and-standard)) |
|
|
67
67
|
| Theme styles, *Enable End Users to Choose Theme Style* | Theme style (automatic/light/dark) and *Users may choose light or dark*; Theme Roller style variants with *Users may choose a style* ([chapter 14](14-globalization.md#style-variants-theme-roller)) |
|
|
68
|
+
| Universal Theme 26.2: *Pillar Light* / *Pillar Dark*, Theme Roller's *Header Pillar Strip*, `u-color-*-subtle` | Theme Roller → *Navigation appearance* and *Header strip colour* (per application or style), the same utility classes ([chapter 14](14-globalization.md#navigation-appearances-pillar-light-and-pillar-dark)) |
|
|
68
69
|
| Template Options (regions, buttons) | *Template options* in the Page Designer: CSS classes from a fixed list ([chapter 4](04-pages-and-regions.md#template-options)) |
|
|
69
70
|
| ORDS | Not needed to serve apps; REST APIs with PostgREST, see [below](#ords-and-postgrest) |
|
|
70
71
|
| Export `f123.sql` / APEXlang | `meta.export_app('alias')` (JSON) |
|
|
@@ -10,6 +10,7 @@ db/
|
|
|
10
10
|
seed/*.sql the HR sample (not for production)
|
|
11
11
|
examples/ example applications as SQL (the tutorial)
|
|
12
12
|
examples/plugins/ plug-in files (template components) to import
|
|
13
|
+
examples/gallery/ the App Gallery: gallery.json, starters/ and utilities/ (blueprints), samples/ (single-file sample apps)
|
|
13
14
|
scripts/migrate.ts migration/seed runner (src/migrate.ts does the work)
|
|
14
15
|
website/ the website pgkiln.vargar.eu (VitePress): landing page + this guide, synced from docs/ at build time;
|
|
15
16
|
cd website && npm install && npm run dev; scripts/deploy.sh publishes it (see website/deploy/)
|
|
@@ -42,7 +43,8 @@ src/
|
|
|
42
43
|
merge into the main application or refresh the copy, both through cli/replace.ts
|
|
43
44
|
cli/ the command line: main.ts (commands, help, exit codes), apps.ts (connect, export,
|
|
44
45
|
read, import), files.ts (directories, zip), diff.ts, replace.ts (import --replace in place),
|
|
45
|
-
mcp.ts (`pgkiln mcp`: the MCP server for AI coding agents, chapter 20)
|
|
46
|
+
mcp.ts (`pgkiln mcp`: the MCP server for AI coding agents, chapter 20), only.ts (sprint 116:
|
|
47
|
+
`import --replace --only pages/12`, the named files merged over the application's current export)
|
|
46
48
|
app.ts / server.ts Fastify setup / entry point
|
|
47
49
|
db.ts the owner and shared runtime pools, `runtime` (the current scope's: runtimeScope), appTx() (SET LOCAL ROLE + pgkiln.* settings, NOTICEs to the debug log), savepoints
|
|
48
50
|
workspace-db.ts isolated workspaces (090): the isolated applications (cached 5 s), a pool per workspace login (passwords from
|
|
@@ -95,6 +97,9 @@ src/
|
|
|
95
97
|
objects, type reporting, roles viewer/editor/administrator as schemes EDITOR and ADMIN, page 1 a Data
|
|
96
98
|
Reporter), reportingApps(), reportingAppCount() (meta.reporting_app_count, for the workspace home)
|
|
97
99
|
tabledef.ts (sprint 95) a table as a definition: readTable(), checkTable(), tableSql() (CREATE, or ALTER from the catalog's version)
|
|
100
|
+
datasec.ts (sprint 119, WS-13) data security per table: readSecurity() (policies, column privileges per role, the
|
|
101
|
+
masking view and its configuration in the view comment), checkSecurity(), securitySql() (GRANT / REVOKE,
|
|
102
|
+
the masking view owned by <schema>_masking); the page is builder/data-security.ts
|
|
98
103
|
sqlformat.ts (sprint 93) formatSql(): the worksheet's Format (clauses per line, keyword case; strings and comments kept)
|
|
99
104
|
sqlplan.ts (sprint 92) EXPLAIN (FORMAT JSON) as a tree: parsePlan() (self time, slowest step, misestimates), planText()
|
|
100
105
|
quicksql.ts Quick SQL: shorthand parser and PostgreSQL DDL generator (unit tested)
|
|
@@ -110,7 +115,12 @@ src/
|
|
|
110
115
|
geocode.ts the installation's geocoder for address items (GEOCODER_URL, Nominatim search API)
|
|
111
116
|
mvt.ts Mapbox Vector Tile encoding for map layers served as tiles
|
|
112
117
|
yamltext.ts the text style of the directory export: a strict YAML subset, written and read
|
|
113
|
-
webclient.ts outgoing HTTP to web services: allow-list, address checks at connect time (SSRF), redirects, limits
|
|
118
|
+
webclient.ts outgoing HTTP to web services: allow-list, address checks at connect time (SSRF), redirects, limits;
|
|
119
|
+
(sprint 118) a request's scope (OutboundScope): the workspace's network access list, checked on every hop
|
|
120
|
+
(checkUrl/scopeProblem), refusals reported to the scope
|
|
121
|
+
network-acl.ts (sprint 118, WS-9) workspace network access lists (meta.workspace.network_*): scopeForApp/scopeForWorkspace
|
|
122
|
+
(no cache), parseHostList, recordRefusal/purgeRefusals (meta.network_refusal, 7 days), mailHostAddress
|
|
123
|
+
(a workspace mail service's SMTP host: both lists, resolved once, the checked address connected to)
|
|
114
124
|
datapump.ts (sprint 103, DA-16) Schema Export / Import jobs (meta.dump_job): findTools (pg_dump/pg_restore ≥ the
|
|
115
125
|
server's major), startExport (pg_dump, argument array, PGPASSWORD), readToc/parseToc (pg_restore --list),
|
|
116
126
|
startImport (pg_restore -f - run in one transaction between schema renames; data-only in FK order),
|
|
@@ -137,7 +147,10 @@ src/
|
|
|
137
147
|
or XOAUTH2, Microsoft Graph sendMail, Amazon SES v2 raw MIME with signV4, Resend, Postmark, SendGrid,
|
|
138
148
|
Mailgun, log; MailError says whether a retry may help; client-credentials token cache; settingsProblems),
|
|
139
149
|
mail.ts (sendWith(): service enabled, allowed sender, secret decrypted; mailTick(): claim with SKIP LOCKED,
|
|
140
|
-
send, retry after 1/4/16/64 minutes, purge after 30 days; the NOTIFY pgkiln_mail listener)
|
|
150
|
+
send, retry after 1/4/16/64 minutes, purge after 30 days; the NOTIFY pgkiln_mail listener);
|
|
151
|
+
(sprint 118) the service of meta.mail_service_for_app (the app's, else its workspace's own), each attempt's
|
|
152
|
+
provider and duration, serviceSettings()/verifyService(): a workspace service's checks (no base or token URL,
|
|
153
|
+
its SMTP host through network-acl.ts mailHostAddress)
|
|
141
154
|
ai/ AI services (migration 060): types.ts (the provider interface, AiError kinds),
|
|
142
155
|
anthropic.ts (Claude through @anthropic-ai/sdk: streamed, effort, structured outputs via
|
|
143
156
|
output_config.format, refusal fallbacks, stop_reason checks, typed SDK errors), openai.ts (the openai
|
|
@@ -164,7 +177,8 @@ src/
|
|
|
164
177
|
shortcuts.ts (103) "NAME" shortcuts in static content, help texts and confirm messages
|
|
165
178
|
render.ts page chrome (nav, breadcrumb), dynamic action JSON, theme (the page's nonce'd <style>, light/dark and style switches)
|
|
166
179
|
styles.ts base styles (BASE_STYLES: Iris, Lavender, Standard; baseStyleOf → html data-style), Theme Roller style variants: fixed lists (fonts, sizes, corners), parseStyle/appStyles checks, the request's
|
|
167
|
-
style (user choice, default), themeCss() (only hex values and constants reach the CSS)
|
|
180
|
+
style (user choice, default), themeCss() (only hex values and constants reach the CSS); (sprint 117) NAV_APPEARANCES
|
|
181
|
+
(Pillar Light / Dark), navAppearance() → the <body> classes nav-pillar-*, the header strip (--strip)
|
|
168
182
|
template-options.ts template options: the fixed CSS class list per region and button, templateClasses() (unknown values ignored)
|
|
169
183
|
regions.ts region shell + chart (drill-down links, gauge settings)/cards/dynamic dispatch with row limits, lazy placeholder and cache, buttons (menu buttons, badges; (124) menu entries {action} → data-menu-entry for menu_entry dynamic actions)
|
|
170
184
|
report.ts, report-views.ts (group by, pivot, chart), compute.ts (computed column expressions), grid.ts (aggregates, row actions, Actions menu, single row view, layoutFromForm), grid-layout.ts (column layouts: clean, arrange, per user), master-detail.ts (signed master row selection, details), facets.ts (facetChart: a facet's counts as a chart, sprint 65), items.ts
|
|
@@ -253,7 +267,10 @@ src/
|
|
|
253
267
|
wizards.ts create page wizards: step 2 forms per page type (defaults from meta.wizard_defaults), POST → meta.generate_page
|
|
254
268
|
(the generators are PL/pgSQL in migration 047: catalog, defaults, form/cards/calendar/chart/map/facets/master-detail)
|
|
255
269
|
home.ts App Builder home at /builder/apps and /builder (tiles, applications report/cards, Recent; /builder redirects
|
|
256
|
-
to the Workspace home when meta.workspace.builder_home = 'home'), Create, Import, Dashboard, Utilities
|
|
270
|
+
to the Workspace home when meta.workspace.builder_home = 'home'), Create, Import, Dashboard, Utilities;
|
|
271
|
+
(116) Updated by, working copies and the application lock in the report and the cards
|
|
272
|
+
app-updates.ts (sprint 116, migration 125) who changed an application last: developer() notes a builder POST under
|
|
273
|
+
/apps/:id or /pages/:pid (or a Create / Import), an onSend hook records a success in meta.app_change
|
|
257
274
|
workspace-home.ts (sprint 109, migration 119) the Workspace home /builder/home, opened after sign-in: tool cards (Data Reporter
|
|
258
275
|
when GET /builder/reporter exists), workspace message edited in place (workspaceAdmin), Summary, Top
|
|
259
276
|
applications / users / developers over meta.developer.home_timeframe, System message (src/release-check.ts),
|
|
@@ -286,7 +303,15 @@ src/
|
|
|
286
303
|
(Workspace home). Every id from a request is looked up in the current workspace
|
|
287
304
|
region-help.ts the Attributes (JSON) help per region type, with links to the guide
|
|
288
305
|
mail.ts Workspace utilities → Mail services (administrators: providers, write-only secret, allowed senders,
|
|
289
|
-
applications with From and daily limit, test) and Applications → Activity → Mail (retry, cancel)
|
|
306
|
+
applications with From and daily limit, test) and Applications → Activity → Mail (retry, cancel);
|
|
307
|
+
serviceForm/formValues/runCheck shared with workspace-mail.ts (sprint 118)
|
|
308
|
+
mail-queue.ts (sprint 118, WS-9) Administration → Mail queue (/builder/mail-queue): queueScope (administrators: all or
|
|
309
|
+
?ws=; workspace administrators: the current workspace), figures, per hour, per workspace / application,
|
|
310
|
+
slowest provider calls, failures; Retry / Purge one or all failed, scope checked again per mail
|
|
311
|
+
network-access.ts (sprint 118, WS-9) Administration → Network access (/builder/network): the installation's list, a workspace's
|
|
312
|
+
list (workspaceAdmin), Check a URL (nothing called), the workspaces (administrators), refused calls
|
|
313
|
+
workspace-mail.ts (sprint 118, WS-9) a workspace's own mail service (/builder/workspaces/:id/mail, WORKSPACE_<id>): its
|
|
314
|
+
administrators only, write-only secret, checks through mail.ts runCheck with the workspace's guard
|
|
290
315
|
shared.ts Shared Components and access control
|
|
291
316
|
designer.ts page designer: component tree (with computations and branches), layout canvas and gallery, property editor, toolbar;
|
|
292
317
|
(sprint 86) GET /builder/apps/:app/pages/:no, /builder/pages/:id redirects browsers there (designerUrl in ui.ts)
|
|
@@ -304,6 +329,7 @@ src/
|
|
|
304
329
|
object-browser.ts (sprint 75) the Object Browser: objects by type, system objects hidden, a table in tabs, column actions as SQL to review
|
|
305
330
|
table-editor.ts (sprint 95) Table Properties: GET/POST /sql/objects/table (create, edit ?o=, ?template=), fromForm(), Preview / Apply
|
|
306
331
|
(one transaction) / Open in the worksheet
|
|
332
|
+
data-security.ts (sprint 119) a table's Security: GET/POST /sql/objects/security?o= (policies, roles × columns, masks), Preview / Apply
|
|
307
333
|
object-actions.ts (sprint 94) an object's ⋯ menu (objectMenu) in the worksheet and the Object Browser: Quick DDL (objectDdl), Drop with
|
|
308
334
|
dependents, Add index / trigger / policy as drafts; GET /sql/objects/action, /sql/objects/panel (Open in a panel)
|
|
309
335
|
data-modeler.ts (sprint 98) SQL Workshop → Data Modeler: /sql/modeler (diagrams, meta.sql_diagram, 111), /:id (SVG), /:id/objects, /layout,
|
|
@@ -348,7 +374,8 @@ src/
|
|
|
348
374
|
ldap.ts Users → LDAP directories
|
|
349
375
|
documents.ts document template preview (Shared Components)
|
|
350
376
|
pwa.ts Settings → Progressive Web App (icon upload)
|
|
351
|
-
themeroller.ts Settings → Theme Roller: style variants (add, edit, rename, delete), default style, users may choose
|
|
377
|
+
themeroller.ts Settings → Theme Roller: style variants (add, edit, rename, delete), default style, users may choose;
|
|
378
|
+
(sprint 117) navigation appearance and header strip colours (application and per style), the preview's menu
|
|
352
379
|
subscriptions.ts Shared Components → Subscriptions: subscribe, refresh, unsubscribe, subscribers and publish; the note under a component
|
|
353
380
|
reporter.ts page designer: Data Reporter settings (sources: table or view, offered columns, labels, masks; sharing;
|
|
354
381
|
(sprint 110) a dataset as a source, who may edit, who may moderate, publishing)
|
|
@@ -374,8 +401,10 @@ src/
|
|
|
374
401
|
templates.ts template components: preview, plug-in export/import, region settings, report column templates
|
|
375
402
|
code-editor.ts code fields (data-code marks), /builder/code/completions (scoped to the app's role), /builder/code/check
|
|
376
403
|
instance.ts Workspace utilities → Instance settings (src/instance.ts: session and sign-in settings, configuration overview)
|
|
377
|
-
gallery.ts the App Gallery (sprint 61): examples/gallery/gallery.json, sample apps (administrators
|
|
378
|
-
|
|
404
|
+
gallery.ts the App Gallery (sprint 61, 120): examples/gallery/gallery.json, sample apps (administrators: migrate --example,
|
|
405
|
+
or one SQL file of examples/ or examples/gallery/samples/ in one transaction), starter and utility apps
|
|
406
|
+
(blueprints of starters/ and utilities/ → openBlueprint's review), custom apps (the workspace's boilerplates);
|
|
407
|
+
four tabs with counts, ?q= search
|
|
379
408
|
app-groups.ts application groups (092): a workspace's groups, a group per application (the App Builder home filters)
|
|
380
409
|
cross-app.ts Cross Application Reports (sprint 61): REPORTS (one SQL per topic over the workspace's applications)
|
|
381
410
|
workspaces.ts workspaces (064): loadWorkspaces/appAllowed (checked in ui.ts developer() for every /apps/:id and /pages/:pid
|
|
@@ -396,7 +425,8 @@ src/
|
|
|
396
425
|
into agents and regions), toolCallTable() (Activity → AI usage → Tool calls), agentOptions()
|
|
397
426
|
supporting.ts supporting objects: review page, running the install/upgrade/deinstall scripts as the app's role in one transaction
|
|
398
427
|
public/
|
|
399
|
-
app.css theme (light/dark, responsive; --font, --font-size, --radius for style variants; template option classes to
|
|
428
|
+
app.css theme (light/dark, responsive; --font, --font-size, --radius for style variants; template option classes to-*;
|
|
429
|
+
(sprint 117) navigation tree states, RTL via logical properties, body.nav-pillar-*, u-color-*-subtle, the busy bar)
|
|
400
430
|
app.js client runtime: dialogs (dialog_closed actions), popup LOVs (sprint 115: the next page loads on scroll through an
|
|
401
431
|
IntersectionObserver, ‹/More without one), dynamic actions (focus, classes, messages; sprint 115: wait_popup /
|
|
402
432
|
remove_wait_popup as a modal <dialog class="wait-popup">, pgkiln.waitPopup(), the menu_entry event), 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)
|
|
@@ -455,6 +485,8 @@ test/
|
|
|
455
485
|
page-logic.test.ts download, chain (background jobs) and workflow processes, function/app branches, dialog_closed (HR page 28)
|
|
456
486
|
code-editor.test.ts code editor: completions scoped to the app's role, the check, marked fields
|
|
457
487
|
builder-home.test.ts App Builder home: search, sort, views, Recent, Create/Import pages, dashboard, utilities
|
|
488
|
+
app-list.test.ts (116) the App Builder list's Updated by, working copies and lock; what counts as a change
|
|
489
|
+
import-only.test.ts (116) pgkiln import --replace --only: a page or component file, refusals
|
|
458
490
|
charts.test.ts chart markup per kind (geometry as classes), gauges, Gantt time axis and dependencies, pyramid, polar, range, box plot, stock, drill-down links
|
|
459
491
|
calendar.test.ts calendar views, create links, moving events (pure and over HTTP)
|
|
460
492
|
rest-sources.test.ts REST data sources, web credentials, SSRF checks, invoke_api (mock service + HR page 23)
|
|
@@ -473,8 +505,14 @@ test/
|
|
|
473
505
|
builder-parity.test.ts lists (HR page 31), page and application locks, comments, developers, supporting objects
|
|
474
506
|
page-wizards.test.ts create page wizards: catalog defaults, every page type generated and rendered, refusals, the builder steps
|
|
475
507
|
theme-styles.test.ts Theme Roller style variants (checks, CSS, user choice per app, builder page), template options, base style Iris
|
|
508
|
+
theme-pillar.test.ts (sprint 117) Pillar Light / Dark appearances and the header strip: checks, CSS, runtime classes, Theme Roller, export
|
|
476
509
|
workspaces.test.ts workspaces (064): Default, administrators' pages, current workspace, refused apps, imports and copies
|
|
477
|
-
|
|
510
|
+
mail-network.test.ts (sprint 118) network access lists (page process refused and logged in debug, narrowing only, redirects,
|
|
511
|
+
the page), a workspace's mail service (sending, SMTP host on the list), the Mail queue (yesterday's
|
|
512
|
+
SMTP failure, Retry, Purge, counts, scope)
|
|
513
|
+
gallery.test.ts the App Gallery: every starter and utility created from its review and every sample app installed, with all
|
|
514
|
+
their pages rendering; sample apps (admins), the search, a failing script leaves nothing
|
|
515
|
+
gallery-samples.ts the gallery's shipped apps for the tests: SAMPLES (schema and role of each script), BLUEPRINTS, drop/install
|
|
478
516
|
builder-apex-screens.test.ts sprint 61: sign-in with a workspace, message and banner, utilization, SQL Workshop home, groups, reports
|
|
479
517
|
workspace-isolation.test.ts isolated workspaces (090): logins, RLS on meta, app_id, roles, SQL Workshop, scripts, imports
|
|
480
518
|
ai.test.ts AI services: Generate text with AI (text, structured outputs, errors, limits, keys), its dynamic action,
|
|
@@ -493,6 +531,9 @@ test/
|
|
|
493
531
|
ai-mock.ts a local mock of the Claude Messages API (SSE stream) and OpenAI Chat Completions
|
|
494
532
|
helpers.ts a cookie-keeping test browser
|
|
495
533
|
e2e/responsive.test.ts browser tests at phone/tablet/desktop widths (Playwright)
|
|
534
|
+
e2e/gallery.test.ts (sprint 120) the gallery's sample apps: every page at 4 widths, CSP, axe; dynamic actions; the four tabs at 390 px
|
|
535
|
+
e2e/admin-mail-network.test.ts (sprint 118) Mail queue, Network access and a workspace's mail service at 390 px without JavaScript
|
|
536
|
+
e2e/pillar.test.ts (sprint 117) Pillar appearances: axe in light and dark, subtle colours, current vs parent entry, Arabic RTL, 390 px, preview
|
|
496
537
|
e2e/code-editor.test.ts the code editor in a browser: highlighting, keys, suggestions, touch, screen readers, syntax colours at AA in both themes (sprint 108)
|
|
497
538
|
e2e/data-modeler.test.ts (sprint 98) the Data Modeler in a browser: drag, save, reload, undo/redo, zoom, mini-map, exports, phone
|
|
498
539
|
e2e/worksheet.test.ts (sprint 91) the SQL Worksheet in a browser: run keys, tabs, navigator, drag and drop, splitters, phone, no JavaScript;
|
|
@@ -245,6 +245,8 @@ application. The base style and colours under Settings → Theme are the *Standa
|
|
|
245
245
|
|---|---|
|
|
246
246
|
| Accent colour, header colour | `#rrggbb` (or "as the base"), for the light theme |
|
|
247
247
|
| Accent and header colour in dark mode | `#rrggbb` (or the base style's dark palette), for the dark theme; choose light colours (text on the accent is dark there) |
|
|
248
|
+
| Navigation appearance | *As the application*, *Default* (the base style's header and menu), *Pillar Light* or *Pillar Dark*, see [below](#navigation-appearances-pillar-light-and-pillar-dark) |
|
|
249
|
+
| Header strip colour, also for dark mode | `#rrggbb` or an item reference (else the application's strip, else the accent) |
|
|
248
250
|
| Font | *System* (default), *Humanist sans*, *Geometric sans*, *Serif*, *Rounded*, *Monospace* (font stacks of fonts on the device; nothing is downloaded) |
|
|
249
251
|
| Font size | 14, 15 (default), 16 or 17 px |
|
|
250
252
|
| Corners | Square, 4, 8 (default) or 14 px, for regions, buttons and fields |
|
|
@@ -276,10 +278,56 @@ per tenant, environment or user group:
|
|
|
276
278
|
a style themselves get the first style (in the list's order) whose condition holds, else the
|
|
277
279
|
default style. The condition runs as the application's database role in the page's transaction;
|
|
278
280
|
an error counts as *false* and is written to the [debug messages](06-processing.md#debug-messages).
|
|
279
|
-
- **Dynamic colours.** Instead of a picked colour, any of a style's
|
|
281
|
+
- **Dynamic colours.** Instead of a picked colour, any of a style's colours may be an item
|
|
280
282
|
reference such as `&APP_BRAND_COLOUR.`: the item's value in session state (set by a computation,
|
|
281
283
|
an application process after login, a form…), used when it is a `#rrggbb` colour and ignored
|
|
282
284
|
otherwise, so a stored value can never become anything but a colour in the CSS.
|
|
283
285
|
|
|
284
286
|
Together: one style *Tenant brand* with condition `:APP_BRAND_COLOUR is not null` and accent
|
|
285
287
|
`&APP_BRAND_COLOUR.` gives each tenant its colour from a table, read once after sign-in.
|
|
288
|
+
|
|
289
|
+
## Navigation appearances: Pillar Light and Pillar Dark
|
|
290
|
+
|
|
291
|
+
APEX 26.2's Universal Theme adds *Pillar* appearances for the header and the navigation menu. In pgkiln:
|
|
292
|
+
**Theme Roller → Navigation appearance** (for the whole application) or a style's own *Navigation appearance*:
|
|
293
|
+
|
|
294
|
+
| Appearance | Look |
|
|
295
|
+
|---|---|
|
|
296
|
+
| **Default** | The base style's header and menu (Iris: a dark header and menu; Standard: a navy header and a white menu) |
|
|
297
|
+
| **Pillar Light** | Header and menu on the page's own light surfaces (in dark mode its dark ones), a line under the header |
|
|
298
|
+
| **Pillar Dark** | Header and menu as one dark column in the header colour; in dark mode a darker one |
|
|
299
|
+
|
|
300
|
+
Both have a **header pillar strip** across the top of the header, in the *Header strip colour* (light and dark mode,
|
|
301
|
+
on the Theme Roller page or per style; a style may take it from an item, like its other colours), else the accent,
|
|
302
|
+
and show the **current page as a filled pill** in the accent. Pillar Light replaces the header colour with the page's
|
|
303
|
+
surface, so the strip carries the brand colour. A style's appearance wins over the application's; *Default* in a style
|
|
304
|
+
switches a pillar appearance off. The appearance works with a side and a top menu, and on tablets and phones in the
|
|
305
|
+
drawer. It is stored as `"appearance"`, `"strip"` and `"strip_dark"` in `meta.app.theme` (and in each style), so it
|
|
306
|
+
travels with export and import; only the two keys of the list and `#rrggbb` colours reach the page (classes
|
|
307
|
+
`nav-pillar nav-pillar-light` / `nav-pillar-dark` on `<body>`, `--strip` in the nonce'd `<style>`).
|
|
308
|
+
|
|
309
|
+
### The navigation tree
|
|
310
|
+
|
|
311
|
+
In every appearance (sprint 117) the menu tells three states apart: the **current page** is filled, in the accent,
|
|
312
|
+
with a bar at the start of the entry (a pill in the pillar appearances); its **parent entries** (the trail) are bold
|
|
313
|
+
with an accent icon but not filled, and the open parent's sub-menu hangs on an accent guide line; the **selected**
|
|
314
|
+
entry (keyboard focus) has a ring inside the menu. A page that is not in the menu marks its nearest menu ancestor as
|
|
315
|
+
the trail.
|
|
316
|
+
|
|
317
|
+
### Right to left
|
|
318
|
+
|
|
319
|
+
Arabic, Hebrew, Persian and Urdu pages (`dir="rtl"`) mirror the chrome: the menu sits on the right, the drawer
|
|
320
|
+
slides in from the right on tablets and phones, the current page's bar, the guide lines and the menu's chevrons turn
|
|
321
|
+
around, menus open from the other side and reflowed report cards are aligned to the start.
|
|
322
|
+
|
|
323
|
+
### Subtle colour utilities and the processing indicator
|
|
324
|
+
|
|
325
|
+
The classes `u-color-1-subtle` … `u-color-15-subtle` and `u-color-success-subtle`, `u-color-danger-subtle`,
|
|
326
|
+
`u-color-warning-subtle`, `u-color-info-subtle`, `u-color-neutral-subtle` give an element a tinted background with
|
|
327
|
+
readable text (WCAG AA in light and dark mode, in every base style), for static content, HTML expressions and
|
|
328
|
+
template components, e.g. `<span class="u-color-4-subtle">Approved</span>`.
|
|
329
|
+
|
|
330
|
+
A region that is busy (a dynamic action, a refresh) is dimmed slightly after 150 ms, so quick answers don't flicker,
|
|
331
|
+
and shows a thin moving bar along its top (a still bar when the device asks for reduced motion); the wait popup's
|
|
332
|
+
spinner is lighter too.
|
|
333
|
+
|
package/docs/guide/18-cli.md
CHANGED
|
@@ -35,7 +35,7 @@ any (see [what is not exported](03-builder.md#export-format)).
|
|
|
35
35
|
| `pgkiln migrate [--example <name>]` | Applies the migrations that were not applied yet, then optionally `examples/<name>/` (same as `npm run db:migrate` / `npm run example:hr`; `--root` and `--seed` as in `scripts/migrate.ts`) |
|
|
36
36
|
| `pgkiln apps [--json]` | Lists the applications: alias, number of pages, name |
|
|
37
37
|
| `pgkiln export <alias> [--format json\|dir\|text] [--out <path>]` | `json` (default): the `pgkiln/2` document with sorted keys, to `--out` or standard output. `dir`: a directory (default `./<alias>`), see below. `text`: the same directory in YAML with the code inline ([text files](#text-files-apexlang)) |
|
|
38
|
-
| `pgkiln import <path> [--alias <alias>] [--replace] [--check [--force] \| --dry-run]` | Imports a JSON export, an application directory or a `.zip` of one. `--alias` gives the copy another alias. `--replace` updates the application with that alias in place (after a [backup](03-builder.md#backups)). `--check` checks the application before it commits, `--dry-run` only checks ([below](#checking-before-an-import)) |
|
|
38
|
+
| `pgkiln import <path> [--alias <alias>] [--replace [--only <file>]…] [--check [--force] \| --dry-run]` | Imports a JSON export, an application directory or a `.zip` of one. `--alias` gives the copy another alias. `--replace` updates the application with that alias in place (after a [backup](03-builder.md#backups)); with `--only pages/12` (repeatable) only that page or component file ([below](#importing-one-page-or-component)). `--check` checks the application before it commits, `--dry-run` only checks ([below](#checking-before-an-import)) |
|
|
39
39
|
| `pgkiln diff <alias> <path> [--name-only \| --quiet]` | What differs between the application in the database and a directory (or JSON file, or zip) |
|
|
40
40
|
| `pgkiln ddl <schema> [--no-comments] [--no-grants] [--out <file>]` | The DDL of a schema's objects, in an order that runs (as SQL Workshop → DDL, [chapter 3](03-builder.md#sql-workshop)) |
|
|
41
41
|
| `pgkiln compare <source> <target> [--script]` | Compares two schemas: `+` only in the source, `-` only in the target, `~` different; exit code 1 when they differ. `--script` writes the script that makes the target like the source (drops commented out); nothing is run |
|
|
@@ -210,6 +210,26 @@ pgkiln diff hr apps/hr # on the target: what would cha
|
|
|
210
210
|
pgkiln import apps/hr --replace # deploy
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
+
### Importing one page or component
|
|
214
|
+
|
|
215
|
+
(sprint 116; APEX 26.2: APEXlang file-level import) With `--replace`, `--only` imports just the named files of a
|
|
216
|
+
directory export (or a .zip of one) and leaves the rest of the application as it is in the database:
|
|
217
|
+
|
|
218
|
+
```sh
|
|
219
|
+
pgkiln import apps/hr --replace --only pages/12 # page 12 with its regions, items, buttons …
|
|
220
|
+
pgkiln import apps/hr --replace --only shared/lovs/jobs.yaml # one shared component
|
|
221
|
+
pgkiln import apps/hr --replace --only pages/12 --only shared/lovs # several: repeat --only
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
`pages/12` (or just `12`) is page 12's folder whatever its name, so a renamed page still matches; any other value is
|
|
225
|
+
a file or folder path inside the export. A page or file that the directory no longer has is removed from the
|
|
226
|
+
application. How it works: pgkiln exports the application in the directory's style, takes the named files from the
|
|
227
|
+
directory, and imports the result with `--replace` as usual: one transaction, a backup first, `--check` and
|
|
228
|
+
`--dry-run` work the same, and what belongs to the installation is kept. It says how many of the named files differ
|
|
229
|
+
(on standard error). `--only` refuses without `--replace`, for a JSON file, for a path outside the export and for a
|
|
230
|
+
selection that matches nothing in the directory or the application (exit code 2). A component that another file
|
|
231
|
+
refers to by name (a list of values used on a page, say) has to exist after the import, as with any import.
|
|
232
|
+
|
|
213
233
|
### Checking before an import
|
|
214
234
|
|
|
215
235
|
An import doesn't need the application's tables, columns and functions to exist (neither does APEX's):
|
|
@@ -53,6 +53,16 @@ The checks on every outgoing request (`src/webclient.ts`), against server-side r
|
|
|
53
53
|
Keep the allow-list as short as you can. `*` lets developers call any public host from the
|
|
54
54
|
server; it never opens private addresses.
|
|
55
55
|
|
|
56
|
+
**A workspace's network access list** (sprint 118; APEX 26.2 workspace network ACLs) narrows this
|
|
57
|
+
list for one workspace: under Administration → [Network access](03-builder.md#network-access), its
|
|
58
|
+
administrators can limit its applications to some hosts (same entry syntax, without `*`). A call made
|
|
59
|
+
for an application of that workspace must then match the workspace's list *and* the installation's,
|
|
60
|
+
on every redirect hop; the address checks above stay with `PGKILN_REST_PRIVATE_HOSTS` alone, so a
|
|
61
|
+
workspace can never widen what the installation allows. It applies to every path above: REST data
|
|
62
|
+
sources (including write-back, synchronisation and the response cache), `meta.web_request`, invoke
|
|
63
|
+
API, token endpoints, object storage and REST source catalogs. Refusals are logged in the
|
|
64
|
+
application's debug log and listed under *Refused calls*.
|
|
65
|
+
|
|
56
66
|
**Changing `PGKILN_SECRET_KEY`** makes the stored secrets unreadable: pgkiln then reports that
|
|
57
67
|
the secret must be entered again. Keep the key with your other server secrets, outside the
|
|
58
68
|
database: a database dump alone does not reveal the secrets.
|
|
@@ -323,6 +333,8 @@ values, processes and workflow steps refer to sources and credentials by name, s
|
|
|
323
333
|
|
|
324
334
|
- Outgoing calls are off until the administrator sets `PGKILN_REST_ALLOWED_HOSTS`; private and
|
|
325
335
|
internal addresses need `PGKILN_REST_PRIVATE_HOSTS` as well.
|
|
336
|
+
- A workspace's [network access list](03-builder.md#network-access) narrows the allow-list for its
|
|
337
|
+
applications (it can't widen it).
|
|
326
338
|
- Secrets are encrypted with a key outside the database, write-only in the builder, excluded from
|
|
327
339
|
exports and from the runtime role, and never logged. Use **Valid for URLs** so a credential is
|
|
328
340
|
only ever sent to its own service.
|
|
@@ -52,7 +52,7 @@ directory the agent started the server in (the project).
|
|
|
52
52
|
| `describe_schema` | schemas with tables, views and functions; or one table with columns, constraints, indexes, RLS policies and triggers | no |
|
|
53
53
|
| `generate_ddl` | the DDL of a schema's objects, in an order that runs: a start for a migration script | no |
|
|
54
54
|
| `compare_schemas` | the differences between two schemas and a script that makes the target like the source (not run) | no |
|
|
55
|
-
| `run_query` | one SQL statement, read-only, rows as JSON | no |
|
|
55
|
+
| `run_query` | one SQL statement, read-only, rows as JSON; with `alias` (and `user`) as that application's role and user | no |
|
|
56
56
|
| `search_docs` | searches this user guide, the parity matrix and SECURITY.md | no |
|
|
57
57
|
| `recent_errors` | the latest errors and refused requests from the activity log | no |
|
|
58
58
|
| `export_app` | writes an application to a directory (default `apps/<alias>`, format `text`) | files on disk |
|
|
@@ -85,7 +85,13 @@ migration scripts, not in the application files (`run_query` can't change them a
|
|
|
85
85
|
columns whose names contain *password*, *secret*, *token*, *hash* or *api_key* are shown as
|
|
86
86
|
`(hidden)`. That keeps credentials out of the agent's context by accident; it is not an access
|
|
87
87
|
control: the server runs as the owner role, like the command line, and is meant for a
|
|
88
|
-
developer's own machine.
|
|
88
|
+
developer's own machine.
|
|
89
|
+
- **As an application's user.** (sprint 119) `run_query` with `alias` runs the statement as that application's
|
|
90
|
+
database role, with `meta.app_id()`, `meta.app_user()` (`user`, default `nobody`) and `meta.has_role()` (the
|
|
91
|
+
user's roles in the application) set, so grants, column privileges, row level security and masking views apply as
|
|
92
|
+
on that user's pages ([chapter 8](08-security.md#data-security-per-table-rows-columns-and-values)). Use it to check
|
|
93
|
+
what a user sees, or let an agent look at data the way the application does. It is no sandbox either: the
|
|
94
|
+
connection is still the owner's. Don't point it at production; deploy with `pgkiln import --replace`
|
|
89
95
|
from git instead.
|
|
90
96
|
- **Writes** are only `export_app` (files; it refuses a non-empty directory that isn't an export,
|
|
91
97
|
so it can't overwrite your project) and `import_app` (the database, in one transaction). Both are
|
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
# App Gallery
|
|
2
2
|
|
|
3
|
-
The builder's **App Gallery** (`/builder/gallery`) lists what `gallery.json` names:
|
|
3
|
+
The builder's **App Gallery** (`/builder/gallery`) lists what `gallery.json` names, in four tabs:
|
|
4
4
|
|
|
5
5
|
- `samples`: applications shipped with pgkiln, installed by an administrator: `example` names a directory of
|
|
6
|
-
`examples/` (installed like `pgkiln migrate --example <name>`), `file` a single SQL file in `examples
|
|
7
|
-
`
|
|
6
|
+
`examples/` (installed like `pgkiln migrate --example <name>`), `file` a single SQL file, in `examples/` (the
|
|
7
|
+
tutorial, `tasks-app.sql`) or in `samples/` here (`samples/sample-charts.sql`). A file runs in one transaction as the
|
|
8
|
+
owner, so a failing script leaves nothing behind. `alias` is the application it creates (an installed one shows Run
|
|
9
|
+
and Edit).
|
|
8
10
|
- `starters`: [blueprints](../../docs/guide/03-builder.md#creating-an-application-from-a-blueprint) in `starters/`.
|
|
9
11
|
Install opens the blueprint's review; the developer creates the application from it.
|
|
12
|
+
- `utilities`: blueprints in `utilities/` of applications a workspace uses (lookup lists, release notes,
|
|
13
|
+
announcements), installed like starters.
|
|
14
|
+
- Custom apps are not listed here: they are the workspace's boilerplate applications.
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
## The sample apps in `samples/`
|
|
17
|
+
|
|
18
|
+
| File | Application | Shows |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `sample-charts.sql` | Sample Charts (`/a/sample-charts`) | the 22 chart types, a page per question, a drill-down to a report |
|
|
21
|
+
| `sample-cards.sql` | Sample Cards | cards with a form, KPI tiles, lists as cards, built-in template components |
|
|
22
|
+
| `sample-calendar.sql` | Sample Calendar | month, week, day and list views, create on click, drag and drop through a function |
|
|
23
|
+
| `sample-grids.sql` | Sample Interactive Grids | an editable grid, select lists, totals, frozen column, row menu, master-detail, views |
|
|
24
|
+
| `sample-dynamic-actions.sql` | Sample Dynamic Actions | show/hide/enable, set value, refresh, messages, wait popup, classes, inline dialog |
|
|
25
|
+
| `sample-reporting.sql` | Sample Reporting | interactive report, faceted search, smart filters, a classic report with column options |
|
|
26
|
+
| `ux-patterns.sql` | UX Pattern Catalog | region templates and options, buttons, items and form layouts, content and page patterns |
|
|
27
|
+
|
|
28
|
+
Each script creates its own schema (`sample_charts`, …), a role (`app_sample_charts`, …) granted to the runtime, the
|
|
29
|
+
application and one account, **demo** / **demo**. Without the builder:
|
|
30
|
+
`psql "$DATABASE_URL" -1 -f examples/gallery/samples/sample-charts.sql`. To remove one, delete the application in the
|
|
31
|
+
App Builder, then `drop schema sample_charts cascade; drop role app_sample_charts;`.
|
|
32
|
+
|
|
33
|
+
A sample script follows the pattern of the HR example: plain SQL that inserts `meta.*` rows, using
|
|
34
|
+
`meta.generate_page()` for wizard-made pages and two temporary helpers (`pg_temp.page_id`, `pg_temp.region_id`).
|
|
35
|
+
Every page starts with a text that says how it is made.
|
|
36
|
+
|
|
37
|
+
## Adding an entry
|
|
38
|
+
|
|
39
|
+
Add a starter or utility by writing a blueprint file in `starters/` or `utilities/` and an entry in `gallery.json` (a
|
|
40
|
+
key of lower-case letters, digits and `-`, a title, an [icon name](../../docs/guide/09-reference.md#icons) and a
|
|
41
|
+
description). Add a sample by writing a script in `samples/` (no `begin`/`commit`: the gallery runs it in a
|
|
42
|
+
transaction) and an entry with its `alias` and `file`. `test/gallery.test.ts` creates every starter and utility,
|
|
43
|
+
installs every sample and opens all their pages; `test/e2e/gallery.test.ts` checks the samples' pages at four widths,
|
|
44
|
+
for CSP violations and with axe-core.
|
|
@@ -3,7 +3,21 @@
|
|
|
3
3
|
{"key": "hr", "title": "HR Demo", "alias": "hr", "icon": "briefcase", "example": "hr",
|
|
4
4
|
"description": "The showcase of pgkiln on the classic EMP and DEPT tables: reports and forms, an interactive grid, charts, maps, a calendar, faceted search, approvals and workflows, documents, a REST API, translations and a Progressive Web App. Demo accounts king, blake, jones, allen, scott and demo, with the username as password."},
|
|
5
5
|
{"key": "tasks", "title": "Tasks", "alias": "tasks", "icon": "check", "file": "tasks-app.sql",
|
|
6
|
-
"description": "The tutorial application: a personal task list where every user sees only their own tasks (row level security), with a business rule in PL/pgSQL behind a button. Demo accounts ann and bob (password ann-password, bob-password)."}
|
|
6
|
+
"description": "The tutorial application: a personal task list where every user sees only their own tasks (row level security), with a business rule in PL/pgSQL behind a button. Demo accounts ann and bob (password ann-password, bob-password)."},
|
|
7
|
+
{"key": "sample-charts", "title": "Sample Charts", "alias": "sample-charts", "icon": "chart-column", "file": "samples/sample-charts.sql",
|
|
8
|
+
"description": "All 22 chart types on a page per question (comparing categories, change over time, parts of a whole, relations and spread, plans) and a drill-down from a chart to a report, each page explaining how the query shapes the chart. Demo account demo / demo."},
|
|
9
|
+
{"key": "sample-cards", "title": "Sample Cards", "alias": "sample-cards", "icon": "layout-grid", "file": "samples/sample-cards.sql",
|
|
10
|
+
"description": "Cards with a title, subtitle, body, badge and icon that open a form; KPI tiles; lists shown as cards, badges, links and tabs; and the built-in template components (metric cards, media list, badges, avatars). Demo account demo / demo."},
|
|
11
|
+
{"key": "sample-calendar", "title": "Sample Calendar", "alias": "sample-calendar", "icon": "calendar-days", "file": "samples/sample-calendar.sql",
|
|
12
|
+
"description": "The calendar region: month, week, day and list views, all-day, timed and multi-day events around today, create on click, drag and drop through a PL/pgSQL function with its own rule, and a calendar filtered by an item. Demo account demo / demo."},
|
|
13
|
+
{"key": "sample-grids", "title": "Sample Interactive Grids", "alias": "sample-grids", "icon": "table", "file": "samples/sample-grids.sql",
|
|
14
|
+
"description": "The interactive grid: an editable grid made by the wizard; select lists, required columns, totals, a frozen column, a row menu and a column layout; master-detail grids; and a read-only grid with the single row, group by and chart views. Demo account demo / demo."},
|
|
15
|
+
{"key": "sample-dynamic-actions", "title": "Sample Dynamic Actions", "alias": "sample-dynamic-actions", "icon": "zap", "file": "samples/sample-dynamic-actions.sql",
|
|
16
|
+
"description": "Behaviour without JavaScript of your own: show, hide, enable on a condition; values computed on the server; a report refreshed when an item changes; alerts, confirmations, a wait popup, classes, item errors and an inline dialog. Demo account demo / demo."},
|
|
17
|
+
{"key": "sample-reporting", "title": "Sample Reporting", "alias": "sample-reporting", "icon": "file-text", "file": "samples/sample-reporting.sql",
|
|
18
|
+
"description": "Reports and the ways to search them: an interactive report with its form, a faceted search, smart filters, and a classic report with column display options, a column template and a link. Demo account demo / demo."},
|
|
19
|
+
{"key": "ux-patterns", "title": "UX Pattern Catalog", "alias": "ux-patterns", "icon": "palette", "file": "samples/ux-patterns.sql",
|
|
20
|
+
"description": "The theme's building blocks to copy from: region templates and template options, button styles, item types and form layouts, alerts, badges, colour classes, lists, media lists, timelines, comments, avatars, metric cards, empty states, dialogs, drawers and side columns. Demo account demo / demo."}
|
|
7
21
|
],
|
|
8
22
|
"starters": [
|
|
9
23
|
{"key": "team-tasks", "title": "Team Tasks", "icon": "layout-grid", "file": "starters/team-tasks.json",
|
|
@@ -16,5 +30,13 @@
|
|
|
16
30
|
"description": "Assets with their tags, locations, owners and purchase data: a faceted search, an editable grid of locations, a chart by category and a dashboard."},
|
|
17
31
|
{"key": "event-registrations", "title": "Event Registrations", "icon": "calendar-days", "file": "starters/event-registrations.json",
|
|
18
32
|
"description": "Events in a calendar and the people who registered for them, with reports, forms and a dashboard."}
|
|
33
|
+
],
|
|
34
|
+
"utilities": [
|
|
35
|
+
{"key": "lookup-lists", "title": "Lookup Lists", "icon": "list-checks", "file": "utilities/lookup-lists.json",
|
|
36
|
+
"description": "The lists of values your applications share (priorities, statuses, countries) kept as data: lists and their values in a master-detail page and an editable grid, and how other applications of the workspace use them."},
|
|
37
|
+
{"key": "release-notes", "title": "Release Notes", "icon": "git-branch", "file": "utilities/release-notes.json",
|
|
38
|
+
"description": "The releases of your applications and what changed in each (features, fixes, security, breaking changes): reports and forms, releases with their changes, a faceted search of the changes, a release calendar and a dashboard."},
|
|
39
|
+
{"key": "announcements", "title": "Announcements", "icon": "megaphone", "file": "utilities/announcements.json",
|
|
40
|
+
"description": "A notice board for the workspace: planned maintenance, outages and new releases with their audience and dates, as cards, a calendar and a dashboard, and the query other applications use to show the current ones."}
|
|
19
41
|
]
|
|
20
42
|
}
|