ballerina-core 1.0.147 → 1.0.149

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/main.ts CHANGED
@@ -211,6 +211,7 @@ export * from "./src/forms/domains/dispatched-forms/runner/domains/abstract-rend
211
211
  export * from "./src/forms/domains/dispatched-forms/built-ins/state";
212
212
  export * from "./src/forms/domains/dispatched-forms/runner/domains/dispatcher/state";
213
213
  export * from "./src/forms/domains/dispatched-forms/runner/domains/abstract-renderers/injectables/state";
214
+ export * from "./src/forms/domains/dispatched-forms/runner/domains/traversal/state";
214
215
  // import { simpleUpdater, simpleUpdaterWithChildren } from "./src/fun/domains/updater/domains/simpleUpdater/state"
215
216
  // import { Updater } from "./src/fun/domains/updater/state"
216
217
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "ballerina-core",
3
3
  "author": "Dr. Giuseppe Maggiore",
4
4
  "private": false,
5
- "version": "1.0.147",
5
+ "version": "1.0.149",
6
6
  "main": "main.ts",
7
7
  "scripts": {
8
8
  "prettier": "prettier --write ."
@@ -73,7 +73,7 @@ const intialiseTable = Co.GetState().then((current) => {
73
73
  );
74
74
  });
75
75
 
76
- export const TableRunner = Co.Template<Unit>(intialiseTable, {
76
+ export const TableRunner = Co.Template<any>(intialiseTable, {
77
77
  interval: 15,
78
78
  runFilter: (props) => {
79
79
  return !props.context.customFormState.isInitialized;
@@ -21,6 +21,7 @@ import {
21
21
  DispatchTableApiSource,
22
22
  DispatchOnChange,
23
23
  DomNodeIdReadonlyContext,
24
+ DispatchParsedType,
24
25
  } from "../../../../../../../../main";
25
26
  import { Debounced } from "../../../../../../../debounced/state";
26
27
  import { BasicFun } from "../../../../../../../fun/state";
@@ -32,7 +33,7 @@ import { ValueInfiniteStreamState } from "../../../../../../../value-infinite-da
32
33
  export type AbstractTableRendererReadonlyContext = {
33
34
  tableApiSource: DispatchTableApiSource;
34
35
  fromTableApiParser: (value: any) => ValueOrErrors<PredicateValue, string>;
35
- type: ParsedType<any>;
36
+ type: DispatchParsedType<any>;
36
37
  bindings: Bindings;
37
38
  value: ValueTable;
38
39
  identifiers: { withLauncher: string; withoutLauncher: string };
@@ -157,6 +158,10 @@ export type AbstractTableRendererView<
157
158
  selectRow: SimpleCallback<string>;
158
159
  selectAllRows: SimpleCallback<void>;
159
160
  clearRows: SimpleCallback<void>;
161
+ add: SimpleCallback<void>;
162
+ remove: SimpleCallback<string>;
163
+ moveTo: (key: string, to: number) => void;
164
+ duplicate: SimpleCallback<string>;
160
165
  },
161
166
  {
162
167
  TableHeaders: string[];
@@ -21,6 +21,11 @@ import {
21
21
  IdWrapperProps,
22
22
  ErrorRendererProps,
23
23
  getLeafIdentifierFromIdentifier,
24
+ TableType,
25
+ ValueTable,
26
+ Updater,
27
+ OrderedMapRepo,
28
+ unit,
24
29
  } from "../../../../../../../../main";
25
30
  import { Template } from "../../../../../../../template/state";
26
31
  import { ValueInfiniteStreamState } from "../../../../../../../value-infinite-data-stream/state";
@@ -29,9 +34,13 @@ import { TableRunner } from "./coroutines/runner";
29
34
  const EmbeddedValueInfiniteStreamTemplate =
30
35
  ValueInfiniteStreamTemplate.mapContext<
31
36
  AbstractTableRendererReadonlyContext & AbstractTableRendererState
32
- >((_) => _.customFormState.stream).mapState<AbstractTableRendererState>(
33
- AbstractTableRendererState.Updaters.Core.customFormState.children.stream,
34
- );
37
+ >((_) => _.customFormState.stream)
38
+ .mapState<AbstractTableRendererState>(
39
+ AbstractTableRendererState.Updaters.Core.customFormState.children.stream,
40
+ )
41
+ .mapForeignMutationsFromProps<any>((props) => ({
42
+ ...props.foreignMutations,
43
+ }));
35
44
 
36
45
  export const TableAbstractRenderer = <
37
46
  Context extends FormLabel & {
@@ -236,7 +245,9 @@ export const TableAbstractRenderer = <
236
245
  return Template.Default<
237
246
  AbstractTableRendererReadonlyContext & AbstractTableRendererState,
238
247
  AbstractTableRendererState,
239
- any,
248
+ ForeignMutationsExpected & {
249
+ onChange: DispatchOnChange<ValueTable>;
250
+ },
240
251
  any
241
252
  >((props) => {
242
253
  if (!PredicateValue.Operations.IsTable(props.context.value)) {
@@ -400,6 +411,70 @@ export const TableAbstractRenderer = <
400
411
  replaceWith(Set()),
401
412
  ),
402
413
  ),
414
+ add: () => {
415
+ const delta: DispatchDelta = {
416
+ kind: "TableAdd",
417
+ type: (props.context.type as TableType<any>).args[0],
418
+ isWholeEntityMutation: true,
419
+ };
420
+ props.foreignMutations.onChange(id, delta);
421
+ props.setState(
422
+ AbstractTableRendererState.Updaters.Core.commonFormState(
423
+ DispatchCommonFormState.Updaters.modifiedByUser(
424
+ replaceWith(true),
425
+ ),
426
+ ),
427
+ );
428
+ },
429
+ remove: (k: string) => {
430
+ const delta: DispatchDelta = {
431
+ kind: "TableRemove",
432
+ id: k,
433
+ type: (props.context.type as TableType<any>).args[0],
434
+ isWholeEntityMutation: true,
435
+ };
436
+ props.foreignMutations.onChange(id, delta);
437
+ props.setState(
438
+ AbstractTableRendererState.Updaters.Core.commonFormState(
439
+ DispatchCommonFormState.Updaters.modifiedByUser(
440
+ replaceWith(true),
441
+ ),
442
+ ),
443
+ );
444
+ },
445
+ moveTo: (k: string, to: number) => {
446
+ const delta: DispatchDelta = {
447
+ kind: "TableMoveTo",
448
+ id: k,
449
+ to,
450
+ type: (props.context.type as TableType<any>).args[0],
451
+ isWholeEntityMutation: true,
452
+ };
453
+ props.foreignMutations.onChange(id, delta);
454
+ props.setState(
455
+ AbstractTableRendererState.Updaters.Core.commonFormState(
456
+ DispatchCommonFormState.Updaters.modifiedByUser(
457
+ replaceWith(true),
458
+ ),
459
+ ),
460
+ );
461
+ },
462
+ duplicate: (k: string) => {
463
+ const delta: DispatchDelta = {
464
+ kind: "TableDuplicate",
465
+ id: k,
466
+ type: (props.context.type as TableType<any>).args[0],
467
+ isWholeEntityMutation: true,
468
+ };
469
+ props.foreignMutations.onChange(id, delta);
470
+ props.setState(
471
+ AbstractTableRendererState.Updaters.Core.commonFormState(
472
+ DispatchCommonFormState.Updaters.modifiedByUser(
473
+ replaceWith(true),
474
+ ),
475
+ ),
476
+ );
477
+ },
403
478
  }}
404
479
  TableHeaders={visibleColumns.value.columns}
405
480
  EmbeddedTableData={tableData}
@@ -186,12 +186,33 @@ export type DispatchDeltaTuple =
186
186
  item: [number, DispatchDelta];
187
187
  tupleType: DispatchParsedType<any>;
188
188
  };
189
- export type DispatchDeltaTable = {
190
- kind: "TableValue";
191
- id: string;
192
- nestedDelta: DispatchDelta;
193
- tableType: DispatchParsedType<any>;
194
- };
189
+ export type DispatchDeltaTable =
190
+ | {
191
+ kind: "TableValue";
192
+ id: string;
193
+ nestedDelta: DispatchDelta;
194
+ tableType: DispatchParsedType<any>;
195
+ }
196
+ | {
197
+ kind: "TableAdd";
198
+ type: DispatchParsedType<any>;
199
+ }
200
+ | {
201
+ kind: "TableRemove";
202
+ id: string;
203
+ type: DispatchParsedType<any>;
204
+ }
205
+ | {
206
+ kind: "TableMoveTo";
207
+ id: string;
208
+ to: number;
209
+ type: DispatchParsedType<any>;
210
+ }
211
+ | {
212
+ kind: "TableDuplicate";
213
+ id: string;
214
+ type: DispatchParsedType<any>;
215
+ };
195
216
 
196
217
  export type DispatchDeltaCustom = {
197
218
  kind: "CustomDelta";
@@ -291,13 +312,18 @@ export type DispatchDeltaTransferTuple<DispatchDeltaTransferCustom> =
291
312
  | ({ Discriminator: string } & {
292
313
  [item: string]: DispatchDeltaTransfer<DispatchDeltaTransferCustom>;
293
314
  });
294
- export type DispatchDeltaTransferTable<DispatchDeltaTransferCustom> = {
295
- Discriminator: "TableValue";
296
- Value: {
297
- Item1: string;
298
- Item2: DispatchDeltaTransfer<DispatchDeltaTransferCustom>;
299
- };
300
- };
315
+ export type DispatchDeltaTransferTable<DispatchDeltaTransferCustom> =
316
+ | {
317
+ Discriminator: "TableValue";
318
+ Value: {
319
+ Item1: string;
320
+ Item2: DispatchDeltaTransfer<DispatchDeltaTransferCustom>;
321
+ };
322
+ }
323
+ | { Discriminator: "TableAdd" }
324
+ | { Discriminator: "TableRemove"; Remove: string }
325
+ | { Discriminator: "TableDuplicate"; Dup: string }
326
+ | { Discriminator: "TableMoveTo"; Move: string; To: number };
301
327
 
302
328
  export type DispatchDeltaTransfer<DispatchDeltaTransferCustom> =
303
329
  | DispatchDeltaTransferPrimitive
@@ -1095,6 +1121,74 @@ export const DispatchDeltaTransfer = {
1095
1121
  ]),
1096
1122
  );
1097
1123
  }
1124
+ if (delta.kind == "TableAdd") {
1125
+ return ValueOrErrors.Default.return<
1126
+ [
1127
+ DispatchDeltaTransfer<DispatchDeltaTransferCustom>,
1128
+ DispatchDeltaTransferComparand,
1129
+ DispatchDeltaTransferIsWholeEntityMutation,
1130
+ ],
1131
+ string
1132
+ >([
1133
+ {
1134
+ Discriminator: "TableAdd",
1135
+ },
1136
+ `[TableAdd]`,
1137
+ delta.isWholeEntityMutation,
1138
+ ]);
1139
+ }
1140
+ if (delta.kind == "TableRemove") {
1141
+ return ValueOrErrors.Default.return<
1142
+ [
1143
+ DispatchDeltaTransfer<DispatchDeltaTransferCustom>,
1144
+ DispatchDeltaTransferComparand,
1145
+ DispatchDeltaTransferIsWholeEntityMutation,
1146
+ ],
1147
+ string
1148
+ >([
1149
+ {
1150
+ Discriminator: "TableRemove",
1151
+ Remove: delta.id,
1152
+ },
1153
+ `[TableRemove][${delta.id}]`,
1154
+ delta.isWholeEntityMutation,
1155
+ ]);
1156
+ }
1157
+ if (delta.kind == "TableDuplicate") {
1158
+ return ValueOrErrors.Default.return<
1159
+ [
1160
+ DispatchDeltaTransfer<DispatchDeltaTransferCustom>,
1161
+ DispatchDeltaTransferComparand,
1162
+ DispatchDeltaTransferIsWholeEntityMutation,
1163
+ ],
1164
+ string
1165
+ >([
1166
+ {
1167
+ Discriminator: "TableDuplicate",
1168
+ Dup: delta.id,
1169
+ },
1170
+ `[TableDuplicate][${delta.id}]`,
1171
+ delta.isWholeEntityMutation,
1172
+ ]);
1173
+ }
1174
+ if (delta.kind == "TableMoveTo") {
1175
+ return ValueOrErrors.Default.return<
1176
+ [
1177
+ DispatchDeltaTransfer<DispatchDeltaTransferCustom>,
1178
+ DispatchDeltaTransferComparand,
1179
+ DispatchDeltaTransferIsWholeEntityMutation,
1180
+ ],
1181
+ string
1182
+ >([
1183
+ {
1184
+ Discriminator: "TableMoveTo",
1185
+ Move: delta.id,
1186
+ To: delta.to,
1187
+ },
1188
+ `[TableMoveTo][${delta.id}][${delta.to}]`,
1189
+ delta.isWholeEntityMutation,
1190
+ ]);
1191
+ }
1098
1192
  if (delta.kind == "CustomDelta") {
1099
1193
  return parseCustomDelta(
1100
1194
  toRawObject,
@@ -0,0 +1,417 @@
1
+ import {
2
+ Option,
3
+ ValueOrErrors,
4
+ MapRepo,
5
+ PredicateValue,
6
+ DispatchParsedType,
7
+ Renderer,
8
+ BasicFun,
9
+ Expr,
10
+ Updater,
11
+ BasicUpdater,
12
+ FormLayout,
13
+ Unit,
14
+ unit,
15
+ } from "ballerina-core";
16
+ import { List, Map, Set } from "immutable";
17
+
18
+ export type EvalContext<T, Res> = {
19
+ global: PredicateValue;
20
+ root: PredicateValue;
21
+ local: PredicateValue;
22
+ traversalIterator: PredicateValue;
23
+ };
24
+
25
+ export type TraversalContext<T, Res> = {
26
+ types: Map<string, DispatchParsedType<T>>;
27
+ forms: Map<string, Renderer<T>>;
28
+ primitiveRendererNamesByType: Map<string, Set<string>>;
29
+ joinRes: BasicFun<[Res, Res], Res>;
30
+ zeroRes: BasicFun<Unit, Res>;
31
+ traverseSingleType: Traversal<T, Res>;
32
+ };
33
+
34
+ export type Traversal<T, Res> = BasicFun<
35
+ DispatchParsedType<T>,
36
+ Option<
37
+ // based on the type provided, it can return `None` depending on some predicate such as "there are no children with the desired type T that we are searching". This is an important performance optimization
38
+ ValueTraversal<T, Res>
39
+ >
40
+ >;
41
+
42
+ export type ValueTraversal<T, Res> = BasicFun<
43
+ EvalContext<T, Res>, // the proper dynamic part of the evaluation depends solely on the eval context (root, global, local) and the actual value being traversed
44
+ ValueOrErrors<Res, string>
45
+ >;
46
+
47
+ export const RendererTraversal = {
48
+ Operations: {
49
+ Run: <T, Res>(
50
+ type: DispatchParsedType<T>,
51
+ renderer: Renderer<T>,
52
+ traversalContext: TraversalContext<T, Res>,
53
+ ): ValueOrErrors<Option<ValueTraversal<T, Res>>, string> => {
54
+ const rec = RendererTraversal.Operations.Run<T, Res>;
55
+
56
+ const mapEvalContext = (
57
+ f: BasicUpdater<EvalContext<T, Res>>,
58
+ ): Updater<Option<ValueTraversal<T, Res>>> =>
59
+ Updater(
60
+ Option.Updaters.some<ValueTraversal<T, Res>>(
61
+ (v) => (ctx) => v(f(ctx)),
62
+ ),
63
+ );
64
+
65
+ const traverseNode = traversalContext.traverseSingleType(type);
66
+
67
+ if (type.kind == "primitive") {
68
+ return ValueOrErrors.Default.return(traverseNode);
69
+ }
70
+
71
+ if (
72
+ (type.kind == "lookup" || type.kind == "record") &&
73
+ renderer.kind == "lookupRenderer"
74
+ ) {
75
+ if (traversalContext.primitiveRendererNamesByType.has(type.name)) {
76
+ if (
77
+ traversalContext.primitiveRendererNamesByType
78
+ .get(type.name)!
79
+ .has(renderer.renderer)
80
+ ) {
81
+ return ValueOrErrors.Default.return(traverseNode);
82
+ }
83
+ }
84
+ if (traversalContext.forms.has(renderer.renderer)) {
85
+ // renderer.renderer is the form name
86
+ // this is a form lookup, so "local" changes here to the traversed value
87
+ return (
88
+ type.kind == "lookup"
89
+ ? MapRepo.Operations.tryFindWithError(
90
+ type.name,
91
+ traversalContext.types,
92
+ () => `Error: cannot find type ${type.name} in types`,
93
+ )
94
+ : ValueOrErrors.Default.return<DispatchParsedType<T>, string>(
95
+ type,
96
+ )
97
+ ).Then((resolvedType) => {
98
+ return rec(
99
+ resolvedType,
100
+ traversalContext.forms.get(renderer.renderer)!,
101
+ traversalContext,
102
+ ).Then((valueTraversal: Option<ValueTraversal<T, Res>>) => {
103
+ return ValueOrErrors.Default.return(
104
+ mapEvalContext((ctx) => ({
105
+ ...ctx,
106
+ local: ctx.traversalIterator,
107
+ }))(valueTraversal),
108
+ );
109
+ });
110
+ });
111
+ }
112
+ return ValueOrErrors.Default.throwOne(
113
+ `Error: cannot resolve lookup renderer ${renderer.renderer} for type ${type.name}.`,
114
+ );
115
+ }
116
+ if (type.kind == "record" && renderer.kind == "recordRenderer") {
117
+ return ValueOrErrors.Operations.All(
118
+ List(
119
+ renderer.fields
120
+ .map((fieldRenderer, fieldName) =>
121
+ rec(
122
+ fieldRenderer.renderer.type,
123
+ fieldRenderer.renderer,
124
+ traversalContext,
125
+ ).Then((fieldTraversal) => {
126
+ return ValueOrErrors.Default.return({
127
+ fieldName: fieldName,
128
+ visibility: fieldRenderer.visible,
129
+ fieldTraversal: fieldTraversal,
130
+ });
131
+ }),
132
+ )
133
+ .valueSeq(),
134
+ ),
135
+ ).Then((fieldTraversals) => {
136
+ if (
137
+ fieldTraversals.every((f) => f.fieldTraversal.kind == "l") &&
138
+ traverseNode.kind == "l"
139
+ ) {
140
+ return ValueOrErrors.Default.return(Option.Default.none());
141
+ }
142
+ return ValueOrErrors.Default.return(
143
+ Option.Default.some((evalContext: EvalContext<T, Res>) => {
144
+ if (
145
+ !PredicateValue.Operations.IsRecord(
146
+ evalContext.traversalIterator,
147
+ )
148
+ )
149
+ return ValueOrErrors.Default.throwOne(
150
+ `Error: traversal iterator is not a record, got ${evalContext.traversalIterator}`,
151
+ );
152
+ const visibleFieldsRes =
153
+ FormLayout.Operations.ComputeVisibleFieldsForRecord(
154
+ Map([
155
+ ["global", evalContext.global],
156
+ ["local", evalContext.local],
157
+ ["root", evalContext.root],
158
+ ]),
159
+ renderer.tabs,
160
+ );
161
+ // TODO later, make this monadic
162
+ if (visibleFieldsRes.kind == "errors") {
163
+ return visibleFieldsRes;
164
+ }
165
+ const visibleFields = visibleFieldsRes.value;
166
+ const traversalIteratorFields =
167
+ evalContext.traversalIterator.fields;
168
+ return ValueOrErrors.Operations.All(
169
+ fieldTraversals.flatMap((f) => {
170
+ // should be a map and instead of flatmap and [] a VoE.default.return([]) then an All on this and then a flatmap, everything is returned in a VoE
171
+ if (
172
+ f.fieldTraversal.kind == "l" ||
173
+ !visibleFields.includes(f.fieldName)
174
+ )
175
+ return [];
176
+ if (f.visibility != undefined) {
177
+ const visible = Expr.Operations.Evaluate(
178
+ Map([
179
+ ["global", evalContext.global],
180
+ ["local", evalContext.local],
181
+ ["root", evalContext.root],
182
+ ]),
183
+ )(f.visibility);
184
+ if (visible.kind == "value" && !visible.value) {
185
+ return [];
186
+ }
187
+ }
188
+
189
+ return [
190
+ f.fieldTraversal.value({
191
+ ...evalContext,
192
+ traversalIterator: traversalIteratorFields.get(
193
+ f.fieldName,
194
+ )!,
195
+ }),
196
+ ];
197
+ }),
198
+ ).Then((fieldResults: List<Res>) => {
199
+ return traverseNode.kind == "r"
200
+ ? traverseNode
201
+ .value(evalContext)
202
+ .Then((nodeResult: Res) =>
203
+ ValueOrErrors.Default.return(
204
+ fieldResults.reduce(
205
+ (acc, res) => traversalContext.joinRes([acc, res]),
206
+ nodeResult,
207
+ ),
208
+ ),
209
+ )
210
+ : ValueOrErrors.Default.return(
211
+ fieldResults.reduce(
212
+ (acc, res) => traversalContext.joinRes([acc, res]),
213
+ traversalContext.zeroRes(unit),
214
+ ),
215
+ );
216
+ });
217
+ }),
218
+ );
219
+ });
220
+ }
221
+ if (
222
+ type.kind == "sum" &&
223
+ (renderer.kind == "sumRenderer" ||
224
+ renderer.kind == "sumUnitDateRenderer")
225
+ ) {
226
+ // this will be removed when sums become proper partials
227
+ if (renderer.kind == "sumUnitDateRenderer") {
228
+ if (traverseNode.kind == "l") {
229
+ return ValueOrErrors.Default.return(Option.Default.none());
230
+ }
231
+ return ValueOrErrors.Default.return(
232
+ Option.Default.some((evalContext: EvalContext<T, Res>) =>
233
+ traverseNode.value(evalContext),
234
+ ),
235
+ );
236
+ }
237
+ if (renderer.kind == "sumRenderer") {
238
+ const res: ValueOrErrors<
239
+ Option<ValueTraversal<T, Res>>,
240
+ string
241
+ > = rec(type.args[0], renderer, traversalContext).Then(
242
+ (leftTraversal) =>
243
+ rec(type.args[1], renderer, traversalContext).Then(
244
+ (rightTraversal) => {
245
+ if (
246
+ leftTraversal.kind == "l" &&
247
+ rightTraversal.kind == "l" &&
248
+ traverseNode.kind == "l"
249
+ ) {
250
+ return ValueOrErrors.Default.return(Option.Default.none());
251
+ }
252
+ return ValueOrErrors.Default.return(
253
+ Option.Default.some<ValueTraversal<T, Res>>(
254
+ (evalContext: EvalContext<T, Res>) => {
255
+ const iterator = evalContext.traversalIterator;
256
+ if (!PredicateValue.Operations.IsSum(iterator)) {
257
+ return ValueOrErrors.Default.throwOne(
258
+ `Error: traversal iterator is not a sum, got ${evalContext.traversalIterator}`,
259
+ );
260
+ }
261
+
262
+ const isRight = iterator.value.kind == "r";
263
+
264
+ if (isRight && rightTraversal.kind == "r") {
265
+ if (traverseNode.kind == "r") {
266
+ return traverseNode
267
+ .value(evalContext)
268
+ .Then((nodeResult: Res) => {
269
+ return rightTraversal
270
+ .value({
271
+ ...evalContext,
272
+ traversalIterator: iterator.value.value,
273
+ })
274
+ .Then((rightRes) => {
275
+ return ValueOrErrors.Default.return<
276
+ Res,
277
+ string
278
+ >(
279
+ traversalContext.joinRes([
280
+ nodeResult,
281
+ rightRes,
282
+ ]),
283
+ );
284
+ });
285
+ });
286
+ }
287
+ return rightTraversal
288
+ .value({
289
+ ...evalContext,
290
+ traversalIterator: iterator.value.value,
291
+ })
292
+ .Then((rightRes) => {
293
+ return ValueOrErrors.Default.return<Res, string>(
294
+ rightRes,
295
+ );
296
+ });
297
+ }
298
+
299
+ if (!isRight && leftTraversal.kind == "r") {
300
+ if (traverseNode.kind == "r") {
301
+ return traverseNode
302
+ .value(evalContext)
303
+ .Then((nodeResult: Res) => {
304
+ return leftTraversal
305
+ .value({
306
+ ...evalContext,
307
+ traversalIterator: iterator.value.value,
308
+ })
309
+ .Then((leftRes) => {
310
+ return ValueOrErrors.Default.return<
311
+ Res,
312
+ string
313
+ >(
314
+ traversalContext.joinRes([
315
+ nodeResult,
316
+ leftRes,
317
+ ]),
318
+ );
319
+ });
320
+ });
321
+ }
322
+ return leftTraversal
323
+ .value({
324
+ ...evalContext,
325
+ traversalIterator: iterator.value.value,
326
+ })
327
+ .Then((leftRes) => {
328
+ return ValueOrErrors.Default.return<Res, string>(
329
+ leftRes,
330
+ );
331
+ });
332
+ }
333
+
334
+ return ValueOrErrors.Default.return<Res, string>(
335
+ traversalContext.zeroRes(unit),
336
+ );
337
+ },
338
+ ),
339
+ );
340
+ },
341
+ ),
342
+ );
343
+ return res;
344
+ }
345
+ }
346
+
347
+ if (type.kind == "tuple" && renderer.kind == "tupleRenderer") {
348
+ return ValueOrErrors.Operations.All(
349
+ List(
350
+ renderer.itemRenderers.map((itemRenderer, index) => {
351
+ return rec(
352
+ type.args[index],
353
+ itemRenderer.renderer,
354
+ traversalContext,
355
+ ).Then((itemTraversal) => {
356
+ return ValueOrErrors.Default.return({
357
+ index: index,
358
+ itemTraversal: itemTraversal,
359
+ });
360
+ });
361
+ }),
362
+ ),
363
+ ).Then((itemTraversals) => {
364
+ if (
365
+ itemTraversals.every((i) => i.itemTraversal.kind == "l") &&
366
+ traverseNode.kind == "l"
367
+ ) {
368
+ return ValueOrErrors.Default.return(Option.Default.none());
369
+ }
370
+
371
+ return ValueOrErrors.Default.return(
372
+ Option.Default.some((evalContext: EvalContext<T, Res>) => {
373
+ const iterator = evalContext.traversalIterator;
374
+ if (!PredicateValue.Operations.IsTuple(iterator)) {
375
+ return ValueOrErrors.Default.throwOne(
376
+ `Error: traversal iterator is not a tuple, got ${evalContext.traversalIterator}`,
377
+ );
378
+ }
379
+ return ValueOrErrors.Operations.All(
380
+ itemTraversals.flatMap((i) =>
381
+ i.itemTraversal.kind == "r"
382
+ ? [
383
+ i.itemTraversal.value({
384
+ ...evalContext,
385
+ traversalIterator: iterator.values.get(i.index)!,
386
+ }),
387
+ ]
388
+ : [],
389
+ ),
390
+ ).Then((itemResults) => {
391
+ return traverseNode.kind == "r"
392
+ ? traverseNode
393
+ .value(evalContext)
394
+ .Then((nodeResult: Res) =>
395
+ ValueOrErrors.Default.return(
396
+ itemResults.reduce(
397
+ (acc, res) => traversalContext.joinRes([acc, res]),
398
+ nodeResult,
399
+ ),
400
+ ),
401
+ )
402
+ : ValueOrErrors.Default.return(
403
+ itemResults.reduce(
404
+ (acc, res) => traversalContext.joinRes([acc, res]),
405
+ traversalContext.zeroRes(unit),
406
+ ),
407
+ );
408
+ });
409
+ }),
410
+ );
411
+ });
412
+ }
413
+
414
+ return ValueOrErrors.Default.return(Option.Default.none());
415
+ },
416
+ },
417
+ };
@@ -227,6 +227,25 @@ export const FormLayout = {
227
227
  ).Then((calculatedTabs) =>
228
228
  ValueOrErrors.Default.return(OrderedMap(calculatedTabs)),
229
229
  ),
230
+ ComputeVisibleFieldsForRecord: (
231
+ bindings: Bindings,
232
+ formLayout: PredicateFormLayout,
233
+ ): ValueOrErrors<Array<FieldName>, string> =>
234
+ FormLayout.Operations.ComputeLayout(bindings, formLayout).Then(
235
+ (recordLayout) =>
236
+ ValueOrErrors.Default.return(
237
+ recordLayout
238
+ .valueSeq()
239
+ .flatMap((tab) =>
240
+ tab.columns
241
+ .valueSeq()
242
+ .flatMap((column) =>
243
+ column.groups.valueSeq().flatMap((group) => group),
244
+ ),
245
+ )
246
+ .toArray(),
247
+ ),
248
+ ),
230
249
  },
231
250
  };
232
251
 
@@ -280,7 +299,6 @@ export const TableLayout = {
280
299
  columns: visibleColumns.columns,
281
300
  });
282
301
  }
283
- console.debug(`Computing visible columns`, visibleColumns.columns);
284
302
  return Expr.Operations.Evaluate(bindings)(visibleColumns.columns).Then(
285
303
  (result) => {
286
304
  if (!PredicateValue.Operations.IsRecord(result)) {
@@ -288,10 +306,6 @@ export const TableLayout = {
288
306
  `Invalid visible columns: ${JSON.stringify(result)}`,
289
307
  );
290
308
  }
291
- console.debug(
292
- `Computed visible columns ${JSON.stringify(Array.from(result.fields.keys()))}`,
293
- result,
294
- );
295
309
  return ValueOrErrors.Default.return({
296
310
  columns: Array.from(result.fields.keys()),
297
311
  });