pgkiln 0.44.0 → 0.45.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 (39) hide show
  1. package/db/migrations/102_app_computations.sql +345 -0
  2. package/db/migrations/103_shortcuts.sql +341 -0
  3. package/db/migrations/104_report_queries.sql +413 -0
  4. package/db/migrations/105_component_settings_groups.sql +367 -0
  5. package/docs/apex-feature-parity.md +10 -10
  6. package/docs/guide/02-concepts.md +24 -0
  7. package/docs/guide/03-builder.md +33 -1
  8. package/docs/guide/04-pages-and-regions.md +10 -1
  9. package/docs/guide/06-processing.md +22 -0
  10. package/docs/guide/09-reference.md +13 -0
  11. package/docs/guide/12-development.md +2 -1
  12. package/docs/guide/16-files.md +23 -0
  13. package/docs/guide/18-cli.md +4 -0
  14. package/package.json +1 -1
  15. package/public/app.css +17 -0
  16. package/public/app.js +63 -0
  17. package/src/appfiles.ts +18 -2
  18. package/src/builder/advisor.ts +7 -2
  19. package/src/builder/code-editor.ts +6 -1
  20. package/src/builder/components.ts +85 -3
  21. package/src/builder/forms.ts +1 -1
  22. package/src/builder/shared.ts +39 -6
  23. package/src/builder/subscriptions.ts +30 -4
  24. package/src/cli/replace.ts +6 -2
  25. package/src/metadata.ts +14 -1
  26. package/src/runtime/component-settings.ts +42 -0
  27. package/src/runtime/context.ts +4 -0
  28. package/src/runtime/documents.ts +29 -3
  29. package/src/runtime/engine.ts +2 -2
  30. package/src/runtime/grid.ts +22 -4
  31. package/src/runtime/items.ts +14 -11
  32. package/src/runtime/logic.ts +12 -7
  33. package/src/runtime/regions.ts +4 -3
  34. package/src/runtime/render.ts +1 -0
  35. package/src/runtime/report.ts +2 -1
  36. package/src/runtime/routes.ts +4 -2
  37. package/src/runtime/shortcuts.ts +43 -0
  38. package/src/security.ts +2 -1
  39. package/src/subscriptions.ts +67 -0
@@ -219,3 +219,70 @@ export async function publish(masterId: number, kind: string, name: string, user
219
219
 
220
220
  export const unsubscribe = async (appId: number, kind: string, name: string) =>
221
221
  ((await owner.query('delete from meta.subscription where app_id = $1 and kind = $2 and name = $3', [appId, kind, name])).rowCount ?? 0) > 0;
222
+
223
+ // ------------------------------------------------------------------ (105) component groups
224
+ // A component group names some of an application's subscribable components
225
+ // ("kind:name"); another application subscribes to all of them at once.
226
+
227
+ /** The kinds a component group can hold: every subscribable kind but the theme. */
228
+ export const GROUP_KINDS = (Object.keys(KINDS) as Kind[]).filter((k) => k !== 'theme');
229
+
230
+ /** Members as the application has them ("lov:JOBS"), and a message for each that it doesn't have. */
231
+ export async function checkGroupMembers(appId: number, members: string[]) {
232
+ const ok: string[] = [];
233
+ const problems: string[] = [];
234
+ for (const m of members.map((x) => x.trim()).filter(Boolean)) {
235
+ const at = m.indexOf(':');
236
+ const kind = m.slice(0, at).trim();
237
+ const name = m.slice(at + 1).trim();
238
+ if (at < 1 || !isKind(kind) || kind === 'theme') {
239
+ problems.push(`${m}: write kind:name, the kind one of ${GROUP_KINDS.join(', ')}.`);
240
+ continue;
241
+ }
242
+ const k = KINDS[kind];
243
+ const row = await owner.one<{ n: string }>(`select ${k.key} as n from ${k.table} where app_id = $1 and lower(${k.key}) = lower($2)`, [appId, name]);
244
+ if (!row) problems.push(`${m}: the application has no ${k.label.toLowerCase()} ${name}.`);
245
+ else if (!ok.includes(`${kind}:${row.n}`)) ok.push(`${kind}:${row.n}`);
246
+ }
247
+ return { members: ok, problems };
248
+ }
249
+
250
+ /** Component groups of the theme and library applications appId can subscribe to. */
251
+ export async function groupsOffered(appId: number) {
252
+ return (
253
+ await owner.query<{ master_id: number; master_name: string; name: string; description: string | null; members: string[] }>(
254
+ `select m.id as master_id, m.name as master_name, g.name, g.description, g.members
255
+ from meta.component_group g join meta.app m on m.id = g.app_id
256
+ where m.app_type in ('theme', 'library') and m.id <> $1 and meta.app_workspace(m.id) = meta.app_workspace($1)
257
+ order by lower(m.name), m.id, lower(g.name)`,
258
+ [appId],
259
+ )
260
+ ).rows;
261
+ }
262
+
263
+ /** Subscribe appId to every member of a master's component group; members the master no longer has are skipped. */
264
+ export async function subscribeGroup(appId: number, masterId: number, group: string, username: string) {
265
+ const g = await owner.one<{ members: string[] }>('select members from meta.component_group where app_id = $1 and name = $2', [masterId, group]);
266
+ if (!g) throw new SubscriptionError('Choose a component group.');
267
+ const done: string[] = [];
268
+ const skipped: string[] = [];
269
+ for (const m of g.members) {
270
+ const at = m.indexOf(':');
271
+ const kind = m.slice(0, at);
272
+ const name = m.slice(at + 1);
273
+ if (!isKind(kind) || kind === 'theme') continue;
274
+ const k = KINDS[kind];
275
+ if (!(await owner.one(`select 1 as ok from ${k.table} where app_id = $1 and ${k.key} = $2`, [masterId, name]))) {
276
+ skipped.push(m);
277
+ continue;
278
+ }
279
+ try {
280
+ await subscribe(appId, masterId, kind, name, username);
281
+ done.push(m);
282
+ } catch (e) {
283
+ if (!(e instanceof SubscriptionError)) throw e;
284
+ skipped.push(m);
285
+ }
286
+ }
287
+ return { done, skipped };
288
+ }