@pnp/spfx-controls-react 3.17.0-beta.6997969 → 3.17.0-beta.7072507

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 (117) hide show
  1. package/CHANGELOG.json +6 -2
  2. package/CHANGELOG.md +8 -0
  3. package/lib/common/SPEntities.d.ts +5 -0
  4. package/lib/common/SPEntities.d.ts.map +1 -1
  5. package/lib/common/telemetry/version.js +1 -1
  6. package/lib/common/utilities/CustomFormatting.d.ts +31 -0
  7. package/lib/common/utilities/CustomFormatting.d.ts.map +1 -0
  8. package/lib/common/utilities/CustomFormatting.js +160 -0
  9. package/lib/common/utilities/CustomFormatting.js.map +1 -0
  10. package/lib/common/utilities/FormulaEvaluation.d.ts +21 -0
  11. package/lib/common/utilities/FormulaEvaluation.d.ts.map +1 -0
  12. package/lib/common/utilities/FormulaEvaluation.js +612 -0
  13. package/lib/common/utilities/FormulaEvaluation.js.map +1 -0
  14. package/lib/common/utilities/FormulaEvaluation.types.d.ts +23 -0
  15. package/lib/common/utilities/FormulaEvaluation.types.d.ts.map +1 -0
  16. package/lib/common/utilities/FormulaEvaluation.types.js +80 -0
  17. package/lib/common/utilities/FormulaEvaluation.types.js.map +1 -0
  18. package/lib/common/utilities/ICustomFormatting.d.ts +27 -0
  19. package/lib/common/utilities/ICustomFormatting.d.ts.map +1 -0
  20. package/lib/common/utilities/ICustomFormatting.js +2 -0
  21. package/lib/common/utilities/ICustomFormatting.js.map +1 -0
  22. package/lib/controls/dynamicForm/DynamicForm.d.ts +56 -5
  23. package/lib/controls/dynamicForm/DynamicForm.d.ts.map +1 -1
  24. package/lib/controls/dynamicForm/DynamicForm.js +966 -545
  25. package/lib/controls/dynamicForm/DynamicForm.js.map +1 -1
  26. package/lib/controls/dynamicForm/DynamicForm.module.css +2 -2
  27. package/lib/controls/dynamicForm/DynamicForm.module.scss.d.ts +5 -0
  28. package/lib/controls/dynamicForm/DynamicForm.module.scss.d.ts.map +1 -1
  29. package/lib/controls/dynamicForm/DynamicForm.module.scss.js +25 -20
  30. package/lib/controls/dynamicForm/DynamicForm.module.scss.js.map +1 -1
  31. package/lib/controls/dynamicForm/IDynamicFormProps.d.ts +23 -0
  32. package/lib/controls/dynamicForm/IDynamicFormProps.d.ts.map +1 -1
  33. package/lib/controls/dynamicForm/IDynamicFormState.d.ts +28 -0
  34. package/lib/controls/dynamicForm/IDynamicFormState.d.ts.map +1 -1
  35. package/lib/controls/dynamicForm/dynamicField/DynamicField.d.ts.map +1 -1
  36. package/lib/controls/dynamicForm/dynamicField/DynamicField.js +57 -42
  37. package/lib/controls/dynamicForm/dynamicField/DynamicField.js.map +1 -1
  38. package/lib/controls/dynamicForm/dynamicField/IDynamicFieldProps.d.ts +32 -11
  39. package/lib/controls/dynamicForm/dynamicField/IDynamicFieldProps.d.ts.map +1 -1
  40. package/lib/controls/fieldCollectionData/collectionDataItem/CollectionDataItem.js.map +1 -1
  41. package/lib/controls/webPartTitle/WebPartTitle.js +1 -1
  42. package/lib/controls/webPartTitle/WebPartTitle.js.map +1 -1
  43. package/lib/loc/bg-bg.js +3 -0
  44. package/lib/loc/bg-bg.js.map +1 -1
  45. package/lib/loc/ca-es.js +3 -0
  46. package/lib/loc/ca-es.js.map +1 -1
  47. package/lib/loc/da-dk.js +3 -0
  48. package/lib/loc/da-dk.js.map +1 -1
  49. package/lib/loc/de-de.js +3 -0
  50. package/lib/loc/de-de.js.map +1 -1
  51. package/lib/loc/el-gr.js +3 -0
  52. package/lib/loc/el-gr.js.map +1 -1
  53. package/lib/loc/en-us.js +3 -0
  54. package/lib/loc/en-us.js.map +1 -1
  55. package/lib/loc/es-es.js +3 -0
  56. package/lib/loc/es-es.js.map +1 -1
  57. package/lib/loc/et-ee.js +3 -0
  58. package/lib/loc/et-ee.js.map +1 -1
  59. package/lib/loc/eu-es.js +3 -0
  60. package/lib/loc/eu-es.js.map +1 -1
  61. package/lib/loc/fi-fi.js +3 -0
  62. package/lib/loc/fi-fi.js.map +1 -1
  63. package/lib/loc/fr-ca.js +3 -0
  64. package/lib/loc/fr-ca.js.map +1 -1
  65. package/lib/loc/fr-fr.js +3 -0
  66. package/lib/loc/fr-fr.js.map +1 -1
  67. package/lib/loc/it-it.js +3 -0
  68. package/lib/loc/it-it.js.map +1 -1
  69. package/lib/loc/ja-jp.js +3 -0
  70. package/lib/loc/ja-jp.js.map +1 -1
  71. package/lib/loc/lt-lt.js +3 -0
  72. package/lib/loc/lt-lt.js.map +1 -1
  73. package/lib/loc/lv-lv.js +3 -0
  74. package/lib/loc/lv-lv.js.map +1 -1
  75. package/lib/loc/nb-no.js +3 -0
  76. package/lib/loc/nb-no.js.map +1 -1
  77. package/lib/loc/nl-nl.js +3 -0
  78. package/lib/loc/nl-nl.js.map +1 -1
  79. package/lib/loc/pl-pl.js +3 -0
  80. package/lib/loc/pl-pl.js.map +1 -1
  81. package/lib/loc/pt-br.js +3 -0
  82. package/lib/loc/pt-br.js.map +1 -1
  83. package/lib/loc/pt-pt.js +3 -0
  84. package/lib/loc/pt-pt.js.map +1 -1
  85. package/lib/loc/ro-ro.js +3 -0
  86. package/lib/loc/ro-ro.js.map +1 -1
  87. package/lib/loc/ru-ru.js +3 -0
  88. package/lib/loc/ru-ru.js.map +1 -1
  89. package/lib/loc/sk-sk.js +3 -0
  90. package/lib/loc/sk-sk.js.map +1 -1
  91. package/lib/loc/sr-latn-rs.js +3 -0
  92. package/lib/loc/sr-latn-rs.js.map +1 -1
  93. package/lib/loc/sv-se.js +3 -0
  94. package/lib/loc/sv-se.js.map +1 -1
  95. package/lib/loc/tr-tr.js +3 -0
  96. package/lib/loc/tr-tr.js.map +1 -1
  97. package/lib/loc/vi-vn.js +3 -0
  98. package/lib/loc/vi-vn.js.map +1 -1
  99. package/lib/loc/zh-cn.js +3 -0
  100. package/lib/loc/zh-cn.js.map +1 -1
  101. package/lib/loc/zh-tw.js +3 -0
  102. package/lib/loc/zh-tw.js.map +1 -1
  103. package/lib/services/ISPService.d.ts +194 -0
  104. package/lib/services/ISPService.d.ts.map +1 -1
  105. package/lib/services/ISPService.js +13 -0
  106. package/lib/services/ISPService.js.map +1 -1
  107. package/lib/services/SPService.d.ts +10 -1
  108. package/lib/services/SPService.d.ts.map +1 -1
  109. package/lib/services/SPService.js +69 -0
  110. package/lib/services/SPService.js.map +1 -1
  111. package/lib/services/SPServiceMock.d.ts +3 -1
  112. package/lib/services/SPServiceMock.d.ts.map +1 -1
  113. package/lib/services/SPServiceMock.js +6 -0
  114. package/lib/services/SPServiceMock.js.map +1 -1
  115. package/package.json +1 -1
  116. package/release/manifests/45165954-80f9-44c1-9967-cd38ae92a33b.manifest.json +58 -3
  117. package/tests/utils/formulaevaluation.test.ts +248 -0
@@ -61,21 +61,28 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
61
61
  }
62
62
  };
63
63
  /* eslint-disable @microsoft/spfx/no-async-await */
64
- import { SPHttpClient } from "@microsoft/sp-http";
65
- import { sp } from "@pnp/sp/presets/all";
64
+ import * as React from "react";
66
65
  import * as strings from "ControlStrings";
66
+ import styles from "./DynamicForm.module.scss";
67
+ // Controls
67
68
  import { DefaultButton, PrimaryButton, } from "@fluentui/react/lib/Button";
69
+ import { Dialog, DialogFooter, DialogType, } from "@fluentui/react/lib/Dialog";
70
+ import { MessageBar, MessageBarType } from "@fluentui/react/lib/MessageBar";
68
71
  import { ProgressIndicator } from "@fluentui/react/lib/ProgressIndicator";
69
72
  import { Stack } from "@fluentui/react/lib/Stack";
70
- import * as React from "react";
71
- import SPservice from "../../services/SPService";
73
+ import { Icon } from "@fluentui/react/lib/components/Icon/Icon";
72
74
  import { DynamicField } from "./dynamicField";
73
- import styles from "./DynamicForm.module.scss";
74
- import { Dialog, DialogFooter, DialogType, } from "@fluentui/react/lib/Dialog";
75
+ import { FilePicker } from "../filePicker";
76
+ // pnp/sp, helpers / utils
77
+ import { sp } from "@pnp/sp";
75
78
  import "@pnp/sp/lists";
76
79
  import "@pnp/sp/content-types";
77
80
  import "@pnp/sp/folders";
78
81
  import "@pnp/sp/items";
82
+ import { cloneDeep, isEqual } from "lodash";
83
+ import SPservice from "../../services/SPService";
84
+ import { FormulaEvaluation } from "../../common/utilities/FormulaEvaluation";
85
+ import CustomFormattingHelper from "../../common/utilities/CustomFormatting";
79
86
  var stackTokens = { childrenGap: 20 };
80
87
  /**
81
88
  * DynamicForm Class Control
@@ -87,58 +94,99 @@ var DynamicForm = /** @class */ (function (_super) {
87
94
  _this.webURL = _this.props.webAbsoluteUrl
88
95
  ? _this.props.webAbsoluteUrl
89
96
  : _this.props.context.pageContext.web.absoluteUrl;
90
- //trigger when the user submits the form.
97
+ _this.renderField = function (field) {
98
+ var fieldOverrides = _this.props.fieldOverrides;
99
+ var _a = _this.state, hiddenByFormula = _a.hiddenByFormula, isSaving = _a.isSaving, validationErrors = _a.validationErrors;
100
+ // If the field is hidden by a formula, don't render it
101
+ if (hiddenByFormula.find(function (h) { return h === field.columnInternalName; })) {
102
+ return null;
103
+ }
104
+ // If validation error, show error message
105
+ var validationErrorMessage = "";
106
+ if (validationErrors[field.columnInternalName]) {
107
+ validationErrorMessage = validationErrors[field.columnInternalName];
108
+ }
109
+ // If field override is provided, use it instead of the DynamicField component
110
+ if (fieldOverrides &&
111
+ Object.prototype.hasOwnProperty.call(fieldOverrides, field.columnInternalName)) {
112
+ field.disabled = field.disabled || isSaving;
113
+ return fieldOverrides[field.columnInternalName](field);
114
+ }
115
+ // Default render
116
+ return (React.createElement(DynamicField, __assign({ key: field.columnInternalName }, field, { disabled: field.disabled || isSaving, validationErrorMessage: validationErrorMessage })));
117
+ };
118
+ /** Triggered when the user submits the form. */
91
119
  _this.onSubmitClick = function () { return __awaiter(_this, void 0, void 0, function () {
92
- var _a, listId, listItemId, contentTypeId, onSubmitted, onBeforeSubmit, onSubmitError, shouldBeReturnBack_1, fields, objects, _loop_1, this_1, i, len, isCancelled, newETag, iur, error_1, contentTypeIdField, iar, error_2, idField, titleField, contentTypeIdField, library, folderTitle, newFolder, fields_1, folderId, iur, error_3, error_4;
93
- var _this = this;
94
- var _b, _c, _d, _e, _f;
95
- return __generator(this, function (_g) {
96
- switch (_g.label) {
120
+ var _a, listId, listItemId, onSubmitted, onBeforeSubmit, onSubmitError, enableFileSelection, validationErrorDialogProps, returnListItemInstanceOnSubmit, contentTypeId, fileSelectRendered, shouldBeReturnBack_1, fields, validationDisabled, validationErrors, objects, _loop_1, this_1, i, len, isCancelled, apiError, newETag, iur, error_1, contentTypeIdField, iar, error_2, idField, titleField, contentTypeIdField, library, folderTitle, newFolder, fields_1, folderId, iur, error_3, error_4;
121
+ var _b, _c, _d, _e;
122
+ return __generator(this, function (_f) {
123
+ switch (_f.label) {
97
124
  case 0:
98
- _a = this.props, listId = _a.listId, listItemId = _a.listItemId, contentTypeId = _a.contentTypeId, onSubmitted = _a.onSubmitted, onBeforeSubmit = _a.onBeforeSubmit, onSubmitError = _a.onSubmitError;
99
- _g.label = 1;
125
+ _a = this.props, listId = _a.listId, listItemId = _a.listItemId, onSubmitted = _a.onSubmitted, onBeforeSubmit = _a.onBeforeSubmit, onSubmitError = _a.onSubmitError, enableFileSelection = _a.enableFileSelection, validationErrorDialogProps = _a.validationErrorDialogProps, returnListItemInstanceOnSubmit = _a.returnListItemInstanceOnSubmit;
126
+ contentTypeId = this.props.contentTypeId;
127
+ if (this.state.contentTypeId !== undefined)
128
+ contentTypeId = this.state.contentTypeId;
129
+ fileSelectRendered = !listItemId && contentTypeId.startsWith("0x0101") && enableFileSelection === true;
130
+ _f.label = 1;
100
131
  case 1:
101
- _g.trys.push([1, 27, , 28]);
132
+ _f.trys.push([1, 30, , 31]);
102
133
  shouldBeReturnBack_1 = false;
103
134
  fields = (this.state.fieldCollection || []).slice();
104
- fields.forEach(function (val) {
105
- if (val.required) {
106
- if (val.newValue === null) {
107
- if (val.fieldDefaultValue === null ||
108
- val.fieldDefaultValue === "" ||
109
- val.fieldDefaultValue.length === 0 ||
110
- val.fieldDefaultValue === undefined) {
111
- if (val.fieldType === "DateTime")
112
- val.fieldDefaultValue = null;
135
+ fields.forEach(function (field) {
136
+ // When a field is required and has no value
137
+ if (field.required) {
138
+ if (field.newValue === null) {
139
+ if (field.defaultValue === null ||
140
+ field.defaultValue === "" ||
141
+ field.defaultValue.length === 0 ||
142
+ field.defaultValue === undefined) {
143
+ if (field.fieldType === "DateTime")
144
+ field.defaultValue = null;
113
145
  else
114
- val.fieldDefaultValue = "";
146
+ field.defaultValue = "";
115
147
  shouldBeReturnBack_1 = true;
116
148
  }
117
149
  }
118
- else if (val.newValue === "") {
119
- val.fieldDefaultValue = "";
150
+ else if (field.newValue === "") {
151
+ field.defaultValue = "";
120
152
  shouldBeReturnBack_1 = true;
121
153
  }
122
- else if (Array.isArray(val.newValue) && val.newValue.length === 0) {
123
- val.fieldDefaultValue = null;
154
+ else if (Array.isArray(field.newValue) && field.newValue.length === 0) {
155
+ field.defaultValue = null;
124
156
  shouldBeReturnBack_1 = true;
125
157
  }
126
158
  }
127
- if (val.fieldType === "Number") {
128
- if (val.showAsPercentage)
129
- val.newValue /= 100;
130
- if (_this.isEmptyNumOrString(val.newValue) && (val.minimumValue !== null || val.maximumValue !== null)) {
131
- val.newValue = val.fieldDefaultValue = null;
132
- }
133
- if (!_this.isEmptyNumOrString(val.newValue) && (isNaN(Number(val.newValue)) || (val.newValue < val.minimumValue) || (val.newValue > val.maximumValue))) {
159
+ // Check min and max values for number fields
160
+ if (field.fieldType === "Number" && field.newValue !== undefined && field.newValue.trim() !== "") {
161
+ if ((field.newValue < field.minimumValue) || (field.newValue > field.maximumValue)) {
134
162
  shouldBeReturnBack_1 = true;
135
163
  }
136
164
  }
137
165
  });
166
+ validationDisabled = this.props.useFieldValidation === false;
167
+ validationErrors = {};
168
+ if (!!validationDisabled) return [3 /*break*/, 3];
169
+ return [4 /*yield*/, this.evaluateFormulas(this.state.validationFormulas, true, true, this.state.hiddenByFormula)];
170
+ case 2:
171
+ validationErrors = (_f.sent());
172
+ if (Object.keys(validationErrors).length > 0) {
173
+ shouldBeReturnBack_1 = true;
174
+ }
175
+ _f.label = 3;
176
+ case 3:
177
+ // If validation failed, return without saving
138
178
  if (shouldBeReturnBack_1) {
139
179
  this.setState({
140
180
  fieldCollection: fields,
141
- isValidationErrorDialogOpen: ((_b = this.props.validationErrorDialogProps) === null || _b === void 0 ? void 0 : _b.showDialogOnValidationError) === true,
181
+ isValidationErrorDialogOpen: (validationErrorDialogProps === null || validationErrorDialogProps === void 0 ? void 0 : validationErrorDialogProps.showDialogOnValidationError) === true,
182
+ });
183
+ return [2 /*return*/];
184
+ }
185
+ if (fileSelectRendered === true && this.state.selectedFile === undefined && this.props.listItemId === undefined) {
186
+ this.setState({
187
+ missingSelectedFile: true,
188
+ isValidationErrorDialogOpen: (validationErrorDialogProps === null || validationErrorDialogProps === void 0 ? void 0 : validationErrorDialogProps.showDialogOnValidationError) === true,
189
+ validationErrors: validationErrors
142
190
  });
143
191
  return [2 /*return*/];
144
192
  }
@@ -147,247 +195,327 @@ var DynamicForm = /** @class */ (function (_super) {
147
195
  });
148
196
  objects = {};
149
197
  _loop_1 = function (i, len) {
150
- var val, fieldType, additionalData, columnInternalName, hiddenFieldName, value_1, uploadedImage;
151
- return __generator(this, function (_h) {
152
- switch (_h.label) {
198
+ var field, fieldType, additionalData, columnInternalName, hiddenFieldName, value_1, uploadedImage;
199
+ return __generator(this, function (_g) {
200
+ switch (_g.label) {
153
201
  case 0:
154
- val = fields[i];
155
- fieldType = val.fieldType, additionalData = val.additionalData, columnInternalName = val.columnInternalName, hiddenFieldName = val.hiddenFieldName;
156
- if (!(val.newValue !== null && val.newValue !== undefined)) return [3 /*break*/, 14];
157
- value_1 = val.newValue;
158
- if (!(fieldType === "Lookup")) return [3 /*break*/, 1];
159
- if (value_1 && value_1.length > 0) {
160
- objects["".concat(columnInternalName, "Id")] = value_1[0].key;
202
+ field = fields[i];
203
+ fieldType = field.fieldType, additionalData = field.additionalData, columnInternalName = field.columnInternalName, hiddenFieldName = field.hiddenFieldName;
204
+ if (!(field.newValue !== null && field.newValue !== undefined)) return [3 /*break*/, 3];
205
+ value_1 = field.newValue;
206
+ if (["Lookup", "LookupMulti", "User", "UserMulti"].indexOf(fieldType) < 0) {
207
+ objects[columnInternalName] = value_1;
161
208
  }
162
- else {
163
- objects["".concat(columnInternalName, "Id")] = null;
209
+ // Choice fields
210
+ if (fieldType === "Choice") {
211
+ objects[columnInternalName] = field.newValue.key;
164
212
  }
165
- return [3 /*break*/, 14];
166
- case 1:
167
- if (!(fieldType === "LookupMulti")) return [3 /*break*/, 2];
168
- value_1 = [];
169
- val.newValue.forEach(function (element) {
170
- value_1.push(element.key);
171
- });
172
- objects["".concat(columnInternalName, "Id")] = {
173
- results: value_1.length === 0 ? null : value_1,
174
- };
175
- return [3 /*break*/, 14];
176
- case 2:
177
- if (!(fieldType === "TaxonomyFieldType")) return [3 /*break*/, 3];
178
- objects[columnInternalName] = {
179
- __metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
180
- Label: (_d = (_c = value_1[0]) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : "",
181
- TermGuid: (_f = (_e = value_1[0]) === null || _e === void 0 ? void 0 : _e.key) !== null && _f !== void 0 ? _f : "11111111-1111-1111-1111-111111111111",
182
- WssId: "-1",
183
- };
184
- return [3 /*break*/, 14];
185
- case 3:
186
- if (!(fieldType === "TaxonomyFieldTypeMulti")) return [3 /*break*/, 4];
187
- objects[hiddenFieldName] = val.newValue
188
- .map(function (term) { return "-1#;".concat(term.name, "|").concat(term.key, ";"); })
189
- .join("#");
190
- return [3 /*break*/, 14];
191
- case 4:
192
- if (!(fieldType === "User")) return [3 /*break*/, 5];
193
- objects["".concat(columnInternalName, "Id")] = val.newValue.length === 0 ? null : val.newValue;
194
- return [3 /*break*/, 14];
195
- case 5:
196
- if (!(fieldType === "Choice")) return [3 /*break*/, 6];
197
- objects[columnInternalName] = val.newValue.key;
198
- return [3 /*break*/, 14];
199
- case 6:
200
- if (!(fieldType === "MultiChoice")) return [3 /*break*/, 7];
201
- objects[columnInternalName] = { results: val.newValue };
202
- return [3 /*break*/, 14];
203
- case 7:
204
- if (!(fieldType === "Location")) return [3 /*break*/, 8];
205
- objects[columnInternalName] = JSON.stringify(val.newValue);
206
- return [3 /*break*/, 14];
207
- case 8:
208
- if (!(fieldType === "UserMulti")) return [3 /*break*/, 9];
209
- objects["".concat(columnInternalName, "Id")] = {
210
- results: val.newValue.length === 0 ? null : val.newValue,
211
- };
212
- return [3 /*break*/, 14];
213
- case 9:
214
- if (!(fieldType === "Thumbnail")) return [3 /*break*/, 13];
215
- if (!additionalData) return [3 /*break*/, 11];
213
+ if (fieldType === "MultiChoice") {
214
+ objects[columnInternalName] = { results: field.newValue };
215
+ }
216
+ // Lookup fields
217
+ if (fieldType === "Lookup") {
218
+ if (value_1 && value_1.length > 0) {
219
+ objects["".concat(columnInternalName, "Id")] = value_1[0].key;
220
+ }
221
+ else {
222
+ objects["".concat(columnInternalName, "Id")] = null;
223
+ }
224
+ }
225
+ if (fieldType === "LookupMulti") {
226
+ value_1 = [];
227
+ field.newValue.forEach(function (element) {
228
+ value_1.push(element.key);
229
+ });
230
+ objects["".concat(columnInternalName, "Id")] = {
231
+ results: value_1.length === 0 ? null : value_1,
232
+ };
233
+ }
234
+ // User fields
235
+ if (fieldType === "User") {
236
+ objects["".concat(columnInternalName, "Id")] = field.newValue.length === 0 ? null : field.newValue;
237
+ }
238
+ if (fieldType === "UserMulti") {
239
+ objects["".concat(columnInternalName, "Id")] = {
240
+ results: field.newValue.length === 0 ? null : field.newValue,
241
+ };
242
+ }
243
+ // Taxonomy / Managed Metadata fields
244
+ if (fieldType === "TaxonomyFieldType") {
245
+ objects[columnInternalName] = {
246
+ __metadata: { type: "SP.Taxonomy.TaxonomyFieldValue" },
247
+ Label: (_c = (_b = value_1[0]) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : "",
248
+ TermGuid: (_e = (_d = value_1[0]) === null || _d === void 0 ? void 0 : _d.key) !== null && _e !== void 0 ? _e : "11111111-1111-1111-1111-111111111111",
249
+ WssId: "-1",
250
+ };
251
+ }
252
+ if (fieldType === "TaxonomyFieldTypeMulti") {
253
+ objects[hiddenFieldName] = field.newValue
254
+ .map(function (term) { return "-1#;".concat(term.name, "|").concat(term.key, ";"); })
255
+ .join("#");
256
+ }
257
+ // Other fields
258
+ if (fieldType === "Location") {
259
+ objects[columnInternalName] = JSON.stringify(field.newValue);
260
+ }
261
+ if (!(fieldType === "Thumbnail")) return [3 /*break*/, 3];
262
+ if (!additionalData) return [3 /*break*/, 2];
216
263
  return [4 /*yield*/, this_1.uploadImage(additionalData)];
217
- case 10:
218
- uploadedImage = _h.sent();
264
+ case 1:
265
+ uploadedImage = _g.sent();
219
266
  objects[columnInternalName] = JSON.stringify({
220
267
  type: "thumbnail",
221
268
  fileName: uploadedImage.Name,
222
269
  serverRelativeUrl: uploadedImage.ServerRelativeUrl,
223
270
  id: uploadedImage.UniqueId,
224
271
  });
225
- return [3 /*break*/, 12];
226
- case 11:
272
+ return [3 /*break*/, 3];
273
+ case 2:
227
274
  objects[columnInternalName] = null;
228
- _h.label = 12;
229
- case 12: return [3 /*break*/, 14];
230
- case 13:
231
- objects[columnInternalName] = val.newValue;
232
- _h.label = 14;
233
- case 14: return [2 /*return*/];
275
+ _g.label = 3;
276
+ case 3: return [2 /*return*/];
234
277
  }
235
278
  });
236
279
  };
237
280
  this_1 = this;
238
281
  i = 0, len = fields.length;
239
- _g.label = 2;
240
- case 2:
241
- if (!(i < len)) return [3 /*break*/, 5];
242
- return [5 /*yield**/, _loop_1(i, len)];
243
- case 3:
244
- _g.sent();
245
- _g.label = 4;
282
+ _f.label = 4;
246
283
  case 4:
247
- i++;
248
- return [3 /*break*/, 2];
284
+ if (!(i < len)) return [3 /*break*/, 7];
285
+ return [5 /*yield**/, _loop_1(i, len)];
249
286
  case 5:
250
- if (!onBeforeSubmit) return [3 /*break*/, 7];
251
- return [4 /*yield*/, onBeforeSubmit(objects)];
287
+ _f.sent();
288
+ _f.label = 6;
252
289
  case 6:
253
- isCancelled = _g.sent();
290
+ i++;
291
+ return [3 /*break*/, 4];
292
+ case 7:
293
+ if (!onBeforeSubmit) return [3 /*break*/, 9];
294
+ return [4 /*yield*/, onBeforeSubmit(objects)];
295
+ case 8:
296
+ isCancelled = _f.sent();
254
297
  if (isCancelled) {
255
298
  this.setState({
256
299
  isSaving: false,
257
300
  });
258
301
  return [2 /*return*/];
259
302
  }
260
- _g.label = 7;
261
- case 7:
303
+ _f.label = 9;
304
+ case 9:
305
+ apiError = void 0;
262
306
  newETag = undefined;
263
- if (!listItemId) return [3 /*break*/, 12];
264
- _g.label = 8;
265
- case 8:
266
- _g.trys.push([8, 10, , 11]);
307
+ if (!listItemId) return [3 /*break*/, 14];
308
+ _f.label = 10;
309
+ case 10:
310
+ _f.trys.push([10, 12, , 13]);
267
311
  return [4 /*yield*/, sp.web.lists
268
312
  .getById(listId)
269
313
  .items.getById(listItemId)
270
314
  .update(objects, this.state.etag)];
271
- case 9:
272
- iur = _g.sent();
315
+ case 11:
316
+ iur = _f.sent();
273
317
  newETag = iur.data["odata.etag"];
274
318
  if (onSubmitted) {
275
- onSubmitted(iur.data, this.props.returnListItemInstanceOnSubmit !== false
319
+ onSubmitted(iur.data, returnListItemInstanceOnSubmit !== false
276
320
  ? iur.item
277
321
  : undefined);
278
322
  }
279
- return [3 /*break*/, 11];
280
- case 10:
281
- error_1 = _g.sent();
323
+ return [3 /*break*/, 13];
324
+ case 12:
325
+ error_1 = _f.sent();
326
+ apiError = error_1.message;
282
327
  if (onSubmitError) {
283
328
  onSubmitError(objects, error_1);
284
329
  }
285
330
  console.log("Error", error_1);
286
- return [3 /*break*/, 11];
287
- case 11: return [3 /*break*/, 26];
288
- case 12:
331
+ return [3 /*break*/, 13];
332
+ case 13: return [3 /*break*/, 29];
333
+ case 14:
289
334
  if (!(contentTypeId === undefined ||
290
335
  contentTypeId === "" ||
291
- !contentTypeId.startsWith("0x0120") ||
292
- contentTypeId.startsWith("0x01"))) return [3 /*break*/, 17];
293
- _g.label = 13;
294
- case 13:
295
- _g.trys.push([13, 15, , 16]);
336
+ (!contentTypeId.startsWith("0x0120") &&
337
+ contentTypeId.startsWith("0x01")))) return [3 /*break*/, 20];
338
+ if (!(fileSelectRendered === true)) return [3 /*break*/, 16];
339
+ return [4 /*yield*/, this.addFileToLibrary(objects)];
340
+ case 15:
341
+ _f.sent();
342
+ return [3 /*break*/, 19];
343
+ case 16:
344
+ _f.trys.push([16, 18, , 19]);
296
345
  contentTypeIdField = "ContentTypeId";
297
- //check if item contenttype is passed, then update the object with content type id, else, pass the object
346
+ // check if item contenttype is passed, then update the object with content type id, else, pass the object
298
347
  if (contentTypeId !== undefined && contentTypeId.startsWith("0x01"))
299
348
  objects[contentTypeIdField] = contentTypeId;
300
349
  return [4 /*yield*/, sp.web.lists.getById(listId).items.add(objects)];
301
- case 14:
302
- iar = _g.sent();
350
+ case 17:
351
+ iar = _f.sent();
303
352
  if (onSubmitted) {
304
353
  onSubmitted(iar.data, this.props.returnListItemInstanceOnSubmit !== false
305
354
  ? iar.item
306
355
  : undefined);
307
356
  }
308
- return [3 /*break*/, 16];
309
- case 15:
310
- error_2 = _g.sent();
357
+ return [3 /*break*/, 19];
358
+ case 18:
359
+ error_2 = _f.sent();
360
+ apiError = error_2.message;
311
361
  if (onSubmitError) {
312
362
  onSubmitError(objects, error_2);
313
363
  }
314
364
  console.log("Error", error_2);
315
- return [3 /*break*/, 16];
316
- case 16: return [3 /*break*/, 26];
317
- case 17:
318
- if (!contentTypeId.startsWith("0x0120")) return [3 /*break*/, 26];
319
- _g.label = 18;
320
- case 18:
321
- _g.trys.push([18, 25, , 26]);
365
+ return [3 /*break*/, 19];
366
+ case 19: return [3 /*break*/, 29];
367
+ case 20:
368
+ if (!contentTypeId.startsWith("0x0120")) return [3 /*break*/, 29];
369
+ _f.label = 21;
370
+ case 21:
371
+ _f.trys.push([21, 28, , 29]);
322
372
  idField = "ID";
323
373
  titleField = "Title";
324
374
  contentTypeIdField = "ContentTypeId";
325
375
  return [4 /*yield*/, sp.web.lists.getById(listId)];
326
- case 19:
327
- library = _g.sent();
376
+ case 22:
377
+ library = _f.sent();
328
378
  folderTitle = objects[titleField] !== undefined && objects[titleField] !== ""
329
379
  ? objects[titleField].replace(/["|*|:|<|>|?|/|\\||]/g, "_") // Replace not allowed chars in folder name
330
380
  : "";
331
381
  return [4 /*yield*/, library.rootFolder.addSubFolderUsingPath(folderTitle)];
332
- case 20:
333
- newFolder = _g.sent();
382
+ case 23:
383
+ newFolder = _f.sent();
334
384
  return [4 /*yield*/, newFolder.listItemAllFields()];
335
- case 21:
336
- fields_1 = _g.sent();
337
- if (!fields_1[idField]) return [3 /*break*/, 23];
385
+ case 24:
386
+ fields_1 = _f.sent();
387
+ if (!fields_1[idField]) return [3 /*break*/, 26];
338
388
  folderId = fields_1[idField];
339
389
  // Set the content type ID for the target item
340
390
  objects[contentTypeIdField] = contentTypeId;
341
391
  return [4 /*yield*/, library.items.getById(folderId).update(objects)];
342
- case 22:
343
- iur = _g.sent();
392
+ case 25:
393
+ iur = _f.sent();
344
394
  if (onSubmitted) {
345
395
  onSubmitted(iur.data, this.props.returnListItemInstanceOnSubmit !== false
346
396
  ? iur.item
347
397
  : undefined);
348
398
  }
349
- return [3 /*break*/, 24];
350
- case 23: throw new Error("Unable to read the ID of the just created folder or Document Set");
351
- case 24: return [3 /*break*/, 26];
352
- case 25:
353
- error_3 = _g.sent();
399
+ return [3 /*break*/, 27];
400
+ case 26: throw new Error("Unable to read the ID of the just created folder or Document Set");
401
+ case 27: return [3 /*break*/, 29];
402
+ case 28:
403
+ error_3 = _f.sent();
404
+ apiError = error_3.message;
354
405
  if (onSubmitError) {
355
406
  onSubmitError(objects, error_3);
356
407
  }
357
408
  console.log("Error", error_3);
358
- return [3 /*break*/, 26];
359
- case 26:
409
+ return [3 /*break*/, 29];
410
+ case 29:
360
411
  this.setState({
361
412
  isSaving: false,
362
413
  etag: newETag,
414
+ infoErrorMessages: apiError ? [{ type: MessageBarType.error, message: apiError }] : [],
363
415
  });
364
- return [3 /*break*/, 28];
365
- case 27:
366
- error_4 = _g.sent();
416
+ return [3 /*break*/, 31];
417
+ case 30:
418
+ error_4 = _f.sent();
367
419
  if (onSubmitError) {
368
420
  onSubmitError(null, error_4);
369
421
  }
370
422
  console.log("Error onSubmit", error_4);
371
- return [3 /*break*/, 28];
372
- case 28: return [2 /*return*/];
423
+ return [3 /*break*/, 31];
424
+ case 31: return [2 /*return*/];
373
425
  }
374
426
  });
375
427
  }); };
376
- // trigger when the user change any value in the form
428
+ /**
429
+ * Adds selected file to the library
430
+ */
431
+ _this.addFileToLibrary = function (objects) { return __awaiter(_this, void 0, void 0, function () {
432
+ var selectedFile, _a, listId, contentTypeId, onSubmitted, onSubmitError, returnListItemInstanceOnSubmit, idField, contentTypeIdField, library, itemTitle, fileCreatedResult, _b, _c, _d, fields, folderId, iur, error_5;
433
+ return __generator(this, function (_e) {
434
+ switch (_e.label) {
435
+ case 0:
436
+ selectedFile = this.state.selectedFile;
437
+ _a = this.props, listId = _a.listId, contentTypeId = _a.contentTypeId, onSubmitted = _a.onSubmitted, onSubmitError = _a.onSubmitError, returnListItemInstanceOnSubmit = _a.returnListItemInstanceOnSubmit;
438
+ if (!(selectedFile !== undefined)) return [3 /*break*/, 10];
439
+ _e.label = 1;
440
+ case 1:
441
+ _e.trys.push([1, 9, , 10]);
442
+ idField = "ID";
443
+ contentTypeIdField = "ContentTypeId";
444
+ return [4 /*yield*/, sp.web.lists.getById(listId)];
445
+ case 2:
446
+ library = _e.sent();
447
+ itemTitle = selectedFile !== undefined && selectedFile.fileName !== undefined && selectedFile.fileName !== ""
448
+ ? selectedFile.fileName.replace(/["|*|:|<|>|?|/|\\||]/g, "_") // Replace not allowed chars in folder name
449
+ : "";
450
+ _c = (_b = library.rootFolder.files).addChunked;
451
+ _d = [encodeURI(itemTitle)];
452
+ return [4 /*yield*/, selectedFile.downloadFileContent()];
453
+ case 3: return [4 /*yield*/, _c.apply(_b, _d.concat([_e.sent()]))];
454
+ case 4:
455
+ fileCreatedResult = _e.sent();
456
+ return [4 /*yield*/, fileCreatedResult.file.listItemAllFields()];
457
+ case 5:
458
+ fields = _e.sent();
459
+ if (!fields[idField]) return [3 /*break*/, 7];
460
+ folderId = fields[idField];
461
+ // Set the content type ID for the target item
462
+ objects[contentTypeIdField] = contentTypeId;
463
+ return [4 /*yield*/, library.items.getById(folderId).update(objects)];
464
+ case 6:
465
+ iur = _e.sent();
466
+ if (onSubmitted) {
467
+ onSubmitted(iur.data, returnListItemInstanceOnSubmit !== false
468
+ ? iur.item
469
+ : undefined);
470
+ }
471
+ return [3 /*break*/, 8];
472
+ case 7: throw new Error("Unable to read the ID of the just created folder or Document Set");
473
+ case 8: return [3 /*break*/, 10];
474
+ case 9:
475
+ error_5 = _e.sent();
476
+ if (onSubmitError) {
477
+ onSubmitError(objects, error_5);
478
+ }
479
+ console.log("Error", error_5);
480
+ return [3 /*break*/, 10];
481
+ case 10: return [2 /*return*/];
482
+ }
483
+ });
484
+ }); };
485
+ /**
486
+ * Triggered when the user makes any field value change in the form
487
+ */
377
488
  _this.onChange = function (internalName,
378
489
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
379
- newValue, additionalData) { return __awaiter(_this, void 0, void 0, function () {
380
- var fieldCol, field, user, result, index, element, user, result;
490
+ newValue, validate, additionalData) { return __awaiter(_this, void 0, void 0, function () {
491
+ var fieldCol, field, user, result, emails, index, element, user, result, validationErrors;
492
+ var _this = this;
381
493
  return __generator(this, function (_a) {
382
494
  switch (_a.label) {
383
495
  case 0:
384
- fieldCol = (this.state.fieldCollection || []).slice();
496
+ fieldCol = cloneDeep(this.state.fieldCollection || []);
385
497
  field = fieldCol.filter(function (element, i) {
386
498
  return element.columnInternalName === internalName;
387
499
  })[0];
500
+ // Init new value(s)
388
501
  field.newValue = newValue;
502
+ field.stringValue = newValue.toString();
389
503
  field.additionalData = additionalData;
390
- if (!(field.fieldType === "User" && newValue.length !== 0)) return [3 /*break*/, 4];
504
+ field.subPropertyValues = {};
505
+ // Store string values for various field types
506
+ if (field.fieldType === "Choice") {
507
+ field.stringValue = newValue.text;
508
+ }
509
+ if (field.fieldType === "MultiChoice") {
510
+ field.stringValue = newValue.join(';#');
511
+ }
512
+ if (field.fieldType === "Lookup" || field.fieldType === "LookupMulti") {
513
+ field.stringValue = newValue.map(function (nv) { return nv.key + ';#' + nv.name; }).join(';#');
514
+ }
515
+ if (field.fieldType === "TaxonomyFieldType" || field.fieldType === "TaxonomyFieldTypeMulti") {
516
+ field.stringValue = newValue.map(function (nv) { return nv.name; }).join(';');
517
+ }
518
+ if (!(field.fieldType === "User" && newValue.length !== 0)) return [3 /*break*/, 3];
391
519
  if (!(newValue[0].id === undefined ||
392
520
  parseInt(newValue[0].id, 10).toString() === "NaN")) return [3 /*break*/, 2];
393
521
  user = newValue[0].secondaryText;
@@ -398,47 +526,187 @@ var DynamicForm = /** @class */ (function (_super) {
398
526
  case 1:
399
527
  result = _a.sent();
400
528
  field.newValue = result.data.Id; // eslint-disable-line require-atomic-updates
529
+ field.stringValue = user;
530
+ field.subPropertyValues = {
531
+ id: result.data.Id,
532
+ title: result.data.Title,
533
+ email: result.data.Email,
534
+ };
401
535
  return [3 /*break*/, 3];
402
536
  case 2:
403
537
  field.newValue = newValue[0].id;
404
538
  _a.label = 3;
405
- case 3: return [3 /*break*/, 9];
406
- case 4:
539
+ case 3:
407
540
  if (!(field.fieldType === "UserMulti" && newValue.length !== 0)) return [3 /*break*/, 9];
408
541
  field.newValue = [];
542
+ emails = [];
409
543
  index = 0;
410
- _a.label = 5;
411
- case 5:
412
- if (!(index < newValue.length)) return [3 /*break*/, 9];
544
+ _a.label = 4;
545
+ case 4:
546
+ if (!(index < newValue.length)) return [3 /*break*/, 8];
413
547
  element = newValue[index];
414
548
  if (!(element.id === undefined ||
415
- parseInt(element.id, 10).toString() === "NaN")) return [3 /*break*/, 7];
549
+ parseInt(element.id, 10).toString() === "NaN")) return [3 /*break*/, 6];
416
550
  user = element.secondaryText;
417
551
  if (user.indexOf("@") === -1) {
418
552
  user = element.loginName;
419
553
  }
420
554
  return [4 /*yield*/, sp.web.ensureUser(user)];
421
- case 6:
555
+ case 5:
422
556
  result = _a.sent();
423
557
  field.newValue.push(result.data.Id);
424
- return [3 /*break*/, 8];
425
- case 7:
558
+ emails.push(user);
559
+ return [3 /*break*/, 7];
560
+ case 6:
426
561
  field.newValue.push(element.id);
427
- _a.label = 8;
428
- case 8:
562
+ _a.label = 7;
563
+ case 7:
429
564
  index++;
430
- return [3 /*break*/, 5];
565
+ return [3 /*break*/, 4];
566
+ case 8:
567
+ field.stringValue = emails.join(";");
568
+ _a.label = 9;
431
569
  case 9:
570
+ validationErrors = __assign({}, this.state.validationErrors);
571
+ if (validationErrors[field.columnInternalName])
572
+ delete validationErrors[field.columnInternalName];
432
573
  this.setState({
433
574
  fieldCollection: fieldCol,
575
+ validationErrors: validationErrors
576
+ }, function () {
577
+ if (validate)
578
+ _this.performValidation();
434
579
  });
435
580
  return [2 /*return*/];
436
581
  }
437
582
  });
438
583
  }); };
439
- //getting all the fields information as part of get ready process
440
- _this.getFieldInformations = function () { return __awaiter(_this, void 0, void 0, function () {
441
- var _a, listId, listItemId, disabledFields, respectETag, onListItemLoaded, contentTypeId, spList, item, etag, defaultContentType, listFields, tempFields, order, responseValue, hiddenFields, defaultDayOfWeek, _loop_2, this_2, i, len, installedLanguages, error_5;
584
+ /** Validation callback, used when form first loads (getListInformation) and following onChange */
585
+ _this.performValidation = function (skipFieldValueValidation) {
586
+ var _a = _this.props, useClientSideValidation = _a.useClientSideValidation, useFieldValidation = _a.useFieldValidation;
587
+ var _b = _this.state, clientValidationFormulas = _b.clientValidationFormulas, validationFormulas = _b.validationFormulas;
588
+ if (Object.keys(clientValidationFormulas).length || Object.keys(validationFormulas).length) {
589
+ _this.setState({
590
+ isSaving: true, // Disable save btn and fields while validation in progress
591
+ }, function () {
592
+ var clientSideValidationDisabled = useClientSideValidation === false;
593
+ var fieldValidationDisabled = useFieldValidation === false;
594
+ var hiddenByFormula = !clientSideValidationDisabled ? _this.evaluateColumnVisibilityFormulas() : [];
595
+ var validationErrors = __assign({}, _this.state.validationErrors);
596
+ if (!skipFieldValueValidation && !fieldValidationDisabled)
597
+ validationErrors = _this.evaluateFieldValueFormulas(hiddenByFormula);
598
+ _this.setState({ hiddenByFormula: hiddenByFormula, isSaving: false, validationErrors: validationErrors });
599
+ });
600
+ }
601
+ };
602
+ /** Determines visibility of fields that have show/hide formulas set in Edit Form > Edit Columns > Edit Conditional Formula */
603
+ _this.evaluateColumnVisibilityFormulas = function () {
604
+ return _this.evaluateFormulas(_this.state.clientValidationFormulas, false);
605
+ };
606
+ /** Evaluates field validation formulas set in column settings and returns a Record of error messages */
607
+ _this.evaluateFieldValueFormulas = function (hiddenFields) {
608
+ return _this.evaluateFormulas(_this.state.validationFormulas, true, true, hiddenFields);
609
+ };
610
+ /**
611
+ * Evaluates formulas and returns a Record of error messages or an array of column names that have failed validation
612
+ * @param formulas A Record / dictionary-like object, where key is internal column name and value is an object with ValidationFormula and ValidationMessage properties
613
+ * @param returnMessages Determines whether a Record of error messages is returned or an array of column names that have failed validation
614
+ * @param requireValue Set to true if the formula should only be evaluated when the field has a value
615
+ * @returns
616
+ */
617
+ _this.evaluateFormulas = function (formulas, returnMessages, requireValue, ignoreFields) {
618
+ if (returnMessages === void 0) { returnMessages = true; }
619
+ if (requireValue === void 0) { requireValue = false; }
620
+ if (ignoreFields === void 0) { ignoreFields = []; }
621
+ var fieldCollection = _this.state.fieldCollection;
622
+ var results = {};
623
+ var _loop_2 = function (i) {
624
+ var fieldName = Object.keys(formulas)[i];
625
+ if (formulas[fieldName]) {
626
+ var field = fieldCollection.find(function (f) { return f.columnInternalName === fieldName; });
627
+ if (!field)
628
+ return "continue";
629
+ if (ignoreFields.indexOf(fieldName) > -1)
630
+ return "continue"; // Skip fields that are being ignored (e.g. hidden by formula)
631
+ var formula = formulas[fieldName].ValidationFormula;
632
+ var message = formulas[fieldName].ValidationMessage;
633
+ if (!formula)
634
+ return "continue";
635
+ var context = _this.getFormValuesForValidation();
636
+ if (requireValue && !context[fieldName])
637
+ return "continue";
638
+ var result = _this._formulaEvaluation.evaluate(formula, context);
639
+ if (Boolean(result) !== true) {
640
+ results[fieldName] = message;
641
+ }
642
+ }
643
+ };
644
+ for (var i = 0; i < Object.keys(formulas).length; i++) {
645
+ _loop_2(i);
646
+ }
647
+ if (!returnMessages) {
648
+ return Object.keys(results);
649
+ }
650
+ return results;
651
+ };
652
+ /**
653
+ * Used for validation. Returns a Record of field values, where key is internal column name and value is the field value.
654
+ * Expands certain properties and stores many of them as primitives (strings, numbers or bools) so the expression evaluator
655
+ * can process them. For example: a User column named Person will have values stored as Person, Person.email, Person.title etc.
656
+ * This is so the expression evaluator can process expressions like '=[$Person.title] == "Contoso Employee 1138"'
657
+ * @param fieldCollection Optional. Could be used to compare field values in state with previous state.
658
+ * @returns
659
+ */
660
+ _this.getFormValuesForValidation = function (fieldCollection) {
661
+ var fieldColFromState = _this.state.fieldCollection;
662
+ if (!fieldCollection)
663
+ fieldCollection = fieldColFromState;
664
+ return fieldCollection.reduce(function (prev, cur) {
665
+ var value = cur.value;
666
+ switch (cur.fieldType) {
667
+ case "Lookup":
668
+ case "Choice":
669
+ case "TaxonomyFieldType":
670
+ case "LookupMulti":
671
+ case "MultiChoice":
672
+ case "TaxonomyFieldTypeMulti":
673
+ case "User":
674
+ case "UserMulti":
675
+ value = cur.stringValue;
676
+ break;
677
+ case "Currency":
678
+ case "Number":
679
+ if (cur.value !== undefined && cur.value !== null)
680
+ value = Number(cur.value);
681
+ if (cur.newValue !== undefined && cur.newValue !== null)
682
+ value = Number(cur.newValue);
683
+ break;
684
+ case "URL":
685
+ if (cur.value !== undefined && cur.value !== null)
686
+ value = cur.value.Url;
687
+ if (cur.newValue !== undefined && cur.newValue !== null)
688
+ value = cur.newValue.Url;
689
+ value = cur.newValue ? cur.newValue.Url : null;
690
+ break;
691
+ default:
692
+ value = cur.newValue || cur.value;
693
+ break;
694
+ }
695
+ prev[cur.columnInternalName] = value;
696
+ if (cur.subPropertyValues) {
697
+ Object.keys(cur.subPropertyValues).forEach(function (key) {
698
+ prev["".concat(cur.columnInternalName, ".").concat(key)] = cur.subPropertyValues[key];
699
+ });
700
+ }
701
+ return prev;
702
+ }, {});
703
+ };
704
+ /**
705
+ * Invoked when component first mounts, loads information about the SharePoint list, fields and list item
706
+ */
707
+ _this.getListInformation = function () { return __awaiter(_this, void 0, void 0, function () {
708
+ var _a, listId, listItemId, disabledFields, respectETag, onListItemLoaded, contentTypeId, listInfo, additionalInfo, numberFields, validationFormulas, contentTypeName, clientValidationFormulas, headerJSON, footerJSON, bodySections, customFormatInfo, spList, item, etag, tempFields, installedLanguages, error_6;
709
+ var _this = this;
442
710
  return __generator(this, function (_b) {
443
711
  switch (_b.label) {
444
712
  case 0:
@@ -446,311 +714,92 @@ var DynamicForm = /** @class */ (function (_super) {
446
714
  contentTypeId = this.props.contentTypeId;
447
715
  _b.label = 1;
448
716
  case 1:
449
- _b.trys.push([1, 16, , 17]);
450
- return [4 /*yield*/, sp.web.lists.getById(listId)];
717
+ _b.trys.push([1, 11, , 12]);
718
+ return [4 /*yield*/, this._spService.getListFormRenderInfo(listId)];
451
719
  case 2:
452
- spList = _b.sent();
720
+ listInfo = _b.sent();
721
+ return [4 /*yield*/, this._spService.getAdditionalListFormFieldInfo(listId)];
722
+ case 3:
723
+ additionalInfo = _b.sent();
724
+ numberFields = additionalInfo.filter(function (f) { return f.TypeAsString === "Number" || f.TypeAsString === "Currency"; });
725
+ validationFormulas = additionalInfo.reduce(function (prev, cur) {
726
+ if (!prev[cur.InternalName] && cur.ValidationFormula) {
727
+ prev[cur.InternalName] = {
728
+ ValidationFormula: cur.ValidationFormula,
729
+ ValidationMessage: cur.ValidationMessage,
730
+ };
731
+ }
732
+ return prev;
733
+ }, {});
734
+ // If no content type ID is provided, use the default (first one in the list)
735
+ if (contentTypeId === undefined || contentTypeId === "") {
736
+ contentTypeId = Object.keys(listInfo.ContentTypeIdToNameMap)[0];
737
+ }
738
+ contentTypeName = listInfo.ContentTypeIdToNameMap[contentTypeId];
739
+ clientValidationFormulas = listInfo.ClientForms.Edit[contentTypeName].reduce(function (prev, cur) {
740
+ if (cur.ClientValidationFormula) {
741
+ prev[cur.InternalName] = {
742
+ ValidationFormula: cur.ClientValidationFormula,
743
+ ValidationMessage: cur.ClientValidationMessage,
744
+ };
745
+ }
746
+ return prev;
747
+ }, {});
748
+ headerJSON = void 0, footerJSON = void 0;
749
+ bodySections = void 0;
750
+ if (listInfo.ClientFormCustomFormatter && listInfo.ClientFormCustomFormatter[contentTypeId]) {
751
+ customFormatInfo = JSON.parse(listInfo.ClientFormCustomFormatter[contentTypeId]);
752
+ bodySections = customFormatInfo.bodyJSONFormatter.sections;
753
+ headerJSON = customFormatInfo.headerJSONFormatter;
754
+ footerJSON = customFormatInfo.footerJSONFormatter;
755
+ }
756
+ spList = sp.web.lists.getById(listId);
453
757
  item = null;
454
758
  etag = undefined;
455
- if (!(listItemId !== undefined && listItemId !== null && listItemId !== 0)) return [3 /*break*/, 6];
456
- return [4 /*yield*/, spList.items.getById(listItemId).get()];
457
- case 3:
759
+ if (!(listItemId !== undefined && listItemId !== null && listItemId !== 0)) return [3 /*break*/, 7];
760
+ return [4 /*yield*/, spList.items.getById(listItemId).get().catch(function (err) { return _this.updateFormMessages(MessageBarType.error, err.message); })];
761
+ case 4:
458
762
  item = _b.sent();
459
- if (!onListItemLoaded) return [3 /*break*/, 5];
763
+ if (!onListItemLoaded) return [3 /*break*/, 6];
460
764
  return [4 /*yield*/, onListItemLoaded(item)];
461
- case 4:
462
- _b.sent();
463
- _b.label = 5;
464
765
  case 5:
766
+ _b.sent();
767
+ _b.label = 6;
768
+ case 6:
465
769
  if (respectETag !== false) {
466
770
  etag = item["odata.etag"];
467
771
  }
468
- _b.label = 6;
469
- case 6:
470
- if (!(contentTypeId === undefined || contentTypeId === "")) return [3 /*break*/, 8];
471
- return [4 /*yield*/, spList.contentTypes
472
- .select("Id", "Name")
473
- .get()];
474
- case 7:
475
- defaultContentType = _b.sent();
476
- contentTypeId = defaultContentType[0].Id.StringValue;
477
- _b.label = 8;
478
- case 8: return [4 /*yield*/, this.getFormFields(listId, contentTypeId, this.webURL)];
772
+ _b.label = 7;
773
+ case 7: return [4 /*yield*/, this.buildFieldCollection(listInfo, contentTypeName, item, numberFields, listId, listItemId, disabledFields)];
774
+ case 8:
775
+ tempFields = _b.sent();
776
+ installedLanguages = void 0;
777
+ if (!(tempFields.filter(function (f) { return f.fieldType === "Currency"; }).length > 0)) return [3 /*break*/, 10];
778
+ return [4 /*yield*/, sp.web.regionalSettings.getInstalledLanguages()];
479
779
  case 9:
480
- listFields = _b.sent();
481
- tempFields = [];
482
- order = 0;
483
- responseValue = listFields.value;
484
- hiddenFields = this.props.hiddenFields !== undefined ? this.props.hiddenFields : [];
485
- defaultDayOfWeek = 0;
486
- _loop_2 = function (i, len) {
487
- var field, fieldType, cultureName, hiddenName, termSetId, anchorId, lookupListId, lookupField, choices_1, defaultValue, selectedTags_1, richText, dateFormat, principalType, minValue, maxValue, showAsPercentage, response, response, schemaXml, dateFormatRegEx, userEmails, _c, _d;
488
- return __generator(this, function (_e) {
489
- switch (_e.label) {
490
- case 0:
491
- field = responseValue[i];
492
- if (!(hiddenFields.indexOf(field.EntityPropertyName) < 0)) return [3 /*break*/, 30];
493
- order++;
494
- fieldType = field.TypeAsString;
495
- field.order = order;
496
- cultureName = void 0;
497
- hiddenName = "";
498
- termSetId = "";
499
- anchorId = "";
500
- lookupListId = "";
501
- lookupField = "";
502
- choices_1 = [];
503
- defaultValue = null;
504
- selectedTags_1 = [];
505
- richText = false;
506
- dateFormat = void 0;
507
- principalType = "";
508
- minValue = void 0;
509
- maxValue = void 0;
510
- showAsPercentage = void 0;
511
- if (item !== null) {
512
- defaultValue = item[field.EntityPropertyName];
513
- }
514
- else {
515
- defaultValue = field.DefaultValue;
516
- }
517
- if (!(fieldType === "Choice" || fieldType === "MultiChoice")) return [3 /*break*/, 1];
518
- field.Choices.forEach(function (element) {
519
- choices_1.push({ key: element, text: element });
520
- });
521
- return [3 /*break*/, 29];
522
- case 1:
523
- if (!(fieldType === "Note")) return [3 /*break*/, 2];
524
- richText = field.RichText;
525
- return [3 /*break*/, 29];
526
- case 2:
527
- if (!(fieldType === "Number" || fieldType === "Currency")) return [3 /*break*/, 3];
528
- minValue = field.MinimumValue;
529
- maxValue = field.MaximumValue;
530
- if (fieldType === "Number") {
531
- showAsPercentage = field.ShowAsPercentage;
532
- }
533
- else {
534
- cultureName = this_2.cultureNameLookup(field.CurrencyLocaleId);
535
- }
536
- return [3 /*break*/, 29];
537
- case 3:
538
- if (!(fieldType === "Lookup")) return [3 /*break*/, 7];
539
- lookupListId = field.LookupList;
540
- lookupField = field.LookupField;
541
- if (!(item !== null)) return [3 /*break*/, 5];
542
- return [4 /*yield*/, this_2._spService.getLookupValue(listId, listItemId, field.EntityPropertyName, lookupField, this_2.webURL)];
543
- case 4:
544
- defaultValue = _e.sent();
545
- return [3 /*break*/, 6];
546
- case 5:
547
- defaultValue = [];
548
- _e.label = 6;
549
- case 6: return [3 /*break*/, 29];
550
- case 7:
551
- if (!(fieldType === "LookupMulti")) return [3 /*break*/, 11];
552
- lookupListId = field.LookupList;
553
- lookupField = field.LookupField;
554
- if (!(item !== null)) return [3 /*break*/, 9];
555
- return [4 /*yield*/, this_2._spService.getLookupValues(listId, listItemId, field.EntityPropertyName, lookupField, this_2.webURL)];
556
- case 8:
557
- defaultValue = _e.sent();
558
- return [3 /*break*/, 10];
559
- case 9:
560
- defaultValue = [];
561
- _e.label = 10;
562
- case 10: return [3 /*break*/, 29];
563
- case 11:
564
- if (!(fieldType === "TaxonomyFieldTypeMulti")) return [3 /*break*/, 13];
565
- return [4 /*yield*/, this_2._spService.getTaxonomyFieldInternalName(this_2.props.listId, field.TextField, this_2.webURL)];
566
- case 12:
567
- response = _e.sent();
568
- hiddenName = response.value;
569
- termSetId = field.TermSetId;
570
- anchorId = field.AnchorId;
571
- if (item !== null && item[field.InternalName] !== null && item[field.InternalName].results !== null) {
572
- item[field.InternalName].results.forEach(function (element) {
573
- selectedTags_1.push({
574
- key: element.TermGuid,
575
- name: element.Label,
576
- });
577
- });
578
- defaultValue = selectedTags_1;
579
- }
580
- else {
581
- if (defaultValue !== null && defaultValue !== "") {
582
- defaultValue.split(/#|;/).forEach(function (element) {
583
- if (element.indexOf("|") !== -1)
584
- selectedTags_1.push({
585
- key: element.split("|")[1],
586
- name: element.split("|")[0],
587
- });
588
- });
589
- defaultValue = selectedTags_1;
590
- }
591
- }
592
- if (defaultValue === "")
593
- defaultValue = null;
594
- return [3 /*break*/, 29];
595
- case 13:
596
- if (!(fieldType === "TaxonomyFieldType")) return [3 /*break*/, 17];
597
- termSetId = field.TermSetId;
598
- anchorId = field.AnchorId;
599
- if (!(item !== null)) return [3 /*break*/, 15];
600
- return [4 /*yield*/, this_2._spService.getSingleManagedMetadataLabel(listId, listItemId, field.InternalName)];
601
- case 14:
602
- response = _e.sent();
603
- if (response) {
604
- selectedTags_1.push({
605
- key: response.TermID,
606
- name: response.Label,
607
- });
608
- defaultValue = selectedTags_1;
609
- }
610
- return [3 /*break*/, 16];
611
- case 15:
612
- if (defaultValue !== "") {
613
- selectedTags_1.push({
614
- key: defaultValue.split("|")[1],
615
- name: defaultValue.split("|")[0].split("#")[1],
616
- });
617
- defaultValue = selectedTags_1;
618
- }
619
- _e.label = 16;
620
- case 16:
621
- if (defaultValue === "")
622
- defaultValue = null;
623
- return [3 /*break*/, 29];
624
- case 17:
625
- if (!(fieldType === "DateTime")) return [3 /*break*/, 19];
626
- if (item !== null && item[field.InternalName])
627
- defaultValue = new Date(item[field.InternalName]);
628
- else if (defaultValue === "[today]") {
629
- defaultValue = new Date();
630
- }
631
- schemaXml = field.SchemaXml;
632
- dateFormatRegEx = /\s+Format="([^"]+)"/gim.exec(schemaXml);
633
- dateFormat =
634
- dateFormatRegEx && dateFormatRegEx.length
635
- ? dateFormatRegEx[1]
636
- : "DateOnly";
637
- return [4 /*yield*/, this_2._spService.getRegionalWebSettings()];
638
- case 18:
639
- defaultDayOfWeek = (_e.sent())
640
- .FirstDayOfWeek;
641
- return [3 /*break*/, 29];
642
- case 19:
643
- if (!(fieldType === "UserMulti")) return [3 /*break*/, 23];
644
- if (!(item !== null)) return [3 /*break*/, 21];
645
- return [4 /*yield*/, this_2._spService.getUsersUPNFromFieldValue(listId, listItemId, field.InternalName, this_2.webURL)];
646
- case 20:
647
- defaultValue = _e.sent();
648
- return [3 /*break*/, 22];
649
- case 21:
650
- defaultValue = [];
651
- _e.label = 22;
652
- case 22:
653
- principalType = field.SchemaXml.split('UserSelectionMode="')[1];
654
- principalType = principalType.substring(0, principalType.indexOf('"'));
655
- return [3 /*break*/, 29];
656
- case 23:
657
- if (!(fieldType === "Thumbnail")) return [3 /*break*/, 24];
658
- if (defaultValue) {
659
- defaultValue = JSON.parse(defaultValue).serverRelativeUrl;
660
- }
661
- return [3 /*break*/, 29];
662
- case 24:
663
- if (!(fieldType === "User")) return [3 /*break*/, 28];
664
- if (!(item !== null)) return [3 /*break*/, 26];
665
- userEmails = [];
666
- _d = (_c = userEmails).push;
667
- return [4 /*yield*/, this_2._spService.getUserUPNFromFieldValue(listId, listItemId, field.InternalName, this_2.webURL)];
668
- case 25:
669
- _d.apply(_c, [(_e.sent()) + ""]);
670
- defaultValue = userEmails;
671
- return [3 /*break*/, 27];
672
- case 26:
673
- defaultValue = [];
674
- _e.label = 27;
675
- case 27:
676
- principalType = field.SchemaXml.split('UserSelectionMode="')[1];
677
- principalType = principalType.substring(0, principalType.indexOf('"'));
678
- return [3 /*break*/, 29];
679
- case 28:
680
- if (fieldType === "Location") {
681
- defaultValue = JSON.parse(defaultValue);
682
- }
683
- else if (fieldType === "Boolean") {
684
- defaultValue = Boolean(Number(defaultValue));
685
- }
686
- _e.label = 29;
687
- case 29:
688
- tempFields.push({
689
- newValue: null,
690
- fieldTermSetId: termSetId,
691
- fieldAnchorId: anchorId,
692
- options: choices_1,
693
- lookupListID: lookupListId,
694
- lookupField: lookupField,
695
- cultureName: cultureName,
696
- changedValue: defaultValue,
697
- fieldType: field.TypeAsString,
698
- fieldTitle: field.Title,
699
- fieldDefaultValue: defaultValue,
700
- context: this_2.props.context,
701
- disabled: this_2.props.disabled ||
702
- (disabledFields &&
703
- disabledFields.indexOf(field.InternalName) > -1),
704
- listId: this_2.props.listId,
705
- columnInternalName: field.EntityPropertyName,
706
- label: field.Title,
707
- onChanged: this_2.onChange,
708
- required: field.Required,
709
- hiddenFieldName: hiddenName,
710
- Order: field.order,
711
- isRichText: richText,
712
- dateFormat: dateFormat,
713
- firstDayOfWeek: defaultDayOfWeek,
714
- listItemId: listItemId,
715
- principalType: principalType,
716
- description: field.Description,
717
- minimumValue: minValue,
718
- maximumValue: maxValue,
719
- showAsPercentage: showAsPercentage
720
- });
721
- tempFields.sort(function (a, b) { return a.Order - b.Order; });
722
- _e.label = 30;
723
- case 30: return [2 /*return*/];
724
- }
725
- });
726
- };
727
- this_2 = this;
728
- i = 0, len = responseValue.length;
780
+ installedLanguages = _b.sent();
729
781
  _b.label = 10;
730
782
  case 10:
731
- if (!(i < len)) return [3 /*break*/, 13];
732
- return [5 /*yield**/, _loop_2(i, len)];
783
+ this.setState({
784
+ contentTypeId: contentTypeId,
785
+ clientValidationFormulas: clientValidationFormulas,
786
+ customFormatting: {
787
+ header: headerJSON,
788
+ body: bodySections,
789
+ footer: footerJSON
790
+ },
791
+ etag: etag,
792
+ fieldCollection: tempFields,
793
+ installedLanguages: installedLanguages,
794
+ validationFormulas: validationFormulas
795
+ }, function () { return _this.performValidation(true); });
796
+ return [3 /*break*/, 12];
733
797
  case 11:
734
- _b.sent();
735
- _b.label = 12;
736
- case 12:
737
- i++;
738
- return [3 /*break*/, 10];
739
- case 13:
740
- installedLanguages = void 0;
741
- if (!(tempFields.filter(function (f) { return f.fieldType === "Currency"; }).length > 0)) return [3 /*break*/, 15];
742
- return [4 /*yield*/, sp.web.regionalSettings.getInstalledLanguages()];
743
- case 14:
744
- installedLanguages = _b.sent();
745
- _b.label = 15;
746
- case 15:
747
- this.setState({ fieldCollection: tempFields, installedLanguages: installedLanguages, etag: etag });
748
- return [3 /*break*/, 17];
749
- case 16:
750
- error_5 = _b.sent();
751
- console.log("Error get field informations", error_5);
798
+ error_6 = _b.sent();
799
+ this.updateFormMessages(MessageBarType.error, 'An error occurred while loading: ' + error_6.message);
800
+ console.error("An error occurred while loading DynamicForm", error_6);
752
801
  return [2 /*return*/, null];
753
- case 17: return [2 /*return*/];
802
+ case 12: return [2 /*return*/];
754
803
  }
755
804
  });
756
805
  }); };
@@ -786,48 +835,6 @@ var DynamicForm = /** @class */ (function (_super) {
786
835
  };
787
836
  });
788
837
  };
789
- _this.getFormFields = function (listId, contentTypeId, webUrl
790
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
791
- ) { return __awaiter(_this, void 0, void 0, function () {
792
- var context, webAbsoluteUrl, apiUrl, data, results, error_6;
793
- return __generator(this, function (_a) {
794
- switch (_a.label) {
795
- case 0:
796
- _a.trys.push([0, 4, , 5]);
797
- context = this.props.context;
798
- webAbsoluteUrl = !webUrl ? this.webURL : webUrl;
799
- apiUrl = "";
800
- if (contentTypeId !== undefined && contentTypeId !== "") {
801
- if (contentTypeId.startsWith("0x0120")) {
802
- apiUrl = "".concat(webAbsoluteUrl, "/_api/web/lists(@listId)/contenttypes('").concat(contentTypeId, "')/fields?@listId=guid'").concat(encodeURIComponent(listId), "'&$filter=ReadOnlyField eq false and (Hidden eq false or StaticName eq 'Title') and (FromBaseType eq false or StaticName eq 'Title')");
803
- }
804
- else {
805
- apiUrl = "".concat(webAbsoluteUrl, "/_api/web/lists(@listId)/contenttypes('").concat(contentTypeId, "')/fields?@listId=guid'").concat(encodeURIComponent(listId), "'&$filter=ReadOnlyField eq false and Hidden eq false and (FromBaseType eq false or StaticName eq 'Title')");
806
- }
807
- }
808
- else {
809
- apiUrl = "".concat(webAbsoluteUrl, "/_api/web/lists(@listId)/fields?@listId=guid'").concat(encodeURIComponent(listId), "'&$filter=ReadOnlyField eq false and Hidden eq false and (FromBaseType eq false or StaticName eq 'Title')");
810
- }
811
- return [4 /*yield*/, context.spHttpClient.get(apiUrl, SPHttpClient.configurations.v1)];
812
- case 1:
813
- data = _a.sent();
814
- if (!data.ok) return [3 /*break*/, 3];
815
- return [4 /*yield*/, data.json()];
816
- case 2:
817
- results = _a.sent();
818
- if (results) {
819
- return [2 /*return*/, results];
820
- }
821
- _a.label = 3;
822
- case 3: return [2 /*return*/, null];
823
- case 4:
824
- error_6 = _a.sent();
825
- console.dir(error_6);
826
- return [2 /*return*/, Promise.reject(error_6)];
827
- case 5: return [2 /*return*/];
828
- }
829
- });
830
- }); };
831
838
  _this.closeValidationErrorDialog = function () {
832
839
  _this.setState({
833
840
  isValidationErrorDialogOpen: false,
@@ -849,6 +856,55 @@ var DynamicForm = /** @class */ (function (_super) {
849
856
  }
850
857
  return errorMessage;
851
858
  };
859
+ _this.renderFileSelectionControl = function () {
860
+ var _a = _this.state, selectedFile = _a.selectedFile, missingSelectedFile = _a.missingSelectedFile;
861
+ var labelEl = React.createElement("label", { className: styles.fieldRequired + ' ' + styles.fieldLabel }, strings.DynamicFormChooseFileLabel);
862
+ return React.createElement("div", null,
863
+ React.createElement("div", { className: styles.titleContainer },
864
+ React.createElement(Icon, { className: styles.fieldIcon, iconName: "DocumentSearch" }),
865
+ labelEl),
866
+ React.createElement(FilePicker, { buttonLabel: strings.DynamicFormChooseFileButtonText, accepts: _this.props.supportedFileExtensions ? _this.props.supportedFileExtensions : [".docx", ".doc", ".pptx", ".ppt", ".xlsx", ".xls", ".pdf"], onSave: function (filePickerResult) {
867
+ if (filePickerResult.length === 1) {
868
+ _this.setState({
869
+ selectedFile: filePickerResult[0],
870
+ missingSelectedFile: false
871
+ });
872
+ }
873
+ else {
874
+ _this.setState({
875
+ missingSelectedFile: true
876
+ });
877
+ }
878
+ }, required: true, context: _this.props.context, hideWebSearchTab: true, hideStockImages: true, hideLocalMultipleUploadTab: true, hideLinkUploadTab: true, hideSiteFilesTab: true, checkIfFileExists: true }),
879
+ selectedFile && React.createElement("div", { className: styles.selectedFileContainer },
880
+ React.createElement(Icon, { iconName: _this.getFileIconFromExtension() }),
881
+ selectedFile.fileName),
882
+ missingSelectedFile === true &&
883
+ React.createElement("div", { className: styles.errormessage }, strings.DynamicFormRequiredFileMessage));
884
+ };
885
+ _this.getFileIconFromExtension = function () {
886
+ var fileExtension = _this.state.selectedFile.fileName.split('.').pop();
887
+ switch (fileExtension) {
888
+ case 'pdf':
889
+ return 'PDF';
890
+ case 'docx':
891
+ case 'doc':
892
+ return 'WordDocument';
893
+ case 'pptx':
894
+ case 'ppt':
895
+ return 'PowerPointDocument';
896
+ case 'xlsx':
897
+ case 'xls':
898
+ return 'ExcelDocument';
899
+ case 'jpg':
900
+ case 'jpeg':
901
+ case 'png':
902
+ case 'gif':
903
+ return 'FileImage';
904
+ default:
905
+ return 'Document';
906
+ }
907
+ };
852
908
  // Initialize pnp sp
853
909
  if (_this.props.webAbsoluteUrl) {
854
910
  sp.setup({
@@ -867,45 +923,115 @@ var DynamicForm = /** @class */ (function (_super) {
867
923
  }
868
924
  // Initialize state
869
925
  _this.state = {
926
+ infoErrorMessages: [],
870
927
  fieldCollection: [],
928
+ validationFormulas: {},
929
+ clientValidationFormulas: {},
930
+ validationErrors: {},
931
+ hiddenByFormula: [],
871
932
  isValidationErrorDialogOpen: false,
872
933
  };
873
934
  // Get SPService Factory
874
935
  _this._spService = _this.props.webAbsoluteUrl
875
936
  ? new SPservice(_this.props.context, _this.props.webAbsoluteUrl)
876
937
  : new SPservice(_this.props.context);
938
+ // Setup Formula Validation utils
939
+ _this._formulaEvaluation = new FormulaEvaluation(_this.props.context, _this.props.webAbsoluteUrl);
940
+ // Setup Custom Formatting utils
941
+ _this._customFormatter = new CustomFormattingHelper(_this._formulaEvaluation);
877
942
  return _this;
878
943
  }
879
944
  /**
880
945
  * Lifecycle hook when component is mounted
881
946
  */
882
947
  DynamicForm.prototype.componentDidMount = function () {
883
- this.getFieldInformations()
948
+ this.getListInformation()
884
949
  .then(function () {
885
950
  /* no-op; */
886
951
  })
887
- .catch(function () {
952
+ .catch(function (err) {
888
953
  /* no-op; */
954
+ console.error(err);
889
955
  });
890
956
  };
957
+ DynamicForm.prototype.componentDidUpdate = function (prevProps, prevState) {
958
+ var _this = this;
959
+ if (!isEqual(prevProps, this.props)) {
960
+ // Props have changed due to parent component or workbench config, reset state
961
+ this.setState({
962
+ infoErrorMessages: [],
963
+ validationErrors: {} // Reset validation errors
964
+ }, function () {
965
+ // If listId or listItemId have changed, reload list information
966
+ if (prevProps.listId !== _this.props.listId || prevProps.listItemId !== _this.props.listItemId) {
967
+ _this.getListInformation()
968
+ .then(function () {
969
+ /* no-op; */
970
+ })
971
+ .catch(function (err) {
972
+ /* no-op; */
973
+ console.error(err);
974
+ });
975
+ }
976
+ else {
977
+ _this.performValidation();
978
+ }
979
+ });
980
+ }
981
+ };
891
982
  /**
892
983
  * Default React component render method
893
984
  */
894
985
  DynamicForm.prototype.render = function () {
986
+ var _a;
895
987
  var _this = this;
896
- var _a = this.state, fieldCollection = _a.fieldCollection, isSaving = _a.isSaving;
897
- var fieldOverrides = this.props.fieldOverrides;
988
+ var _b = this.state, customFormatting = _b.customFormatting, fieldCollection = _b.fieldCollection, hiddenByFormula = _b.hiddenByFormula, infoErrorMessages = _b.infoErrorMessages, isSaving = _b.isSaving;
989
+ var customFormattingDisabled = this.props.useCustomFormatting === false;
990
+ // Custom Formatting - Header
991
+ var headerContent;
992
+ if (!customFormattingDisabled && (customFormatting === null || customFormatting === void 0 ? void 0 : customFormatting.header)) {
993
+ headerContent = this._customFormatter.renderCustomFormatContent(customFormatting.header, this.getFormValuesForValidation(), true);
994
+ }
995
+ // Custom Formatting - Body
996
+ var bodySections = [];
997
+ if (!customFormattingDisabled && (customFormatting === null || customFormatting === void 0 ? void 0 : customFormatting.body)) {
998
+ bodySections.push.apply(bodySections, customFormatting.body.slice());
999
+ if (bodySections.length > 0) {
1000
+ var specifiedFields_1 = bodySections.reduce(function (prev, cur) {
1001
+ prev.push.apply(prev, cur.fields);
1002
+ return prev;
1003
+ }, []);
1004
+ var omittedFields = fieldCollection.filter(function (f) { return !specifiedFields_1.includes(f.label); }).map(function (f) { return f.label; });
1005
+ (_a = bodySections[bodySections.length - 1].fields).push.apply(_a, omittedFields);
1006
+ }
1007
+ }
1008
+ // Custom Formatting - Footer
1009
+ var footerContent;
1010
+ if (!customFormattingDisabled && (customFormatting === null || customFormatting === void 0 ? void 0 : customFormatting.footer)) {
1011
+ footerContent = this._customFormatter.renderCustomFormatContent(customFormatting.footer, this.getFormValuesForValidation(), true);
1012
+ }
1013
+ // Content Type
1014
+ var contentTypeId = this.props.contentTypeId;
1015
+ if (this.state.contentTypeId !== undefined)
1016
+ contentTypeId = this.state.contentTypeId;
898
1017
  return (React.createElement("div", null,
1018
+ infoErrorMessages.map(function (ie, i) { return (React.createElement(MessageBar, { key: i, messageBarType: ie.type }, ie.message)); }),
899
1019
  fieldCollection.length === 0 ? (React.createElement("div", null,
900
1020
  React.createElement(ProgressIndicator, { label: strings.DynamicFormLoading, description: strings.DynamicFormPleaseWait }))) : (React.createElement("div", null,
901
- fieldCollection.map(function (v, i) {
902
- if (fieldOverrides &&
903
- Object.prototype.hasOwnProperty.call(fieldOverrides, v.columnInternalName)) {
904
- v.disabled = v.disabled || isSaving;
905
- return fieldOverrides[v.columnInternalName](v);
906
- }
907
- return (React.createElement(DynamicField, __assign({ key: v.columnInternalName }, v, { disabled: v.disabled || isSaving })));
908
- }),
1021
+ headerContent,
1022
+ this.props.enableFileSelection === true &&
1023
+ this.props.listItemId === undefined &&
1024
+ contentTypeId !== undefined &&
1025
+ contentTypeId.startsWith("0x0101") &&
1026
+ this.renderFileSelectionControl(),
1027
+ (bodySections.length > 0 && !customFormattingDisabled) && bodySections
1028
+ .filter(function (bs) { return bs.fields.filter(function (bsf) { return hiddenByFormula.indexOf(bsf) < 0; }).length > 0; })
1029
+ .map(function (section, i) { return (React.createElement(React.Fragment, null,
1030
+ React.createElement("h2", { className: styles.sectionTitle }, section.displayname),
1031
+ React.createElement("div", { className: styles.sectionFormFields }, section.fields.map(function (f, i) { return (React.createElement("div", { key: f, className: styles.sectionFormField }, _this.renderField(fieldCollection.find(function (fc) { return fc.label === f; })))); })),
1032
+ i < bodySections.length - 1 && React.createElement("hr", { className: styles.sectionLine, "aria-hidden": true }))); }),
1033
+ (bodySections.length === 0 || customFormattingDisabled) && fieldCollection.map(function (f, i) { return _this.renderField(f); }),
1034
+ footerContent,
909
1035
  !this.props.disabled && (React.createElement(Stack, { className: styles.buttons, horizontal: true, tokens: stackTokens },
910
1036
  React.createElement(PrimaryButton, { disabled: isSaving, text: strings.Save, onClick: function () { return _this.onSubmitClick(); } }),
911
1037
  React.createElement(DefaultButton, { disabled: isSaving, text: strings.Cancel, onClick: this.props.onCancelled }))))),
@@ -923,6 +1049,305 @@ var DynamicForm = /** @class */ (function (_super) {
923
1049
  React.createElement("div", { className: "ms-Dialog-actionsRight ".concat(styles.actionsRight) },
924
1050
  React.createElement(DefaultButton, { className: styles.action, onClick: this.closeValidationErrorDialog, text: strings.CloseButton }))))));
925
1051
  };
1052
+ DynamicForm.prototype.updateFormMessages = function (type, message) {
1053
+ var infoErrorMessages = this.state.infoErrorMessages;
1054
+ var newMessages = infoErrorMessages.slice();
1055
+ newMessages.push({ type: type, message: message });
1056
+ this.setState({ infoErrorMessages: newMessages });
1057
+ };
1058
+ /**
1059
+ * Builds a collection of fields to be rendered in the form
1060
+ * @param listInfo Data returned by RenderListDataAsStream with RenderOptions = 64 (ClientFormSchema)
1061
+ * @param contentTypeName SharePoint List Content Type
1062
+ * @param item SharePoint List Item
1063
+ * @param numberFields Additional information about Number fields (min and max values)
1064
+ * @param listId SharePoint List ID
1065
+ * @param listItemId SharePoint List Item ID
1066
+ * @param disabledFields Fields that should be disabled due to configuration
1067
+ * @returns
1068
+ */
1069
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1070
+ DynamicForm.prototype.buildFieldCollection = function (listInfo, contentTypeName, item, numberFields, listId, listItemId, disabledFields) {
1071
+ return __awaiter(this, void 0, void 0, function () {
1072
+ var tempFields, order, hiddenFields, defaultDayOfWeek, _loop_3, this_2, i, len;
1073
+ return __generator(this, function (_a) {
1074
+ switch (_a.label) {
1075
+ case 0:
1076
+ tempFields = [];
1077
+ order = 0;
1078
+ hiddenFields = this.props.hiddenFields !== undefined ? this.props.hiddenFields : [];
1079
+ defaultDayOfWeek = 0;
1080
+ _loop_3 = function (i, len) {
1081
+ var field, hiddenName, termSetId, anchorId, lookupListId, lookupField, choices_1, defaultValue, value, stringValue, subPropertyValues, richText, dateFormat, principalType, cultureName, minValue, maxValue, showAsPercentage, selectedTags_1, numberField, userEmails, _b, _c, response;
1082
+ return __generator(this, function (_d) {
1083
+ switch (_d.label) {
1084
+ case 0:
1085
+ field = listInfo.ClientForms.Edit[contentTypeName][i];
1086
+ if (!(hiddenFields.indexOf(field.InternalName) < 0)) return [3 /*break*/, 18];
1087
+ order++;
1088
+ hiddenName = "";
1089
+ termSetId = "";
1090
+ anchorId = "";
1091
+ lookupListId = "";
1092
+ lookupField = "";
1093
+ choices_1 = [];
1094
+ defaultValue = null;
1095
+ value = undefined;
1096
+ stringValue = null;
1097
+ subPropertyValues = {};
1098
+ richText = false;
1099
+ dateFormat = void 0;
1100
+ principalType = "";
1101
+ cultureName = void 0;
1102
+ minValue = void 0;
1103
+ maxValue = void 0;
1104
+ showAsPercentage = void 0;
1105
+ selectedTags_1 = [];
1106
+ // If a SharePoint Item was loaded, get the field value from it
1107
+ if (item !== null && item[field.InternalName]) {
1108
+ value = item[field.InternalName];
1109
+ stringValue = value.toString();
1110
+ }
1111
+ else {
1112
+ defaultValue = field.DefaultValue;
1113
+ }
1114
+ // Store choices for Choice fields
1115
+ if (field.FieldType === "Choice") {
1116
+ field.Choices.forEach(function (element) {
1117
+ choices_1.push({ key: element, text: element });
1118
+ });
1119
+ }
1120
+ if (field.FieldType === "MultiChoice") {
1121
+ field.MultiChoices.forEach(function (element) {
1122
+ choices_1.push({ key: element, text: element });
1123
+ });
1124
+ }
1125
+ // Setup Note, Number and Currency fields
1126
+ if (field.FieldType === "Note") {
1127
+ richText = field.RichText;
1128
+ }
1129
+ if (field.FieldType === "Number" || field.FieldType === "Currency") {
1130
+ numberField = numberFields.find(function (f) { return f.InternalName === field.InternalName; });
1131
+ if (numberField) {
1132
+ minValue = numberField.MinimumValue;
1133
+ maxValue = numberField.MaximumValue;
1134
+ }
1135
+ showAsPercentage = field.ShowAsPercentage;
1136
+ if (field.FieldType === "Currency") {
1137
+ cultureName = this_2.cultureNameLookup(numberField.CurrencyLocaleId);
1138
+ }
1139
+ }
1140
+ if (!(field.FieldType === "Lookup" || field.FieldType === "LookupMulti")) return [3 /*break*/, 3];
1141
+ lookupListId = field.LookupListId;
1142
+ lookupField = field.LookupFieldName;
1143
+ if (!(item !== null)) return [3 /*break*/, 2];
1144
+ return [4 /*yield*/, this_2._spService.getLookupValues(listId, listItemId, field.InternalName, lookupField, this_2.webURL)];
1145
+ case 1:
1146
+ value = _d.sent();
1147
+ stringValue = value === null || value === void 0 ? void 0 : value.map(function (dv) { return dv.key + ';#' + dv.name; }).join(';#');
1148
+ if (item[field.InternalName + "Id"]) {
1149
+ subPropertyValues.id = item[field.InternalName + "Id"];
1150
+ subPropertyValues.lookupId = subPropertyValues.id;
1151
+ }
1152
+ subPropertyValues.lookupValue = value === null || value === void 0 ? void 0 : value.map(function (dv) { return dv.name; });
1153
+ return [3 /*break*/, 3];
1154
+ case 2:
1155
+ value = [];
1156
+ _d.label = 3;
1157
+ case 3:
1158
+ if (!(field.FieldType === "User")) return [3 /*break*/, 7];
1159
+ if (!(item !== null)) return [3 /*break*/, 5];
1160
+ userEmails = [];
1161
+ _c = (_b = userEmails).push;
1162
+ return [4 /*yield*/, this_2._spService.getUserUPNFromFieldValue(listId, listItemId, field.InternalName, this_2.webURL)];
1163
+ case 4:
1164
+ _c.apply(_b, [(_d.sent()) + ""]);
1165
+ value = userEmails;
1166
+ stringValue = userEmails === null || userEmails === void 0 ? void 0 : userEmails.map(function (dv) { return dv.split('/').shift(); }).join(';');
1167
+ if (item[field.InternalName + "Id"]) {
1168
+ subPropertyValues.id = item[field.InternalName + "Id"];
1169
+ }
1170
+ subPropertyValues.title = userEmails === null || userEmails === void 0 ? void 0 : userEmails.map(function (dv) { return dv.split('/').pop(); })[0];
1171
+ subPropertyValues.email = userEmails[0];
1172
+ return [3 /*break*/, 6];
1173
+ case 5:
1174
+ value = [];
1175
+ _d.label = 6;
1176
+ case 6:
1177
+ principalType = field.PrincipalAccountType;
1178
+ _d.label = 7;
1179
+ case 7:
1180
+ if (!(field.FieldType === "UserMulti")) return [3 /*break*/, 11];
1181
+ if (!(item !== null)) return [3 /*break*/, 9];
1182
+ return [4 /*yield*/, this_2._spService.getUsersUPNFromFieldValue(listId, listItemId, field.InternalName, this_2.webURL)];
1183
+ case 8:
1184
+ value = _d.sent();
1185
+ stringValue = value === null || value === void 0 ? void 0 : value.map(function (dv) { return dv.split('/').pop(); }).join(';');
1186
+ return [3 /*break*/, 10];
1187
+ case 9:
1188
+ value = [];
1189
+ _d.label = 10;
1190
+ case 10:
1191
+ principalType = field.PrincipalAccountType;
1192
+ _d.label = 11;
1193
+ case 11:
1194
+ if (!(field.FieldType === "TaxonomyFieldType")) return [3 /*break*/, 15];
1195
+ termSetId = field.TermSetId;
1196
+ anchorId = field.AnchorId;
1197
+ if (!(item !== null)) return [3 /*break*/, 13];
1198
+ return [4 /*yield*/, this_2._spService.getSingleManagedMetadataLabel(listId, listItemId, field.InternalName)];
1199
+ case 12:
1200
+ response = _d.sent();
1201
+ if (response) {
1202
+ selectedTags_1.push({
1203
+ key: response.TermID,
1204
+ name: response.Label,
1205
+ });
1206
+ value = selectedTags_1;
1207
+ stringValue = selectedTags_1 === null || selectedTags_1 === void 0 ? void 0 : selectedTags_1.map(function (dv) { return dv.key + ';#' + dv.name; }).join(';#');
1208
+ }
1209
+ return [3 /*break*/, 14];
1210
+ case 13:
1211
+ if (defaultValue !== "") {
1212
+ selectedTags_1.push({
1213
+ key: defaultValue.split("|")[1],
1214
+ name: defaultValue.split("|")[0].split("#")[1],
1215
+ });
1216
+ value = selectedTags_1;
1217
+ }
1218
+ _d.label = 14;
1219
+ case 14:
1220
+ if (defaultValue === "")
1221
+ defaultValue = null;
1222
+ _d.label = 15;
1223
+ case 15:
1224
+ if (field.FieldType === "TaxonomyFieldTypeMulti") {
1225
+ hiddenName = field.HiddenListInternalName;
1226
+ termSetId = field.TermSetId;
1227
+ anchorId = field.AnchorId;
1228
+ if (item !== null) {
1229
+ item[field.InternalName].forEach(function (element) {
1230
+ selectedTags_1.push({
1231
+ key: element.TermGuid,
1232
+ name: element.Label,
1233
+ });
1234
+ });
1235
+ defaultValue = selectedTags_1;
1236
+ }
1237
+ else {
1238
+ if (defaultValue !== null && defaultValue !== "") {
1239
+ defaultValue.split(/#|;/).forEach(function (element) {
1240
+ if (element.indexOf("|") !== -1)
1241
+ selectedTags_1.push({
1242
+ key: element.split("|")[1],
1243
+ name: element.split("|")[0],
1244
+ });
1245
+ });
1246
+ value = selectedTags_1;
1247
+ stringValue = selectedTags_1 === null || selectedTags_1 === void 0 ? void 0 : selectedTags_1.map(function (dv) { return dv.key + ';#' + dv.name; }).join(';#');
1248
+ }
1249
+ }
1250
+ if (defaultValue === "")
1251
+ defaultValue = null;
1252
+ }
1253
+ if (!(field.FieldType === "DateTime")) return [3 /*break*/, 17];
1254
+ if (item !== null && item[field.InternalName]) {
1255
+ value = new Date(item[field.InternalName]);
1256
+ stringValue = value.toISOString();
1257
+ }
1258
+ else if (defaultValue === "[today]") {
1259
+ defaultValue = new Date();
1260
+ }
1261
+ else if (defaultValue) {
1262
+ defaultValue = new Date(defaultValue);
1263
+ }
1264
+ dateFormat = field.DateFormat || "DateOnly";
1265
+ return [4 /*yield*/, this_2._spService.getRegionalWebSettings()];
1266
+ case 16:
1267
+ defaultDayOfWeek = (_d.sent()).FirstDayOfWeek;
1268
+ _d.label = 17;
1269
+ case 17:
1270
+ // Setup Thumbnail, Location and Boolean fields
1271
+ if (field.FieldType === "Thumbnail") {
1272
+ if (defaultValue) {
1273
+ defaultValue = JSON.parse(defaultValue).serverRelativeUrl;
1274
+ }
1275
+ if (value) {
1276
+ value = JSON.parse(value).serverRelativeUrl;
1277
+ }
1278
+ }
1279
+ if (field.FieldType === "Location") {
1280
+ if (defaultValue)
1281
+ defaultValue = JSON.parse(defaultValue);
1282
+ if (value)
1283
+ value = JSON.parse(value);
1284
+ }
1285
+ if (field.FieldType === "Boolean") {
1286
+ if (defaultValue !== undefined && defaultValue !== null)
1287
+ defaultValue = Boolean(Number(defaultValue));
1288
+ if (value !== undefined && value !== null)
1289
+ value = Boolean(Number(value));
1290
+ }
1291
+ tempFields.push({
1292
+ value: value,
1293
+ newValue: undefined,
1294
+ stringValue: stringValue,
1295
+ subPropertyValues: subPropertyValues,
1296
+ cultureName: cultureName,
1297
+ fieldTermSetId: termSetId,
1298
+ fieldAnchorId: anchorId,
1299
+ options: choices_1,
1300
+ lookupListID: lookupListId,
1301
+ lookupField: lookupField,
1302
+ // changedValue: defaultValue,
1303
+ fieldType: field.FieldType,
1304
+ // fieldTitle: field.Title,
1305
+ defaultValue: defaultValue,
1306
+ context: this_2.props.context,
1307
+ disabled: this_2.props.disabled ||
1308
+ (disabledFields &&
1309
+ disabledFields.indexOf(field.InternalName) > -1),
1310
+ // listId: this.props.listId,
1311
+ columnInternalName: field.InternalName,
1312
+ label: field.Title,
1313
+ onChanged: this_2.onChange,
1314
+ required: field.Required,
1315
+ hiddenFieldName: hiddenName,
1316
+ Order: order,
1317
+ isRichText: richText,
1318
+ dateFormat: dateFormat,
1319
+ firstDayOfWeek: defaultDayOfWeek,
1320
+ listItemId: listItemId,
1321
+ principalType: principalType,
1322
+ description: field.Description,
1323
+ minimumValue: minValue,
1324
+ maximumValue: maxValue,
1325
+ showAsPercentage: showAsPercentage,
1326
+ });
1327
+ // This may not be necessary now using RenderListDataAsStream
1328
+ tempFields.sort(function (a, b) { return a.Order - b.Order; });
1329
+ _d.label = 18;
1330
+ case 18: return [2 /*return*/];
1331
+ }
1332
+ });
1333
+ };
1334
+ this_2 = this;
1335
+ i = 0, len = listInfo.ClientForms.Edit[contentTypeName].length;
1336
+ _a.label = 1;
1337
+ case 1:
1338
+ if (!(i < len)) return [3 /*break*/, 4];
1339
+ return [5 /*yield**/, _loop_3(i, len)];
1340
+ case 2:
1341
+ _a.sent();
1342
+ _a.label = 3;
1343
+ case 3:
1344
+ i++;
1345
+ return [3 /*break*/, 1];
1346
+ case 4: return [2 /*return*/, tempFields];
1347
+ }
1348
+ });
1349
+ });
1350
+ };
926
1351
  DynamicForm.prototype.cultureNameLookup = function (lcid) {
927
1352
  var _a, _b;
928
1353
  var pageCulture = this.props.context.pageContext.cultureInfo.currentCultureName;
@@ -930,10 +1355,6 @@ var DynamicForm = /** @class */ (function (_super) {
930
1355
  return pageCulture;
931
1356
  return (_b = (_a = this.state.installedLanguages) === null || _a === void 0 ? void 0 : _a.find(function (lang) { return lang.Lcid === lcid; }).DisplayName) !== null && _b !== void 0 ? _b : pageCulture;
932
1357
  };
933
- DynamicForm.prototype.isEmptyNumOrString = function (value) {
934
- if (((value === null || value === void 0 ? void 0 : value.toString().trim().length) || 0) === 0)
935
- return true;
936
- };
937
1358
  return DynamicForm;
938
1359
  }(React.Component));
939
1360
  export { DynamicForm };