@protobase/schema 0.26.6 → 0.26.8

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.
@@ -1,5 +1,6 @@
1
1
  import { checkedAccept, checkedProvider, parseSize } from "./files/file-options.js";
2
2
  import { actionInputErrors, shownInputs } from "./action-inputs.js";
3
+ import { actionConditionError } from "./view-actions.js";
3
4
  import { chartFields, isGroupChart } from "./view-chart.js";
4
5
  import { boardErrors, cardPhotoLimit, datesErrors, displayFields, tableDisplay } from "./view-displays.js";
5
6
  import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
@@ -22,4 +23,4 @@ import { readEventStream } from "./assistant/event-stream.js";
22
23
  import { layoutItems } from "./layout-items.js";
23
24
  import { viewOfList } from "./named-list.js";
24
25
  import { Locale, isLocale, locales, pickLocale } from "./locale.js";
25
- export { type AddressCheck, type FormulaNode, type Locale, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
26
+ export { type AddressCheck, type FormulaNode, type Locale, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionConditionError, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
package/dist/internal.js CHANGED
@@ -9,6 +9,7 @@ import { viewOfList } from "./named-list.js";
9
9
  import { defaultRecentLimit, navRecentErrors, statusTones } from "./nav-recent.js";
10
10
  import { actionInputErrors, shownInputs } from "./action-inputs.js";
11
11
  import { updateSetErrors, updateValues } from "./update-set.js";
12
+ import { actionConditionError } from "./view-actions.js";
12
13
  import { chartFields, isGroupChart } from "./view-chart.js";
13
14
  import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
14
15
  import { boardErrors, cardPhotoLimit, datesErrors, displayFields, tableDisplay } from "./view-displays.js";
@@ -22,4 +23,4 @@ import { addressErrors } from "./address-errors.js";
22
23
  import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
23
24
  import { readEventStream } from "./assistant/event-stream.js";
24
25
  import { isLocale, locales, pickLocale } from "./locale.js";
25
- export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
26
+ export { actionConditionError, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
package/dist/model.d.ts CHANGED
@@ -968,14 +968,27 @@ export type ActionModel = {
968
968
  /** The button's label. */
969
969
  label: string;
970
970
  /**
971
- * The button's icon: `ban`, `bath`, `bed`, `bell`, `bookmark`, `calendar`, `door-open`, `external-link`, `file-text`, `heart`,
972
- * `house`, `key`, `land-plot`, `leaf`, `ruler`, `send`, `tag` or `wallet`; another name shows a lightning bolt.
971
+ * The button's icon: `archive`, `arrow-right-left`, `ban`, `bath`, `bed`, `bell`, `bookmark`, `calendar`, `camera`, `copy`, `cpu`,
972
+ * `door-open`, `download`, `external-link`, `file-text`, `hard-drive`, `heart`, `house`, `key`, `land-plot`, `leaf`, `memory`,
973
+ * `network`, `play`, `plug`, `power`, `restart`, `ruler`, `send`, `server`, `stop`, `tag`, `terminal`, `upload`, `wallet` or
974
+ * `wrench`; another name shows a lightning bolt.
973
975
  */
974
976
  icon?: string;
975
977
  /** The question the button asks before it runs the action. */
976
978
  confirm?: string;
977
- /** Whether the action is meant for several records at once (`a.action`'s `bulk`). */
979
+ /** Whether the action is offered for the rows selected in the list, running on each it applies to (`bulk`). */
978
980
  bulk: boolean;
981
+ /**
982
+ * An AIP-160 condition over the record's own fields, as `status = 'running'`, for the records the action applies to.
983
+ * It only decides what the buttons show; the API's access rules decide what may run.
984
+ */
985
+ when?: string;
986
+ /** What the button does on a record `when` does not hold for: it is left out, or shown disabled with `reason`. */
987
+ otherwise?: 'hide' | 'disable';
988
+ /** Why the button is disabled on a record `when` does not hold for, shown to the user. */
989
+ reason?: string;
990
+ /** `danger` draws an action that destroys or interrupts something, such as Force off, in red. */
991
+ variant?: 'danger';
979
992
  /** What it does; without it the app runs the handler registered under `name`. */
980
993
  run?: ActionRun;
981
994
  /** 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`. */
@@ -1,12 +1,23 @@
1
1
  import { ActionInputModel, ActionModel, AppAddress } from "./model.js";
2
2
  import { inputs } from "./action-inputs.js";
3
3
  //#region src/view-actions.d.ts
4
- /** @inline */
4
+ /**
5
+ * A button's label, icon and question, and the records it applies to: `when`, an AIP-160 condition over the record's own
6
+ * fields such as `status = 'running'`, leaves the button out on a record it does not hold for, or with
7
+ * `otherwise: 'disable'` shows it disabled with `reason`. `variant: 'danger'` draws it in red.
8
+ * @inline
9
+ */
5
10
  type ActionOptions = {
6
11
  label: string;
7
12
  icon?: string;
8
13
  confirm?: string;
14
+ when?: string;
15
+ otherwise?: 'hide' | 'disable';
16
+ reason?: string;
17
+ variant?: 'danger';
9
18
  };
19
+ /** What is wrong with an action's `when`, `otherwise` and `reason`: a fallback needs a condition, and a disabled button says why. */
20
+ export declare const actionConditionError: (o: Pick<ActionOptions, "when" | "otherwise" | "reason">) => "\"otherwise\" and \"reason\" need a \"when\" condition" | "\"when\" is empty" | "a button disabled by \"when\" needs a \"reason\"" | "\"reason\" shows only with otherwise: 'disable'" | undefined;
10
21
  /** @inline */
11
22
  type InputsOption = {
12
23
  inputs?: (i: typeof inputs) => ActionInputModel[];
@@ -15,7 +26,7 @@ export declare const actions: {
15
26
  /**
16
27
  * An action the app implements: it runs the handler registered under `name`. With `inputs`, such as
17
28
  * `(i) => [i.text('reason', { label: 'Reason' })]`, the button first asks for them in a dialog, and the handler gets the
18
- * answers as `values`.
29
+ * answers as `values`. With `bulk` and no `inputs`, the list offers it for the selected rows too, and runs the handler on each it applies to.
19
30
  */
20
31
  action: (name: string, o: ActionOptions & InputsOption & {
21
32
  bulk?: boolean;
@@ -25,9 +36,11 @@ export declare const actions: {
25
36
  * record that holds these values already. With `inputs`, the button first asks for them in a dialog, and a `set` value
26
37
  * that is exactly `'{name}'` is written as that input's answer, with no handler code:
27
38
  * `a.update('answer', { label: 'Answer', inputs: (i) => [i.text('answer', { label: 'Answer', multiline: true })], set: { answer: '{answer}' } })`.
39
+ * With `bulk` and no `inputs`, the list offers it for the selected rows too, and updates each it applies to.
28
40
  */
29
41
  update: (name: string, o: ActionOptions & InputsOption & {
30
42
  set: Record<string, unknown>;
43
+ bulk?: boolean;
31
44
  }) => ActionModel;
32
45
  /** Deletes the record (soft delete when the resource has one). */
33
46
  remove: (name: string, o: ActionOptions) => ActionModel;
@@ -43,6 +56,11 @@ export declare const actions: {
43
56
  } | {
44
57
  href: string;
45
58
  })) => ActionModel;
59
+ /**
60
+ * Has the model write the `writes` field of the record from `prompt`, `{field}` replaced by the record's values, as the
61
+ * user who clicks; see [AI fields and actions](website/src/content/docs/reference/ai.mdx). The prompt may name the
62
+ * field it writes, to rewrite or translate it in place.
63
+ */
46
64
  ai: (name: string, o: ActionOptions & {
47
65
  prompt: string;
48
66
  writes: string;
@@ -3,13 +3,30 @@ import { promptError } from "./ai-prompt.js";
3
3
  import { actionInputErrors, inputs } from "./action-inputs.js";
4
4
  import { updateSetErrors } from "./update-set.js";
5
5
  //#region src/view-actions.ts
6
- const named = (name, o) => ({
7
- name,
8
- label: o.label,
9
- bulk: o.bulk ?? false,
10
- ...o.icon !== void 0 && { icon: o.icon },
11
- ...o.confirm !== void 0 && { confirm: o.confirm }
12
- });
6
+ /** What is wrong with an action's `when`, `otherwise` and `reason`: a fallback needs a condition, and a disabled button says why. */
7
+ const actionConditionError = (o) => {
8
+ if (o.when === void 0) return o.otherwise !== void 0 || o.reason !== void 0 ? "\"otherwise\" and \"reason\" need a \"when\" condition" : void 0;
9
+ if (o.when.trim() === "") return "\"when\" is empty";
10
+ if (o.otherwise === "disable") return o.reason ? void 0 : "a button disabled by \"when\" needs a \"reason\"";
11
+ return o.reason === void 0 ? void 0 : "\"reason\" shows only with otherwise: 'disable'";
12
+ };
13
+ const named = (name, o) => {
14
+ const error = actionConditionError(o);
15
+ if (error) throw new Error(`Action "${name}": ${error}`);
16
+ return {
17
+ name,
18
+ label: o.label,
19
+ bulk: o.bulk ?? false,
20
+ ...o.icon !== void 0 && { icon: o.icon },
21
+ ...o.confirm !== void 0 && { confirm: o.confirm },
22
+ ...o.when !== void 0 && { when: o.when },
23
+ ...o.otherwise === "disable" && {
24
+ otherwise: o.otherwise,
25
+ reason: o.reason
26
+ },
27
+ ...o.variant !== void 0 && { variant: o.variant }
28
+ };
29
+ };
13
30
  const builtInputs = (name, option) => {
14
31
  if (!option) return {};
15
32
  const built = option(inputs);
@@ -21,7 +38,7 @@ const actions = {
21
38
  /**
22
39
  * An action the app implements: it runs the handler registered under `name`. With `inputs`, such as
23
40
  * `(i) => [i.text('reason', { label: 'Reason' })]`, the button first asks for them in a dialog, and the handler gets the
24
- * answers as `values`.
41
+ * answers as `values`. With `bulk` and no `inputs`, the list offers it for the selected rows too, and runs the handler on each it applies to.
25
42
  */
26
43
  action: (name, o) => ({
27
44
  ...named(name, o),
@@ -32,6 +49,7 @@ const actions = {
32
49
  * record that holds these values already. With `inputs`, the button first asks for them in a dialog, and a `set` value
33
50
  * that is exactly `'{name}'` is written as that input's answer, with no handler code:
34
51
  * `a.update('answer', { label: 'Answer', inputs: (i) => [i.text('answer', { label: 'Answer', multiline: true })], set: { answer: '{answer}' } })`.
52
+ * With `bulk` and no `inputs`, the list offers it for the selected rows too, and updates each it applies to.
35
53
  */
36
54
  update: (name, o) => {
37
55
  const built = builtInputs(name, o.inputs);
@@ -76,6 +94,11 @@ const actions = {
76
94
  }
77
95
  };
78
96
  },
97
+ /**
98
+ * Has the model write the `writes` field of the record from `prompt`, `{field}` replaced by the record's values, as the
99
+ * user who clicks; see [AI fields and actions](website/src/content/docs/reference/ai.mdx). The prompt may name the
100
+ * field it writes, to rewrite or translate it in place.
101
+ */
79
102
  ai: (name, o) => {
80
103
  const error = promptError(o.prompt) ?? (o.writes === "" ? "it writes no field" : void 0);
81
104
  if (error) throw new Error(`Action "${name}": ${error}`);
@@ -90,4 +113,4 @@ const actions = {
90
113
  }
91
114
  };
92
115
  //#endregion
93
- export { actions };
116
+ export { actionConditionError, actions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/schema",
3
- "version": "0.26.6",
3
+ "version": "0.26.8",
4
4
  "description": "Resource, field, view and access definitions for Protobase configs.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {