@fieldia/core 0.11.0 → 0.13.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.
Files changed (203) hide show
  1. package/README.md +5 -0
  2. package/package.json +1 -1
  3. package/schema/page.schema.json +3998 -893
  4. package/src/index.d.mts +1 -1
  5. package/src/index.d.ts +1 -1
  6. package/src/index.js +4 -1
  7. package/src/index.js.map +1 -1
  8. package/src/index.mjs +1 -1
  9. package/src/index.mjs.map +1 -1
  10. package/src/lib/expression/built-ins.d.mts +4 -0
  11. package/src/lib/expression/built-ins.d.ts +4 -0
  12. package/src/lib/expression/built-ins.js +8 -0
  13. package/src/lib/expression/built-ins.js.map +1 -0
  14. package/src/lib/expression/built-ins.mjs +5 -0
  15. package/src/lib/expression/built-ins.mjs.map +1 -0
  16. package/src/lib/expression/evaluator.js +17 -7
  17. package/src/lib/expression/evaluator.js.map +1 -1
  18. package/src/lib/expression/evaluator.mjs +17 -7
  19. package/src/lib/expression/evaluator.mjs.map +1 -1
  20. package/src/lib/expression/expression.d.mts +7 -0
  21. package/src/lib/expression/expression.d.ts +7 -0
  22. package/src/lib/expression/expression.js +2 -0
  23. package/src/lib/expression/expression.js.map +1 -1
  24. package/src/lib/expression/expression.mjs +3 -1
  25. package/src/lib/expression/expression.mjs.map +1 -1
  26. package/src/lib/expression/functions.d.mts +2 -0
  27. package/src/lib/expression/functions.d.ts +2 -0
  28. package/src/lib/expression/functions.js +38 -5
  29. package/src/lib/expression/functions.js.map +1 -1
  30. package/src/lib/expression/functions.mjs +38 -5
  31. package/src/lib/expression/functions.mjs.map +1 -1
  32. package/src/lib/expression/modifier.d.mts +7 -0
  33. package/src/lib/expression/modifier.d.ts +7 -0
  34. package/src/lib/expression/modifier.js +3 -1
  35. package/src/lib/expression/modifier.js.map +1 -1
  36. package/src/lib/expression/modifier.mjs +4 -2
  37. package/src/lib/expression/modifier.mjs.map +1 -1
  38. package/src/lib/expression/parser.d.mts +8 -1
  39. package/src/lib/expression/parser.d.ts +8 -1
  40. package/src/lib/expression/parser.js +30 -2
  41. package/src/lib/expression/parser.js.map +1 -1
  42. package/src/lib/expression/parser.mjs +30 -2
  43. package/src/lib/expression/parser.mjs.map +1 -1
  44. package/src/lib/expression/reads.d.mts +7 -0
  45. package/src/lib/expression/reads.d.ts +7 -0
  46. package/src/lib/expression/reads.js +23 -0
  47. package/src/lib/expression/reads.js.map +1 -1
  48. package/src/lib/expression/reads.mjs +21 -0
  49. package/src/lib/expression/reads.mjs.map +1 -1
  50. package/src/lib/format/actions.d.mts +486 -2
  51. package/src/lib/format/actions.d.ts +486 -2
  52. package/src/lib/format/actions.js +9 -0
  53. package/src/lib/format/actions.js.map +1 -1
  54. package/src/lib/format/actions.mjs +9 -0
  55. package/src/lib/format/actions.mjs.map +1 -1
  56. package/src/lib/format/check-page.d.mts +7 -2
  57. package/src/lib/format/check-page.d.ts +7 -2
  58. package/src/lib/format/check-page.js +6 -3
  59. package/src/lib/format/check-page.js.map +1 -1
  60. package/src/lib/format/check-page.mjs +6 -3
  61. package/src/lib/format/check-page.mjs.map +1 -1
  62. package/src/lib/format/field.d.mts +3285 -214
  63. package/src/lib/format/field.d.ts +3285 -214
  64. package/src/lib/format/field.js +101 -14
  65. package/src/lib/format/field.js.map +1 -1
  66. package/src/lib/format/field.mjs +100 -13
  67. package/src/lib/format/field.mjs.map +1 -1
  68. package/src/lib/format/hotkeys.d.mts +6 -0
  69. package/src/lib/format/hotkeys.d.ts +6 -0
  70. package/src/lib/format/hotkeys.js +11 -0
  71. package/src/lib/format/hotkeys.js.map +1 -0
  72. package/src/lib/format/hotkeys.mjs +7 -0
  73. package/src/lib/format/hotkeys.mjs.map +1 -0
  74. package/src/lib/format/layout.d.mts +4185 -352
  75. package/src/lib/format/layout.d.ts +4185 -352
  76. package/src/lib/format/layout.js +131 -20
  77. package/src/lib/format/layout.js.map +1 -1
  78. package/src/lib/format/layout.mjs +130 -19
  79. package/src/lib/format/layout.mjs.map +1 -1
  80. package/src/lib/format/page.d.mts +2938 -196
  81. package/src/lib/format/page.d.ts +2938 -196
  82. package/src/lib/format/page.js +7 -1
  83. package/src/lib/format/page.js.map +1 -1
  84. package/src/lib/format/page.mjs +6 -1
  85. package/src/lib/format/page.mjs.map +1 -1
  86. package/src/lib/format/references.d.mts +35 -2
  87. package/src/lib/format/references.d.ts +35 -2
  88. package/src/lib/format/references.js +321 -43
  89. package/src/lib/format/references.js.map +1 -1
  90. package/src/lib/format/references.mjs +321 -43
  91. package/src/lib/format/references.mjs.map +1 -1
  92. package/src/lib/format/themes.d.mts +9 -0
  93. package/src/lib/format/themes.d.ts +9 -0
  94. package/src/lib/format/themes.js +13 -0
  95. package/src/lib/format/themes.js.map +1 -0
  96. package/src/lib/format/themes.mjs +10 -0
  97. package/src/lib/format/themes.mjs.map +1 -0
  98. package/src/lib/format/translate.js +5 -3
  99. package/src/lib/format/translate.js.map +1 -1
  100. package/src/lib/format/translate.mjs +5 -3
  101. package/src/lib/format/translate.mjs.map +1 -1
  102. package/src/lib/format/words.d.mts +9 -0
  103. package/src/lib/format/words.d.ts +9 -0
  104. package/src/lib/format/words.js +35 -0
  105. package/src/lib/format/words.js.map +1 -0
  106. package/src/lib/format/words.mjs +30 -0
  107. package/src/lib/format/words.mjs.map +1 -0
  108. package/src/lib/record/cells.d.mts +37 -0
  109. package/src/lib/record/cells.d.ts +37 -0
  110. package/src/lib/record/cells.js +59 -0
  111. package/src/lib/record/cells.js.map +1 -0
  112. package/src/lib/record/cells.mjs +54 -0
  113. package/src/lib/record/cells.mjs.map +1 -0
  114. package/src/lib/record/compute.d.mts +5 -4
  115. package/src/lib/record/compute.d.ts +5 -4
  116. package/src/lib/record/compute.js +11 -10
  117. package/src/lib/record/compute.js.map +1 -1
  118. package/src/lib/record/compute.mjs +12 -11
  119. package/src/lib/record/compute.mjs.map +1 -1
  120. package/src/lib/record/data-source.d.mts +32 -2
  121. package/src/lib/record/data-source.d.ts +32 -2
  122. package/src/lib/record/data-source.js.map +1 -1
  123. package/src/lib/record/data-source.mjs.map +1 -1
  124. package/src/lib/record/env.d.mts +38 -1
  125. package/src/lib/record/env.d.ts +38 -1
  126. package/src/lib/record/env.js +41 -3
  127. package/src/lib/record/env.js.map +1 -1
  128. package/src/lib/record/env.mjs +38 -3
  129. package/src/lib/record/env.mjs.map +1 -1
  130. package/src/lib/record/filter.d.mts +10 -0
  131. package/src/lib/record/filter.d.ts +10 -0
  132. package/src/lib/record/filter.js +49 -0
  133. package/src/lib/record/filter.js.map +1 -1
  134. package/src/lib/record/filter.mjs +48 -0
  135. package/src/lib/record/filter.mjs.map +1 -1
  136. package/src/lib/record/form.d.mts +143 -8
  137. package/src/lib/record/form.d.ts +143 -8
  138. package/src/lib/record/form.js +495 -58
  139. package/src/lib/record/form.js.map +1 -1
  140. package/src/lib/record/form.mjs +496 -60
  141. package/src/lib/record/form.mjs.map +1 -1
  142. package/src/lib/record/locales/ar.js +3 -0
  143. package/src/lib/record/locales/ar.js.map +1 -1
  144. package/src/lib/record/locales/ar.mjs +3 -0
  145. package/src/lib/record/locales/ar.mjs.map +1 -1
  146. package/src/lib/record/locales/de.js +3 -0
  147. package/src/lib/record/locales/de.js.map +1 -1
  148. package/src/lib/record/locales/de.mjs +3 -0
  149. package/src/lib/record/locales/de.mjs.map +1 -1
  150. package/src/lib/record/locales/fr.js +3 -0
  151. package/src/lib/record/locales/fr.js.map +1 -1
  152. package/src/lib/record/locales/fr.mjs +3 -0
  153. package/src/lib/record/locales/fr.mjs.map +1 -1
  154. package/src/lib/record/memory-data-source.d.mts +26 -2
  155. package/src/lib/record/memory-data-source.d.ts +26 -2
  156. package/src/lib/record/memory-data-source.js +98 -7
  157. package/src/lib/record/memory-data-source.js.map +1 -1
  158. package/src/lib/record/memory-data-source.mjs +98 -7
  159. package/src/lib/record/memory-data-source.mjs.map +1 -1
  160. package/src/lib/record/messages.d.mts +5 -0
  161. package/src/lib/record/messages.d.ts +5 -0
  162. package/src/lib/record/messages.js +3 -0
  163. package/src/lib/record/messages.js.map +1 -1
  164. package/src/lib/record/messages.mjs +3 -0
  165. package/src/lib/record/messages.mjs.map +1 -1
  166. package/src/lib/record/roles.d.mts +10 -0
  167. package/src/lib/record/roles.d.ts +10 -0
  168. package/src/lib/record/roles.js +21 -0
  169. package/src/lib/record/roles.js.map +1 -0
  170. package/src/lib/record/roles.mjs +18 -0
  171. package/src/lib/record/roles.mjs.map +1 -0
  172. package/src/lib/record/rules.js +30 -0
  173. package/src/lib/record/rules.js.map +1 -1
  174. package/src/lib/record/rules.mjs +31 -1
  175. package/src/lib/record/rules.mjs.map +1 -1
  176. package/src/lib/record/run.d.mts +79 -0
  177. package/src/lib/record/run.d.ts +79 -0
  178. package/src/lib/record/run.js +105 -0
  179. package/src/lib/record/run.js.map +1 -1
  180. package/src/lib/record/run.mjs +105 -0
  181. package/src/lib/record/run.mjs.map +1 -1
  182. package/src/lib/record/set-when.d.mts +5 -2
  183. package/src/lib/record/set-when.d.ts +5 -2
  184. package/src/lib/record/set-when.js +28 -12
  185. package/src/lib/record/set-when.js.map +1 -1
  186. package/src/lib/record/set-when.mjs +30 -14
  187. package/src/lib/record/set-when.mjs.map +1 -1
  188. package/src/lib/record/value-map.d.mts +41 -0
  189. package/src/lib/record/value-map.d.ts +41 -0
  190. package/src/lib/record/value-map.js +80 -0
  191. package/src/lib/record/value-map.js.map +1 -0
  192. package/src/lib/record/value-map.mjs +73 -0
  193. package/src/lib/record/value-map.mjs.map +1 -0
  194. package/src/lib/record/values.d.mts +10 -0
  195. package/src/lib/record/values.d.ts +10 -0
  196. package/src/lib/record/values.js.map +1 -1
  197. package/src/lib/record/values.mjs.map +1 -1
  198. package/src/runtime.d.mts +11 -6
  199. package/src/runtime.d.ts +11 -6
  200. package/src/runtime.js +13 -1
  201. package/src/runtime.js.map +1 -1
  202. package/src/runtime.mjs +4 -0
  203. package/src/runtime.mjs.map +1 -1
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.matchesFilter = matchesFilter;
4
+ exports.resolveFilter = resolveFilter;
4
5
  /**
5
6
  * Whether a record passes a filter, the way a search should judge it: every
6
7
  * item of the list holds, an `any` group when one of its items holds, an `all`
@@ -20,6 +21,12 @@ function holds(values, item) {
20
21
  function isSet(value) {
21
22
  return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);
22
23
  }
24
+ /** The ids a list of links holds: records by their id, ids as they are. */
25
+ function idsIn(value) {
26
+ if (!Array.isArray(value))
27
+ return [];
28
+ return value.map((item) => (item !== null && typeof item === 'object' && 'id' in item ? item.id : item));
29
+ }
23
30
  function meets(values, condition) {
24
31
  const raw = values[condition.field];
25
32
  // A link compares by its id.
@@ -30,6 +37,15 @@ function meets(values, condition) {
30
37
  switch (condition.op) {
31
38
  case '=':
32
39
  return actual === expected;
40
+ case '=?':
41
+ return !isSet(expected) || actual === expected;
42
+ case 'contains':
43
+ case 'not contains': {
44
+ const held = idsIn(raw);
45
+ const wanted = Array.isArray(expected) ? expected : [expected];
46
+ const found = wanted.some((value) => held.includes(value));
47
+ return condition.op === 'contains' ? found : !found;
48
+ }
33
49
  case '!=':
34
50
  return actual !== expected;
35
51
  case '<':
@@ -64,4 +80,37 @@ function meets(values, condition) {
64
80
  }
65
81
  }
66
82
  }
83
+ /** What a condition left out stands for: it always holds. */
84
+ const ALWAYS = null;
85
+ /**
86
+ * A filter as a search or a list receives it: each `valueFrom` — a field, or a
87
+ * path such as `parent.company_id` or `user.id` — replaced by its value in
88
+ * `context`. A `=?` whose value is empty is left out, and so is a group it
89
+ * makes always hold: an `any` group with one item always holding, an `all`
90
+ * group left with none. A `=?` with a value goes as `=`, so a data source
91
+ * never sees `=?`.
92
+ */
93
+ function resolveFilter(items, context) {
94
+ const resolve = (item) => {
95
+ if ('any' in item) {
96
+ const inner = item.any.map(resolve);
97
+ return inner.includes(ALWAYS) ? ALWAYS : { any: inner };
98
+ }
99
+ if ('all' in item) {
100
+ const inner = item.all.map(resolve).filter((r) => r !== ALWAYS);
101
+ return inner.length ? { all: inner } : ALWAYS;
102
+ }
103
+ const value = (item.valueFrom !== undefined ? valueAt(context, item.valueFrom) : (item.value ?? null));
104
+ if (item.op === '=?')
105
+ return isSet(value) ? { field: item.field, op: '=', value } : ALWAYS;
106
+ return { field: item.field, op: item.op, value };
107
+ };
108
+ return items.map(resolve).filter((r) => r !== ALWAYS);
109
+ }
110
+ function valueAt(context, path) {
111
+ let at = context;
112
+ for (const part of path.split('.'))
113
+ at = at === null || typeof at !== 'object' ? undefined : at[part];
114
+ return at ?? null;
115
+ }
67
116
  //# sourceMappingURL=filter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/record/filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/record/filter.ts"],"names":[],"mappings":";;AAUA,sCAEC;AAmFD,sCAeC;AAzGD;;;;GAIG;AACH,SAAgB,aAAa,CAAC,MAAc,EAAE,MAAiC;IAC7E,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,KAAK,CAAC,MAAc,EAAE,IAAoB;IACjD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACzE,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC1E,OAAO,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,6DAA6D;AAC7D,SAAS,KAAK,CAAC,KAAc;IAC3B,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AAC9H,CAAC;AAED,2EAA2E;AAC3E,SAAS,KAAK,CAAC,KAAc;IAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAE,IAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9H,CAAC;AAED,SAAS,KAAK,CAAC,MAAc,EAAE,SAAkC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACpC,6BAA6B;IAC7B,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC,CAAE,GAAqB,CAAC,EAAE,CAAC,CAAC,CAAE,GAA6B,CAAC;IAC1J,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC;IACjC,iEAAiE;IACjE,MAAM,IAAI,GAAG,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAE,GAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC5J,QAAQ,SAAS,CAAC,EAAE,EAAE,CAAC;QACrB,KAAK,GAAG;YACN,OAAO,MAAM,KAAK,QAAQ,CAAC;QAC7B,KAAK,IAAI;YACP,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,MAAM,KAAK,QAAQ,CAAC;QACjD,KAAK,UAAU,CAAC;QAChB,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;YAC3D,OAAO,SAAS,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QACtD,CAAC;QACD,KAAK,IAAI;YACP,OAAO,MAAM,KAAK,QAAQ,CAAC;QAC7B,KAAK,GAAG;YACN,OAAO,KAAK,CAAC,MAAM,CAAC,IAAK,MAAiB,GAAI,QAAmB,CAAC;QACpE,KAAK,GAAG;YACN,OAAO,KAAK,CAAC,MAAM,CAAC,IAAK,MAAiB,GAAI,QAAmB,CAAC;QACpE,KAAK,IAAI;YACP,OAAO,KAAK,CAAC,MAAM,CAAC,IAAK,MAAiB,IAAK,QAAmB,CAAC;QACrE,KAAK,IAAI;YACP,OAAO,KAAK,CAAC,MAAM,CAAC,IAAK,MAAiB,IAAK,QAAmB,CAAC;QACrE,KAAK,IAAI;YACP,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAmB,CAAC,CAAC;QAC3E,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAmB,CAAC,CAAC;QAC5E,KAAK,MAAM;YACT,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACzC,KAAK,OAAO;YACV,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACrE,KAAK,YAAY;YACf,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACvE,KAAK,UAAU;YACb,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;QACrE,KAAK,KAAK;YACR,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;QACpB,KAAK,QAAQ;YACX,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrB,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAAE,OAAO,KAAK,CAAC;YAC7D,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,QAA+B,CAAC;YACpD,OAAQ,MAA0B,IAAI,GAAG,IAAK,MAA0B,IAAI,IAAI,CAAC;QACnF,CAAC;IACH,CAAC;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,MAAM,GAAG,IAAI,CAAC;AAEpB;;;;;;;GAOG;AACH,SAAgB,aAAa,CAAC,KAA4B,EAAE,OAA0C;IACpG,MAAM,OAAO,GAAG,CAAC,IAAgB,EAAkC,EAAE;QACnE,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACpC,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAyB,EAAE,CAAC;QAC9E,CAAC;QACD,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;YACrF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,CAAC;QACD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,CAAc,CAAC;QACpH,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QAC3F,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC;IACnD,CAAC,CAAC;IACF,OAAO,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,OAAO,CAAC,OAA0C,EAAE,IAAY;IACvE,IAAI,EAAE,GAAY,OAAO,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAAE,EAAE,GAAG,EAAE,KAAK,IAAI,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,EAA8B,CAAC,IAAI,CAAC,CAAC;IACnI,OAAO,EAAE,IAAI,IAAI,CAAC;AACpB,CAAC"}
@@ -17,6 +17,12 @@ function holds(values, item) {
17
17
  function isSet(value) {
18
18
  return value !== null && value !== undefined && value !== '' && value !== false && !(Array.isArray(value) && !value.length);
19
19
  }
20
+ /** The ids a list of links holds: records by their id, ids as they are. */
21
+ function idsIn(value) {
22
+ if (!Array.isArray(value))
23
+ return [];
24
+ return value.map((item) => (item !== null && typeof item === 'object' && 'id' in item ? item.id : item));
25
+ }
20
26
  function meets(values, condition) {
21
27
  const raw = values[condition.field];
22
28
  // A link compares by its id.
@@ -27,6 +33,15 @@ function meets(values, condition) {
27
33
  switch (condition.op) {
28
34
  case '=':
29
35
  return actual === expected;
36
+ case '=?':
37
+ return !isSet(expected) || actual === expected;
38
+ case 'contains':
39
+ case 'not contains': {
40
+ const held = idsIn(raw);
41
+ const wanted = Array.isArray(expected) ? expected : [expected];
42
+ const found = wanted.some((value) => held.includes(value));
43
+ return condition.op === 'contains' ? found : !found;
44
+ }
30
45
  case '!=':
31
46
  return actual !== expected;
32
47
  case '<':
@@ -61,4 +76,37 @@ function meets(values, condition) {
61
76
  }
62
77
  }
63
78
  }
79
+ /** What a condition left out stands for: it always holds. */
80
+ const ALWAYS = null;
81
+ /**
82
+ * A filter as a search or a list receives it: each `valueFrom` — a field, or a
83
+ * path such as `parent.company_id` or `user.id` — replaced by its value in
84
+ * `context`. A `=?` whose value is empty is left out, and so is a group it
85
+ * makes always hold: an `any` group with one item always holding, an `all`
86
+ * group left with none. A `=?` with a value goes as `=`, so a data source
87
+ * never sees `=?`.
88
+ */
89
+ export function resolveFilter(items, context) {
90
+ const resolve = (item) => {
91
+ if ('any' in item) {
92
+ const inner = item.any.map(resolve);
93
+ return inner.includes(ALWAYS) ? ALWAYS : { any: inner };
94
+ }
95
+ if ('all' in item) {
96
+ const inner = item.all.map(resolve).filter((r) => r !== ALWAYS);
97
+ return inner.length ? { all: inner } : ALWAYS;
98
+ }
99
+ const value = (item.valueFrom !== undefined ? valueAt(context, item.valueFrom) : (item.value ?? null));
100
+ if (item.op === '=?')
101
+ return isSet(value) ? { field: item.field, op: '=', value } : ALWAYS;
102
+ return { field: item.field, op: item.op, value };
103
+ };
104
+ return items.map(resolve).filter((r) => r !== ALWAYS);
105
+ }
106
+ function valueAt(context, path) {
107
+ let at = context;
108
+ for (const part of path.split('.'))
109
+ at = at === null || typeof at !== 'object' ? undefined : at[part];
110
+ return at ?? null;
111
+ }
64
112
  //# sourceMappingURL=filter.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"filter.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/record/filter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"filter.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/record/filter.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,12 @@
1
1
  import type { ActionStep } from '../format/actions.mjs';
2
- import type { Option } from '../format/field.mjs';
2
+ import type { Field, LineField, Option, PropertyDefinition } from '../format/field.mjs';
3
3
  import type { Page } from '../format/page.mjs';
4
+ import type { JsonValue } from '../format/json.mjs';
5
+ import { type FieldTone, type LineState } from './cells.mjs';
4
6
  import { type Messages } from './messages.mjs';
5
7
  import { type DataSource, type RecordChanges, type SaveProblem } from './data-source.mjs';
6
8
  import { type Scheduler } from './scheduler.mjs';
7
- import { type ActionHost, type ActionRequest, type ActionResult, type OnAction, type RunContext, type RunResult } from './run.mjs';
9
+ import { type ActionHost, type ActionRequest, type ActionResult, type OnAction, type PostedMessage, type RunContext, type RunResult } from './run.mjs';
8
10
  import { type RecordId, type RelatedRecord, type Value, type Values } from './values.mjs';
9
11
  export type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';
10
12
  export interface FormState {
@@ -38,6 +40,16 @@ export interface FormState {
38
40
  readonly saveProblem: SaveProblem | null;
39
41
  /** The choices loaded from the app's lists, by field: those of a selection with `optionsFrom`, once asked for. */
40
42
  readonly choices: Readonly<Record<string, Choices>>;
43
+ /** The definitions loaded for a properties field with `definitionsFrom`, by field, once asked for. */
44
+ readonly definitions: Readonly<Record<string, Definitions>>;
45
+ }
46
+ /** A properties field's definitions from the app, as they load. */
47
+ export interface Definitions {
48
+ /** The definitions last loaded: null until the first load ends well. */
49
+ readonly definitions: PropertyDefinition[] | null;
50
+ readonly loading?: boolean;
51
+ /** Why the last load failed. */
52
+ readonly error?: string;
41
53
  }
42
54
  /** A field's choices from one of the app's lists, as they load. */
43
55
  export interface Choices {
@@ -100,6 +112,28 @@ export interface FormEvents {
100
112
  recordId: RecordId | null;
101
113
  values: Readonly<Values>;
102
114
  };
115
+ /** The record was archived (`archived` true) or brought back, by a step. */
116
+ archive: {
117
+ recordId: RecordId;
118
+ archived: boolean;
119
+ };
120
+ /** The record was copied, by a step: the form shows the copy now. */
121
+ duplicate: {
122
+ from: RecordId;
123
+ recordId: RecordId;
124
+ };
125
+ /**
126
+ * The record was deleted, by a step. A listener may show another record
127
+ * (`openRecord`), as a pager moves on; else the form starts a new one.
128
+ */
129
+ delete: {
130
+ recordId: RecordId;
131
+ };
132
+ /** Words to post in the record's conversation, from a `post` step or the app's answer: the chatter beside it listens. */
133
+ post: {
134
+ recordId: RecordId | null;
135
+ message: PostedMessage;
136
+ };
103
137
  }
104
138
  export interface FormOptions {
105
139
  page: Page;
@@ -132,6 +166,40 @@ export interface FormOptions {
132
166
  messages?: Messages;
133
167
  /** The clock, for `today()` and for dates that must be past or future. The computer's own when left out. */
134
168
  now?: () => Date;
169
+ /**
170
+ * The person using the form: conditions read it as `user` (`user.id`,
171
+ * `user.name`, `user.roles`), and a part with `roles` shows only to people
172
+ * in them. Left out, the person has no id and no roles.
173
+ */
174
+ user?: FormUser;
175
+ /** Whether the record starts being edited, as conditions read `editing`; true unless said. A view locking it says so with `setEditing`. */
176
+ editing?: boolean;
177
+ /**
178
+ * Values the app passes in, as Flectra's context: read by conditions and
179
+ * expressions as `context.name`, and by a filter's `valueFrom:
180
+ * "context.name"` — a transfer opened from Receipts restricting its
181
+ * operation types. They are the app's, never the page's: nothing saves
182
+ * them, and a page's field of that name comes first.
183
+ */
184
+ context?: Readonly<Record<string, JsonValue>>;
185
+ /**
186
+ * The record this form's values are a line of, when the form edits one
187
+ * table's line in a form of its own (a node's `lineForm`): its values and
188
+ * fields, read by conditions and filters as `parent`, as a line's are —
189
+ * `parent.state`, a filter's `valueFrom: "parent.company_id"`.
190
+ */
191
+ parent?: {
192
+ values: Readonly<Values>;
193
+ fields: Readonly<Record<string, Field | LineField>>;
194
+ id?: RecordId | null;
195
+ };
196
+ }
197
+ /** The person using a form, as the app knows them. */
198
+ export interface FormUser {
199
+ id: RecordId | null;
200
+ name?: string;
201
+ /** The roles they hold, by the names the page's `roles` use: Flectra's groups, such as `sales_team.group_sale_manager`. */
202
+ roles?: readonly string[];
135
203
  }
136
204
  export interface Form {
137
205
  readonly page: Page;
@@ -145,6 +213,8 @@ export interface Form {
145
213
  /** Write several fields at once, worked out once: the app's change, never a person's. Throws for a field the page lacks. */
146
214
  setValues(values: Values): void;
147
215
  node(id: string): NodeState;
216
+ /** Whether the record is being edited, as conditions read `editing`: a view that locks it to be read says false, and parts follow. */
217
+ setEditing(editing: boolean): void;
148
218
  fieldReadonly(name: string): boolean;
149
219
  /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */
150
220
  problem(field: string): string | null;
@@ -163,25 +233,68 @@ export interface Form {
163
233
  * written: the record, its changes and its autosave stay as they are.
164
234
  */
165
235
  previewLine(field: string, key: string, values: Values): Promise<Values>;
236
+ /**
237
+ * Show another record of the page's model in this form, loaded from the
238
+ * data source as a pager moves to it, or a new one for null. Changes not
239
+ * saved are dropped: save first. The page's `open` steps run for it.
240
+ */
241
+ openRecord(id: RecordId | null): Promise<void>;
242
+ /**
243
+ * Post words in the record's conversation, as a `post` step does: through
244
+ * the form's host when it has a way to, else told to the form's own
245
+ * listeners (`post`). False when nothing heard them.
246
+ */
247
+ post(message: PostedMessage): Promise<boolean>;
166
248
  /**
167
249
  * Load, or load again, the choices of a selection whose options come from
168
250
  * the app's list (`optionsFrom`). Once loaded, they load again by themselves
169
251
  * when a field they change with changes; the latest answer wins.
170
252
  */
171
253
  loadChoices(field: string): void;
172
- /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */
254
+ /**
255
+ * Load, or load again, the definitions of a properties field whose
256
+ * definitions come from a linked record (`definitionsFrom`). Once loaded,
257
+ * they load again by themselves when a field they change with changes.
258
+ */
259
+ loadDefinitions(field: string): void;
260
+ /** A property added in place to such a field: kept in its definitions, and handed to the data source's `saveDefinitions`. */
261
+ addDefinition(field: string, definition: PropertyDefinition): Promise<void>;
262
+ /**
263
+ * Records a many2one, many2many or reference may point to. A reference needs
264
+ * `options.model`, and so does structured data naming records of a model (a
265
+ * json field, such as an analytic distribution's accounts); `options.ids`
266
+ * finds those records alone, for their names.
267
+ */
173
268
  search(field: string, query: string, limit?: number, options?: {
174
269
  model?: string;
270
+ ids?: RecordId[];
175
271
  }): Promise<RelatedRecord[]>;
176
- /** The same, for a relation inside a one2many line, filtered by that line's values. */
177
- searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;
272
+ /** The same, for a relation inside a one2many line, filtered by that line's values — or structured data of a line naming records of a model (`options.model`). */
273
+ searchLine(field: string, key: string, subfield: string, query: string, limit?: number, options?: {
274
+ model?: string;
275
+ ids?: RecordId[];
276
+ }): Promise<RelatedRecord[]>;
277
+ /**
278
+ * The values of records a many2many links to, for a table of them: `fields`
279
+ * of the records with these ids, in the order asked, read with the data
280
+ * source's `list`. None without one.
281
+ */
282
+ linkedValues(field: string, ids: readonly RecordId[], fields: readonly string[]): Promise<{
283
+ id: RecordId;
284
+ values: Values;
285
+ }[]>;
178
286
  /** Whether a link field can make a record from a typed name: the data source must be able to. */
179
287
  canCreate(field: string): boolean;
180
- /** Make a record from a typed name, for the link field to point to. */
288
+ /** Make a record from a typed name, for the link field to point to, with what its `createValues` hand on. */
181
289
  quickCreate(field: string, name: string): Promise<RelatedRecord>;
182
- /** The same, for a link inside a one2many's lines. */
290
+ /** The same, for a link inside a one2many's lines; with the line's key, its `createValues` are read on that line. */
183
291
  canCreateLine(field: string, subfield: string): boolean;
184
- quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;
292
+ quickCreateLine(field: string, subfield: string, name: string, key?: string): Promise<RelatedRecord>;
293
+ /** What a record made from a link starts with besides its name: its `createValues`, read now — on a line, on that line. */
294
+ createValues(field: string, line?: {
295
+ lines: string;
296
+ key: string;
297
+ }): Values;
185
298
  steps(): string[];
186
299
  next(): boolean;
187
300
  back(): boolean;
@@ -201,6 +314,26 @@ export interface Form {
201
314
  runAction(id: string, chosen?: {
202
315
  recordIds: RecordId[];
203
316
  }): Promise<RunResult>;
317
+ /** A field's own value as its tones have it now: its tone and whether it is bold, read on the record. */
318
+ fieldTone(nodeId: string): FieldTone;
319
+ /** A table's line as its rules have it now — its tone, each ruled column's cells, which of its buttons show — by the table's field node. */
320
+ lineState(nodeId: string, key: string): LineState;
321
+ /** Whether a table's column is hidden now by its `hidden` rule, read on the record. */
322
+ columnHidden(nodeId: string, column: string): boolean;
323
+ /**
324
+ * The words a field's empty box shows now, by its node (`#title` for a
325
+ * sheet's title): its first `placeholderWhen` that holds, else its
326
+ * `placeholder`; undefined when it has neither.
327
+ */
328
+ placeholder(nodeId: string): string | undefined;
329
+ /** Press a button on a table's line: its confirmation, its steps, then its action, each call carrying the line. Hidden on that line, it does not run. */
330
+ runRowAction(nodeId: string, buttonId: string, key: string): Promise<RunResult>;
331
+ /**
332
+ * Press a button for the lines chosen in a table (its `selectedButtons`),
333
+ * by their keys: its confirmation, its steps, then its action, each call
334
+ * carrying the lines. Hidden, or with no line chosen, it does not run.
335
+ */
336
+ runLinesAction(nodeId: string, buttonId: string, keys: readonly string[]): Promise<RunResult>;
204
337
  /** Run steps on this form, as a button would: `context.id` is what their calls carry (`run` when left out). */
205
338
  run(steps: readonly ActionStep[], context?: RunContext): Promise<RunResult>;
206
339
  /** A tab was shown: the viewer says so, and the page's `show` steps for it run. */
@@ -232,3 +365,5 @@ export interface Form {
232
365
  * binding renders from `getState()` and calls these methods.
233
366
  */
234
367
  export declare function createForm(options: FormOptions): Form;
368
+ /** Words held where a number goes ("4.001234567.5"): a box the person typed in and the browser could not read as one. */
369
+ export declare function notANumber(def: Field | undefined, value: unknown): boolean;
@@ -1,10 +1,12 @@
1
1
  import type { ActionStep } from '../format/actions';
2
- import type { Option } from '../format/field';
2
+ import type { Field, LineField, Option, PropertyDefinition } from '../format/field';
3
3
  import type { Page } from '../format/page';
4
+ import type { JsonValue } from '../format/json';
5
+ import { type FieldTone, type LineState } from './cells';
4
6
  import { type Messages } from './messages';
5
7
  import { type DataSource, type RecordChanges, type SaveProblem } from './data-source';
6
8
  import { type Scheduler } from './scheduler';
7
- import { type ActionHost, type ActionRequest, type ActionResult, type OnAction, type RunContext, type RunResult } from './run';
9
+ import { type ActionHost, type ActionRequest, type ActionResult, type OnAction, type PostedMessage, type RunContext, type RunResult } from './run';
8
10
  import { type RecordId, type RelatedRecord, type Value, type Values } from './values';
9
11
  export type FormStatus = 'idle' | 'loading' | 'ready' | 'saving' | 'saved' | 'error';
10
12
  export interface FormState {
@@ -38,6 +40,16 @@ export interface FormState {
38
40
  readonly saveProblem: SaveProblem | null;
39
41
  /** The choices loaded from the app's lists, by field: those of a selection with `optionsFrom`, once asked for. */
40
42
  readonly choices: Readonly<Record<string, Choices>>;
43
+ /** The definitions loaded for a properties field with `definitionsFrom`, by field, once asked for. */
44
+ readonly definitions: Readonly<Record<string, Definitions>>;
45
+ }
46
+ /** A properties field's definitions from the app, as they load. */
47
+ export interface Definitions {
48
+ /** The definitions last loaded: null until the first load ends well. */
49
+ readonly definitions: PropertyDefinition[] | null;
50
+ readonly loading?: boolean;
51
+ /** Why the last load failed. */
52
+ readonly error?: string;
41
53
  }
42
54
  /** A field's choices from one of the app's lists, as they load. */
43
55
  export interface Choices {
@@ -100,6 +112,28 @@ export interface FormEvents {
100
112
  recordId: RecordId | null;
101
113
  values: Readonly<Values>;
102
114
  };
115
+ /** The record was archived (`archived` true) or brought back, by a step. */
116
+ archive: {
117
+ recordId: RecordId;
118
+ archived: boolean;
119
+ };
120
+ /** The record was copied, by a step: the form shows the copy now. */
121
+ duplicate: {
122
+ from: RecordId;
123
+ recordId: RecordId;
124
+ };
125
+ /**
126
+ * The record was deleted, by a step. A listener may show another record
127
+ * (`openRecord`), as a pager moves on; else the form starts a new one.
128
+ */
129
+ delete: {
130
+ recordId: RecordId;
131
+ };
132
+ /** Words to post in the record's conversation, from a `post` step or the app's answer: the chatter beside it listens. */
133
+ post: {
134
+ recordId: RecordId | null;
135
+ message: PostedMessage;
136
+ };
103
137
  }
104
138
  export interface FormOptions {
105
139
  page: Page;
@@ -132,6 +166,40 @@ export interface FormOptions {
132
166
  messages?: Messages;
133
167
  /** The clock, for `today()` and for dates that must be past or future. The computer's own when left out. */
134
168
  now?: () => Date;
169
+ /**
170
+ * The person using the form: conditions read it as `user` (`user.id`,
171
+ * `user.name`, `user.roles`), and a part with `roles` shows only to people
172
+ * in them. Left out, the person has no id and no roles.
173
+ */
174
+ user?: FormUser;
175
+ /** Whether the record starts being edited, as conditions read `editing`; true unless said. A view locking it says so with `setEditing`. */
176
+ editing?: boolean;
177
+ /**
178
+ * Values the app passes in, as Flectra's context: read by conditions and
179
+ * expressions as `context.name`, and by a filter's `valueFrom:
180
+ * "context.name"` — a transfer opened from Receipts restricting its
181
+ * operation types. They are the app's, never the page's: nothing saves
182
+ * them, and a page's field of that name comes first.
183
+ */
184
+ context?: Readonly<Record<string, JsonValue>>;
185
+ /**
186
+ * The record this form's values are a line of, when the form edits one
187
+ * table's line in a form of its own (a node's `lineForm`): its values and
188
+ * fields, read by conditions and filters as `parent`, as a line's are —
189
+ * `parent.state`, a filter's `valueFrom: "parent.company_id"`.
190
+ */
191
+ parent?: {
192
+ values: Readonly<Values>;
193
+ fields: Readonly<Record<string, Field | LineField>>;
194
+ id?: RecordId | null;
195
+ };
196
+ }
197
+ /** The person using a form, as the app knows them. */
198
+ export interface FormUser {
199
+ id: RecordId | null;
200
+ name?: string;
201
+ /** The roles they hold, by the names the page's `roles` use: Flectra's groups, such as `sales_team.group_sale_manager`. */
202
+ roles?: readonly string[];
135
203
  }
136
204
  export interface Form {
137
205
  readonly page: Page;
@@ -145,6 +213,8 @@ export interface Form {
145
213
  /** Write several fields at once, worked out once: the app's change, never a person's. Throws for a field the page lacks. */
146
214
  setValues(values: Values): void;
147
215
  node(id: string): NodeState;
216
+ /** Whether the record is being edited, as conditions read `editing`: a view that locks it to be read says false, and parts follow. */
217
+ setEditing(editing: boolean): void;
148
218
  fieldReadonly(name: string): boolean;
149
219
  /** What a field would be told if the form were checked now, or null when it passes. Nothing is shown. */
150
220
  problem(field: string): string | null;
@@ -163,25 +233,68 @@ export interface Form {
163
233
  * written: the record, its changes and its autosave stay as they are.
164
234
  */
165
235
  previewLine(field: string, key: string, values: Values): Promise<Values>;
236
+ /**
237
+ * Show another record of the page's model in this form, loaded from the
238
+ * data source as a pager moves to it, or a new one for null. Changes not
239
+ * saved are dropped: save first. The page's `open` steps run for it.
240
+ */
241
+ openRecord(id: RecordId | null): Promise<void>;
242
+ /**
243
+ * Post words in the record's conversation, as a `post` step does: through
244
+ * the form's host when it has a way to, else told to the form's own
245
+ * listeners (`post`). False when nothing heard them.
246
+ */
247
+ post(message: PostedMessage): Promise<boolean>;
166
248
  /**
167
249
  * Load, or load again, the choices of a selection whose options come from
168
250
  * the app's list (`optionsFrom`). Once loaded, they load again by themselves
169
251
  * when a field they change with changes; the latest answer wins.
170
252
  */
171
253
  loadChoices(field: string): void;
172
- /** Records a many2one, many2many or reference may point to. A reference needs `options.model`. */
254
+ /**
255
+ * Load, or load again, the definitions of a properties field whose
256
+ * definitions come from a linked record (`definitionsFrom`). Once loaded,
257
+ * they load again by themselves when a field they change with changes.
258
+ */
259
+ loadDefinitions(field: string): void;
260
+ /** A property added in place to such a field: kept in its definitions, and handed to the data source's `saveDefinitions`. */
261
+ addDefinition(field: string, definition: PropertyDefinition): Promise<void>;
262
+ /**
263
+ * Records a many2one, many2many or reference may point to. A reference needs
264
+ * `options.model`, and so does structured data naming records of a model (a
265
+ * json field, such as an analytic distribution's accounts); `options.ids`
266
+ * finds those records alone, for their names.
267
+ */
173
268
  search(field: string, query: string, limit?: number, options?: {
174
269
  model?: string;
270
+ ids?: RecordId[];
175
271
  }): Promise<RelatedRecord[]>;
176
- /** The same, for a relation inside a one2many line, filtered by that line's values. */
177
- searchLine(field: string, key: string, subfield: string, query: string, limit?: number): Promise<RelatedRecord[]>;
272
+ /** The same, for a relation inside a one2many line, filtered by that line's values — or structured data of a line naming records of a model (`options.model`). */
273
+ searchLine(field: string, key: string, subfield: string, query: string, limit?: number, options?: {
274
+ model?: string;
275
+ ids?: RecordId[];
276
+ }): Promise<RelatedRecord[]>;
277
+ /**
278
+ * The values of records a many2many links to, for a table of them: `fields`
279
+ * of the records with these ids, in the order asked, read with the data
280
+ * source's `list`. None without one.
281
+ */
282
+ linkedValues(field: string, ids: readonly RecordId[], fields: readonly string[]): Promise<{
283
+ id: RecordId;
284
+ values: Values;
285
+ }[]>;
178
286
  /** Whether a link field can make a record from a typed name: the data source must be able to. */
179
287
  canCreate(field: string): boolean;
180
- /** Make a record from a typed name, for the link field to point to. */
288
+ /** Make a record from a typed name, for the link field to point to, with what its `createValues` hand on. */
181
289
  quickCreate(field: string, name: string): Promise<RelatedRecord>;
182
- /** The same, for a link inside a one2many's lines. */
290
+ /** The same, for a link inside a one2many's lines; with the line's key, its `createValues` are read on that line. */
183
291
  canCreateLine(field: string, subfield: string): boolean;
184
- quickCreateLine(field: string, subfield: string, name: string): Promise<RelatedRecord>;
292
+ quickCreateLine(field: string, subfield: string, name: string, key?: string): Promise<RelatedRecord>;
293
+ /** What a record made from a link starts with besides its name: its `createValues`, read now — on a line, on that line. */
294
+ createValues(field: string, line?: {
295
+ lines: string;
296
+ key: string;
297
+ }): Values;
185
298
  steps(): string[];
186
299
  next(): boolean;
187
300
  back(): boolean;
@@ -201,6 +314,26 @@ export interface Form {
201
314
  runAction(id: string, chosen?: {
202
315
  recordIds: RecordId[];
203
316
  }): Promise<RunResult>;
317
+ /** A field's own value as its tones have it now: its tone and whether it is bold, read on the record. */
318
+ fieldTone(nodeId: string): FieldTone;
319
+ /** A table's line as its rules have it now — its tone, each ruled column's cells, which of its buttons show — by the table's field node. */
320
+ lineState(nodeId: string, key: string): LineState;
321
+ /** Whether a table's column is hidden now by its `hidden` rule, read on the record. */
322
+ columnHidden(nodeId: string, column: string): boolean;
323
+ /**
324
+ * The words a field's empty box shows now, by its node (`#title` for a
325
+ * sheet's title): its first `placeholderWhen` that holds, else its
326
+ * `placeholder`; undefined when it has neither.
327
+ */
328
+ placeholder(nodeId: string): string | undefined;
329
+ /** Press a button on a table's line: its confirmation, its steps, then its action, each call carrying the line. Hidden on that line, it does not run. */
330
+ runRowAction(nodeId: string, buttonId: string, key: string): Promise<RunResult>;
331
+ /**
332
+ * Press a button for the lines chosen in a table (its `selectedButtons`),
333
+ * by their keys: its confirmation, its steps, then its action, each call
334
+ * carrying the lines. Hidden, or with no line chosen, it does not run.
335
+ */
336
+ runLinesAction(nodeId: string, buttonId: string, keys: readonly string[]): Promise<RunResult>;
204
337
  /** Run steps on this form, as a button would: `context.id` is what their calls carry (`run` when left out). */
205
338
  run(steps: readonly ActionStep[], context?: RunContext): Promise<RunResult>;
206
339
  /** A tab was shown: the viewer says so, and the page's `show` steps for it run. */
@@ -232,3 +365,5 @@ export interface Form {
232
365
  * binding renders from `getState()` and calls these methods.
233
366
  */
234
367
  export declare function createForm(options: FormOptions): Form;
368
+ /** Words held where a number goes ("4.001234567.5"): a box the person typed in and the browser could not read as one. */
369
+ export declare function notANumber(def: Field | undefined, value: unknown): boolean;