@protobase/cli 0.19.16 → 0.21.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.
@@ -16,11 +16,30 @@ const blockSort = (node, model, view) => {
16
16
  return node.type === "RecordRow" ? listSort(model, view) : void 0;
17
17
  };
18
18
  const title = (node) => text(node.props.title) ?? text(node.props.label);
19
- /** The reads of a composed page: each block that lists records, with its filter and sort. */
19
+ const chartShape = (page, node, model) => {
20
+ const source = text(node.props.filter);
21
+ const filter = configFilter(model, source);
22
+ const groupBy = String(node.props.groupBy);
23
+ const named = title(node);
24
+ return {
25
+ resource: model.name,
26
+ request: `GET /${model.name}:aggregate?group_by=${groupBy}${source?.trim() ? `&filter=${source}` : ""}`,
27
+ from: `page "${page.name}", <Chart${named ? ` "${named}"` : ""}>`,
28
+ query: {
29
+ ...filter && { filter },
30
+ groupBy
31
+ }
32
+ };
33
+ };
34
+ /** The reads of a composed page: each block that lists records, with its filter and sort, and each chart's grouping. */
20
35
  const pageShapes = (page, models, views) => {
21
36
  const shapes = [];
22
37
  walkTree(page.tree, (node) => {
23
38
  const model = node.custom ? void 0 : models[text(node.props.resource) ?? ""];
39
+ if (model && node.type === "Chart") {
40
+ shapes.push(chartShape(page, node, model));
41
+ return;
42
+ }
24
43
  if (!model || !listing.includes(node.type) || node.type === "RecordCard" && node.props.recordKey !== void 0) return;
25
44
  const source = text(node.props.filter);
26
45
  const filter = configFilter(model, source);
@@ -1,4 +1,5 @@
1
1
  import { all, any, anyOf, compare, configFilter, configSort, isTrue, sortText } from "./shape-filters.js";
2
+ import { isGroupChart } from "@protobase/schema/internal";
2
3
  //#region src/doctor/view-shapes.ts
3
4
  const numberTypes = [
4
5
  "integer",
@@ -139,6 +140,16 @@ const searchesShapes = (view, models) => {
139
140
  }
140
141
  }];
141
142
  };
143
+ const chartShapes = (model, view, list) => {
144
+ const chart = view.chart;
145
+ if (!chart || !isGroupChart(chart) || !model.fields[chart.groupBy]) return [];
146
+ return [{
147
+ resource: model.name,
148
+ request: `GET /${model.name}:aggregate?group_by=${chart.groupBy}`,
149
+ from: `${list}'s chart`,
150
+ query: { groupBy: chart.groupBy }
151
+ }];
152
+ };
142
153
  const recentShapes = (model, view) => {
143
154
  const recent = view.nav?.recent;
144
155
  if (!recent) return [];
@@ -155,7 +166,7 @@ const recentShapes = (model, view) => {
155
166
  }];
156
167
  };
157
168
  /**
158
- * The reads a view's pages make: its list in its order, the filter widgets and their counts, its displays' maps,
169
+ * The reads a view's pages make: its list in its order, the filter widgets and their counts, its chart per value, its displays' maps,
159
170
  * board columns and photos, the records of its related sections and the photos of its galleries, the recent records in the sidebar and a saved search's new records.
160
171
  */
161
172
  const viewShapes = (view, models) => {
@@ -172,6 +183,7 @@ const viewShapes = (view, models) => {
172
183
  },
173
184
  ...view.filters.flatMap((widget) => widgetShapes(model, widget, `${list}'s ${widget.kind === "dateRange" ? "date range" : widget.kind} filter`)),
174
185
  ...displayShapes(model, view, models),
186
+ ...chartShapes(model, view, list),
175
187
  ...view.layout.flatMap((item) => item.kind === "related" ? relatedShapes(item, model.name, models) : item.kind === "gallery" ? galleryShapes(item, model.name, models) : []),
176
188
  ...recentShapes(model, view),
177
189
  ...searchesShapes(view, models)
@@ -1,4 +1,4 @@
1
- import { authSchemaMigration, changesMigration, jobsSchemaMigration, webhooksMigration } from "@protobase/server";
1
+ import { authSchemaMigration, changesMigration, isCaptured, jobsSchemaMigration, webhooksMigration } from "@protobase/server";
2
2
  //#region src/migration/parts.ts
3
3
  /** Every feature the project's config enables, in the order their files are written. */
4
4
  const migrationParts = (project) => [
@@ -7,14 +7,14 @@ const migrationParts = (project) => [
7
7
  title: "The auth schema changes this version of Protobase needs",
8
8
  sql: () => authSchemaMigration(project.auth)
9
9
  }] : [],
10
- ...project.jobs.length > 0 || project.models.some((model) => model.events) || project.webhooks ? [{
10
+ ...project.jobs.length > 0 || project.models.some(isCaptured) || project.webhooks ? [{
11
11
  name: "jobs",
12
12
  title: "The jobs schema this version of Protobase needs",
13
13
  sql: () => jobsSchemaMigration(project.db)
14
14
  }] : [],
15
15
  {
16
16
  name: "changes",
17
- title: "The change capture the resources' events need",
17
+ title: "The change capture the resources' events and history need",
18
18
  sql: () => changesMigration(project.db, project.models, project.events)
19
19
  },
20
20
  ...project.webhooks ? [{
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.19.16";
2
+ var version = "0.21.0";
3
3
  //#endregion
4
4
  export { version };
@@ -3,7 +3,7 @@ import { configExports, createAdmin, jobDefinitions } from "@protobase/server";
3
3
  /**
4
4
  * The admin API of a project over `db`, as `dev`, `serve` and `worker` build it: its config module's resources, views,
5
5
  * pages and subscriptions, and the rest of its config; served from a bundle, the plugins it carries and their field
6
- * types. `jobs` are the project's own and the delivery of its events. With a `reporter`, every error the API turns
6
+ * types. `jobs` are the project's own and the delivery of its events and history. With a `reporter`, every error the API turns
7
7
  * into a 500 goes to the error tracker too, besides the project's `onUnhandledError` or the console.
8
8
  */
9
9
  const projectAdmin = (project, config, db, ui, reporter) => {
@@ -22,6 +22,7 @@ const projectAdmin = (project, config, db, ui, reporter) => {
22
22
  ...project.functions && { functions: project.functions },
23
23
  ...project.files && { files: project.files },
24
24
  ...project.events && { events: project.events },
25
+ ...project.history && { history: project.history },
25
26
  ...project.webhooks && { webhooks: project.webhooks },
26
27
  jobs: own,
27
28
  subscriptions,
@@ -5,7 +5,7 @@ import { createPgDb } from "../project/pg-db.js";
5
5
  import { loadBundle } from "../serve/load-bundle.js";
6
6
  import { statSync } from "node:fs";
7
7
  import path from "node:path";
8
- import { checkJobsSchema, configExports, jobDefinitions, startJobs } from "@protobase/server";
8
+ import { checkJobsSchema, configExports, isCaptured, jobDefinitions, startJobs } from "@protobase/server";
9
9
  import pg from "pg";
10
10
  //#region src/worker/start-worker.ts
11
11
  const bundleConfigFile = async (bundle) => {
@@ -17,8 +17,8 @@ const bundleConfigFile = async (bundle) => {
17
17
  * their own. It reads the jobs schema at start and refuses one that is missing or behind, like `serve`.
18
18
  */
19
19
  const startWorker = async ({ project, databaseUrl, createDb = (url) => createPgDb(pg, url) }) => {
20
- const withEvents = configExports(project.config).resources.some((resource) => resource.toModel().events);
21
- if (jobDefinitions(project.jobs ?? {}).length === 0 && !withEvents) throw new Error("The bundle has no jobs: export them from protobase.config.ts as `jobs`, or give a resource events");
20
+ const captured = configExports(project.config).resources.some((resource) => isCaptured(resource.toModel()));
21
+ if (jobDefinitions(project.jobs ?? {}).length === 0 && !captured) throw new Error("The bundle has no jobs: export them from protobase.config.ts as `jobs`, or give a resource events or history");
22
22
  if (!project.db && !databaseUrl) throw new Error("No database: set DATABASE_URL or export `db` from protobase.config.ts");
23
23
  const ownDb = project.db ? void 0 : createDb(databaseUrl);
24
24
  const db = project.db ?? ownDb;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/cli",
3
- "version": "0.19.16",
3
+ "version": "0.21.0",
4
4
  "description": "The protobase command: scaffold, doctor, dev, build and serve a Protobase project.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -34,11 +34,11 @@
34
34
  "dependencies": {
35
35
  "@hono/node-server": "^2.1.3",
36
36
  "@hono/vite-dev-server": "^0.26.1",
37
- "@protobase/layout": "0.19.16",
38
- "@protobase/query": "0.19.16",
39
- "@protobase/schema": "0.19.16",
40
- "@protobase/server": "0.19.16",
41
- "@protobase/ui": "0.19.16",
37
+ "@protobase/layout": "0.21.0",
38
+ "@protobase/query": "0.21.0",
39
+ "@protobase/schema": "0.21.0",
40
+ "@protobase/server": "0.21.0",
41
+ "@protobase/ui": "0.21.0",
42
42
  "@react-email/render": "^2.1.0",
43
43
  "@scalar/hono-api-reference": "^0.12.10",
44
44
  "@tailwindcss/vite": "^4.3.3",