@protobase/schema 0.15.5 → 0.16.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/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ import { BottomBarNames, bottomBarErrors } from "./bottom-bar-errors.js";
20
20
  import { layout } from "./layout.js";
21
21
  import { KeyType, keyTypes } from "./keys.js";
22
22
  import { addressWords, appPath, readAppPath } from "./app-address.js";
23
+ import { SignInAddress, SignInStep, readSignInAddress, signInParams, signInPath, signInRoute, signInSteps } from "./sign-in-address.js";
23
24
  import { FilterLimits, FilterParse, parseFilter } from "./filter/parse.js";
24
25
  import { CheckResult, checkFilter } from "./filter/check.js";
25
26
  import { EvaluateOptions, evaluateFilter } from "./filter/evaluate.js";
@@ -36,4 +37,4 @@ import { AccessSource, ResolveOptions, ResolvedAccess, RowFilterOperation, acces
36
37
  import { restrictModel } from "./access/restrict.js";
37
38
  import "./access/index.js";
38
39
  import { AssistantAction, AssistantActionRequest, AssistantCardPart, AssistantDiff, AssistantEvent, AssistantMessage, AssistantMessageRequest, AssistantPart, AssistantState, AssistantStep, AssistantStepState, AssistantTablePart, AssistantTextPart, AssistantTone, AssistantWidgetPart } from "./assistant/protocol.js";
39
- export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionModel, type ActionRun, type AnyField, type AppAddress, type AssistantAction, type AssistantActionRequest, type AssistantCardPart, type AssistantDiff, type AssistantEvent, type AssistantMessage, type AssistantMessageRequest, type AssistantPart, type AssistantState, type AssistantStep, type AssistantStepState, type AssistantTablePart, type AssistantTextPart, type AssistantTone, type AssistantWidgetPart, type BadgeShape, type BottomBarItemModel, type BottomBarModel, type BottomBarNames, type BottomBarSource, type Capability, type CapabilityAction, type CapabilityLimit, type CapabilityScope, type CardFavoriteModel, type CardPhotosModel, type ChartGranularity, type ChartModel, type ChartRange, type CheckResult, type CheckedFilter, type CompareOp, type ComponentRef, type Constraint, type CreatedOptions, type CustomSectionModel, type DatePreset, type DeletedOptions, type DurationLiteral, type DurationUnit, type EvaluateOptions, type EventActor, type EventContext, type EventHelpers, type EventMatch, type EventModel, type EventOperation, type EventSpec, type Field, type FieldAccess, type FieldFormat, type FieldMeta, type FieldModel, type FieldPath, type FieldRefValue, type FieldRefs, type FieldRule, type FieldType, type FieldTypeDef, type FieldView, type FieldViewModel, type FieldViews, type FieldWidgetModel, type FieldsInput, type FileField, type FileFieldModel, type FileOptions, type FileProcessor, type FileProcessorInput, type FilterError, type FilterErrorCode, type FilterExpr, type FilterLayout, type FilterLimits, type FilterOf, type FilterParse, type FilterValue, type FilterWidgetModel, type Grant, type HeldCapability, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListDisplayModel, type ListModel, type ListQuery, type Literal, type MapSectionModel, type MapView, type NavModel, type NavRecentModel, type NowValue, type OrderByCheck, type OrderByItem, type OrderByParse, type RecordKey, type RecordOf, type Ref, type Refs, type RelatedModel, type RelationField, type ResolveOptions, type ResolvedAccess, type ResourceBuilder, type ResourceModel, type RoleEntry, type RoleLimit, type Roles, type RolesOptions, type RowFilterOperation, type Rule, type SaveFeedback, type SaveSearchModel, type SearchMatch, type SearchRef, type SearchRefs, type SearchResultModel, type SearchesOfModel, type SignInPromptModel, type SignInViewModel, type SortSpec, type Span, type StatusTone, type UndeletedOptions, type UpdatedOptions, type UserMenuItemModel, type UserMenuModel, type UserMenuSource, type Validator, type ViewBuilder, type ViewModel, type ViewProps, accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, imageFormats, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, resolveAccess, resource, restrictModel, rule, userMenu, view, where };
40
+ export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionModel, type ActionRun, type AnyField, type AppAddress, type AssistantAction, type AssistantActionRequest, type AssistantCardPart, type AssistantDiff, type AssistantEvent, type AssistantMessage, type AssistantMessageRequest, type AssistantPart, type AssistantState, type AssistantStep, type AssistantStepState, type AssistantTablePart, type AssistantTextPart, type AssistantTone, type AssistantWidgetPart, type BadgeShape, type BottomBarItemModel, type BottomBarModel, type BottomBarNames, type BottomBarSource, type Capability, type CapabilityAction, type CapabilityLimit, type CapabilityScope, type CardFavoriteModel, type CardPhotosModel, type ChartGranularity, type ChartModel, type ChartRange, type CheckResult, type CheckedFilter, type CompareOp, type ComponentRef, type Constraint, type CreatedOptions, type CustomSectionModel, type DatePreset, type DeletedOptions, type DurationLiteral, type DurationUnit, type EvaluateOptions, type EventActor, type EventContext, type EventHelpers, type EventMatch, type EventModel, type EventOperation, type EventSpec, type Field, type FieldAccess, type FieldFormat, type FieldMeta, type FieldModel, type FieldPath, type FieldRefValue, type FieldRefs, type FieldRule, type FieldType, type FieldTypeDef, type FieldView, type FieldViewModel, type FieldViews, type FieldWidgetModel, type FieldsInput, type FileField, type FileFieldModel, type FileOptions, type FileProcessor, type FileProcessorInput, type FilterError, type FilterErrorCode, type FilterExpr, type FilterLayout, type FilterLimits, type FilterOf, type FilterParse, type FilterValue, type FilterWidgetModel, type Grant, type HeldCapability, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListDisplayModel, type ListModel, type ListQuery, type Literal, type MapSectionModel, type MapView, type NavModel, type NavRecentModel, type NowValue, type OrderByCheck, type OrderByItem, type OrderByParse, type RecordKey, type RecordOf, type Ref, type Refs, type RelatedModel, type RelationField, type ResolveOptions, type ResolvedAccess, type ResourceBuilder, type ResourceModel, type RoleEntry, type RoleLimit, type Roles, type RolesOptions, type RowFilterOperation, type Rule, type SaveFeedback, type SaveSearchModel, type SearchMatch, type SearchRef, type SearchRefs, type SearchResultModel, type SearchesOfModel, type SignInAddress, type SignInPromptModel, type SignInStep, type SignInViewModel, type SortSpec, type Span, type StatusTone, type UndeletedOptions, type UpdatedOptions, type UserMenuItemModel, type UserMenuModel, type UserMenuSource, type Validator, type ViewBuilder, type ViewModel, type ViewProps, accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, imageFormats, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, readSignInAddress, resolveAccess, resource, restrictModel, rule, signInParams, signInPath, signInRoute, signInSteps, userMenu, view, where };
package/dist/index.js CHANGED
@@ -18,8 +18,9 @@ import { bottomBarErrors } from "./bottom-bar-errors.js";
18
18
  import { layout } from "./layout.js";
19
19
  import { keyTypes } from "./keys.js";
20
20
  import { addressWords, appPath, readAppPath } from "./app-address.js";
21
+ import { readSignInAddress, signInParams, signInPath, signInRoute, signInSteps } from "./sign-in-address.js";
21
22
  import { rule } from "./access/rule.js";
22
23
  import { defineRoles } from "./access/roles.js";
23
24
  import { pickView } from "./access/pick-view.js";
24
25
  import { restrictModel } from "./access/restrict.js";
25
- export { accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, imageFormats, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, resolveAccess, resource, restrictModel, rule, userMenu, view, where };
26
+ export { accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, imageFormats, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, readSignInAddress, resolveAccess, resource, restrictModel, rule, signInParams, signInPath, signInRoute, signInSteps, userMenu, view, where };
package/dist/model.d.ts CHANGED
@@ -209,6 +209,8 @@ export type FieldViewModel = {
209
209
  help?: string;
210
210
  /** How the value is shown. */
211
211
  format?: FieldFormat;
212
+ /** A text that runs over several lines: forms edit it in a box that grows with it, and its line breaks show. */
213
+ multiline?: boolean;
212
214
  /** Text before a number wherever it is shown, such as `€`. */
213
215
  prefix?: string;
214
216
  /** Text after a number wherever it is shown, such as a unit: `m²` shows `120 m²`. */
@@ -292,6 +294,16 @@ export type ListDisplayModel = {
292
294
  longitude: string;
293
295
  /** The cards display whose card a chosen marker shows; the list's first cards display when omitted. */
294
296
  cards?: string;
297
+ /** The boolean field that is true when the record's position is approximate. */
298
+ approximate?: string;
299
+ /** The boolean field that is false when the record's position is approximate. */
300
+ exact?: string;
301
+ /** The number field holding the radius, in metres, of the circle around an approximate position. */
302
+ radius?: string;
303
+ /** The radius, in metres, of the circle around an approximate position whose record states no area or radius. */
304
+ defaultRadius?: number;
305
+ /** The field holding the GeoJSON geometry around an approximate position: a polygon, or a line such as a street. */
306
+ area?: string;
295
307
  } | {
296
308
  /** The rows drawn by a project component. */
297
309
  kind: 'custom';
@@ -0,0 +1,33 @@
1
+ //#region src/sign-in-address.d.ts
2
+ /** The path of the sign-in route, below the app's base path. Its steps and the page to come back to are in its query. */
3
+ export declare const signInRoute = "/-/sign-in";
4
+ /** The names of the sign-in route's query parameters: the step it shows, and the page to come back to after it. */
5
+ export declare const signInParams: {
6
+ /** The step the route shows, when it is not the first. */
7
+ readonly step: "step";
8
+ /** The page below the base path to come back to after signing in. */
9
+ readonly next: "next";
10
+ };
11
+ /**
12
+ * A step of signing in or making an account, each with an address of its own: Back from a step returns to the one
13
+ * before. `email-code` and `sign-up-code` enter the code emailed to an address the step before asked for, and
14
+ * `sign-up-details` asks for the name and password once that code was right.
15
+ */
16
+ export declare const signInSteps: readonly ["sign-in", "forgot-password", "email-code", "sign-up", "sign-up-code", "sign-up-details"];
17
+ /** A step of the sign-in route: one of `signInSteps`. */
18
+ export type SignInStep = (typeof signInSteps)[number];
19
+ /** Where the sign-in route is: its step, and the page below the base path to come back to, when it names one. */
20
+ export type SignInAddress = {
21
+ /** The step the route shows. */
22
+ step: SignInStep;
23
+ /** The page below the base path to come back to, when it names one. */
24
+ next?: string;
25
+ };
26
+ /** The path below the base path of a step of the sign-in route, coming back to `next` after it, the start by default. */
27
+ export declare const signInPath: ({ step, next }?: {
28
+ step?: SignInStep;
29
+ next?: string;
30
+ }) => string;
31
+ /** The sign-in route's step and the page to come back to, for the path below the base path; `undefined` elsewhere. */
32
+ export declare const readSignInAddress: (path: string, params: URLSearchParams) => SignInAddress | undefined;
33
+ //#endregion
@@ -0,0 +1,51 @@
1
+ //#region src/sign-in-address.ts
2
+ /** The path of the sign-in route, below the app's base path. Its steps and the page to come back to are in its query. */
3
+ const signInRoute = "/-/sign-in";
4
+ /** The names of the sign-in route's query parameters: the step it shows, and the page to come back to after it. */
5
+ const signInParams = {
6
+ /** The step the route shows, when it is not the first. */
7
+ step: "step",
8
+ /** The page below the base path to come back to after signing in. */
9
+ next: "next"
10
+ };
11
+ /**
12
+ * A step of signing in or making an account, each with an address of its own: Back from a step returns to the one
13
+ * before. `email-code` and `sign-up-code` enter the code emailed to an address the step before asked for, and
14
+ * `sign-up-details` asks for the name and password once that code was right.
15
+ */
16
+ const signInSteps = [
17
+ "sign-in",
18
+ "forgot-password",
19
+ "email-code",
20
+ "sign-up",
21
+ "sign-up-code",
22
+ "sign-up-details"
23
+ ];
24
+ const isStep = (value) => signInSteps.includes(value);
25
+ const localPage = (next) => {
26
+ if (!next?.startsWith("/")) return void 0;
27
+ const url = new URL(next, "http://local");
28
+ if (url.origin !== "http://local" || url.pathname === "/-/sign-in") return void 0;
29
+ return `${url.pathname}${url.search}`;
30
+ };
31
+ /** The path below the base path of a step of the sign-in route, coming back to `next` after it, the start by default. */
32
+ const signInPath = ({ step = "sign-in", next } = {}) => {
33
+ const params = new URLSearchParams();
34
+ if (step !== "sign-in") params.set(signInParams.step, step);
35
+ const page = localPage(next);
36
+ if (page && page !== "/") params.set(signInParams.next, page);
37
+ const query = params.toString();
38
+ return query ? `${signInRoute}?${query}` : signInRoute;
39
+ };
40
+ /** The sign-in route's step and the page to come back to, for the path below the base path; `undefined` elsewhere. */
41
+ const readSignInAddress = (path, params) => {
42
+ if (path !== "/-/sign-in") return void 0;
43
+ const step = params.get(signInParams.step);
44
+ const next = localPage(params.get(signInParams.next));
45
+ return {
46
+ step: isStep(step) ? step : "sign-in",
47
+ ...next && { next }
48
+ };
49
+ };
50
+ //#endregion
51
+ export { readSignInAddress, signInParams, signInPath, signInRoute, signInSteps };
@@ -53,13 +53,22 @@ export declare const displays: {
53
53
  * map style. It asks for the records in its view as it pans and zooms: from far out a count for each part of the map,
54
54
  * which zooms in when chosen, closer in the records. A marker stands for the records that lie close together at the
55
55
  * zoom; choosing it shows their card at the map's bottom, with arrows through them. The card is the one of the cards display named `cards`, the list's first cards display
56
- * when it names none, or the record's title alone without one. Named `map` unless `name` says otherwise.
56
+ * when it names none, or the record's title alone without one. A record's position is approximate when its boolean
57
+ * `approximate` field is true, or its `exact` field false: its marker is drawn hollow and says so, and close enough in
58
+ * an area is drawn around it, the GeoJSON polygon or line its `area` field holds, else a circle of its `radius` field
59
+ * in metres, else one of `defaultRadius`. Named `map` unless `name` says otherwise. See
60
+ * [Approximate positions](website/src/content/docs/reference/ui-config.mdx#approximate-positions).
57
61
  */
58
62
  map: (fields: {
59
63
  latitude: Ref;
60
64
  longitude: Ref;
65
+ approximate?: Ref;
66
+ exact?: Ref;
67
+ radius?: Ref;
68
+ area?: Ref;
61
69
  }, o?: Naming & {
62
70
  cards?: string;
71
+ defaultRadius?: number;
63
72
  }) => ListDisplayModel;
64
73
  /**
65
74
  * The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
@@ -72,6 +81,6 @@ export declare const displays: {
72
81
  props?: ViewProps<P>;
73
82
  }) => ListDisplayModel;
74
83
  };
75
- /** Every field a display names: what it shows, a map's position, and the field references in a custom display's props. */
84
+ /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, and the field references in a custom display's props. */
76
85
  export declare const displayFields: (display: ListDisplayModel) => string[];
77
86
  //#endregion
@@ -48,7 +48,11 @@ const displays = {
48
48
  * map style. It asks for the records in its view as it pans and zooms: from far out a count for each part of the map,
49
49
  * which zooms in when chosen, closer in the records. A marker stands for the records that lie close together at the
50
50
  * zoom; choosing it shows their card at the map's bottom, with arrows through them. The card is the one of the cards display named `cards`, the list's first cards display
51
- * when it names none, or the record's title alone without one. Named `map` unless `name` says otherwise.
51
+ * when it names none, or the record's title alone without one. A record's position is approximate when its boolean
52
+ * `approximate` field is true, or its `exact` field false: its marker is drawn hollow and says so, and close enough in
53
+ * an area is drawn around it, the GeoJSON polygon or line its `area` field holds, else a circle of its `radius` field
54
+ * in metres, else one of `defaultRadius`. Named `map` unless `name` says otherwise. See
55
+ * [Approximate positions](website/src/content/docs/reference/ui-config.mdx#approximate-positions).
52
56
  */
53
57
  map: (fields, o = {}) => ({
54
58
  kind: "map",
@@ -56,7 +60,12 @@ const displays = {
56
60
  ...naming(o),
57
61
  latitude: fields.latitude.name,
58
62
  longitude: fields.longitude.name,
59
- ...o.cards !== void 0 && { cards: o.cards }
63
+ ...o.cards !== void 0 && { cards: o.cards },
64
+ ...fields.approximate && { approximate: fields.approximate.name },
65
+ ...fields.exact && { exact: fields.exact.name },
66
+ ...fields.radius && { radius: fields.radius.name },
67
+ ...o.defaultRadius !== void 0 && { defaultRadius: o.defaultRadius },
68
+ ...fields.area && { area: fields.area.name }
60
69
  }),
61
70
  /**
62
71
  * The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
@@ -81,12 +90,25 @@ const displayErrors = (list) => {
81
90
  ...names.filter((name) => name === tableDisplay).map(() => `"${tableDisplay}" is the list's own display; give the display another name`),
82
91
  ...names.filter((name, index) => names.indexOf(name) !== index).map((name) => `display "${name}" is defined twice`),
83
92
  ...(list.displays ?? []).flatMap((display) => display.kind === "map" && display.cards !== void 0 && !list.displays.some((other) => other.kind === "cards" && other.name === display.cards) ? [`display "${display.name}" names cards "${display.cards}", which is not a cards display of the list`] : []),
93
+ ...(list.displays ?? []).flatMap((display) => display.kind === "map" ? approximateErrors(display).map((error) => `display "${display.name}": ${error}`) : []),
84
94
  ...list.default === void 0 || list.default === "table" || names.includes(list.default) ? [] : [`default "${list.default}" is not one of the displays (${[tableDisplay, ...names].join(", ")})`]
85
95
  ];
86
96
  };
87
- /** Every field a display names: what it shows, a map's position, and the field references in a custom display's props. */
97
+ const approximateErrors = (display) => {
98
+ const { approximate, exact, radius, defaultRadius, area } = display;
99
+ if (approximate !== void 0 && exact !== void 0) return ["name approximate or exact, not both"];
100
+ return [...(radius !== void 0 || defaultRadius !== void 0 || area !== void 0) && approximate === void 0 && exact === void 0 ? ["an area around approximate positions needs the approximate or exact field"] : [], ...defaultRadius === void 0 || Number.isFinite(defaultRadius) && defaultRadius > 0 ? [] : [`defaultRadius ${defaultRadius} is not a number of metres above 0`]];
101
+ };
102
+ /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, and the field references in a custom display's props. */
88
103
  const displayFields = (display) => {
89
- if (display.kind === "map") return [display.latitude, display.longitude];
104
+ if (display.kind === "map") return [
105
+ display.latitude,
106
+ display.longitude,
107
+ display.approximate,
108
+ display.exact,
109
+ display.radius,
110
+ display.area
111
+ ].filter((name) => name !== void 0);
90
112
  if (display.kind === "custom") return [...display.fields, ...fieldRefsIn(display.props)];
91
113
  return [
92
114
  display.image,
@@ -18,6 +18,11 @@ export declare class FieldView<N extends string = string, V = unknown> {
18
18
  help(help: string): FieldView<N, V>;
19
19
  /** How the value shows: `badge` for statuses, `code` in monospace, `percent` with a % sign. */
20
20
  format(format: FieldFormat): FieldView<N, V>;
21
+ /**
22
+ * A text of several lines, such as a description: forms edit it in a box that grows with the text, and the record
23
+ * page and cards keep its line breaks. Only a text field takes it.
24
+ */
25
+ multiline(): FieldView<N, V>;
21
26
  /** Text before a number wherever it is shown, such as a currency: `.prefix('€')`. */
22
27
  prefix(prefix: string): FieldView<N, V>;
23
28
  /** Text after a number wherever it is shown, such as a unit: `.suffix(' m²')`. */
@@ -21,6 +21,13 @@ var FieldView = class FieldView {
21
21
  format(format) {
22
22
  return this.with({ format });
23
23
  }
24
+ /**
25
+ * A text of several lines, such as a description: forms edit it in a box that grows with the text, and the record
26
+ * page and cards keep its line breaks. Only a text field takes it.
27
+ */
28
+ multiline() {
29
+ return this.with({ multiline: true });
30
+ }
24
31
  /** Text before a number wherever it is shown, such as a currency: `.prefix('€')`. */
25
32
  prefix(prefix) {
26
33
  return this.with({ prefix });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/schema",
3
- "version": "0.15.5",
3
+ "version": "0.16.0",
4
4
  "description": "Resource, field, view and access definitions for Protobase configs.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {