ballerina-core 1.0.50 → 1.0.51

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/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.50",
5
+ "version": "1.0.51",
6
6
  "main": "main.ts",
7
7
  "dependencies": {
8
8
  "immutable": "^5.0.0-beta.5",
@@ -7,25 +7,25 @@ export type ValueOrErrors<v, e> = (
7
7
  | (Value<v> & { kind: "value" })
8
8
  | { errors: List<e>; kind: "errors" }
9
9
  ) & {
10
- map: <a, b, e>(
10
+ Map: <a, b, e>(
11
11
  this: ValueOrErrors<a, e>,
12
12
  f: BasicFun<a, b>
13
13
  ) => ValueOrErrors<b, e>;
14
- mapErrors: <a, e, e2>(
14
+ MapErrors: <a, e, e2>(
15
15
  this: ValueOrErrors<a, e>,
16
16
  f: BasicFun<List<e>, List<e2>>
17
17
  ) => ValueOrErrors<a, e2>;
18
- flatten: <a, e>(
18
+ Flatten: <a, e>(
19
19
  this: ValueOrErrors<ValueOrErrors<a, e>, e>
20
20
  ) => ValueOrErrors<a, e>;
21
- bind: <a, b, e>(
21
+ Then: <a, b, e>(
22
22
  this: ValueOrErrors<a, e>,
23
23
  k: BasicFun<a, ValueOrErrors<b, e>>
24
24
  ) => ValueOrErrors<b, e>;
25
25
  };
26
26
 
27
27
  const operations = {
28
- map: function <a, b, e>(
28
+ Map: function <a, b, e>(
29
29
  this: ValueOrErrors<a, e>,
30
30
  f: BasicFun<a, b>
31
31
  ): ValueOrErrors<b, e> {
@@ -34,7 +34,7 @@ const operations = {
34
34
  }
35
35
  return ValueOrErrors.Default.return(f(this.value));
36
36
  },
37
- mapErrors: function <a, e, e2>(
37
+ MapErrors: function <a, e, e2>(
38
38
  this: ValueOrErrors<a, e>,
39
39
  f: BasicFun<List<e>, List<e2>>
40
40
  ): ValueOrErrors<a, e2> {
@@ -43,7 +43,7 @@ const operations = {
43
43
  }
44
44
  return this;
45
45
  },
46
- flatten: function <a, e>(
46
+ Flatten: function <a, e>(
47
47
  this: ValueOrErrors<ValueOrErrors<a, e>, e>
48
48
  ): ValueOrErrors<a, e> {
49
49
  if (this.kind == "errors") {
@@ -54,11 +54,11 @@ const operations = {
54
54
  return this.value;
55
55
  }
56
56
  },
57
- bind: function <a, b, e>(
57
+ Then: function <a, b, e>(
58
58
  this: ValueOrErrors<a, e>,
59
59
  k: BasicFun<a, ValueOrErrors<b, e>>
60
60
  ): ValueOrErrors<b, e> {
61
- return this.map(k).flatten();
61
+ return this.Map(k).Flatten();
62
62
  },
63
63
  };
64
64
 
@@ -76,23 +76,23 @@ export const ValueOrErrors = {
76
76
  }),
77
77
  },
78
78
  Operations: {
79
- return: <v, e>(_: v): ValueOrErrors<v, e> =>
79
+ Return: <v, e>(_: v): ValueOrErrors<v, e> =>
80
80
  ValueOrErrors.Default.return(_),
81
- throw: <v, e>(_: e): ValueOrErrors<v, e> =>
82
- ValueOrErrors.Default.throw(List([_])),
83
- map: <a, b, e>(
81
+ Throw: <v, e>(_: List<e>): ValueOrErrors<v, e> =>
82
+ ValueOrErrors.Default.throw(_),
83
+ Map: <a, b, e>(
84
84
  f: BasicFun<a, b>
85
85
  ): Fun<ValueOrErrors<a, e>, ValueOrErrors<b, e>> =>
86
86
  Fun((_) =>
87
87
  _.kind == "errors" ? _ : ValueOrErrors.Default.return(f(_.value))
88
88
  ),
89
- mapErrors: <a, e, e2>(
89
+ MapErrors: <a, e, e2>(
90
90
  f: BasicFun<List<e>, List<e2>>
91
91
  ): BasicFun<ValueOrErrors<a, e>, ValueOrErrors<a, e2>> =>
92
92
  Fun((_) =>
93
93
  _.kind == "errors" ? ValueOrErrors.Default.throw(f(_.errors)) : _
94
94
  ),
95
- flatten: <a, e>(): Fun<
95
+ Flatten: <a, e>(): Fun<
96
96
  ValueOrErrors<ValueOrErrors<a, e>, e>,
97
97
  ValueOrErrors<a, e>
98
98
  > =>
@@ -105,30 +105,30 @@ export const ValueOrErrors = {
105
105
  return _.value;
106
106
  }
107
107
  }),
108
- then: <a, b, e>(
108
+ Then: <a, b, e>(
109
109
  k: BasicFun<a, ValueOrErrors<b, e>>
110
110
  ): Fun<ValueOrErrors<a, e>, ValueOrErrors<b, e>> =>
111
111
  Fun((_: ValueOrErrors<a, e>) =>
112
- ValueOrErrors.Operations.flatten<b, e>()(
113
- ValueOrErrors.Operations.map<a, ValueOrErrors<b, e>, e>(k)(_)
112
+ ValueOrErrors.Operations.Flatten<b, e>()(
113
+ ValueOrErrors.Operations.Map<a, ValueOrErrors<b, e>, e>(k)(_)
114
114
  )
115
115
  ),
116
- fold: <v, e, c>(
116
+ Fold: <v, e, c>(
117
117
  l: BasicFun<v, c>,
118
118
  r: BasicFun<List<e>, c>
119
119
  ): Fun<ValueOrErrors<v, e>, c> =>
120
120
  Fun((_) => (_.kind == "value" ? l(_.value) : r(_.errors))),
121
- all: <v, e>(_: List<ValueOrErrors<v, e>>): ValueOrErrors<List<v>, e> =>
121
+ All: <v, e>(_: List<ValueOrErrors<v, e>>): ValueOrErrors<List<v>, e> =>
122
122
  _.reduce(
123
123
  (reduction, value) =>
124
- ValueOrErrors.Operations.fold<v, e, ValueOrErrors<List<v>, e>>(
124
+ ValueOrErrors.Operations.Fold<v, e, ValueOrErrors<List<v>, e>>(
125
125
  (v: v) =>
126
126
  reduction.kind == "errors"
127
127
  ? reduction
128
- : reduction.map((_) => _.concat(v)),
128
+ : reduction.Map((_) => _.concat(v)),
129
129
  (es: List<e>) =>
130
130
  reduction.kind == "errors"
131
- ? reduction.mapErrors((_) => _.concat(es))
131
+ ? reduction.MapErrors((_) => _.concat(es))
132
132
  : ValueOrErrors.Default.throw(es)
133
133
  )(value),
134
134
  ValueOrErrors.Default.return(List<v>())
@@ -37,15 +37,27 @@ export const editFormRunner = <E, FS>() => {
37
37
  EditFormState<E, FS>().Updaters.Template.toUnchecked()
38
38
  ),
39
39
  Debounce<Synchronized<Unit, ApiErrors>, EditFormWritableState<E, FS>>(
40
- Synchronize<Unit, ApiErrors, EditFormWritableState<E, FS>>(
41
- (_) =>
42
- current.entity.sync.kind == "loaded"
43
- ? current.api.update(current.entityId, current.entity.sync.value, current.formState)
44
- : Promise.resolve([]),
45
- (_) => "transient failure",
46
- 5,
47
- 50
48
- ),
40
+ (() => {
41
+ if(current.entity.sync.kind != "loaded") return Synchronize<Unit, ApiErrors, EditFormWritableState<E, FS>>(
42
+ (_) => Promise.resolve([]),
43
+ (_) => "transient failure",
44
+ 5,
45
+ 50
46
+ )
47
+ const parsed = current.parser(current.entity.sync.value, current.formState)
48
+
49
+ return Synchronize<Unit, ApiErrors, EditFormWritableState<E, FS>>(
50
+ (_) =>
51
+ {
52
+ if(parsed.kind == "errors") return Promise.reject(parsed.errors)
53
+ return current.api.update(current.entityId, parsed)
54
+ },
55
+ (_) => "transient failure",
56
+ parsed.kind == "errors" ? 1 : 5,
57
+ 50
58
+ )
59
+ })(),
60
+
49
61
  15
50
62
  ).embed(
51
63
  (_) => ({ ..._, ..._.apiRunner }),
@@ -1,4 +1,5 @@
1
1
  import { ApiResponseChecker, AsyncState, BasicUpdater, Debounced, ForeignMutationsInput, Guid, id, SimpleCallback, simpleUpdater, Synchronized, Template, unit, Unit, Updater, Value } from "../../../../../../main"
2
+ import { ValueOrErrors } from "../../../../../collections/domains/valueOrErrors/state"
2
3
  import { BasicFun } from "../../../../../fun/state"
3
4
 
4
5
  export type ApiErrors = Array<string>
@@ -7,8 +8,9 @@ export type EditFormContext<E,FS> = {
7
8
  entityId:string,
8
9
  api:{
9
10
  get:(id: Guid) => Promise<E>,
10
- update:(id: Guid, entity:E, formstate: FS) => Promise<ApiErrors>
11
+ update:(id: Guid, raw: any) => Promise<ApiErrors>
11
12
  },
13
+ parser: (entity:E, formstate: FS) => ValueOrErrors<E, ApiErrors>
12
14
  actualForm:Template<Value<E> & FS, FS, { onChange:SimpleCallback<BasicUpdater<E>>}>
13
15
  }
14
16
 
@@ -2,7 +2,7 @@ import { Map, List, Set, OrderedMap } from "immutable"
2
2
  import { CollectionReference } from "../../../collection/domains/reference/state";
3
3
  import { CollectionSelection } from "../../../collection/domains/selection/state";
4
4
  import { BasicFun } from "../../../../../fun/state";
5
- import { InjectedPrimitives, Maybe, replaceKeyword, replaceKeywords, revertKeyword, Type, TypeDefinition, TypeName, Unit, Value } from "../../../../../../main";
5
+ import { InjectedPrimitives, Maybe, replaceKeyword, replaceKeywords, revertKeyword, Sum, Type, TypeDefinition, TypeName, Unit, Value } from "../../../../../../main";
6
6
  import { ValueOrErrors } from "../../../../../collections/domains/valueOrErrors/state";
7
7
 
8
8
  export const PrimitiveTypes =
@@ -186,7 +186,6 @@ export const fromAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>
186
186
  return result
187
187
  }
188
188
  if (t.value == "Map" && t.args.length == 2) {
189
- console.log("t", t)
190
189
  let result = converters[t.value].fromAPIRawValue(obj)
191
190
 
192
191
  const isKeyPrimitive = typeof t.args[0] == "string" && PrimitiveTypes.some(_ => _ == t.args[0]) || injectedPrimitives?.injectedPrimitives.has(t.args[0] as keyof T)
@@ -229,24 +228,24 @@ export const fromAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>
229
228
  export const toAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>, builtIns: BuiltIns, converters: BuiltInApiConverters, isKeywordsReverted: boolean = false, injectedPrimitives?: InjectedPrimitives<T>) => (raw: any, formState: any) : ValueOrErrors<any, string> => {
230
229
  const obj = !isKeywordsReverted ? replaceKeywords(raw, "to api") : raw
231
230
  if (t.kind == "primitive") {
232
- return ValueOrErrors.Operations.return(converters[t.value].toAPIRawValue([obj, formState.modifiedByUser] as never))
231
+ return ValueOrErrors.Operations.Return(converters[t.value].toAPIRawValue([obj, formState.modifiedByUser] as never))
233
232
  } else if (t.kind == "application") { // application here means "generic type application"
234
233
  if (t.value == "SingleSelection" && t.args.length == 1) {
235
234
  const result = converters[t.value].toAPIRawValue([obj, formState.modifiedByUser])
236
- if(typeof result != "object") return ValueOrErrors.Operations.return(result)
235
+ if(typeof result != "object") return ValueOrErrors.Operations.Return(result)
237
236
 
238
237
  return toAPIRawValue({ kind:"lookup", name:t.args[0] }, types, builtIns, converters, true, injectedPrimitives)(result, formState)
239
238
  }
240
239
  if ((t.value == "Multiselection" || t.value == "MultiSelection") && t.args.length == 1) {
241
240
  const result = converters["MultiSelection"].toAPIRawValue([obj, formState.modifiedByUser])
242
241
 
243
- return ValueOrErrors.Operations.all(List<ValueOrErrors<any, string>>(result.map((_:any) =>
244
- typeof _ == "object" ? toAPIRawValue({ kind:"lookup", name: t.args[0] }, types, builtIns, converters, true, injectedPrimitives)(_, formState) : ValueOrErrors.Operations.return(_))))
242
+ return ValueOrErrors.Operations.All(List<ValueOrErrors<any, string>>(result.map((_:any) =>
243
+ typeof _ == "object" ? toAPIRawValue({ kind:"lookup", name: t.args[0] }, types, builtIns, converters, true, injectedPrimitives)(_, formState) : ValueOrErrors.Operations.Return(_))))
245
244
  }
246
245
  if (t.value == "List" && t.args.length == 1) {
247
246
  const converterResult = converters[t.value].toAPIRawValue([obj, formState.modifiedByUser])
248
247
  const isPrimitive = PrimitiveTypes.some(_ => _ == t.args[0]) || injectedPrimitives?.injectedPrimitives.has(t.args[0] as keyof T)
249
- return ValueOrErrors.Operations.all(List<ValueOrErrors<any, string>>(converterResult.map((item: any, index: number) =>
248
+ return ValueOrErrors.Operations.All(List<ValueOrErrors<any, string>>(converterResult.map((item: any, index: number) =>
250
249
  toAPIRawValue(
251
250
  isPrimitive ?
252
251
  { kind:"primitive", value:t.args[0] as PrimitiveType }
@@ -256,12 +255,12 @@ export const toAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>,
256
255
  ))))
257
256
  }
258
257
  if (t.value == "Map" && t.args.length == 2) {
259
- const converterResult = converters[t.value].toAPIRawValue([obj, formState.modifiedByUser])
258
+ const [converterResult, toIdentiferAndDisplayName] = converters[t.value].toAPIRawValue([obj, formState.modifiedByUser])
260
259
  const isKeyPrimitive = PrimitiveTypes.some(_ => _ == t.args[0]) || injectedPrimitives?.injectedPrimitives.has(t.args[0] as keyof T)
261
260
  const isValuePrimitive = PrimitiveTypes.some(_ => _ == t.args[1]) || injectedPrimitives?.injectedPrimitives.has(t.args[1] as keyof T)
262
261
 
263
- const parsedMap: ValueOrErrors<{key: ValueOrErrors<any, any>, value: ValueOrErrors<any, any>}, any>[] = converterResult.map((keyValue: any, index: number) => {
264
- const key = toAPIRawValue(
262
+ const parsedMap: List<ValueOrErrors<{key: ValueOrErrors<any, any>, value: ValueOrErrors<any, any>}, any>> = converterResult.map((keyValue: any, index: number) => {
263
+ const possiblyUndefinedKey = toAPIRawValue(
265
264
  typeof t.args[0] == "string" ?
266
265
  isKeyPrimitive ?
267
266
  { kind: "primitive", value: t.args[0] as PrimitiveType }
@@ -271,11 +270,12 @@ export const toAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>,
271
270
  types, builtIns, converters, true, injectedPrimitives)(keyValue[0], formState.elementFormStates.get(index).KeyFormState
272
271
  )
273
272
 
274
- if(key.kind == "value" && (key.value == undefined || key.value == null)) {
275
- return ValueOrErrors.Operations.throw([`A mapped key is undefined for type ${JSON.stringify(t.args[0])}`])
276
- } else if ( key.kind == "errors"){
277
- return key
278
- }
273
+ const key: ValueOrErrors<any, string> = (() => {
274
+ if(possiblyUndefinedKey.kind == "value" && (possiblyUndefinedKey.value == undefined || possiblyUndefinedKey.value == null || possiblyUndefinedKey.value == "" || (typeof possiblyUndefinedKey.value == "object" && Object.keys(possiblyUndefinedKey.value).length == 0))) {
275
+ return ValueOrErrors.Operations.Throw(List([`A mapped key is undefined for type ${JSON.stringify(t.args[0])}`]))
276
+ }
277
+ return possiblyUndefinedKey
278
+ })()
279
279
 
280
280
  const value = toAPIRawValue(
281
281
  typeof t.args[1] == "string" ?
@@ -286,31 +286,22 @@ export const toAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>,
286
286
  t.args[1],
287
287
  types, builtIns, converters, true, injectedPrimitives)(keyValue[1], formState.elementFormStates.get(index).ValueFormState)
288
288
 
289
- if(value.kind == "errors") return value
290
-
291
- return ValueOrErrors.Operations.return({key, value})
289
+ return key.kind == "errors" || value.kind == "errors" ? ValueOrErrors.Operations.All(List([key, value])) : ValueOrErrors.Default.return({key: key.value, value: value.value})
292
290
  }
293
291
  )
294
-
295
- if(parsedMap.length > 0 && parsedMap.some((_: ValueOrErrors<any, any>) => _.kind == "errors")) {
296
- return ValueOrErrors.Operations.all(List(parsedMap))
297
- }
298
- // TODO this needs improvement
299
- const allKeysStringified = parsedMap.map((_) => _.kind == "value" ? JSON.stringify((_.value.key as any).value) : "")
300
- const allKeysUnique = Set(allKeysStringified).size == allKeysStringified.length
301
-
302
- if(allKeysStringified.length > 0 && !allKeysUnique) {
303
- return ValueOrErrors.Operations.throw(`Keys in the map are not unique: ${JSON.stringify(allKeysStringified)}`)
304
- }
305
292
 
306
- // return ValueOrErrors.Operations.return(parsedMap.map(_ => _.flatten()))
307
- return ValueOrErrors.Operations.return(parsedMap.map(_ => (_ as any).map(({key, value}: {key: any, value: any}) => ({key: key.value, value: value.value}))).map((_: any) => _.value))
293
+ const nonUniqueKeyErrors = parsedMap.filter(_ => _.kind == "value").reduce((acc, _) => {
294
+ const [id, displayName] = toIdentiferAndDisplayName(_.value.key)
295
+ acc.ids.contains(id) ? acc.errors = acc.errors.push(ValueOrErrors.Default.throw(List([`Keys in the map are not unique: ${displayName}`]))) : acc.ids = acc.ids.push(id)
296
+ return acc
297
+ }, {ids: List<string>(), errors: List<ValueOrErrors<any, string>>()}).errors
308
298
 
299
+ return ValueOrErrors.Operations.All(parsedMap.concat(nonUniqueKeyErrors))
309
300
  }
310
301
  } else { // t.kind == lookup: we are dealing with a record/object or extended type
311
302
  const tDef = types.get(t.name)!
312
303
  if("extends" in tDef && tDef.extends.length == 1) {
313
- return ValueOrErrors.Operations.return(converters[(tDef.extends[0] as keyof BuiltInApiConverters)].toAPIRawValue([obj, formState.modifiedByUser] as never))
304
+ return ValueOrErrors.Operations.Return(converters[(tDef.extends[0] as keyof BuiltInApiConverters)].toAPIRawValue([obj, formState.modifiedByUser] as never))
314
305
  }
315
306
  const convertedMap = tDef.fields.mapEntries(([fieldName, fieldType] ) => {
316
307
  const revertedFieldName = revertKeyword(fieldName)
@@ -320,10 +311,10 @@ export const toAPIRawValue = <T>(t: Type, types: Map<TypeName, TypeDefinition>,
320
311
  })
321
312
  if(convertedMap.some((valueOrError) => valueOrError.kind == "errors")) {
322
313
  const propertiesWithErrors = convertedMap.filter((valueOrError) => valueOrError.kind == "errors")
323
- const namedErrors = propertiesWithErrors.map((value, key) => value.mapErrors(_ => _.map((_: string) => `${key}: ${_}`)))
324
- return ValueOrErrors.Operations.all(List<ValueOrErrors<any, string>>(namedErrors.valueSeq().toList()))
314
+ const namedErrors = propertiesWithErrors.map((value, key) => value.MapErrors(_ => _.map((_: string) => `${key}: ${_}`)))
315
+ return ValueOrErrors.Operations.All(List<ValueOrErrors<any, string>>(namedErrors.valueSeq().toList()))
325
316
  }
326
- return ValueOrErrors.Operations.return(convertedMap.map(valueOrError => valueOrError.kind == "value" ? valueOrError.value : valueOrError.errors).toJS())
317
+ return ValueOrErrors.Operations.Return(convertedMap.map(valueOrError => valueOrError.kind == "value" ? valueOrError.value : valueOrError.errors).toJS())
327
318
  }
328
- return ValueOrErrors.Operations.return(defaultValue(types, builtIns, injectedPrimitives)(t.value))
319
+ return ValueOrErrors.Operations.Return(defaultValue(types, builtIns, injectedPrimitives)(t.value))
329
320
  }
@@ -161,7 +161,6 @@ export const FormsConfig = {
161
161
  errors = errors.push(`type ${typeName} extends non-existent type ${extendedTypeName}`);
162
162
  });
163
163
  typeDef.fields.forEach((fieldDef, fieldName) => {
164
- // TODO - check application args are a valid type (-refs, primtives, lookups, possible here? or may have to do at end) also no undefined
165
164
  if (fieldDef.kind == "primitive" && (!builtIns.primitives.has(fieldDef.value) && !injectedPrimitives?.injectedPrimitives.has(fieldDef.value as keyof T) ))
166
165
  errors = errors.push(`field ${fieldName} of type ${typeName} is non-existent primitive type ${fieldDef.value}`);
167
166
  if (fieldDef.kind == "lookup" && !types.has(fieldDef.name))
@@ -570,8 +569,6 @@ export const FormsConfig = {
570
569
  return
571
570
  }
572
571
  const launcherKind = formsConfig["launchers"][launcherName]["kind"] as Launcher["kind"] | MappingLauncher["kind"]
573
- console.log(formsConfig["launchers"][launcherName]["form"])
574
- console.log(forms.keySeq().toArray());
575
572
  if (forms.has(formsConfig["launchers"][launcherName]["form"]) == false) {
576
573
  errors = errors.push(`launcher '${launcherName}' references non-existing form '${formsConfig.launchers[launcherName].form}'`);
577
574
  return
@@ -209,7 +209,7 @@ export const ParseForm = <T,>(
209
209
  .mapContext<any>(_ => ({ ..._, label, tooltip }))
210
210
  } else { // the list argument is a primitive
211
211
  const elementForm = FieldView(fieldConfig, fieldViews, fieldNameToElementViewCategory(formFieldElementRenderers)(fieldName) as any, elementRendererName, elementLabel, elementTooltip, EnumOptionsSources, fieldsOptionsConfig, leafPredicates, injectedPrimitives)
212
- const initialFormState = FieldFormState(fieldConfig, fieldViews, fieldNameToElementViewCategory(formFieldElementRenderers)(fieldName) as any, elementRendererName, InfiniteStreamSources, fieldsInfiniteStreamsConfig, injectedPrimitives);
212
+ const initialFormState = FieldFormState(fieldConfig, fieldViews, fieldNameToElementViewCategory(formFieldElementRenderers)(fieldName) as any, elementRendererName, fieldName, InfiniteStreamSources, fieldsInfiniteStreamsConfig, injectedPrimitives);
213
213
  formConfig[fieldName] = ListForm<any, any, any & FormLabel, Unit>(
214
214
  { Default: () => initialFormState },
215
215
  { Default: () => initialElementValue },
@@ -305,7 +305,7 @@ export type EditLauncherContext<Entity, FormState, ExtraContext> =
305
305
  extraContext: ExtraContext,
306
306
  containerFormView: any,
307
307
  submitButtonWrapper: any
308
- }, "api" | "actualForm">
308
+ }, "api" | "parser" | "actualForm">
309
309
 
310
310
  export type CreateLauncherContext<Entity, FormState, ExtraContext> =
311
311
  Omit<
@@ -477,9 +477,8 @@ export const parseForms =
477
477
  get: (id: string) => entityApis.get(launcher.api)(id).then((raw: any) => {
478
478
  return fromAPIRawValue({ kind: "lookup", name: parsedForm.formDef.type }, formsConfig.types, builtIns, apiConverters, false, injectedPrimitives)(raw)
479
479
  }),
480
- update: (id: Guid, value: any, formState: any) => {
481
- const raw = toAPIRawValue({ kind: "lookup", name: parsedForm.formDef.type }, formsConfig.types, builtIns, apiConverters, false, injectedPrimitives)(value, formState)
482
- return raw.kind == "errors" ? Promise.reject(raw.errors) : entityApis.update(launcher.api)(id, raw.value)
480
+ update: (id: any, parsed: any) => {
481
+ return entityApis.update(launcher.api)(id, parsed)
483
482
  }
484
483
  }
485
484
  parsedLaunchers.edit = parsedLaunchers.edit.set(
@@ -489,6 +488,7 @@ export const parseForms =
489
488
  ({
490
489
  ...parentContext,
491
490
  api: api,
491
+ parser: (value: any, formState: any) => toAPIRawValue({ kind: "lookup", name: parsedForm.formDef.type }, formsConfig.types, builtIns, apiConverters, false, injectedPrimitives)(value, formState),
492
492
  actualForm: form.withView(containerFormView).mapContext((_: any) => ({ ..._, rootValue: _.value, ...parentContext.extraContext }))
493
493
  }) as any)
494
494
  .withViewFromProps(props => props.context.submitButtonWrapper)
@@ -8,44 +8,44 @@ import { ListFieldState, ListFieldView } from "./state";
8
8
 
9
9
  export const ListForm = <Element, ElementFormState, Context extends FormLabel, ForeignMutationsExpected>(
10
10
  ElementFormState: { Default: () => ElementFormState },
11
- Element: { Default: () => Element },
11
+ Element: { Default: () => Element | undefined},
12
12
  elementTemplate: Template<
13
- Context & Value<Element> & ElementFormState,
13
+ Context & Value<Element | undefined> & ElementFormState,
14
14
  ElementFormState,
15
15
  ForeignMutationsExpected & {
16
- onChange: OnChange<Element>;
16
+ onChange: OnChange<Element | undefined>;
17
17
  }>,
18
- validation?: BasicFun<List<Element>, Promise<FieldValidation>>,
18
+ validation?: BasicFun<List<Element | undefined>, Promise<FieldValidation>>,
19
19
  ) => {
20
20
  const embeddedElementTemplate = (elementIndex:number) =>
21
21
  elementTemplate
22
22
  .mapForeignMutationsFromProps<ForeignMutationsExpected & {
23
- onChange: OnChange<List<Element>>;
23
+ onChange: OnChange<List<Element| undefined>>;
24
24
  add: SimpleCallback<Unit>;
25
- remove: SimpleCallback<number>;}>((props): ForeignMutationsExpected & {onChange: OnChange<Element>} => ({
25
+ remove: SimpleCallback<number>;}>((props): ForeignMutationsExpected & {onChange: OnChange<Element | undefined>} => ({
26
26
  ...props.foreignMutations,
27
27
  onChange: (elementUpdater, path) => {
28
- props.foreignMutations.onChange(Updater((elements:List<Element>) =>
29
- elements.update(elementIndex, (_:Element | undefined) => _ == undefined ? _ : elementUpdater(_))), path)
28
+ props.foreignMutations.onChange(Updater((elements:List<Element | undefined>) =>
29
+ elements.has(elementIndex) ? elements.update(elementIndex, undefined, elementUpdater) : elements), path)
30
30
  props.setState(_ => ({..._,
31
31
  modifiedByUser:true,
32
32
  })) },
33
33
  add: (newElement: Element) => { },
34
34
  remove: (elementIndex: number) => { }
35
35
  }))
36
- .mapContext((_: Context & Value<List<Element>> & ListFieldState<Element, ElementFormState>) : (Context & Value<Element> & ElementFormState) | undefined => {
36
+ .mapContext((_: Context & Value<List<Element | undefined>> & ListFieldState<Element | undefined, ElementFormState>) : (Context & Value<Element | undefined> & ElementFormState) | undefined => {
37
+ if(!_.value.has(elementIndex)) return undefined
37
38
  const element = _.value.get(elementIndex)
38
- if (element == undefined) return undefined
39
39
  const elementFormState = _.elementFormStates.get(elementIndex) || ElementFormState.Default()
40
- const elementContext : Context & Value<Element> & ElementFormState = ({ ..._, ...elementFormState, value: element })
40
+ const elementContext : Context & Value<Element | undefined> & ElementFormState = ({ ..._, ...elementFormState, value: element })
41
41
  return elementContext
42
42
  })
43
- .mapState((_:BasicUpdater<ElementFormState>) : Updater<ListFieldState<Element, ElementFormState>> =>
44
- ListFieldState<Element, ElementFormState>().Updaters.Core.elementFormStates(
43
+ .mapState((_:BasicUpdater<ElementFormState>) : Updater<ListFieldState<Element | undefined, ElementFormState>> =>
44
+ ListFieldState<Element | undefined, ElementFormState>().Updaters.Core.elementFormStates(
45
45
  MapRepo.Updaters.upsert(elementIndex, () => ElementFormState.Default(), _)
46
46
  ))
47
- return Template.Default<Context & Value<List<Element>> & { disabled: boolean }, ListFieldState<Element, ElementFormState>, ForeignMutationsExpected & { onChange: OnChange<List<Element>>; },
48
- ListFieldView<Element, ElementFormState, Context, ForeignMutationsExpected>>(props => <>
47
+ return Template.Default<Context & Value<List<Element | undefined>> & { disabled: boolean }, ListFieldState<Element | undefined, ElementFormState>, ForeignMutationsExpected & { onChange: OnChange<List<Element | undefined>>; },
48
+ ListFieldView<Element | undefined, ElementFormState, Context, ForeignMutationsExpected>>(props => <>
49
49
  <props.view {...props}
50
50
  context={{
51
51
  ...props.context,
@@ -54,7 +54,7 @@ export const ListForm = <Element, ElementFormState, Context extends FormLabel, F
54
54
  ...props.foreignMutations,
55
55
  add: (_) => {
56
56
  props.foreignMutations.onChange(
57
- ListRepo.Updaters.push(Element.Default()), List()
57
+ ListRepo.Updaters.push<Element | undefined>(Element.Default()), List()
58
58
  )
59
59
  },
60
60
  remove: (_) => {
@@ -67,7 +67,7 @@ export const ListForm = <Element, ElementFormState, Context extends FormLabel, F
67
67
  />
68
68
  </>
69
69
  ).any([
70
- ValidateRunner<Context & { disabled: boolean }, ListFieldState<Element, ElementFormState>, ForeignMutationsExpected, List<Element>>(
70
+ ValidateRunner<Context & { disabled: boolean }, ListFieldState<Element | undefined, ElementFormState>, ForeignMutationsExpected, List<Element | undefined>>(
71
71
  validation ? _ => validation(_).then(FieldValidationWithPath.Default.fromFieldValidation) : undefined
72
72
  ),
73
73
  ]);