@protobase/schema 0.22.0 → 0.22.2
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/internal.d.ts +2 -1
- package/dist/internal.js +2 -1
- package/dist/model.d.ts +6 -3
- package/dist/update-set.d.ts +12 -0
- package/dist/update-set.js +19 -0
- package/dist/view-actions.d.ts +9 -4
- package/dist/view-actions.js +26 -16
- package/package.json +1 -1
package/dist/internal.d.ts
CHANGED
|
@@ -12,10 +12,11 @@ import { SearchTerm, matchedSearchField, matchesSearch, searchTerms, termMatches
|
|
|
12
12
|
import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.js";
|
|
13
13
|
import { PluginHost, PluginRequirement, inRange, pluginProblem } from "./plugin-version.js";
|
|
14
14
|
import { redactSecrets } from "./redact-secrets.js";
|
|
15
|
+
import { updateSetErrors, updateValues } from "./update-set.js";
|
|
15
16
|
import { addressPlaceholders, appHrefError, fillAddress, hrefField, hrefPlaceholders, leavesApp, linkActionError } from "./address-template.js";
|
|
16
17
|
import { promptError, promptFields, renderPrompt } from "./ai-prompt.js";
|
|
17
18
|
import { AddressCheck, addressErrors } from "./address-errors.js";
|
|
18
19
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
19
20
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
20
21
|
import { layoutItems } from "./layout-items.js";
|
|
21
|
-
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
22
|
+
export { type AddressCheck, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, webhookResources };
|
package/dist/internal.js
CHANGED
|
@@ -5,6 +5,7 @@ import { matchedSearchField, matchesSearch, searchTerms, termMatches } from "./s
|
|
|
5
5
|
import { checkEventFilter } from "./events/event-models.js";
|
|
6
6
|
import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.js";
|
|
7
7
|
import { actionInputErrors, shownInputs } from "./action-inputs.js";
|
|
8
|
+
import { updateSetErrors, updateValues } from "./update-set.js";
|
|
8
9
|
import { chartFields, isGroupChart } from "./view-chart.js";
|
|
9
10
|
import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
|
|
10
11
|
import { boardErrors, calendarErrors, cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
|
|
@@ -18,4 +19,4 @@ import { addressErrors } from "./address-errors.js";
|
|
|
18
19
|
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
19
20
|
import { readEventStream } from "./assistant/event-stream.js";
|
|
20
21
|
import { layoutItems } from "./layout-items.js";
|
|
21
|
-
export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, webhookResources };
|
|
22
|
+
export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, layoutItems, leavesApp, linkActionError, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseSize, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, webhookResources };
|
package/dist/model.d.ts
CHANGED
|
@@ -603,6 +603,7 @@ export type FilterWidgetModel = {
|
|
|
603
603
|
/**
|
|
604
604
|
* Records of another resource on the record page: those whose `field` holds this record's key or, with `through`,
|
|
605
605
|
* those whose `field` holds one of the `key` values of the `through` records that point at this record (a join table).
|
|
606
|
+
* With `from`, those whose `field` holds the value of that field of this record.
|
|
606
607
|
* See [Related records](website/src/content/docs/reference/ui-config.mdx#related-records).
|
|
607
608
|
*/
|
|
608
609
|
export type RelatedModel = {
|
|
@@ -614,8 +615,10 @@ export type RelatedModel = {
|
|
|
614
615
|
help?: string;
|
|
615
616
|
/** The resource whose records it lists. */
|
|
616
617
|
resource: string;
|
|
617
|
-
/** The filterable field of `resource` matched against this record's key, or with `through` against the join records' keys. */
|
|
618
|
+
/** The filterable field of `resource` matched against this record's key, or with `through` against the join records' keys, or with `from` against that field's value. */
|
|
618
619
|
field: string;
|
|
620
|
+
/** A field of this record whose value `field` is matched against instead of its key; not with `through`. */
|
|
621
|
+
from?: string;
|
|
619
622
|
/** The join records between this record and the listed ones. */
|
|
620
623
|
through?: {
|
|
621
624
|
/** The join resource. */
|
|
@@ -822,7 +825,7 @@ export type SaveFeedback = 'toast' | 'button';
|
|
|
822
825
|
export type ActionRun = {
|
|
823
826
|
/** Updates the record. */
|
|
824
827
|
kind: 'update';
|
|
825
|
-
/** The fields it sets, by name. */
|
|
828
|
+
/** The fields it sets, by name; a value that is exactly `{input}` is that input's answer. */
|
|
826
829
|
values: Record<string, unknown>;
|
|
827
830
|
} | {
|
|
828
831
|
/** Deletes the record, soft deleting when the resource does. */
|
|
@@ -865,7 +868,7 @@ export type ActionModel = {
|
|
|
865
868
|
bulk: boolean;
|
|
866
869
|
/** What it does; without it the app runs the handler registered under `name`. */
|
|
867
870
|
run?: ActionRun;
|
|
868
|
-
/** What the button asks for in a dialog before the
|
|
871
|
+
/** What the button asks for in a dialog before the action runs: a handler gets the answers as `values`, an update writes them through `set`. */
|
|
869
872
|
inputs?: ActionInputModel[];
|
|
870
873
|
};
|
|
871
874
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ActionInputModel } from "./model.js";
|
|
2
|
+
//#region src/update-set.d.ts
|
|
3
|
+
/** Why an update's `set` cannot be used: a value that is exactly `{name}` must name one of the inputs the action asks for. */
|
|
4
|
+
export declare const updateSetErrors: (set: Record<string, unknown>, inputs?: ActionInputModel[]) => string[];
|
|
5
|
+
/**
|
|
6
|
+
* The fields an update writes: a literal as it is, a value that is exactly `{input}` as that input's answer. A field whose
|
|
7
|
+
* input was hidden has no answer in `values` and is left out, so it keeps what it holds.
|
|
8
|
+
*/
|
|
9
|
+
export declare const updateValues: (set: Record<string, unknown>, values: Record<string, unknown>) => {
|
|
10
|
+
[k: string]: unknown;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { hrefField } from "./address-template.js";
|
|
2
|
+
//#region src/update-set.ts
|
|
3
|
+
/** Why an update's `set` cannot be used: a value that is exactly `{name}` must name one of the inputs the action asks for. */
|
|
4
|
+
const updateSetErrors = (set, inputs = []) => Object.entries(set).flatMap(([field, value]) => {
|
|
5
|
+
const input = typeof value === "string" ? hrefField(value) : void 0;
|
|
6
|
+
if (input === void 0 || inputs.some((entry) => entry.name === input)) return [];
|
|
7
|
+
return [`set "${field}" names input "${input}", which it does not ask for`];
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* The fields an update writes: a literal as it is, a value that is exactly `{input}` as that input's answer. A field whose
|
|
11
|
+
* input was hidden has no answer in `values` and is left out, so it keeps what it holds.
|
|
12
|
+
*/
|
|
13
|
+
const updateValues = (set, values) => Object.fromEntries(Object.entries(set).flatMap(([field, value]) => {
|
|
14
|
+
const input = typeof value === "string" ? hrefField(value) : void 0;
|
|
15
|
+
if (input === void 0) return [[field, value]];
|
|
16
|
+
return Object.hasOwn(values, input) ? [[field, values[input]]] : [];
|
|
17
|
+
}));
|
|
18
|
+
//#endregion
|
|
19
|
+
export { updateSetErrors, updateValues };
|
package/dist/view-actions.d.ts
CHANGED
|
@@ -7,21 +7,26 @@ type ActionOptions = {
|
|
|
7
7
|
icon?: string;
|
|
8
8
|
confirm?: string;
|
|
9
9
|
};
|
|
10
|
+
/** @inline */
|
|
11
|
+
type InputsOption = {
|
|
12
|
+
inputs?: (i: typeof inputs) => ActionInputModel[];
|
|
13
|
+
};
|
|
10
14
|
export declare const actions: {
|
|
11
15
|
/**
|
|
12
16
|
* An action the app implements: it runs the handler registered under `name`. With `inputs`, such as
|
|
13
17
|
* `(i) => [i.text('reason', { label: 'Reason' })]`, the button first asks for them in a dialog, and the handler gets the
|
|
14
18
|
* answers as `values`.
|
|
15
19
|
*/
|
|
16
|
-
action: (name: string, o: ActionOptions & {
|
|
20
|
+
action: (name: string, o: ActionOptions & InputsOption & {
|
|
17
21
|
bulk?: boolean;
|
|
18
|
-
inputs?: (i: typeof inputs) => ActionInputModel[];
|
|
19
22
|
}) => ActionModel;
|
|
20
23
|
/**
|
|
21
24
|
* 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.
|
|
25
|
+
* record that holds these values already. With `inputs`, the button first asks for them in a dialog, and a `set` value
|
|
26
|
+
* that is exactly `'{name}'` is written as that input's answer, with no handler code:
|
|
27
|
+
* `a.update('answer', { label: 'Answer', inputs: (i) => [i.text('answer', { label: 'Answer', multiline: true })], set: { answer: '{answer}' } })`.
|
|
23
28
|
*/
|
|
24
|
-
update: (name: string, o: ActionOptions & {
|
|
29
|
+
update: (name: string, o: ActionOptions & InputsOption & {
|
|
25
30
|
set: Record<string, unknown>;
|
|
26
31
|
}) => ActionModel;
|
|
27
32
|
/** Deletes the record (soft delete when the resource has one). */
|
package/dist/view-actions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { linkActionError } from "./address-template.js";
|
|
2
2
|
import { promptError } from "./ai-prompt.js";
|
|
3
3
|
import { actionInputErrors, inputs } from "./action-inputs.js";
|
|
4
|
+
import { updateSetErrors } from "./update-set.js";
|
|
4
5
|
//#region src/view-actions.ts
|
|
5
6
|
const named = (name, o) => ({
|
|
6
7
|
name,
|
|
@@ -9,33 +10,42 @@ const named = (name, o) => ({
|
|
|
9
10
|
...o.icon !== void 0 && { icon: o.icon },
|
|
10
11
|
...o.confirm !== void 0 && { confirm: o.confirm }
|
|
11
12
|
});
|
|
13
|
+
const builtInputs = (name, option) => {
|
|
14
|
+
if (!option) return {};
|
|
15
|
+
const built = option(inputs);
|
|
16
|
+
const errors = actionInputErrors(built);
|
|
17
|
+
if (errors.length > 0) throw new Error(`Action "${name}": ${errors.join("; ")}`);
|
|
18
|
+
return { inputs: built };
|
|
19
|
+
};
|
|
12
20
|
const actions = {
|
|
13
21
|
/**
|
|
14
22
|
* An action the app implements: it runs the handler registered under `name`. With `inputs`, such as
|
|
15
23
|
* `(i) => [i.text('reason', { label: 'Reason' })]`, the button first asks for them in a dialog, and the handler gets the
|
|
16
24
|
* answers as `values`.
|
|
17
25
|
*/
|
|
18
|
-
action: (name, o) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
action: (name, o) => ({
|
|
27
|
+
...named(name, o),
|
|
28
|
+
...builtInputs(name, o.inputs)
|
|
29
|
+
}),
|
|
30
|
+
/**
|
|
31
|
+
* Sets fields of the record, as one update with its ETag, for example `{ status: 'paid' }`. It is not offered on a
|
|
32
|
+
* record that holds these values already. With `inputs`, the button first asks for them in a dialog, and a `set` value
|
|
33
|
+
* that is exactly `'{name}'` is written as that input's answer, with no handler code:
|
|
34
|
+
* `a.update('answer', { label: 'Answer', inputs: (i) => [i.text('answer', { label: 'Answer', multiline: true })], set: { answer: '{answer}' } })`.
|
|
35
|
+
*/
|
|
36
|
+
update: (name, o) => {
|
|
37
|
+
const built = builtInputs(name, o.inputs);
|
|
38
|
+
const errors = updateSetErrors(o.set, built.inputs);
|
|
22
39
|
if (errors.length > 0) throw new Error(`Action "${name}": ${errors.join("; ")}`);
|
|
23
40
|
return {
|
|
24
41
|
...named(name, o),
|
|
25
|
-
|
|
42
|
+
...built,
|
|
43
|
+
run: {
|
|
44
|
+
kind: "update",
|
|
45
|
+
values: o.set
|
|
46
|
+
}
|
|
26
47
|
};
|
|
27
48
|
},
|
|
28
|
-
/**
|
|
29
|
-
* Sets fields of the record, as one update with its ETag, for example `{ status: 'paid' }`. It is not offered on a
|
|
30
|
-
* record that holds these values already.
|
|
31
|
-
*/
|
|
32
|
-
update: (name, o) => ({
|
|
33
|
-
...named(name, o),
|
|
34
|
-
run: {
|
|
35
|
-
kind: "update",
|
|
36
|
-
values: o.set
|
|
37
|
-
}
|
|
38
|
-
}),
|
|
39
49
|
/** Deletes the record (soft delete when the resource has one). */
|
|
40
50
|
remove: (name, o) => ({
|
|
41
51
|
...named(name, o),
|