@protobase/schema 0.19.15 → 0.19.16
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 +2 -2
- package/dist/index.js +2 -2
- package/dist/internal.d.ts +2 -2
- package/dist/internal.js +2 -2
- package/dist/keys.d.ts +2 -0
- package/dist/keys.js +10 -1
- package/dist/model.d.ts +26 -0
- package/dist/view-actions.d.ts +4 -1
- package/dist/view-actions.js +4 -1
- package/dist/view-displays.d.ts +28 -2
- package/dist/view-displays.js +41 -2
- package/dist/view.d.ts +6 -3
- package/dist/view.js +12 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { UserMenuSource, userMenu } from "./user-menu.js";
|
|
|
19
19
|
import { BottomBarSource, bottomBar, maxBottomBarItems } from "./bottom-bar.js";
|
|
20
20
|
import { BottomBarNames, bottomBarErrors } from "./bottom-bar-errors.js";
|
|
21
21
|
import { layout } from "./layout.js";
|
|
22
|
-
import { KeyType, keyTypes } from "./keys.js";
|
|
22
|
+
import { KeyType, fitsKeyType, keyTypes } from "./keys.js";
|
|
23
23
|
import { addressWords, appPath, readAppPath } from "./app-address.js";
|
|
24
24
|
import { SignInAddress, SignInStep, readSignInAddress, signInParams, signInPath, signInRoute, signInSteps } from "./sign-in-address.js";
|
|
25
25
|
import { FilterLimits, FilterParse, parseFilter } from "./filter/parse.js";
|
|
@@ -38,4 +38,4 @@ import { AccessSource, ResolveOptions, ResolvedAccess, RowFilterOperation, acces
|
|
|
38
38
|
import { restrictModel } from "./access/restrict.js";
|
|
39
39
|
import "./access/index.js";
|
|
40
40
|
import { AssistantAction, AssistantActionRequest, AssistantCardPart, AssistantDiff, AssistantEvent, AssistantMessage, AssistantMessageRequest, AssistantPart, AssistantState, AssistantStep, AssistantStepState, AssistantTablePart, AssistantTextPart, AssistantTone, AssistantWidgetPart } from "./assistant/protocol.js";
|
|
41
|
-
export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionInputKind, type ActionInputModel, 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 CreateModel, 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 ExportModel, 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 GalleryModel, type Grant, type HeldCapability, type HelpWhen, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListColumn, 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 RecordMode, type RecordOf, type Ref, type Refs, type RelatedColumnModel, 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 SectionPresentation, type ShowWhen, 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 };
|
|
41
|
+
export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionInputKind, type ActionInputModel, 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 CreateModel, 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 ExportModel, 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 GalleryModel, type Grant, type HeldCapability, type HelpWhen, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListColumn, 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 RecordMode, type RecordOf, type Ref, type Refs, type RelatedColumnModel, 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 SectionPresentation, type ShowWhen, 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, fitsKeyType, 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
|
@@ -16,11 +16,11 @@ import { userMenu } from "./user-menu.js";
|
|
|
16
16
|
import { bottomBar, maxBottomBarItems } from "./bottom-bar.js";
|
|
17
17
|
import { bottomBarErrors } from "./bottom-bar-errors.js";
|
|
18
18
|
import { layout } from "./layout.js";
|
|
19
|
-
import { keyTypes } from "./keys.js";
|
|
19
|
+
import { fitsKeyType, keyTypes } from "./keys.js";
|
|
20
20
|
import { addressWords, appPath, readAppPath } from "./app-address.js";
|
|
21
21
|
import { readSignInAddress, signInParams, signInPath, signInRoute, signInSteps } from "./sign-in-address.js";
|
|
22
22
|
import { rule } from "./access/rule.js";
|
|
23
23
|
import { defineRoles } from "./access/roles.js";
|
|
24
24
|
import { pickView } from "./access/pick-view.js";
|
|
25
25
|
import { restrictModel } from "./access/restrict.js";
|
|
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 };
|
|
26
|
+
export { accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, fitsKeyType, 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/internal.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { checkedAccept, checkedProvider, parseSize } from "./files/file-options.js";
|
|
2
2
|
import { actionInputErrors, shownInputs } from "./action-inputs.js";
|
|
3
|
-
import { cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
3
|
+
import { boardErrors, cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
4
4
|
import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
|
|
5
5
|
import { bottomBarFor } from "./bottom-bar.js";
|
|
6
6
|
import { decodeKey, encodeKey } from "./keys.js";
|
|
@@ -15,4 +15,4 @@ import { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlacehol
|
|
|
15
15
|
import { AddressCheck, addressErrors } from "./address-errors.js";
|
|
16
16
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
17
17
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
18
|
-
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
18
|
+
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
package/dist/internal.js
CHANGED
|
@@ -5,7 +5,7 @@ import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.j
|
|
|
5
5
|
import { actionInputErrors, shownInputs } from "./action-inputs.js";
|
|
6
6
|
import { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlaceholders, leavesApp, linkActionError } from "./address-template.js";
|
|
7
7
|
import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
|
|
8
|
-
import { cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
8
|
+
import { boardErrors, cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
9
9
|
import { bottomBarFor } from "./bottom-bar.js";
|
|
10
10
|
import { decodeKey, encodeKey } from "./keys.js";
|
|
11
11
|
import { webhookResources } from "./webhooks/webhook-resources.js";
|
|
@@ -15,4 +15,4 @@ import { redactSecrets } from "./redact-secrets.js";
|
|
|
15
15
|
import { addressErrors } from "./address-errors.js";
|
|
16
16
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
17
17
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
18
|
-
export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
18
|
+
export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, pruneByShape, readEventStream, redactSecrets, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
package/dist/keys.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { FieldType, KeyValue, ResourceModel } from "./model.js";
|
|
|
2
2
|
//#region src/keys.d.ts
|
|
3
3
|
/** The field types a primary key part may have: `integer`, `bigint`, `uuid` or `text`. */
|
|
4
4
|
export type KeyType = Extract<FieldType, 'integer' | 'bigint' | 'uuid' | 'text'>;
|
|
5
|
+
/** Whether a column of `type` can hold `value`, such as a user id an owner field stores. */
|
|
6
|
+
export declare const fitsKeyType: (value: string, type: KeyType) => boolean;
|
|
5
7
|
export declare const encodeKey: (key: KeyValue | readonly KeyValue[]) => string;
|
|
6
8
|
export declare const decodeKey: (encoded: string, types: readonly KeyType[]) => string | number | (string | number)[];
|
|
7
9
|
/**
|
package/dist/keys.js
CHANGED
|
@@ -13,6 +13,15 @@ const decodePart = (part, type) => {
|
|
|
13
13
|
if (!Number.isSafeInteger(value)) throw new Error("Invalid integer key part");
|
|
14
14
|
return value;
|
|
15
15
|
};
|
|
16
|
+
/** Whether a column of `type` can hold `value`, such as a user id an owner field stores. */
|
|
17
|
+
const fitsKeyType = (value, type) => {
|
|
18
|
+
if (type === "text") return true;
|
|
19
|
+
if (type === "uuid") return uuidPattern.test(value);
|
|
20
|
+
if (!integerPattern.test(value)) return false;
|
|
21
|
+
if (type === "bigint") return true;
|
|
22
|
+
const number = Number(value);
|
|
23
|
+
return Number.isSafeInteger(number) && Math.abs(number) <= 2 ** 31 - 1;
|
|
24
|
+
};
|
|
16
25
|
const decodeComponent = (part) => {
|
|
17
26
|
try {
|
|
18
27
|
return decodeURIComponent(part);
|
|
@@ -54,4 +63,4 @@ const keyTypes = (model, resolve, seen = []) => model.primaryKey.flatMap((name)
|
|
|
54
63
|
return types;
|
|
55
64
|
});
|
|
56
65
|
//#endregion
|
|
57
|
-
export { decodeKey, encodeKey, keyTypes };
|
|
66
|
+
export { decodeKey, encodeKey, fitsKeyType, keyTypes };
|
package/dist/model.d.ts
CHANGED
|
@@ -304,6 +304,8 @@ export type ListDisplayModel = {
|
|
|
304
304
|
footer?: string[];
|
|
305
305
|
/** Boolean fields shown as small badges of their labels when true. */
|
|
306
306
|
flags?: string[];
|
|
307
|
+
/** Related columns of the list (`c.related`) shown as lines of their dots at the card's bottom, by their names. */
|
|
308
|
+
dots?: string[];
|
|
307
309
|
/** The component that draws each card's content instead of the built-in card. */
|
|
308
310
|
card?: string;
|
|
309
311
|
/** Where the card's further photos come from. */
|
|
@@ -335,6 +337,25 @@ export type ListDisplayModel = {
|
|
|
335
337
|
defaultRadius?: number;
|
|
336
338
|
/** The field holding the GeoJSON geometry around an approximate position: a polygon, or a line such as a street. */
|
|
337
339
|
area?: string;
|
|
340
|
+
} | {
|
|
341
|
+
/** A column per value of an enum field, a card per record in its value's column, moved by dragging. */
|
|
342
|
+
kind: 'board';
|
|
343
|
+
/** What the address names (`?display=board`). */
|
|
344
|
+
name: string;
|
|
345
|
+
/** The display's name in the switch. */
|
|
346
|
+
label?: string;
|
|
347
|
+
/** The display's icon in the switch. */
|
|
348
|
+
icon?: string;
|
|
349
|
+
/** The filterable enum field whose values are the columns, and which a card dragged to another column sets. */
|
|
350
|
+
by: string;
|
|
351
|
+
/** The card's title; the view's title when omitted. */
|
|
352
|
+
title?: string;
|
|
353
|
+
/** The line under the title. */
|
|
354
|
+
subtitle?: string;
|
|
355
|
+
/** A field drawn as a badge with its value labels. */
|
|
356
|
+
badge?: string;
|
|
357
|
+
/** A few small fields, such as dates, each shown when it has a value. */
|
|
358
|
+
meta?: string[];
|
|
338
359
|
} | {
|
|
339
360
|
/** The rows drawn by a project component. */
|
|
340
361
|
kind: 'custom';
|
|
@@ -465,6 +486,11 @@ export type ListModel = {
|
|
|
465
486
|
default?: string;
|
|
466
487
|
/** The columns of related records among `columns`, each named there by its `name`. */
|
|
467
488
|
relatedColumns?: RelatedColumnModel[];
|
|
489
|
+
/**
|
|
490
|
+
* The fields among `columns` edited in their cell, by a user who may change the record and the field; see
|
|
491
|
+
* [Editing in the list](website/src/content/docs/reference/ui-config.mdx#editing-in-the-list).
|
|
492
|
+
*/
|
|
493
|
+
editable?: string[];
|
|
468
494
|
};
|
|
469
495
|
/**
|
|
470
496
|
* A list column of the records of another resource that point at each row, directly or through a join resource, as a
|
package/dist/view-actions.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ export declare const actions: {
|
|
|
17
17
|
bulk?: boolean;
|
|
18
18
|
inputs?: (i: typeof inputs) => ActionInputModel[];
|
|
19
19
|
}) => ActionModel;
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Sets fields of the record, as one update with its ETag, for example `{ status: 'paid' }`. It is not offered on a
|
|
22
|
+
* record that holds these values already.
|
|
23
|
+
*/
|
|
21
24
|
update: (name: string, o: ActionOptions & {
|
|
22
25
|
set: Record<string, unknown>;
|
|
23
26
|
}) => ActionModel;
|
package/dist/view-actions.js
CHANGED
|
@@ -24,7 +24,10 @@ const actions = {
|
|
|
24
24
|
inputs: built
|
|
25
25
|
};
|
|
26
26
|
},
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Sets fields of the record, as one update with its ETag, for example `{ status: 'paid' }`. It is not offered on a
|
|
29
|
+
* record that holds these values already.
|
|
30
|
+
*/
|
|
28
31
|
update: (name, o) => ({
|
|
29
32
|
...named(name, o),
|
|
30
33
|
run: {
|
package/dist/view-displays.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { CardFavoriteModel, CardPhotosModel, ListDisplayModel } from "./model.js";
|
|
1
|
+
import { CardFavoriteModel, CardPhotosModel, ListDisplayModel, ResourceModel } from "./model.js";
|
|
2
2
|
import { Ref } from "./refs.js";
|
|
3
|
+
import { ListColumn } from "./view-columns.js";
|
|
3
4
|
//#region src/view-displays.d.ts
|
|
4
5
|
/** A custom component as `component(name)` from `@protobase/layout` declares it. */
|
|
5
6
|
export type ComponentRef<P> = ((props: P) => unknown) & {
|
|
@@ -26,6 +27,8 @@ export declare const displays: {
|
|
|
26
27
|
* view's title) over `subtitle`, `badge` drawn as a badge with its value labels, `amount` the first of its fields with a
|
|
27
28
|
* value in bold, such as a purchase price or a rent, and a few small `meta` fields such as dates. `footer` is a line at
|
|
28
29
|
* the card's bottom of its fields with a value, joined by bullets. `flags` are boolean fields shown as small badges of their labels when true, such as a garden or parking.
|
|
30
|
+
* `dots` are related columns of the list (`c.related`), each a line of its dots under the rest of the card, with the
|
|
31
|
+
* colours, order and hover cards they have in the table; a column with no records for the row shows no line.
|
|
29
32
|
* With `card`, a component of the project or a plugin draws each card's content instead, from the row of those
|
|
30
33
|
* fields (`{ row }`); without it, or when it throws, the card is the built-in one. With `photos`, the built-in card's
|
|
31
34
|
* picture gets arrows through the `image` of the records of another resource that point at the card's record, after
|
|
@@ -43,6 +46,7 @@ export declare const displays: {
|
|
|
43
46
|
meta?: Ref[];
|
|
44
47
|
footer?: Ref[];
|
|
45
48
|
flags?: Ref[];
|
|
49
|
+
dots?: ListColumn[];
|
|
46
50
|
}, o?: Naming & {
|
|
47
51
|
card?: ComponentRef<never>;
|
|
48
52
|
photos?: CardPhotosModel;
|
|
@@ -70,6 +74,24 @@ export declare const displays: {
|
|
|
70
74
|
cards?: string;
|
|
71
75
|
defaultRadius?: number;
|
|
72
76
|
}) => ListDisplayModel;
|
|
77
|
+
/**
|
|
78
|
+
* A column per value of the enum field `by`, in the order the field lists them, each headed by its value label and how
|
|
79
|
+
* many of the list's records have it; with a column for records without a value when the field may be empty. Each
|
|
80
|
+
* column pages through the list API with the list's filter and search, its value added, in the list's order. A card
|
|
81
|
+
* shows `title` (default: the view's title) over `subtitle`, with `badge` and a few small `meta` fields, as the built-in
|
|
82
|
+
* card of `d.cards` does, and opens the record. Dragging a card to another column, or picking it up with Space and
|
|
83
|
+
* moving it with the arrow keys, saves the record with `by` set to that column's value, as one update with its ETag,
|
|
84
|
+
* so the resource's access rules and `validate` decide, and a refusal puts the card back and says why. `by` must be
|
|
85
|
+
* a filterable enum field. Named `board` unless `name` says otherwise. See
|
|
86
|
+
* [Boards](website/src/content/docs/reference/ui-config.mdx#boards).
|
|
87
|
+
*/
|
|
88
|
+
board: (fields: {
|
|
89
|
+
by: Ref;
|
|
90
|
+
title?: Ref;
|
|
91
|
+
subtitle?: Ref;
|
|
92
|
+
badge?: Ref;
|
|
93
|
+
meta?: Ref[];
|
|
94
|
+
}, o?: Naming) => ListDisplayModel;
|
|
73
95
|
/**
|
|
74
96
|
* The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
|
|
75
97
|
* reads the rows with `useListDisplay()`; `fields` are the fields it shows, fetched with relation names.
|
|
@@ -81,6 +103,10 @@ export declare const displays: {
|
|
|
81
103
|
props?: ViewProps<P>;
|
|
82
104
|
}) => ListDisplayModel;
|
|
83
105
|
};
|
|
84
|
-
/**
|
|
106
|
+
/** What makes a board unable to put the records in columns: a `by` field that is no filterable enum. */
|
|
107
|
+
export declare const boardErrors: (display: Extract<ListDisplayModel, {
|
|
108
|
+
kind: "board";
|
|
109
|
+
}>, model: ResourceModel) => string[];
|
|
110
|
+
/** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, and the field references in a custom display's props. */
|
|
85
111
|
export declare const displayFields: (display: ListDisplayModel) => string[];
|
|
86
112
|
//#endregion
|
package/dist/view-displays.js
CHANGED
|
@@ -19,6 +19,8 @@ const displays = {
|
|
|
19
19
|
* view's title) over `subtitle`, `badge` drawn as a badge with its value labels, `amount` the first of its fields with a
|
|
20
20
|
* value in bold, such as a purchase price or a rent, and a few small `meta` fields such as dates. `footer` is a line at
|
|
21
21
|
* the card's bottom of its fields with a value, joined by bullets. `flags` are boolean fields shown as small badges of their labels when true, such as a garden or parking.
|
|
22
|
+
* `dots` are related columns of the list (`c.related`), each a line of its dots under the rest of the card, with the
|
|
23
|
+
* colours, order and hover cards they have in the table; a column with no records for the row shows no line.
|
|
22
24
|
* With `card`, a component of the project or a plugin draws each card's content instead, from the row of those
|
|
23
25
|
* fields (`{ row }`); without it, or when it throws, the card is the built-in one. With `photos`, the built-in card's
|
|
24
26
|
* picture gets arrows through the `image` of the records of another resource that point at the card's record, after
|
|
@@ -39,6 +41,7 @@ const displays = {
|
|
|
39
41
|
...fields.meta && { meta: fields.meta.map((ref) => ref.name) },
|
|
40
42
|
...fields.footer && { footer: fields.footer.map((ref) => ref.name) },
|
|
41
43
|
...fields.flags && { flags: fields.flags.map((ref) => ref.name) },
|
|
44
|
+
...fields.dots && { dots: fields.dots.map((column) => column.name) },
|
|
42
45
|
...o.card && { card: customComponent(o.card, "d.cards card") },
|
|
43
46
|
...o.photos && { photos: { ...o.photos } },
|
|
44
47
|
...o.favorite && { favorite: { ...o.favorite } }
|
|
@@ -68,6 +71,27 @@ const displays = {
|
|
|
68
71
|
...fields.area && { area: fields.area.name }
|
|
69
72
|
}),
|
|
70
73
|
/**
|
|
74
|
+
* A column per value of the enum field `by`, in the order the field lists them, each headed by its value label and how
|
|
75
|
+
* many of the list's records have it; with a column for records without a value when the field may be empty. Each
|
|
76
|
+
* column pages through the list API with the list's filter and search, its value added, in the list's order. A card
|
|
77
|
+
* shows `title` (default: the view's title) over `subtitle`, with `badge` and a few small `meta` fields, as the built-in
|
|
78
|
+
* card of `d.cards` does, and opens the record. Dragging a card to another column, or picking it up with Space and
|
|
79
|
+
* moving it with the arrow keys, saves the record with `by` set to that column's value, as one update with its ETag,
|
|
80
|
+
* so the resource's access rules and `validate` decide, and a refusal puts the card back and says why. `by` must be
|
|
81
|
+
* a filterable enum field. Named `board` unless `name` says otherwise. See
|
|
82
|
+
* [Boards](website/src/content/docs/reference/ui-config.mdx#boards).
|
|
83
|
+
*/
|
|
84
|
+
board: (fields, o = {}) => ({
|
|
85
|
+
kind: "board",
|
|
86
|
+
name: o.name ?? "board",
|
|
87
|
+
...naming(o),
|
|
88
|
+
by: fields.by.name,
|
|
89
|
+
...fields.title && { title: fields.title.name },
|
|
90
|
+
...fields.subtitle && { subtitle: fields.subtitle.name },
|
|
91
|
+
...fields.badge && { badge: fields.badge.name },
|
|
92
|
+
...fields.meta && { meta: fields.meta.map((ref) => ref.name) }
|
|
93
|
+
}),
|
|
94
|
+
/**
|
|
71
95
|
* The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
|
|
72
96
|
* reads the rows with `useListDisplay()`; `fields` are the fields it shows, fetched with relation names.
|
|
73
97
|
*/
|
|
@@ -90,6 +114,7 @@ const displayErrors = (list) => {
|
|
|
90
114
|
...names.filter((name) => name === tableDisplay).map(() => `"${tableDisplay}" is the list's own display; give the display another name`),
|
|
91
115
|
...names.filter((name, index) => names.indexOf(name) !== index).map((name) => `display "${name}" is defined twice`),
|
|
92
116
|
...(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`] : []),
|
|
117
|
+
...(list.displays ?? []).flatMap((display) => display.kind === "cards" ? (display.dots ?? []).filter((name) => !list.relatedColumns?.some((column) => column.name === name)).map((name) => `display "${display.name}" shows dots of "${name}", which is not a related column of the list`) : []),
|
|
93
118
|
...(list.displays ?? []).flatMap((display) => display.kind === "map" ? approximateErrors(display).map((error) => `display "${display.name}": ${error}`) : []),
|
|
94
119
|
...list.default === void 0 || list.default === "table" || names.includes(list.default) ? [] : [`default "${list.default}" is not one of the displays (${[tableDisplay, ...names].join(", ")})`]
|
|
95
120
|
];
|
|
@@ -99,7 +124,14 @@ const approximateErrors = (display) => {
|
|
|
99
124
|
if (approximate !== void 0 && exact !== void 0) return ["name approximate or exact, not both"];
|
|
100
125
|
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
126
|
};
|
|
102
|
-
/**
|
|
127
|
+
/** What makes a board unable to put the records in columns: a `by` field that is no filterable enum. */
|
|
128
|
+
const boardErrors = (display, model) => {
|
|
129
|
+
const field = Object.hasOwn(model.fields, display.by) ? model.fields[display.by] : void 0;
|
|
130
|
+
if (!field) return [];
|
|
131
|
+
if (field.type !== "enum") return [`"${display.by}" on ${model.name} is ${field.type}, not an enum, whose values are the board's columns`];
|
|
132
|
+
return field.filterable ? [] : [`"${display.by}" on ${model.name} is not filterable, and each column of the board filters by its value`];
|
|
133
|
+
};
|
|
134
|
+
/** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, and the field references in a custom display's props. */
|
|
103
135
|
const displayFields = (display) => {
|
|
104
136
|
if (display.kind === "map") return [
|
|
105
137
|
display.latitude,
|
|
@@ -110,6 +142,13 @@ const displayFields = (display) => {
|
|
|
110
142
|
display.area
|
|
111
143
|
].filter((name) => name !== void 0);
|
|
112
144
|
if (display.kind === "custom") return [...display.fields, ...fieldRefsIn(display.props)];
|
|
145
|
+
if (display.kind === "board") return [
|
|
146
|
+
display.by,
|
|
147
|
+
display.title,
|
|
148
|
+
display.subtitle,
|
|
149
|
+
display.badge,
|
|
150
|
+
...display.meta ?? []
|
|
151
|
+
].filter((name) => name !== void 0);
|
|
113
152
|
return [
|
|
114
153
|
display.image,
|
|
115
154
|
display.title,
|
|
@@ -122,4 +161,4 @@ const displayFields = (display) => {
|
|
|
122
161
|
].filter((name) => name !== void 0);
|
|
123
162
|
};
|
|
124
163
|
//#endregion
|
|
125
|
-
export { cardPhotoLimit, customComponent, displayErrors, displayFields, displays, tableDisplay };
|
|
164
|
+
export { boardErrors, cardPhotoLimit, customComponent, displayErrors, displayFields, displays, tableDisplay };
|
package/dist/view.d.ts
CHANGED
|
@@ -66,14 +66,17 @@ export declare class ViewBuilder<R extends {
|
|
|
66
66
|
/** Hints per field, such as `{ total: r.total.prefix('€').decimals(2) }`; calls add up. */
|
|
67
67
|
fields(build: (r: FieldViews<R>) => Record<string, FieldView>): ViewBuilder<R>;
|
|
68
68
|
/**
|
|
69
|
-
* The list: its table's `columns`, fields or columns of related records (`c.related`), `sort` and `search`,
|
|
70
|
-
* `displays` to switch to (`d.cards`, `d.custom`), one of which
|
|
71
|
-
* display or column names collide
|
|
69
|
+
* The list: its table's `columns`, fields or columns of related records (`c.related`), `sort` and `search`, the
|
|
70
|
+
* columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.custom`), one of which
|
|
71
|
+
* may be the `default` the list opens in. Throws when display or column names collide, `default` names none or an
|
|
72
|
+
* editable field is not among the columns. See
|
|
73
|
+
* [Editing in the list](website/src/content/docs/reference/ui-config.mdx#editing-in-the-list).
|
|
72
74
|
*/
|
|
73
75
|
list(build: (r: FieldRefs<FieldsOf<R>>, d: typeof displays, c: typeof columns) => {
|
|
74
76
|
columns: Array<Ref | ListColumn>;
|
|
75
77
|
sort?: Array<[Ref, 'asc' | 'desc']>;
|
|
76
78
|
search?: Ref[];
|
|
79
|
+
editable?: Ref[];
|
|
77
80
|
displays?: ListDisplayModel[];
|
|
78
81
|
default?: string;
|
|
79
82
|
}): ViewBuilder<R>;
|
package/dist/view.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isMenuHref } from "./menu-href.js";
|
|
|
3
3
|
import { navRecentErrors } from "./nav-recent.js";
|
|
4
4
|
import { actions } from "./view-actions.js";
|
|
5
5
|
import { columns, isListColumn } from "./view-columns.js";
|
|
6
|
-
import { displayErrors, displayFields, displays } from "./view-displays.js";
|
|
6
|
+
import { boardErrors, displayErrors, displayFields, displays } from "./view-displays.js";
|
|
7
7
|
import { FieldView } from "./view-field.js";
|
|
8
8
|
import { widgets } from "./view-widgets.js";
|
|
9
9
|
//#region src/view.ts
|
|
@@ -73,21 +73,26 @@ var ViewBuilder = class ViewBuilder {
|
|
|
73
73
|
} });
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
* The list: its table's `columns`, fields or columns of related records (`c.related`), `sort` and `search`,
|
|
77
|
-
* `displays` to switch to (`d.cards`, `d.custom`), one of which
|
|
78
|
-
* display or column names collide
|
|
76
|
+
* The list: its table's `columns`, fields or columns of related records (`c.related`), `sort` and `search`, the
|
|
77
|
+
* columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.custom`), one of which
|
|
78
|
+
* may be the `default` the list opens in. Throws when display or column names collide, `default` names none or an
|
|
79
|
+
* editable field is not among the columns. See
|
|
80
|
+
* [Editing in the list](website/src/content/docs/reference/ui-config.mdx#editing-in-the-list).
|
|
79
81
|
*/
|
|
80
82
|
list(build) {
|
|
81
|
-
const { columns: columns$1, sort, search, displays: shown = [], default: opens } = build(this.refs(), displays, columns);
|
|
83
|
+
const { columns: columns$1, sort, search, editable, displays: shown = [], default: opens } = build(this.refs(), displays, columns);
|
|
82
84
|
const related = columns$1.filter(isListColumn).map(({ kind: _, ...column }) => column);
|
|
83
85
|
const names = columns$1.map((column) => column.name);
|
|
84
86
|
const repeated = names.find((name, index) => names.indexOf(name) !== index);
|
|
85
87
|
if (repeated !== void 0) throw new Error(`View "${this.state.resource}": the list has two columns named "${repeated}"`);
|
|
88
|
+
const stray = editable?.find((ref) => !names.includes(ref.name));
|
|
89
|
+
if (stray) throw new Error(`View "${this.state.resource}": editable field "${stray.name}" is not among the list's columns`);
|
|
86
90
|
const list = {
|
|
87
91
|
columns: names,
|
|
88
92
|
...related.length > 0 && { relatedColumns: related },
|
|
89
93
|
...sort && { sort: sort.map(([ref, dir]) => [ref.name, dir]) },
|
|
90
94
|
...search && { search: search.map((ref) => ref.name) },
|
|
95
|
+
...editable && editable.length > 0 && { editable: editable.map((ref) => ref.name) },
|
|
91
96
|
...shown.length > 0 && { displays: shown },
|
|
92
97
|
...opens !== void 0 && { default: opens }
|
|
93
98
|
};
|
|
@@ -237,6 +242,8 @@ var ViewBuilder = class ViewBuilder {
|
|
|
237
242
|
if (display.kind === "cards" && display.image !== void 0 && resource.fields[display.image].type !== "file") throw new Error(`View "${this.state.resource}": display "${display.name}" shows "${display.image}" as its image, which is not a file field`);
|
|
238
243
|
const flag = display.kind === "cards" ? display.flags?.find((name) => resource.fields[name].type !== "boolean") : void 0;
|
|
239
244
|
if (flag !== void 0) throw new Error(`View "${this.state.resource}": display "${display.name}" shows "${flag}" as a flag, which is not a boolean field`);
|
|
245
|
+
const board = display.kind === "board" ? boardErrors(display, resource) : [];
|
|
246
|
+
if (board.length > 0) throw new Error(`View "${this.state.resource}": display "${display.name}": ${board.join("; ")}`);
|
|
240
247
|
}
|
|
241
248
|
const clash = resource ? list?.relatedColumns?.find((column) => Object.hasOwn(resource.fields, column.name)) : void 0;
|
|
242
249
|
if (clash) throw new Error(`View "${this.state.resource}": related column "${clash.name}" has the name of a field of the resource`);
|