ngx-t-forms-types 0.0.29 → 0.0.33

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 (65) hide show
  1. package/dist/interfaces/Form/ArrayFunctions.d.ts +3 -1
  2. package/dist/interfaces/Form/ArrayFunctions.js +2 -0
  3. package/dist/interfaces/Form/formSubmissionHandleInterface.d.ts +6 -0
  4. package/dist/interfaces/FormBuilder/DefaultEelement.js +76 -0
  5. package/dist/interfaces/FormBuilder/DefaultInputConfigInterface.d.ts +13 -0
  6. package/dist/interfaces/FormBuilder/FormInputKeys.d.ts +6 -0
  7. package/dist/interfaces/FormBuilder/FormInputKeys.js +6 -0
  8. package/dist/interfaces/FormBuilder/inputConfig/ElementEditConfig.js +188 -3
  9. package/dist/interfaces/formInput/APIDataFetchingConfigurationInterface.d.ts +34 -0
  10. package/dist/interfaces/formInput/BasicFormInputInterface.d.ts +1 -0
  11. package/dist/interfaces/formInput/BasicFormInputInterface.js +1 -0
  12. package/dist/interfaces/formInput/IMscoaAccount.d.ts +19 -3
  13. package/dist/interfaces/formInput/ISelectInputInterface.d.ts +12 -0
  14. package/dist/interfaces/formInput/MultipleInterface.d.ts +10 -0
  15. package/dist/interfaces/formInput/WorkflowDocumentPicker.d.ts +2 -0
  16. package/dist/schemas/FormInputSchema.js +41 -2
  17. package/dist/schemas/MatOptionsSchema.js +7 -0
  18. package/dist/schemas/MscoaConfigSchema.js +1 -0
  19. package/dist/schemas/index.d.ts +2 -1
  20. package/dist/schemas/index.js +2 -1
  21. package/dist/skillet/authoring-rules.d.ts +41 -0
  22. package/dist/skillet/authoring-rules.js +61 -0
  23. package/dist/skillet/extra-members.d.ts +143 -0
  24. package/dist/skillet/extra-members.js +79 -0
  25. package/dist/skillet/form.d.ts +170 -0
  26. package/dist/skillet/form.js +139 -0
  27. package/dist/skillet/index.d.ts +43 -0
  28. package/dist/skillet/index.js +46 -0
  29. package/dist/skillet/input-members.d.ts +375 -0
  30. package/dist/skillet/input-members.js +186 -0
  31. package/dist/skillet/internal/coupling.d.ts +63 -0
  32. package/dist/skillet/internal/coupling.js +69 -0
  33. package/dist/skillet/internal/editor-guidance.d.ts +64 -0
  34. package/dist/skillet/internal/editor-guidance.js +291 -0
  35. package/dist/skillet/members/calculated-field.d.ts +155 -0
  36. package/dist/skillet/members/calculated-field.js +105 -0
  37. package/dist/skillet/members/conditional.d.ts +69 -0
  38. package/dist/skillet/members/conditional.js +16 -0
  39. package/dist/skillet/members/document-picker.d.ts +182 -0
  40. package/dist/skillet/members/document-picker.js +111 -0
  41. package/dist/skillet/members/mat-options.d.ts +187 -0
  42. package/dist/skillet/members/mat-options.js +92 -0
  43. package/dist/skillet/members/mscoa.d.ts +182 -0
  44. package/dist/skillet/members/mscoa.js +129 -0
  45. package/dist/skillet/members/pagination.d.ts +59 -0
  46. package/dist/skillet/members/pagination.js +16 -0
  47. package/dist/skillet/members/table.d.ts +178 -0
  48. package/dist/skillet/members/table.js +105 -0
  49. package/dist/skillet/members/validators.d.ts +197 -0
  50. package/dist/skillet/members/validators.js +74 -0
  51. package/dist/skillet/members/value.d.ts +154 -0
  52. package/dist/skillet/members/value.js +97 -0
  53. package/dist/skillet/shared-types.d.ts +57 -0
  54. package/dist/skillet/shared-types.js +69 -0
  55. package/dist/skillet/tests/house-rules.spec.d.ts +1 -0
  56. package/dist/skillet/tests/house-rules.spec.js +162 -0
  57. package/dist/skillet/tests/skillet-coupling.spec.d.ts +1 -0
  58. package/dist/skillet/tests/skillet-coupling.spec.js +191 -0
  59. package/dist/skillet/tests/variant-assembly.spec.d.ts +1 -0
  60. package/dist/skillet/tests/variant-assembly.spec.js +643 -0
  61. package/dist/skillet/variants.d.ts +138 -0
  62. package/dist/skillet/variants.js +536 -0
  63. package/dist/skillet/workflow-context.d.ts +95 -0
  64. package/dist/skillet/workflow-context.js +128 -0
  65. package/package.json +78 -60
@@ -29,7 +29,9 @@ export declare enum FunctionTypes {
29
29
  /** Group items into buckets keyed by one or more paths. Returns a record of arrays. Terminal. */
30
30
  GroupBy = "groupBy",
31
31
  /** Aggregate items into a scalar or summary object (sum/avg/min/max/count/first/last/join). Terminal. */
32
- Reduce = "reduce"
32
+ Reduce = "reduce",
33
+ /** Add derived fields to each item via an arithmetic expression (`alias = a * b`, child aggregates, `round`). Returns an array. */
34
+ Compute = "compute"
33
35
  }
34
36
  /**
35
37
  * A single declarative array-transform step.
@@ -31,5 +31,7 @@ export var FunctionTypes;
31
31
  FunctionTypes["GroupBy"] = "groupBy";
32
32
  /** Aggregate items into a scalar or summary object (sum/avg/min/max/count/first/last/join). Terminal. */
33
33
  FunctionTypes["Reduce"] = "reduce";
34
+ /** Add derived fields to each item via an arithmetic expression (`alias = a * b`, child aggregates, `round`). Returns an array. */
35
+ FunctionTypes["Compute"] = "compute";
34
36
  // Add more function types here as needed
35
37
  })(FunctionTypes || (FunctionTypes = {}));
@@ -1,6 +1,12 @@
1
1
  import { APIDataFetchingConfigurationInterface, MongoDbPipeLineConfigInterface } from "../formInput/index.js";
2
2
  import { DataSources } from "../formInput/APIDataFetchingConfigurationInterface.js";
3
3
  export interface FormSubmissionHandleInterface {
4
+ /**
5
+ * @deprecated Retained only so existing stored forms keep deserialising. Do
6
+ * not set it on new forms, and do not offer it to a model — it is excluded
7
+ * from the Skillet generation schema for the same reason
8
+ * `iServeInputWithRequisitionItems` is.
9
+ */
4
10
  innerComponentShowSubmitButton?: boolean;
5
11
  canSubmitAPI?: Array<APIDataFetchingConfigurationInterface>;
6
12
  submissionAPI: Array<APIDataFetchingConfigurationInterface>;
@@ -33,6 +33,14 @@ export const DefaultInputConfig = {
33
33
  AllFormInputPrimaryKeys.HintLabel,
34
34
  AllFormInputPrimaryKeys.MatOptions,
35
35
  AllFormInputPrimaryKeys.ConditionalInputConfig,
36
+ FormInputKeys.Pattern,
37
+ FormInputKeys.Placeholder,
38
+ FormInputKeys.Autocomplete,
39
+ FormInputKeys.PrefixText,
40
+ FormInputKeys.SuffixText,
41
+ FormInputKeys.PrefixIcon,
42
+ FormInputKeys.SuffixIcon,
43
+ FormInputKeys.Disabled,
36
44
  ],
37
45
  elementTemplate: {
38
46
  element: ElementTypes.Input,
@@ -62,6 +70,7 @@ export const DefaultInputConfig = {
62
70
  AllFormInputPrimaryKeys.FormControlName,
63
71
  AllFormInputPrimaryKeys.Validators, // Assuming Validators is also needed here
64
72
  AllFormInputPrimaryKeys.ConditionalInputConfig,
73
+ FormInputKeys.Disabled,
65
74
  ],
66
75
  elementTemplate: {
67
76
  element: ElementTypes.Location,
@@ -97,6 +106,14 @@ export const DefaultInputConfig = {
97
106
  AllFormInputPrimaryKeys.Value,
98
107
  AllFormInputPrimaryKeys.MatOptions,
99
108
  AllFormInputPrimaryKeys.ConditionalInputConfig,
109
+ FormInputKeys.Pattern,
110
+ FormInputKeys.Placeholder,
111
+ FormInputKeys.Autocomplete,
112
+ FormInputKeys.PrefixText,
113
+ FormInputKeys.SuffixText,
114
+ FormInputKeys.PrefixIcon,
115
+ FormInputKeys.SuffixIcon,
116
+ FormInputKeys.Disabled,
100
117
  ],
101
118
  elementTemplate: {
102
119
  element: ElementTypes.AutoCompleteInput,
@@ -134,6 +151,7 @@ export const DefaultInputConfig = {
134
151
  AllFormInputPrimaryKeys.TrueLabel,
135
152
  AllFormInputPrimaryKeys.FalseLabel,
136
153
  AllFormInputPrimaryKeys.ConditionalInputConfig,
154
+ FormInputKeys.Disabled,
137
155
  ],
138
156
  elementTemplate: {
139
157
  element: ElementTypes.Toggle,
@@ -181,6 +199,9 @@ export const DefaultInputConfig = {
181
199
  AllFormInputPrimaryKeys.OptionSelectType,
182
200
  AllFormInputPrimaryKeys.AllowMultipleSelection,
183
201
  AllFormInputPrimaryKeys.ConditionalInputConfig,
202
+ FormInputKeys.Pattern,
203
+ FormInputKeys.SelectUpto,
204
+ FormInputKeys.Disabled,
184
205
  ],
185
206
  elementTemplate: {
186
207
  element: ElementTypes.Select,
@@ -226,6 +247,8 @@ export const DefaultInputConfig = {
226
247
  AllFormInputPrimaryKeys.AllowMultipleSelection,
227
248
  AllFormInputPrimaryKeys.PaginationSelectionConfig,
228
249
  AllFormInputPrimaryKeys.ConditionalInputConfig,
250
+ FormInputKeys.SelectUpto,
251
+ FormInputKeys.Disabled,
229
252
  ],
230
253
  elementTemplate: {
231
254
  element: ElementTypes.PaginatedSelectionTable,
@@ -260,6 +283,7 @@ export const DefaultInputConfig = {
260
283
  AllFormInputPrimaryKeys.Value,
261
284
  AllFormInputPrimaryKeys.HintLabel,
262
285
  AllFormInputPrimaryKeys.ConditionalInputConfig,
286
+ FormInputKeys.Disabled,
263
287
  ],
264
288
  elementTemplate: {
265
289
  element: ElementTypes.IconSelect,
@@ -304,6 +328,7 @@ export const DefaultInputConfig = {
304
328
  FormInputKeys.Placeholder,
305
329
  AllFormInputPrimaryKeys.Wrap,
306
330
  AllFormInputPrimaryKeys.ConditionalInputConfig,
331
+ FormInputKeys.Disabled,
307
332
  ],
308
333
  elementTemplate: {
309
334
  element: ElementTypes.Textarea,
@@ -350,6 +375,7 @@ export const DefaultInputConfig = {
350
375
  FormInputKeys.PrefixText,
351
376
  FormInputKeys.SuffixText,
352
377
  AllFormInputPrimaryKeys.ConditionalInputConfig,
378
+ FormInputKeys.Disabled,
353
379
  ],
354
380
  elementTemplate: {
355
381
  element: ElementTypes.DatePicker,
@@ -362,6 +388,45 @@ export const DefaultInputConfig = {
362
388
  validators: [],
363
389
  },
364
390
  },
391
+ [ElementTypes.DateTimePicker]: {
392
+ label: 'dateTimePicker',
393
+ illustration: '/assets/datePicker.svg',
394
+ disabled: false,
395
+ requiredProperties: [
396
+ AllFormInputPrimaryKeys.Label,
397
+ AllFormInputPrimaryKeys.Appearance,
398
+ AllFormInputPrimaryKeys.FormControlName,
399
+ AllFormInputPrimaryKeys.Required,
400
+ ],
401
+ properties: [
402
+ AllFormInputPrimaryKeys.Label,
403
+ AllFormInputPrimaryKeys.Appearance,
404
+ AllFormInputPrimaryKeys.FormControlName,
405
+ AllFormInputPrimaryKeys.Validators,
406
+ AllFormInputPrimaryKeys.Required,
407
+ AllFormInputPrimaryKeys.ColSize,
408
+ AllFormInputPrimaryKeys.Value,
409
+ AllFormInputPrimaryKeys.Min,
410
+ AllFormInputPrimaryKeys.Max,
411
+ AllFormInputPrimaryKeys.HintLabel,
412
+ FormInputKeys.SuffixIcon,
413
+ FormInputKeys.PrefixIcon,
414
+ FormInputKeys.PrefixText,
415
+ FormInputKeys.SuffixText,
416
+ AllFormInputPrimaryKeys.ConditionalInputConfig,
417
+ FormInputKeys.Disabled,
418
+ ],
419
+ elementTemplate: {
420
+ element: ElementTypes.DateTimePicker,
421
+ dataType: InputDataTypes.Date,
422
+ appearance: 'outline',
423
+ isCalculatedField: false,
424
+ required: true,
425
+ onlySetTempErrorOnTouch: false,
426
+ colSize: 12,
427
+ validators: [],
428
+ },
429
+ },
365
430
  [ElementTypes.DateRangePicker]: {
366
431
  label: 'dateRangePicker',
367
432
  illustration: '/assets/dateRange.svg',
@@ -394,6 +459,7 @@ export const DefaultInputConfig = {
394
459
  FormInputKeys.PrefixText,
395
460
  FormInputKeys.SuffixText,
396
461
  AllFormInputPrimaryKeys.ConditionalInputConfig,
462
+ FormInputKeys.Disabled,
397
463
  ],
398
464
  elementTemplate: {
399
465
  element: ElementTypes.DateRangePicker,
@@ -436,6 +502,7 @@ export const DefaultInputConfig = {
436
502
  AllFormInputPrimaryKeys.FileType,
437
503
  FormInputKeys.Accept,
438
504
  AllFormInputPrimaryKeys.ConditionalInputConfig,
505
+ FormInputKeys.Disabled,
439
506
  ],
440
507
  elementTemplate: {
441
508
  element: ElementTypes.FileUpload,
@@ -471,6 +538,7 @@ export const DefaultInputConfig = {
471
538
  AllFormInputPrimaryKeys.Required,
472
539
  AllFormInputPrimaryKeys.Value,
473
540
  AllFormInputPrimaryKeys.ConditionalInputConfig,
541
+ FormInputKeys.Disabled,
474
542
  ],
475
543
  elementTemplate: {
476
544
  element: ElementTypes.Signature,
@@ -561,6 +629,7 @@ export const DefaultInputConfig = {
561
629
  AllFormInputPrimaryKeys.Required,
562
630
  AllFormInputPrimaryKeys.Value,
563
631
  AllFormInputPrimaryKeys.ConditionalInputConfig,
632
+ FormInputKeys.Disabled,
564
633
  ],
565
634
  elementTemplate: {
566
635
  element: ElementTypes.ImageCapture,
@@ -643,6 +712,8 @@ export const DefaultInputConfig = {
643
712
  AllFormInputPrimaryKeys.WorkflowPickerConfig,
644
713
  AllFormInputPrimaryKeys.AllowMultipleSelection,
645
714
  AllFormInputPrimaryKeys.ConditionalInputConfig,
715
+ FormInputKeys.SelectUpto,
716
+ FormInputKeys.Disabled,
646
717
  ],
647
718
  elementTemplate: {
648
719
  element: ElementTypes.WorkflowDocumentPicker,
@@ -679,6 +750,7 @@ export const DefaultInputConfig = {
679
750
  AllFormInputPrimaryKeys.MinLength,
680
751
  AllFormInputPrimaryKeys.MaxLength,
681
752
  AllFormInputPrimaryKeys.ConditionalInputConfig,
753
+ FormInputKeys.Disabled,
682
754
  ],
683
755
  elementTemplate: {
684
756
  element: ElementTypes.WorkflowAdjudication,
@@ -751,6 +823,8 @@ export const DefaultInputConfig = {
751
823
  AllFormInputPrimaryKeys.HandleLabel,
752
824
  SpecialElementKeys.MultipleInputAvailableOperations,
753
825
  AllFormInputPrimaryKeys.ConditionalInputConfig,
826
+ FormInputKeys.ShowTotalsOf,
827
+ FormInputKeys.Disabled,
754
828
  ],
755
829
  elementTemplate: {
756
830
  element: ElementTypes.MultipleInput,
@@ -787,6 +861,7 @@ export const DefaultInputConfig = {
787
861
  AllFormInputPrimaryKeys.HintLabel,
788
862
  AllFormInputPrimaryKeys.RichTextEditorLibrary,
789
863
  AllFormInputPrimaryKeys.ConditionalInputConfig,
864
+ FormInputKeys.Disabled,
790
865
  ],
791
866
  elementTemplate: {
792
867
  element: ElementTypes.Editor,
@@ -821,6 +896,7 @@ export const DefaultInputConfig = {
821
896
  AllFormInputPrimaryKeys.MatOptions,
822
897
  AllFormInputPrimaryKeys.MscoaConfig,
823
898
  AllFormInputPrimaryKeys.ConditionalInputConfig,
899
+ FormInputKeys.Disabled,
824
900
  ],
825
901
  elementTemplate: {
826
902
  element: ElementTypes.MscoaSelection,
@@ -88,6 +88,19 @@ export interface DefaultInputConfigInterface {
88
88
  elementTemplate: IFormElementTemplate;
89
89
  requiredProperties: Array<FormInputKeys | AllFormInputPrimaryKeys>;
90
90
  };
91
+ /**
92
+ * Single date-and-time control. Shares {@link IFormElementTemplate} with the
93
+ * plain date picker — it adds no member of its own, because the time is part
94
+ * of the one `Date` the element already stores.
95
+ */
96
+ [ElementTypes.DateTimePicker]?: {
97
+ label: string;
98
+ disabled: boolean;
99
+ illustration: string;
100
+ properties: Array<FormInputKeys | AllFormInputPrimaryKeys>;
101
+ elementTemplate: IFormElementTemplate;
102
+ requiredProperties: Array<FormInputKeys | AllFormInputPrimaryKeys>;
103
+ };
91
104
  [ElementTypes.DateRangePicker]?: {
92
105
  label: string;
93
106
  disabled: boolean;
@@ -62,6 +62,12 @@ export declare enum AllFormInputPrimaryKeys {
62
62
  Value = "value",
63
63
  DataType = "dataType",
64
64
  Readonly = "readonly",
65
+ /**
66
+ * @deprecated Superseded and retained only so existing stored forms keep
67
+ * deserialising. Do not set it on new inputs, and do not offer it to a
68
+ * model: it is excluded from the Skillet generation schemas by way of
69
+ * `DEPRECATED_INPUT_MEMBERS`.
70
+ */
65
71
  IServeInputWithRequisitionItems = "iServeInputWithRequisitionItems",
66
72
  CalculatedFieldRules = "calculatedFieldRules",
67
73
  MatOptions = "matOptions",
@@ -66,6 +66,12 @@ export var AllFormInputPrimaryKeys;
66
66
  AllFormInputPrimaryKeys["Value"] = "value";
67
67
  AllFormInputPrimaryKeys["DataType"] = "dataType";
68
68
  AllFormInputPrimaryKeys["Readonly"] = "readonly";
69
+ /**
70
+ * @deprecated Superseded and retained only so existing stored forms keep
71
+ * deserialising. Do not set it on new inputs, and do not offer it to a
72
+ * model: it is excluded from the Skillet generation schemas by way of
73
+ * `DEPRECATED_INPUT_MEMBERS`.
74
+ */
69
75
  AllFormInputPrimaryKeys["IServeInputWithRequisitionItems"] = "iServeInputWithRequisitionItems";
70
76
  AllFormInputPrimaryKeys["CalculatedFieldRules"] = "calculatedFieldRules";
71
77
  AllFormInputPrimaryKeys["MatOptions"] = "matOptions";
@@ -1,13 +1,13 @@
1
1
  import { CurrenciesList } from "../../../Configs/currencies.js";
2
2
  import { DatePipeOptions } from "../../../Configs/datePipes.js";
3
- import { AdjudicationSteps, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from "../../formInput/index.js";
3
+ import { AdjudicationSteps, AutocompleteOptions, ElementTypes, InputDataTypes, InputPipeTypes, InputTypes } from "../../formInput/index.js";
4
4
  import { DataSources } from "../../formInput/APIDataFetchingConfigurationInterface.js";
5
5
  import { OptionSelectTypes } from "../../formInput/BasicFormInputInterface.js";
6
6
  import { InputFileType } from "../../formInput/FileUploadInputInterface.js";
7
7
  import { MultipleInputAvailableOperations } from "../../formInput/MultipleInterface.js";
8
8
  import { RichTextEditorType } from "../../formInput/RichTextEditorInput.js";
9
9
  import { LabelPosition } from "../../formInput/ToggleInputInterface.js";
10
- import { AllFormInputPrimaryKeys, SpecialElementKeys } from "../FormInputKeys.js";
10
+ import { AllFormInputPrimaryKeys, FormInputKeys, SpecialElementKeys } from "../FormInputKeys.js";
11
11
  import { BlurHandleTypes, ElementEditorTypes } from "../elementEditor.js";
12
12
  import { DOCUMENT_PICKER_FILTER_OPERATORS, DOCUMENT_PICKER_FILTER_VALUE_SOURCES, DOCUMENT_PICKER_FILTER_VALUE_TYPES } from "../../formInput/WorkflowDocumentPicker.js";
13
13
  /** Human-facing names for the document-picker filter operators. */
@@ -191,7 +191,7 @@ export const MSCOA_DUAL_CASH_EXCLUSION_RULE_EDITOR = () => [
191
191
  label: 'Regular expression',
192
192
  required: true,
193
193
  placeholder: '^Expenditure:Depreciation',
194
- hint: `A JavaScript regular expression (without the surrounding slashes). It is tested against each selected accrual account's SCOA account value and against the configured account value label field. An invalid expression never matches, so it can never suppress cash by accident.`,
194
+ hint: `A JavaScript regular expression (without the surrounding slashes). It is tested against each selected accrual account's SCOA account value and against one labelled field — the account value label configured for this input, unless this rule names a different one under 'Test against field'. An invalid expression never matches, so it can never suppress cash by accident.`,
195
195
  id: "3b7e9f52-0d84-4c16-a2e8-7f5c1d90b364"
196
196
  },
197
197
  {
@@ -203,6 +203,25 @@ export const MSCOA_DUAL_CASH_EXCLUSION_RULE_EDITOR = () => [
203
203
  hint: `Optional regular-expression flags, e.g. "i" for a case-insensitive match. Leave empty for an exact-case match.`,
204
204
  id: "6a1c8e40-935f-4d27-b8e3-0c4d7f26a591"
205
205
  },
206
+ {
207
+ name: SpecialElementKeys.Default,
208
+ deepBind: ['matchField'],
209
+ editType: ElementEditorTypes.ChipSelect,
210
+ label: 'Test against field',
211
+ // The full pool is listed here rather than filled in at runtime: unlike
212
+ // the segment scope, which only this input knows, the fields an account
213
+ // can be read by are the same everywhere. The MSCOA setup editor still
214
+ // relabels the leading entry with the field actually configured, so an
215
+ // administrator can see what the default resolves to. NO `defaultValue`,
216
+ // so opening a saved rule never stamps a field onto it — absent means
217
+ // "whatever the input displays accounts by", and must stay absent.
218
+ options: [
219
+ { label: 'Configured account value label', value: '' },
220
+ ...MSCOA_ACCOUNT_VALUE_LABEL_OPTIONS,
221
+ ],
222
+ hint: `Optional. Which labelled field of the account the expression is tested against. Leave it on 'Configured account value label' to test the field this input displays accounts by. The account's SCOA account value is always tested as well, whichever field is chosen — this only changes the second one. A field the selected accounts do not carry contributes nothing to test, so the rule falls back to the SCOA account value alone.`,
223
+ id: "9d4a1c6e-2f83-4b57-a0d6-3e7b5c81f294"
224
+ },
206
225
  {
207
226
  name: SpecialElementKeys.Default,
208
227
  deepBind: ['segment'],
@@ -451,6 +470,24 @@ export var ElementConfig = {
451
470
  label: 'Allow multiple selection',
452
471
  hint: `When enabled, users can select multiple options from the list. This is useful for inputs like tags or categories.`,
453
472
  },
473
+ {
474
+ // Sits directly below the toggle it depends on, and stays hidden until
475
+ // that toggle is on: a cap on how many options may be chosen says
476
+ // nothing about a control that already allows exactly one.
477
+ name: FormInputKeys.SelectUpto,
478
+ deepBind: [FormInputKeys.SelectUpto],
479
+ editType: ElementEditorTypes.Input,
480
+ label: 'Maximum selections',
481
+ min: 1,
482
+ hint: `Leave it empty for no limit.`,
483
+ additionalTest: [
484
+ {
485
+ expression: `${AllFormInputPrimaryKeys.AllowMultipleSelection} === true`,
486
+ deepBind: [AllFormInputPrimaryKeys.AllowMultipleSelection],
487
+ },
488
+ ],
489
+ id: "5c1a7e93-2b48-4d6f-9a07-e83b15fc2d40"
490
+ },
454
491
  {
455
492
  name: AllFormInputPrimaryKeys.FileType,
456
493
  editType: ElementEditorTypes.OptionSelect,
@@ -512,6 +549,14 @@ export var ElementConfig = {
512
549
  label: 'Max length of characters',
513
550
  id: "9bc50894-5230-46f2-91de-b45673b3a80a"
514
551
  },
552
+ {
553
+ name: FormInputKeys.Pattern,
554
+ deepBind: [FormInputKeys.Pattern],
555
+ editType: ElementEditorTypes.Input,
556
+ label: 'Value format (regex)',
557
+ hint: 'A regular expression the value must match in full — it is anchored for you, so \\d{13} means exactly 13 digits and nothing else. Leave blank for no format restriction. An expression that does not compile is ignored rather than rejecting every entry.',
558
+ id: "3305046e-1ef6-4595-acef-946c9beb2fb1"
559
+ },
515
560
  {
516
561
  name: SpecialElementKeys.MultipleInputAvailableOperations,
517
562
  deepBind: [SpecialElementKeys.MultipleInputAvailableOperations],
@@ -535,6 +580,19 @@ export var ElementConfig = {
535
580
  label: 'Handle label',
536
581
  id: "3f056cc9-e639-4db7-aa41-3f96593356b2"
537
582
  },
583
+ {
584
+ // Only an item list has rows to total, so this is scoped to it through
585
+ // `properties` rather than shown everywhere. The names it takes are the
586
+ // columns declared in `formInputs`, which is why it sits with the list
587
+ // settings rather than with the formatting rows.
588
+ name: FormInputKeys.ShowTotalsOf,
589
+ deepBind: [FormInputKeys.ShowTotalsOf],
590
+ editType: ElementEditorTypes.FormInputSelector,
591
+ multipleSelection: true,
592
+ label: 'Show totals for',
593
+ hint: `The total is shown beneath the rows. Only numeric columns total meaningfully.`,
594
+ id: "9b6f0d27-3c54-41ae-8d19-7a2e6b40cf85"
595
+ },
538
596
  {
539
597
  name: AllFormInputPrimaryKeys.MscoaConfig,
540
598
  deepBind: ['mscoaConfig'],
@@ -745,6 +803,19 @@ export var ElementConfig = {
745
803
  label: 'Set as readonly field',
746
804
  id: "cdc5173b-8464-4e03-b0fb-6258437fa50b"
747
805
  },
806
+ {
807
+ // Deliberately NOT a `SpecialElementKeys.Default` row like `readonly`
808
+ // above it. A Default row shows on every element, and a section heading
809
+ // captures no value and renders no control, so there is nothing there to
810
+ // disable. Naming the key scopes the row to the elements whose
811
+ // `properties` list it — every element except the section title.
812
+ name: FormInputKeys.Disabled,
813
+ deepBind: [FormInputKeys.Disabled],
814
+ editType: ElementEditorTypes.Toggle,
815
+ label: 'Set as disabled field',
816
+ hint: `Its value is left out of the submitted form entirely. Use readonly instead when the value should still be submitted.`,
817
+ id: "7d4c8a15-6e29-4b30-a5f1-c026b9e78314"
818
+ },
748
819
  {
749
820
  name: SpecialElementKeys.Default,
750
821
  editType: ElementEditorTypes.Toggle,
@@ -849,6 +920,71 @@ export var ElementConfig = {
849
920
  label: 'API endpoint',
850
921
  id: "c9e2f7a4-1b58-4d03-9a6e-2f84c1b0d597"
851
922
  },
923
+ {
924
+ // Opt-out of the read-only lock the tower puts on every value
925
+ // it owns — the SCALAR half. Offered only for an `api` value
926
+ // source: a scalar that is inherited from another input
927
+ // (`local`) or calculated recomputes from a field the user can
928
+ // already edit, so it stays read-only with no opt-out. The
929
+ // complex (object / array) half is the NEXT entry, which binds
930
+ // the same key under a different rule — see there. Lives inside
931
+ // the fetch slot so the source chip's `clearOnChange` above
932
+ // wipes it when the source changes.
933
+ name: SpecialElementKeys.Default,
934
+ deepBind: ['matOptions', 'fetch', 'value', 'allowManualValueEntry'],
935
+ editType: ElementEditorTypes.Toggle,
936
+ additionalTest: [
937
+ {
938
+ expression: `source === ${DataSources.Api}`,
939
+ deepBind: ['matOptions', 'fetch', 'value', 'source'],
940
+ },
941
+ {
942
+ // Scalars only — this is what keeps the two halves of the key
943
+ // mutually exclusive. `additionalTest` entries are AND-ed and
944
+ // each one sees ONLY its own bound key, so an either/or across
945
+ // two paths is expressed as two complementary tests, one per
946
+ // entry. An input with no declared `dataType` reads as scalar,
947
+ // which is what every config written before this rule was.
948
+ expression: `dataType !== '${InputDataTypes.Object}' && dataType !== '${InputDataTypes.Array}'`,
949
+ deepBind: ['dataType'],
950
+ },
951
+ ],
952
+ hint: `Off by default: a value fetched from an API is locked, because anything typed over it is replaced the next time the endpoint answers. Turn this on to leave the field editable so a user can supply a value themselves when the endpoint returns nothing — no response yet, an empty response, or a failed request. A non-empty response still wins and replaces what they typed.`,
953
+ label: 'Allow manual entry when the API returns nothing',
954
+ id: "0f0a1c7e-4d92-4f6b-9a31-7c5e8b2d64af"
955
+ },
956
+ {
957
+ // The COMPLEX half of the same key: an input whose value is an
958
+ // object or an array (mSCOA, MultipleInput). Offered for an
959
+ // inherited (`local`) source as well as an `api` one, because a
960
+ // multi-dimensional value can arrive PARTIALLY populated — an
961
+ // mSCOA that inherits two of its segments, rows that come back
962
+ // missing a column — and the user has to be able to finish it.
963
+ // The lock is lifted and the tower re-merges instead: each change
964
+ // in the derived value is applied as a delta, so what the tower
965
+ // supplies updates and what the user added survives.
966
+ //
967
+ // Gated on a picked source because the flag has nowhere to live
968
+ // until the fetch value slot exists; a purely calculated complex
969
+ // value therefore has no toggle here, though the engine honours
970
+ // the flag if one is present.
971
+ name: SpecialElementKeys.Default,
972
+ deepBind: ['matOptions', 'fetch', 'value', 'allowManualValueEntry'],
973
+ editType: ElementEditorTypes.Toggle,
974
+ additionalTest: [
975
+ {
976
+ expression: `dataType === '${InputDataTypes.Object}' || dataType === '${InputDataTypes.Array}'`,
977
+ deepBind: ['dataType'],
978
+ },
979
+ {
980
+ expression: `source === ${DataSources.Api} || source === ${DataSources.Local}`,
981
+ deepBind: ['matOptions', 'fetch', 'value', 'source'],
982
+ },
983
+ ],
984
+ hint: `Off by default: a value the form works out for itself — fetched from an API or inherited from another field — is locked, because anything typed over it is replaced the next time the form works it out. Turn this on when the value can arrive incomplete and the user has to finish it: an API that answers with rows that are missing a column, or an mSCOA that inherits only some of its segments. The field stays editable, and when the form works the value out again only what actually changed is applied over it — whatever the user added is kept.`,
985
+ label: 'Allow the user to complete this value',
986
+ id: "3c6b58d1-9f42-4e07-b8a5-1d90e7c4af62"
987
+ },
852
988
  {
853
989
  name: SpecialElementKeys.Default,
854
990
  deepBind: ['matOptions', 'fetch', 'value'],
@@ -1076,6 +1212,55 @@ export var ElementConfig = {
1076
1212
  deepBind: ['conditionalInputConfig'],
1077
1213
  id: "3f2b1c74-9d6e-4a58-9b2f-27c5a1e4d803"
1078
1214
  },
1215
+ {
1216
+ name: FormInputKeys.Placeholder,
1217
+ deepBind: [FormInputKeys.Placeholder],
1218
+ editType: ElementEditorTypes.Input,
1219
+ label: 'Placeholder',
1220
+ hint: `Give an example of a valid value rather than repeating the label.`,
1221
+ id: "1e8b47f0-9a25-4c63-b7d8-2f5091ac36be"
1222
+ },
1223
+ {
1224
+ name: FormInputKeys.Autocomplete,
1225
+ deepBind: [FormInputKeys.Autocomplete],
1226
+ editType: ElementEditorTypes.ChipSelect,
1227
+ label: 'Browser autofill',
1228
+ hint: `Turn this off for one-time values such as a reference number or an OTP, which should never be autofilled.`,
1229
+ options: Object.values(AutocompleteOptions).map((option) => ({ label: option, value: option })),
1230
+ id: "4a09c6d3-5e71-4820-9bf6-83d2e5107ca9"
1231
+ },
1232
+ {
1233
+ name: FormInputKeys.PrefixText,
1234
+ deepBind: [FormInputKeys.PrefixText],
1235
+ editType: ElementEditorTypes.Input,
1236
+ label: 'Prefix text',
1237
+ hint: `For example a currency symbol.`,
1238
+ id: "6c35f9a2-0b84-4e17-95da-71c8046be3f2"
1239
+ },
1240
+ {
1241
+ name: FormInputKeys.SuffixText,
1242
+ deepBind: [FormInputKeys.SuffixText],
1243
+ editType: ElementEditorTypes.Input,
1244
+ label: 'Suffix text',
1245
+ hint: `For example a unit such as kg or %.`,
1246
+ id: "b8e14d70-2c96-4a5b-8317-df60259ea4c1"
1247
+ },
1248
+ {
1249
+ name: FormInputKeys.PrefixIcon,
1250
+ deepBind: [FormInputKeys.PrefixIcon],
1251
+ editType: ElementEditorTypes.Input,
1252
+ label: 'Prefix icon',
1253
+ hint: `For example search or person.`,
1254
+ id: "d27a6301-4f58-49ce-b0a2-95e7361c8fd4"
1255
+ },
1256
+ {
1257
+ name: FormInputKeys.SuffixIcon,
1258
+ deepBind: [FormInputKeys.SuffixIcon],
1259
+ editType: ElementEditorTypes.Input,
1260
+ label: 'Suffix icon',
1261
+ hint: `For example visibility or calendar_today.`,
1262
+ id: "af503b8e-1d67-4290-83c5-6e214b90daf7"
1263
+ },
1079
1264
  ],
1080
1265
  },
1081
1266
  ],
@@ -199,6 +199,40 @@ export interface APIDataFetchingConfigurationInterface extends DataFetchingBaseC
199
199
  * interpreted — mirrors the other `captured*` seeds.
200
200
  */
201
201
  capturedDocs?: string;
202
+ /**
203
+ * Opts this value out of the automatic read-only lock, so a user may supply
204
+ * what the tower's own value leaves out.
205
+ *
206
+ * An input whose value the tower owns is rendered read-only by default — a
207
+ * typed-over value would only be overwritten on the derived signal's next
208
+ * evaluation. This flag lifts that lock, and what it then means depends on
209
+ * the SHAPE the input declares in its `dataType`:
210
+ *
211
+ * **Scalar** (`string`, `number`, `boolean`, `date`, …) — the editor's *Allow
212
+ * manual entry when the API returns nothing* toggle, offered only on an `api`
213
+ * value source. The manually entered value stands **whenever the fetch
214
+ * contributes nothing** — no response yet, a `null` / empty response, or a
215
+ * failed request. A non-empty response always wins. A scalar that is
216
+ * calculated (`calculatedFieldRules`) or inherited from another input
217
+ * (`source: 'local'`) is read-only unconditionally and ignores this flag,
218
+ * because its derived signal recomputes synchronously from inputs the user
219
+ * can already edit.
220
+ *
221
+ * **Complex** (`dataType: 'object' | 'array'` — mSCOA, MultipleInput) — the
222
+ * editor's *Allow the user to complete this value* toggle, offered on a
223
+ * `local` value source as well as an `api` one. A multi-dimensional value can
224
+ * arrive partially populated (an mSCOA that inherits two of its segments,
225
+ * rows that come back missing a column), so the field stays editable and the
226
+ * tower **re-merges** rather than replacing: every change in the derived value
227
+ * is applied over the live value as a delta — what the tower supplies updates,
228
+ * what the user added survives. The first value the tower produces is taken
229
+ * whole; there is no earlier value to diff it against.
230
+ *
231
+ * Absent / `false` ⇒ the historical behaviour: the field is locked.
232
+ *
233
+ * @defaultValue false
234
+ */
235
+ allowManualValueEntry?: boolean;
202
236
  backEndConfig: {
203
237
  /**
204
238
  * The default/mapTo mapping that shapes the POST body in `'mappedInputs'` mode.
@@ -24,6 +24,7 @@ export declare enum ElementTypes {
24
24
  IconSelect = "iconSelect",
25
25
  Textarea = "textarea",
26
26
  DatePicker = "datePicker",
27
+ DateTimePicker = "dateTimePicker",
27
28
  DateRangePicker = "dateRangePicker",
28
29
  FileUpload = "fileUpload",
29
30
  Signature = "signature",
@@ -8,6 +8,7 @@ export var ElementTypes;
8
8
  ElementTypes["IconSelect"] = "iconSelect";
9
9
  ElementTypes["Textarea"] = "textarea";
10
10
  ElementTypes["DatePicker"] = "datePicker";
11
+ ElementTypes["DateTimePicker"] = "dateTimePicker";
11
12
  ElementTypes["DateRangePicker"] = "dateRangePicker";
12
13
  ElementTypes["FileUpload"] = "fileUpload";
13
14
  ElementTypes["Signature"] = "signature";
@@ -133,9 +133,11 @@ export type DualCashExclusionMatchMode = 'any' | 'all';
133
133
  * one selected accrual account value in its segment scope.
134
134
  *
135
135
  * The pattern is tested against the account's `SCOAAccount` value AND the value
136
- * of the field named by {@link IScoaInputConfig.accountValueLabel} (what the
137
- * user sees selected in the chart). An invalid pattern never matches — it can
138
- * therefore never suppress the cash requirement by accident.
136
+ * of ONE labelled field: by default the field named by
137
+ * {@link IScoaInputConfig.accountValueLabel} (what the user sees selected in the
138
+ * chart), or when the rule sets one — the field named by
139
+ * {@link IDualCashExclusionRule.matchField}. An invalid pattern never matches, so
140
+ * it can never suppress the cash requirement by accident.
139
141
  */
140
142
  export interface IDualCashExclusionRule {
141
143
  /** Stable record id (stamped by the builder's record-list editor). */
@@ -144,6 +146,20 @@ export interface IDualCashExclusionRule {
144
146
  pattern: string;
145
147
  /** Optional regex flags (e.g. `i`). Invalid flags make the rule evaluate as not matched. */
146
148
  flags?: string;
149
+ /**
150
+ * Optional per-rule override of WHICH labelled account field the pattern is
151
+ * tested against, named exactly as the account carries it — the same pool the
152
+ * `accountValueLabel` picker offers (e.g. `ShortDescription`).
153
+ *
154
+ * Empty or absent means the input's configured
155
+ * {@link IScoaInputConfig.accountValueLabel}, which is the default and leaves
156
+ * every rule saved before this member existed evaluating exactly as it did.
157
+ * The account's `SCOAAccount` value is always tested as well, whatever this
158
+ * holds — the override replaces the labelled field only. A field the selected
159
+ * account does not carry contributes no candidate, so such a rule falls back to
160
+ * testing `SCOAAccount` alone rather than matching everything.
161
+ */
162
+ matchField?: string;
147
163
  /**
148
164
  * Optional segment scope (matched case-insensitively against the accrual
149
165
  * segment key, e.g. `ITEM`). Empty/absent = every accrual segment.