@flusys/nestjs-form-builder 9.1.1 → 9.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/config/message-keys.d.ts +1 -0
- package/fesm/432.js +177 -220
- package/fesm/config/index.js +2 -1
- package/fesm/index.js +7 -3
- package/package.json +3 -3
- package/services/form.service.d.ts +1 -0
- package/utils/computed-field.utils.d.ts +13 -37
package/README.md
CHANGED
|
@@ -206,6 +206,17 @@ FormBuilderModule.forRoot({
|
|
|
206
206
|
|
|
207
207
|
---
|
|
208
208
|
|
|
209
|
+
## 4. Computed Fields
|
|
210
|
+
|
|
211
|
+
`schema.settings.computedFields[]` are calculated on final submission (not drafts) and stored under `data._computed[key]`. Each field has ordered `rules` - `{ condition?, value }`, first match wins, else `defaultValue` - where `value` is an [Expression](../nestjs-shared/README.md#10-expressions) and `condition` an expression condition group. Combinations (regex extract, then join with another field, then upper-case; inline if / else) are just nested expressions.
|
|
212
|
+
|
|
213
|
+
- References: a field id, a field `name` (what templates use, `{{ email }}`), or `computed.<key>` for a computed field defined **earlier**.
|
|
214
|
+
- `valueType` (`number` | `string` | `boolean`) casts the result; a rule that fails at run time falls back to `defaultValue` instead of failing the submission.
|
|
215
|
+
- Saving a form validates its computed fields (`findComputedFieldIssue`): key format and uniqueness, shape, unknown references or functions, argument counts, literal regex patterns. A problem is a 400 with `form.invalid.computed.field` and `{ field, code, ... }`.
|
|
216
|
+
- **Breaking (v9):** the old rule shape (`computation: { type: 'direct' | 'field_reference' | 'arithmetic', config }` with `{ fieldId, comparison }` conditions) is not read or converted. A form saved with it computes only `defaultValue` on submit and is refused on save until its computed fields are rebuilt in the builder.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
209
220
|
## License
|
|
210
221
|
|
|
211
222
|
MIT © FLUSYS
|
package/config/message-keys.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare const FORM_MESSAGES: {
|
|
|
15
15
|
readonly OTP_EXPIRED: "form.email.otp.expired";
|
|
16
16
|
readonly OTP_TOO_MANY_ATTEMPTS: "form.email.otp.too.many.attempts";
|
|
17
17
|
readonly OTP_VERIFIED: "form.email.otp.verified";
|
|
18
|
+
readonly INVALID_COMPUTED_FIELD: "form.invalid.computed.field";
|
|
18
19
|
};
|
|
19
20
|
export declare const FORM_RESULT_MESSAGES: {
|
|
20
21
|
readonly GET_ALL_SUCCESS: "form.result.get.all.success";
|
package/fesm/432.js
CHANGED
|
@@ -68,7 +68,8 @@ const FORM_MESSAGES = {
|
|
|
68
68
|
OTP_INVALID: 'form.email.otp.invalid',
|
|
69
69
|
OTP_EXPIRED: 'form.email.otp.expired',
|
|
70
70
|
OTP_TOO_MANY_ATTEMPTS: 'form.email.otp.too.many.attempts',
|
|
71
|
-
OTP_VERIFIED: 'form.email.otp.verified'
|
|
71
|
+
OTP_VERIFIED: 'form.email.otp.verified',
|
|
72
|
+
INVALID_COMPUTED_FIELD: 'form.invalid.computed.field'
|
|
72
73
|
};
|
|
73
74
|
const FORM_RESULT_MESSAGES = {
|
|
74
75
|
GET_ALL_SUCCESS: 'form.result.get.all.success',
|
|
@@ -1173,16 +1174,16 @@ FormEmailAuthService = _ts_decorate([
|
|
|
1173
1174
|
/* import */ var _flusys_nestjs_shared_modules__rspack_import_3 = __webpack_require__(236);
|
|
1174
1175
|
/* import */ var _nestjs_common__rspack_import_4 = __webpack_require__(157);
|
|
1175
1176
|
/* import */ var typeorm__rspack_import_5 = __webpack_require__(158);
|
|
1176
|
-
/* import */ var
|
|
1177
|
-
/* import */ var
|
|
1177
|
+
/* import */ var _config_index_js__rspack_import_13 = __webpack_require__(769);
|
|
1178
|
+
/* import */ var _config_index_js__rspack_import_14 = __webpack_require__(137);
|
|
1178
1179
|
/* import */ var _dtos_form_result_dto_js__rspack_import_6 = __webpack_require__(788);
|
|
1179
1180
|
/* import */ var _entities_index_js__rspack_import_7 = __webpack_require__(814);
|
|
1180
|
-
/* import */ var
|
|
1181
|
-
/* import */ var
|
|
1182
|
-
/* import */ var
|
|
1183
|
-
/* import */ var
|
|
1184
|
-
/* import */ var
|
|
1185
|
-
/* import */ var
|
|
1181
|
+
/* import */ var _enums_form_access_type_enum_js__rspack_import_15 = __webpack_require__(376);
|
|
1182
|
+
/* import */ var _utils_computed_field_utils_js__rspack_import_8 = __webpack_require__(801);
|
|
1183
|
+
/* import */ var _utils_permission_utils_js__rspack_import_9 = __webpack_require__(988);
|
|
1184
|
+
/* import */ var _form_builder_config_service_js__rspack_import_10 = __webpack_require__(781);
|
|
1185
|
+
/* import */ var _form_builder_datasource_provider_js__rspack_import_11 = __webpack_require__(593);
|
|
1186
|
+
/* import */ var _form_email_auth_service_js__rspack_import_12 = __webpack_require__(474);
|
|
1186
1187
|
function _ts_decorate(decorators, target, key, desc) {
|
|
1187
1188
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1188
1189
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -1237,7 +1238,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1237
1238
|
// Does not span multiple app instances; see withSubmissionLock().
|
|
1238
1239
|
static submissionLocks = new Map();
|
|
1239
1240
|
constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider, formEmailAuthService, permissionResolver, permissionCache){
|
|
1240
|
-
super(
|
|
1241
|
+
super(_config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ENTITIES.FORM_RESULT */.eF.FORM_RESULT, cacheManager, utilsService, FormResultService.name, true, _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_MODULE */.T$, dataSourceProvider, _entities_index_js__rspack_import_7/* .FormResult */.ez), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.dataSourceProvider = dataSourceProvider, this.formEmailAuthService = formEmailAuthService, this.permissionResolver = permissionResolver, this.permissionCache = permissionCache;
|
|
1241
1242
|
}
|
|
1242
1243
|
async ensureFormRepositoryInitialized() {
|
|
1243
1244
|
if (!this.formRepository) {
|
|
@@ -1275,7 +1276,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1275
1276
|
if (!form) {
|
|
1276
1277
|
throw new _nestjs_common__rspack_import_4.NotFoundException({
|
|
1277
1278
|
message: 'Form not found or inactive',
|
|
1278
|
-
messageKey:
|
|
1279
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.NOT_FOUND */.Q.NOT_FOUND
|
|
1279
1280
|
});
|
|
1280
1281
|
}
|
|
1281
1282
|
return form;
|
|
@@ -1288,67 +1289,67 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1288
1289
|
}
|
|
1289
1290
|
}
|
|
1290
1291
|
static PUBLICLY_SUBMITTABLE_ACCESS_TYPES = new Set([
|
|
1291
|
-
|
|
1292
|
-
|
|
1292
|
+
_enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.PUBLIC */.h.PUBLIC,
|
|
1293
|
+
_enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED
|
|
1293
1294
|
]);
|
|
1294
1295
|
async validateSubmissionAccess(form, user, isPublic) {
|
|
1295
1296
|
if (isPublic) {
|
|
1296
1297
|
if (!FormResultService.PUBLICLY_SUBMITTABLE_ACCESS_TYPES.has(form.accessType)) {
|
|
1297
1298
|
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1298
1299
|
message: 'This form is not available for public submission',
|
|
1299
|
-
messageKey:
|
|
1300
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.NOT_PUBLIC */.Q.NOT_PUBLIC
|
|
1300
1301
|
});
|
|
1301
1302
|
}
|
|
1302
1303
|
return;
|
|
1303
1304
|
}
|
|
1304
1305
|
switch(form.accessType){
|
|
1305
|
-
case
|
|
1306
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.PUBLIC */.h.PUBLIC:
|
|
1306
1307
|
return;
|
|
1307
|
-
case
|
|
1308
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED:
|
|
1308
1309
|
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1309
1310
|
message: 'Email-verified forms must be submitted through the public endpoint',
|
|
1310
|
-
messageKey:
|
|
1311
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1311
1312
|
});
|
|
1312
|
-
case
|
|
1313
|
-
case
|
|
1313
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP:
|
|
1314
|
+
case _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED:
|
|
1314
1315
|
break;
|
|
1315
1316
|
default:
|
|
1316
1317
|
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1317
1318
|
message: 'Invalid form access type',
|
|
1318
|
-
messageKey:
|
|
1319
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1319
1320
|
});
|
|
1320
1321
|
}
|
|
1321
1322
|
if (!user) {
|
|
1322
1323
|
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1323
1324
|
message: 'Authentication required to submit this form',
|
|
1324
|
-
messageKey:
|
|
1325
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.AUTH_REQUIRED */.Q.AUTH_REQUIRED
|
|
1325
1326
|
});
|
|
1326
1327
|
}
|
|
1327
|
-
if (form.accessType ===
|
|
1328
|
-
const permitted = await (0,
|
|
1328
|
+
if (form.accessType === _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP && form.permissionLogic) {
|
|
1329
|
+
const permitted = await (0,_utils_permission_utils_js__rspack_import_9/* .hasFormPermission */.E)(user, form.permissionLogic, {
|
|
1329
1330
|
resolver: this.permissionResolver,
|
|
1330
1331
|
cache: this.permissionCache
|
|
1331
1332
|
});
|
|
1332
1333
|
if (!permitted) {
|
|
1333
1334
|
throw new _nestjs_common__rspack_import_4.ForbiddenException({
|
|
1334
1335
|
message: 'You do not have permission to submit this form',
|
|
1335
|
-
messageKey:
|
|
1336
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.ACCESS_DENIED */.Q.ACCESS_DENIED
|
|
1336
1337
|
});
|
|
1337
1338
|
}
|
|
1338
|
-
} else if (form.accessType !==
|
|
1339
|
+
} else if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED) {
|
|
1339
1340
|
throw new _nestjs_common__rspack_import_4.BadRequestException({
|
|
1340
1341
|
message: 'Invalid form access type',
|
|
1341
|
-
messageKey:
|
|
1342
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
|
|
1342
1343
|
});
|
|
1343
1344
|
}
|
|
1344
1345
|
}
|
|
1345
1346
|
async resolveEmailVerifiedSubmitter(form, user, accessToken) {
|
|
1346
|
-
if (form.accessType !==
|
|
1347
|
+
if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_15/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED) return null;
|
|
1347
1348
|
const email = await this.formEmailAuthService.resolveSubmitterEmail(form.id, user ?? undefined, accessToken);
|
|
1348
1349
|
if (!email) {
|
|
1349
1350
|
throw new _nestjs_common__rspack_import_4.UnauthorizedException({
|
|
1350
1351
|
message: 'Email verification required to submit this form',
|
|
1351
|
-
messageKey:
|
|
1352
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_MESSAGES.EMAIL_VERIFICATION_REQUIRED */.Q.EMAIL_VERIFICATION_REQUIRED
|
|
1352
1353
|
});
|
|
1353
1354
|
}
|
|
1354
1355
|
return email;
|
|
@@ -1368,7 +1369,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1368
1369
|
if (count > 0) {
|
|
1369
1370
|
throw new _nestjs_common__rspack_import_4.ConflictException({
|
|
1370
1371
|
message: 'You have already submitted a response to this form',
|
|
1371
|
-
messageKey:
|
|
1372
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_RESULT_MESSAGES.ALREADY_SUBMITTED */.y.ALREADY_SUBMITTED
|
|
1372
1373
|
});
|
|
1373
1374
|
}
|
|
1374
1375
|
}
|
|
@@ -1413,13 +1414,10 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1413
1414
|
if (isDraft) {
|
|
1414
1415
|
return data;
|
|
1415
1416
|
}
|
|
1416
|
-
const
|
|
1417
|
-
|
|
1418
|
-
const computedFields = settings?.computedFields;
|
|
1419
|
-
if (!computedFields || computedFields.length === 0) {
|
|
1417
|
+
const computedValues = (0,_utils_computed_field_utils_js__rspack_import_8/* .calculateComputedFields */.XZ)(data, form.schema);
|
|
1418
|
+
if (Object.keys(computedValues).length === 0) {
|
|
1420
1419
|
return data;
|
|
1421
1420
|
}
|
|
1422
|
-
const computedValues = (0,_utils_computed_field_utils_js__rspack_import_15/* .calculateComputedFields */.X)(data, computedFields);
|
|
1423
1421
|
return {
|
|
1424
1422
|
...data,
|
|
1425
1423
|
_computed: computedValues
|
|
@@ -1528,7 +1526,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1528
1526
|
if (!draft) {
|
|
1529
1527
|
throw new _nestjs_common__rspack_import_4.NotFoundException({
|
|
1530
1528
|
message: 'Draft not found',
|
|
1531
|
-
messageKey:
|
|
1529
|
+
messageKey: _config_index_js__rspack_import_14/* .FORM_RESULT_MESSAGES.NOT_FOUND */.y.NOT_FOUND
|
|
1532
1530
|
});
|
|
1533
1531
|
}
|
|
1534
1532
|
const form = await this.getActiveForm(dto.formId);
|
|
@@ -1548,7 +1546,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
|
|
|
1548
1546
|
return this.convertEntityToResponseDto(saved, false);
|
|
1549
1547
|
}
|
|
1550
1548
|
async publishSubmissionEvent(result, formId, isDraft, user) {
|
|
1551
|
-
await this.publishDomainAction(isDraft ?
|
|
1549
|
+
await this.publishDomainAction(isDraft ? _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED */.ov.DRAFT_SAVED : _config_index_js__rspack_import_13/* .FORM_BUILDER_EVENT_ACTIONS.SUBMITTED */.ov.SUBMITTED, {
|
|
1552
1550
|
ids: [
|
|
1553
1551
|
result.id
|
|
1554
1552
|
],
|
|
@@ -1641,9 +1639,9 @@ FormResultService = _ts_decorate([
|
|
|
1641
1639
|
}),
|
|
1642
1640
|
_ts_param(0, (0,_nestjs_common__rspack_import_4.Inject)('CACHE_INSTANCE')),
|
|
1643
1641
|
_ts_param(1, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_modules__rspack_import_3.UtilsService)),
|
|
1644
|
-
_ts_param(2, (0,_nestjs_common__rspack_import_4.Inject)(
|
|
1645
|
-
_ts_param(3, (0,_nestjs_common__rspack_import_4.Inject)(
|
|
1646
|
-
_ts_param(4, (0,_nestjs_common__rspack_import_4.Inject)(
|
|
1642
|
+
_ts_param(2, (0,_nestjs_common__rspack_import_4.Inject)(_form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j)),
|
|
1643
|
+
_ts_param(3, (0,_nestjs_common__rspack_import_4.Inject)(_form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._)),
|
|
1644
|
+
_ts_param(4, (0,_nestjs_common__rspack_import_4.Inject)(_form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w)),
|
|
1647
1645
|
_ts_param(5, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
1648
1646
|
_ts_param(5, (0,_nestjs_common__rspack_import_4.Inject)(_flusys_nestjs_shared_interfaces__rspack_import_2.PERMISSION_RESOLVER)),
|
|
1649
1647
|
_ts_param(6, (0,_nestjs_common__rspack_import_4.Optional)()),
|
|
@@ -1652,9 +1650,9 @@ FormResultService = _ts_decorate([
|
|
|
1652
1650
|
_ts_metadata("design:paramtypes", [
|
|
1653
1651
|
typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
|
|
1654
1652
|
typeof _flusys_nestjs_shared_modules__rspack_import_3.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.UtilsService,
|
|
1655
|
-
typeof
|
|
1656
|
-
typeof
|
|
1657
|
-
typeof
|
|
1653
|
+
typeof _form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j === "undefined" ? Object : _form_builder_config_service_js__rspack_import_10/* .FormBuilderConfigService */.j,
|
|
1654
|
+
typeof _form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : _form_builder_datasource_provider_js__rspack_import_11/* .FormBuilderDataSourceProvider */._,
|
|
1655
|
+
typeof _form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w === "undefined" ? Object : _form_email_auth_service_js__rspack_import_12/* .FormEmailAuthService */.w,
|
|
1658
1656
|
typeof IPermissionResolver === "undefined" ? Object : IPermissionResolver,
|
|
1659
1657
|
typeof _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_3.SharedPermissionCacheService
|
|
1660
1658
|
])
|
|
@@ -1695,6 +1693,8 @@ var message_keys = __webpack_require__(137);
|
|
|
1695
1693
|
var entities = __webpack_require__(814);
|
|
1696
1694
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/enums/form-access-type.enum.ts
|
|
1697
1695
|
var form_access_type_enum = __webpack_require__(376);
|
|
1696
|
+
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/utils/computed-field.utils.ts
|
|
1697
|
+
var computed_field_utils = __webpack_require__(801);
|
|
1698
1698
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/utils/permission.utils.ts
|
|
1699
1699
|
var permission_utils = __webpack_require__(988);
|
|
1700
1700
|
// EXTERNAL MODULE: ./projects/nestjs-form-builder/src/services/form-builder-config.service.ts
|
|
@@ -1738,6 +1738,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1738
1738
|
|
|
1739
1739
|
|
|
1740
1740
|
|
|
1741
|
+
|
|
1741
1742
|
class FormService extends classes_.ApiService {
|
|
1742
1743
|
cacheManager;
|
|
1743
1744
|
utilsService;
|
|
@@ -1751,6 +1752,9 @@ class FormService extends classes_.ApiService {
|
|
|
1751
1752
|
async convertSingleDtoToEntity(dto, user) {
|
|
1752
1753
|
let form = {};
|
|
1753
1754
|
let isUpdate = false;
|
|
1755
|
+
if (dto.schema) {
|
|
1756
|
+
this.assertValidComputedFields(dto.schema);
|
|
1757
|
+
}
|
|
1754
1758
|
// NOTE: Using 'id' in dto check instead of instanceof - instanceof may not work after esbuild bundling
|
|
1755
1759
|
if ('id' in dto && dto.id && typeof dto.id === 'string') {
|
|
1756
1760
|
const dbData = await this.repository.findOne({
|
|
@@ -1795,6 +1799,19 @@ class FormService extends classes_.ApiService {
|
|
|
1795
1799
|
}
|
|
1796
1800
|
return form;
|
|
1797
1801
|
}
|
|
1802
|
+
assertValidComputedFields(schema) {
|
|
1803
|
+
const issue = (0,computed_field_utils/* .findComputedFieldIssue */.Qc)(schema);
|
|
1804
|
+
if (!issue) return;
|
|
1805
|
+
throw new common_.BadRequestException({
|
|
1806
|
+
message: `Computed field "${issue.field}" is invalid (${issue.code}).`,
|
|
1807
|
+
messageKey: message_keys/* .FORM_MESSAGES.INVALID_COMPUTED_FIELD */.Q.INVALID_COMPUTED_FIELD,
|
|
1808
|
+
messageVariables: {
|
|
1809
|
+
field: issue.field,
|
|
1810
|
+
code: issue.code,
|
|
1811
|
+
...issue.variables
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1798
1815
|
async getSelectQuery(query, _user, select) {
|
|
1799
1816
|
if (!select || !select.length) {
|
|
1800
1817
|
select = [
|
|
@@ -2074,204 +2091,144 @@ FormService = _ts_decorate([
|
|
|
2074
2091
|
|
|
2075
2092
|
},
|
|
2076
2093
|
801(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
* NOTE: Interface definitions here mirror @flusys/ng-form-builder interfaces
|
|
2084
|
-
* but are defined separately to avoid cross-package dependencies.
|
|
2085
|
-
* Both use compatible JSON structures for form schema serialization.
|
|
2086
|
-
*
|
|
2087
|
-
* @see FLUSYS_NG/projects/ng-form-builder/interfaces/computed-field.interface.ts
|
|
2088
|
-
*/ // ============================================================================
|
|
2089
|
-
// Type Definitions
|
|
2090
|
-
// ============================================================================
|
|
2091
|
-
// ============================================================================
|
|
2092
|
-
// Type Guards & Helpers
|
|
2093
|
-
// ============================================================================
|
|
2094
|
-
function isObject(value) {
|
|
2095
|
-
return typeof value === 'object' && value !== null;
|
|
2096
|
-
}
|
|
2097
|
-
function isDirectValueConfig(config) {
|
|
2098
|
-
return isObject(config) && config.type === 'direct' && 'value' in config;
|
|
2094
|
+
/* import */ var _flusys_nestjs_shared_utils__rspack_import_0 = __webpack_require__(216);
|
|
2095
|
+
|
|
2096
|
+
/** A field reference to an earlier computed field: `computed.<key>`. */ const COMPUTED_REF_PREFIX = 'computed.';
|
|
2097
|
+
const COMPUTED_KEY_PATTERN = /^[A-Za-z_]\w*$/;
|
|
2098
|
+
function asSchema(schema) {
|
|
2099
|
+
return typeof schema === 'object' && schema !== null ? schema : {};
|
|
2099
2100
|
}
|
|
2100
|
-
function
|
|
2101
|
-
return
|
|
2101
|
+
function formFields(schema) {
|
|
2102
|
+
return (schema.sections ?? []).flatMap((section)=>section.fields ?? []).filter((field)=>typeof field?.id === 'string');
|
|
2102
2103
|
}
|
|
2103
|
-
function
|
|
2104
|
-
|
|
2104
|
+
/** References resolve by field id, by field name (what templates use), or `computed.<key>`. */ function createResolver(data, fields, computed) {
|
|
2105
|
+
const idByName = new Map(fields.filter((f)=>f.name).map((f)=>[
|
|
2106
|
+
f.name,
|
|
2107
|
+
f.id
|
|
2108
|
+
]));
|
|
2109
|
+
return (ref)=>{
|
|
2110
|
+
if (ref.startsWith(COMPUTED_REF_PREFIX)) {
|
|
2111
|
+
const key = ref.slice(COMPUTED_REF_PREFIX.length);
|
|
2112
|
+
return Object.hasOwn(computed, key) ? computed[key] : undefined;
|
|
2113
|
+
}
|
|
2114
|
+
if (Object.hasOwn(data, ref)) return data[ref];
|
|
2115
|
+
const id = idByName.get(ref);
|
|
2116
|
+
return id !== undefined && Object.hasOwn(data, id) ? data[id] : undefined;
|
|
2117
|
+
};
|
|
2105
2118
|
}
|
|
2106
|
-
function
|
|
2107
|
-
|
|
2119
|
+
function castValue(value, valueType) {
|
|
2120
|
+
if (value === null || value === undefined) return null;
|
|
2121
|
+
switch(valueType){
|
|
2122
|
+
case 'number':
|
|
2123
|
+
try {
|
|
2124
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToNumber)(value);
|
|
2125
|
+
} catch {
|
|
2126
|
+
return null;
|
|
2127
|
+
}
|
|
2128
|
+
case 'boolean':
|
|
2129
|
+
if (typeof value === 'boolean') return value;
|
|
2130
|
+
return [
|
|
2131
|
+
'true',
|
|
2132
|
+
'1',
|
|
2133
|
+
'yes'
|
|
2134
|
+
].includes(((0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToText)(value) ?? '').trim().toLowerCase());
|
|
2135
|
+
default:
|
|
2136
|
+
return (0,_flusys_nestjs_shared_utils__rspack_import_0.expressionToText)(value);
|
|
2137
|
+
}
|
|
2108
2138
|
}
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
return
|
|
2139
|
+
function computeField(field, ctx) {
|
|
2140
|
+
for (const rule of field.rules ?? []){
|
|
2141
|
+
if (!rule.condition || (0,_flusys_nestjs_shared_utils__rspack_import_0.evaluateConditionGroup)(rule.condition, ctx)) return (0,_flusys_nestjs_shared_utils__rspack_import_0.evaluateExpression)(rule.value, ctx);
|
|
2142
|
+
}
|
|
2143
|
+
return field.defaultValue ?? null;
|
|
2114
2144
|
}
|
|
2115
2145
|
/**
|
|
2116
|
-
*
|
|
2117
|
-
*
|
|
2118
|
-
*
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
if (!computedFields || computedFields.length === 0) {
|
|
2123
|
-
return {};
|
|
2124
|
-
}
|
|
2146
|
+
* Computed values for a submission, keyed by each computed field's `key`. Fields run in order,
|
|
2147
|
+
* so a field may use earlier ones (`computed.<key>`); a field whose rules fail at run time gets
|
|
2148
|
+
* its default value instead of failing the submission.
|
|
2149
|
+
*/ function calculateComputedFields(data, schema) {
|
|
2150
|
+
const parsed = asSchema(schema);
|
|
2151
|
+
const computedFields = parsed.settings?.computedFields ?? [];
|
|
2125
2152
|
const result = {};
|
|
2153
|
+
if (computedFields.length === 0) return result;
|
|
2154
|
+
const ctx = {
|
|
2155
|
+
resolveRef: createResolver(data, formFields(parsed), result)
|
|
2156
|
+
};
|
|
2126
2157
|
for (const field of computedFields){
|
|
2158
|
+
let value;
|
|
2127
2159
|
try {
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
// If calculation fails, use default value or null
|
|
2132
|
-
result[field.key] = field.defaultValue ?? null;
|
|
2160
|
+
value = computeField(field, ctx);
|
|
2161
|
+
} catch {
|
|
2162
|
+
value = field.defaultValue ?? null;
|
|
2133
2163
|
}
|
|
2164
|
+
result[field.key] = castValue(value, field.valueType);
|
|
2134
2165
|
}
|
|
2135
2166
|
return result;
|
|
2136
2167
|
}
|
|
2137
|
-
/**
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2168
|
+
/** First problem in the schema's computed fields, or null. Run on save so authors see it there, not at submit. */ function findComputedFieldIssue(schema) {
|
|
2169
|
+
const parsed = asSchema(schema);
|
|
2170
|
+
const computedFields = parsed.settings?.computedFields ?? [];
|
|
2171
|
+
const fields = formFields(parsed);
|
|
2172
|
+
const knownRefs = new Set(fields.flatMap((f)=>f.name ? [
|
|
2173
|
+
f.id,
|
|
2174
|
+
f.name
|
|
2175
|
+
] : [
|
|
2176
|
+
f.id
|
|
2177
|
+
]));
|
|
2178
|
+
const earlierKeys = new Set();
|
|
2179
|
+
for (const field of computedFields){
|
|
2180
|
+
const label = String(field?.name || field?.key || '');
|
|
2181
|
+
if (typeof field?.key !== 'string' || !COMPUTED_KEY_PATTERN.test(field.key)) {
|
|
2182
|
+
return {
|
|
2183
|
+
field: label,
|
|
2184
|
+
code: 'invalid_key',
|
|
2185
|
+
variables: {
|
|
2186
|
+
key: String(field?.key ?? '')
|
|
2187
|
+
}
|
|
2188
|
+
};
|
|
2144
2189
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
}
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
return isEmptyValue(fieldValue);
|
|
2177
|
-
case 'is_not_empty':
|
|
2178
|
-
return !isEmptyValue(fieldValue);
|
|
2179
|
-
case 'contains':
|
|
2180
|
-
return String(fieldValue).includes(String(compareValue));
|
|
2181
|
-
case 'not_contains':
|
|
2182
|
-
return !String(fieldValue).includes(String(compareValue));
|
|
2183
|
-
case 'starts_with':
|
|
2184
|
-
return String(fieldValue).startsWith(String(compareValue));
|
|
2185
|
-
case 'ends_with':
|
|
2186
|
-
return String(fieldValue).endsWith(String(compareValue));
|
|
2187
|
-
case 'greater_than':
|
|
2188
|
-
return Number(fieldValue) > Number(compareValue);
|
|
2189
|
-
case 'less_than':
|
|
2190
|
-
return Number(fieldValue) < Number(compareValue);
|
|
2191
|
-
case 'greater_or_equal':
|
|
2192
|
-
return Number(fieldValue) >= Number(compareValue);
|
|
2193
|
-
case 'less_or_equal':
|
|
2194
|
-
return Number(fieldValue) <= Number(compareValue);
|
|
2195
|
-
case 'is_before':
|
|
2196
|
-
return new Date(String(fieldValue)) < new Date(String(compareValue));
|
|
2197
|
-
case 'is_after':
|
|
2198
|
-
return new Date(String(fieldValue)) > new Date(String(compareValue));
|
|
2199
|
-
case 'is_checked':
|
|
2200
|
-
return fieldValue === true || fieldValue === 'true' || fieldValue === 1;
|
|
2201
|
-
case 'is_not_checked':
|
|
2202
|
-
return fieldValue === false || fieldValue === 'false' || fieldValue === 0 || !fieldValue;
|
|
2203
|
-
case 'is_any_of':
|
|
2204
|
-
case 'in':
|
|
2205
|
-
return Array.isArray(compareValue) && compareValue.includes(fieldValue);
|
|
2206
|
-
case 'is_none_of':
|
|
2207
|
-
case 'not_in':
|
|
2208
|
-
return !Array.isArray(compareValue) || !compareValue.includes(fieldValue);
|
|
2209
|
-
default:
|
|
2210
|
-
return false;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
/**
|
|
2214
|
-
* Execute a computation and return the result
|
|
2215
|
-
*/ function executeComputation(formData, computation, valueType) {
|
|
2216
|
-
const { config } = computation;
|
|
2217
|
-
// Use type guards for safe access
|
|
2218
|
-
if (computation.type === 'direct' && isDirectValueConfig(config)) {
|
|
2219
|
-
return valueType === 'number' ? Number(config.value) : String(config.value);
|
|
2220
|
-
}
|
|
2221
|
-
if (computation.type === 'field_reference' && isFieldReferenceConfig(config)) {
|
|
2222
|
-
const value = formData[config.fieldId];
|
|
2223
|
-
if (value === null || value === undefined) {
|
|
2224
|
-
return null;
|
|
2190
|
+
if (earlierKeys.has(field.key)) return {
|
|
2191
|
+
field: label,
|
|
2192
|
+
code: 'duplicate_key',
|
|
2193
|
+
variables: {
|
|
2194
|
+
key: field.key
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
if (!Array.isArray(field.rules)) return {
|
|
2198
|
+
field: label,
|
|
2199
|
+
code: 'invalid_node',
|
|
2200
|
+
variables: {
|
|
2201
|
+
type: 'rules'
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
const isKnownRef = (ref)=>knownRefs.has(ref) || ref.startsWith(COMPUTED_REF_PREFIX) && earlierKeys.has(ref.slice(COMPUTED_REF_PREFIX.length));
|
|
2205
|
+
try {
|
|
2206
|
+
for (const rule of field.rules){
|
|
2207
|
+
if (rule.condition) (0,_flusys_nestjs_shared_utils__rspack_import_0.assertValidConditionGroup)(rule.condition, {
|
|
2208
|
+
isKnownRef
|
|
2209
|
+
});
|
|
2210
|
+
(0,_flusys_nestjs_shared_utils__rspack_import_0.assertValidExpression)(rule.value, {
|
|
2211
|
+
isKnownRef
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
} catch (error) {
|
|
2215
|
+
if ((0,_flusys_nestjs_shared_utils__rspack_import_0.isExpressionError)(error)) return {
|
|
2216
|
+
field: label,
|
|
2217
|
+
code: error.code,
|
|
2218
|
+
variables: error.variables
|
|
2219
|
+
};
|
|
2220
|
+
throw error;
|
|
2225
2221
|
}
|
|
2226
|
-
|
|
2222
|
+
earlierKeys.add(field.key);
|
|
2227
2223
|
}
|
|
2228
|
-
if (computation.type === 'arithmetic' && isArithmeticConfig(config)) {
|
|
2229
|
-
return calculateArithmetic(formData, config);
|
|
2230
|
-
}
|
|
2231
|
-
// Unknown computation type
|
|
2232
2224
|
return null;
|
|
2233
2225
|
}
|
|
2234
|
-
/**
|
|
2235
|
-
* Perform arithmetic calculation
|
|
2236
|
-
*/ function calculateArithmetic(formData, config) {
|
|
2237
|
-
const values = config.operands.map((operand)=>{
|
|
2238
|
-
if (operand.type === 'constant') {
|
|
2239
|
-
return operand.value ?? 0;
|
|
2240
|
-
} else {
|
|
2241
|
-
const fieldValue = formData[operand.fieldId ?? ''];
|
|
2242
|
-
return fieldValue !== null && fieldValue !== undefined ? Number(fieldValue) : 0;
|
|
2243
|
-
}
|
|
2244
|
-
});
|
|
2245
|
-
if (values.length === 0) {
|
|
2246
|
-
return null;
|
|
2247
|
-
}
|
|
2248
|
-
switch(config.operation){
|
|
2249
|
-
case 'sum':
|
|
2250
|
-
case 'increment':
|
|
2251
|
-
return values.reduce((acc, val)=>acc + val, 0);
|
|
2252
|
-
case 'subtract':
|
|
2253
|
-
case 'decrement':
|
|
2254
|
-
return values.reduce((acc, val, idx)=>idx === 0 ? val : acc - val, 0);
|
|
2255
|
-
case 'multiply':
|
|
2256
|
-
return values.reduce((acc, val)=>acc * val, 1);
|
|
2257
|
-
case 'divide':
|
|
2258
|
-
{
|
|
2259
|
-
const [first, ...rest] = values;
|
|
2260
|
-
return rest.reduce((acc, val)=>val !== 0 ? acc / val : acc, first);
|
|
2261
|
-
}
|
|
2262
|
-
case 'average':
|
|
2263
|
-
return values.reduce((acc, val)=>acc + val, 0) / values.length;
|
|
2264
|
-
case 'min':
|
|
2265
|
-
return Math.min(...values);
|
|
2266
|
-
case 'max':
|
|
2267
|
-
return Math.max(...values);
|
|
2268
|
-
default:
|
|
2269
|
-
return null;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
2226
|
|
|
2273
2227
|
__webpack_require__.d(__webpack_exports__, {
|
|
2274
|
-
|
|
2228
|
+
Qc: () => (findComputedFieldIssue),
|
|
2229
|
+
XZ: () => (calculateComputedFields)
|
|
2230
|
+
}, {
|
|
2231
|
+
xI: COMPUTED_REF_PREFIX
|
|
2275
2232
|
});
|
|
2276
2233
|
|
|
2277
2234
|
|
package/fesm/config/index.js
CHANGED
|
@@ -71,7 +71,8 @@ const FORM_MESSAGES = {
|
|
|
71
71
|
OTP_INVALID: 'form.email.otp.invalid',
|
|
72
72
|
OTP_EXPIRED: 'form.email.otp.expired',
|
|
73
73
|
OTP_TOO_MANY_ATTEMPTS: 'form.email.otp.too.many.attempts',
|
|
74
|
-
OTP_VERIFIED: 'form.email.otp.verified'
|
|
74
|
+
OTP_VERIFIED: 'form.email.otp.verified',
|
|
75
|
+
INVALID_COMPUTED_FIELD: 'form.invalid.computed.field'
|
|
75
76
|
};
|
|
76
77
|
const FORM_RESULT_MESSAGES = {
|
|
77
78
|
GET_ALL_SUCCESS: 'form.result.get.all.success',
|
package/fesm/index.js
CHANGED
|
@@ -194,6 +194,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
194
194
|
|
|
195
195
|
// EXPORTS
|
|
196
196
|
__webpack_require__.d(__webpack_exports__, {
|
|
197
|
+
xI: () => (/* reexport */ computed_field_utils/* .COMPUTED_REF_PREFIX */.xI),
|
|
197
198
|
YD: () => (/* reexport */ dtos/* .CreateFormDto */.YD),
|
|
198
199
|
pZ: () => (/* reexport */ dtos/* .CreateFormResultDto */.pZ),
|
|
199
200
|
d7: () => (/* reexport */ dtos/* .EmailVerifiedFormResponseDto */.d7),
|
|
@@ -236,7 +237,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
236
237
|
Uj: () => (/* reexport */ dtos/* .UpdateFormResultDto */.Uj),
|
|
237
238
|
uY: () => (/* reexport */ dtos/* .VerifyFormEmailOtpDto */.uY),
|
|
238
239
|
TU: () => (/* reexport */ dtos/* .VerifyOtpResponseDto */.TU),
|
|
239
|
-
XZ: () => (/* reexport */ computed_field_utils/* .calculateComputedFields */.
|
|
240
|
+
XZ: () => (/* reexport */ computed_field_utils/* .calculateComputedFields */.XZ),
|
|
241
|
+
Qc: () => (/* reexport */ computed_field_utils/* .findComputedFieldIssue */.Qc),
|
|
240
242
|
aY: () => (/* reexport */ docs/* .formBuilderSwaggerConfig */.a),
|
|
241
243
|
iO: () => (/* reexport */ entities.getFormBuilderEntitiesByConfig),
|
|
242
244
|
EY: () => (/* reexport */ permission_utils/* .hasFormPermission */.E)
|
|
@@ -488,7 +490,8 @@ import * as __rspack_chunk_2 from './720.js';
|
|
|
488
490
|
__webpack_require__.C(__rspack_chunk_2);
|
|
489
491
|
import * as __rspack_chunk_3 from './index.js';
|
|
490
492
|
__webpack_require__.C(__rspack_chunk_3);
|
|
491
|
-
var __webpack_exports__ = __webpack_exec__(851);var
|
|
493
|
+
var __webpack_exports__ = __webpack_exec__(851);var __webpack_exports__COMPUTED_REF_PREFIX = __webpack_exports__.xI;
|
|
494
|
+
var __webpack_exports__CreateFormDto = __webpack_exports__.YD;
|
|
492
495
|
var __webpack_exports__CreateFormResultDto = __webpack_exports__.pZ;
|
|
493
496
|
var __webpack_exports__EmailVerifiedFormResponseDto = __webpack_exports__.d7;
|
|
494
497
|
var __webpack_exports__FORM_BUILDER_EMAIL_PROVIDER = __webpack_exports__.Q3;
|
|
@@ -531,7 +534,8 @@ var __webpack_exports__UpdateFormResultDto = __webpack_exports__.Uj;
|
|
|
531
534
|
var __webpack_exports__VerifyFormEmailOtpDto = __webpack_exports__.uY;
|
|
532
535
|
var __webpack_exports__VerifyOtpResponseDto = __webpack_exports__.TU;
|
|
533
536
|
var __webpack_exports__calculateComputedFields = __webpack_exports__.XZ;
|
|
537
|
+
var __webpack_exports__findComputedFieldIssue = __webpack_exports__.Qc;
|
|
534
538
|
var __webpack_exports__formBuilderSwaggerConfig = __webpack_exports__.aY;
|
|
535
539
|
var __webpack_exports__getFormBuilderEntitiesByConfig = __webpack_exports__.iO;
|
|
536
540
|
var __webpack_exports__hasFormPermission = __webpack_exports__.EY;
|
|
537
|
-
export { __webpack_exports__CreateFormDto as CreateFormDto, __webpack_exports__CreateFormResultDto as CreateFormResultDto, __webpack_exports__EmailVerifiedFormResponseDto as EmailVerifiedFormResponseDto, __webpack_exports__FORM_BUILDER_EMAIL_PROVIDER as FORM_BUILDER_EMAIL_PROVIDER, __webpack_exports__FORM_BUILDER_EVENT_ACTIONS as FORM_BUILDER_EVENT_ACTIONS, __webpack_exports__FORM_BUILDER_EVENT_ENTITIES as FORM_BUILDER_EVENT_ENTITIES, __webpack_exports__FORM_BUILDER_EVENT_MODULE as FORM_BUILDER_EVENT_MODULE, __webpack_exports__FORM_BUILDER_MODULE_OPTIONS as FORM_BUILDER_MODULE_OPTIONS, __webpack_exports__FORM_MESSAGES as FORM_MESSAGES, __webpack_exports__FORM_RESULT_MESSAGES as FORM_RESULT_MESSAGES, __webpack_exports__Form as Form, __webpack_exports__FormAccessInfoResponseDto as FormAccessInfoResponseDto, __webpack_exports__FormAccessType as FormAccessType, __webpack_exports__FormBase as FormBase, __webpack_exports__FormBuilderConfigService as FormBuilderConfigService, __webpack_exports__FormBuilderDataSourceProvider as FormBuilderDataSourceProvider, __webpack_exports__FormBuilderModule as FormBuilderModule, __webpack_exports__FormCompanyEntities as FormCompanyEntities, __webpack_exports__FormController as FormController, __webpack_exports__FormCoreEntities as FormCoreEntities, __webpack_exports__FormEmailAuthController as FormEmailAuthController, __webpack_exports__FormEmailAuthService as FormEmailAuthService, __webpack_exports__FormEmailVerification as FormEmailVerification, __webpack_exports__FormResponseDto as FormResponseDto, __webpack_exports__FormResult as FormResult, __webpack_exports__FormResultController as FormResultController, __webpack_exports__FormResultResponseDto as FormResultResponseDto, __webpack_exports__FormResultService as FormResultService, __webpack_exports__FormService as FormService, __webpack_exports__FormWithCompany as FormWithCompany, __webpack_exports__GetMyDraftDto as GetMyDraftDto, __webpack_exports__GetResultsByFormDto as GetResultsByFormDto, __webpack_exports__HasSubmittedEmailDto as HasSubmittedEmailDto, __webpack_exports__LoadEmailVerifiedFormDto as LoadEmailVerifiedFormDto, __webpack_exports__PublicFormResponseDto as PublicFormResponseDto, __webpack_exports__RequestFormEmailOtpDto as RequestFormEmailOtpDto, __webpack_exports__SubmitFormDto as SubmitFormDto, __webpack_exports__UpdateDraftDto as UpdateDraftDto, __webpack_exports__UpdateFormDto as UpdateFormDto, __webpack_exports__UpdateFormResultDto as UpdateFormResultDto, __webpack_exports__VerifyFormEmailOtpDto as VerifyFormEmailOtpDto, __webpack_exports__VerifyOtpResponseDto as VerifyOtpResponseDto, __webpack_exports__calculateComputedFields as calculateComputedFields, __webpack_exports__formBuilderSwaggerConfig as formBuilderSwaggerConfig, __webpack_exports__getFormBuilderEntitiesByConfig as getFormBuilderEntitiesByConfig, __webpack_exports__hasFormPermission as hasFormPermission };
|
|
541
|
+
export { __webpack_exports__COMPUTED_REF_PREFIX as COMPUTED_REF_PREFIX, __webpack_exports__CreateFormDto as CreateFormDto, __webpack_exports__CreateFormResultDto as CreateFormResultDto, __webpack_exports__EmailVerifiedFormResponseDto as EmailVerifiedFormResponseDto, __webpack_exports__FORM_BUILDER_EMAIL_PROVIDER as FORM_BUILDER_EMAIL_PROVIDER, __webpack_exports__FORM_BUILDER_EVENT_ACTIONS as FORM_BUILDER_EVENT_ACTIONS, __webpack_exports__FORM_BUILDER_EVENT_ENTITIES as FORM_BUILDER_EVENT_ENTITIES, __webpack_exports__FORM_BUILDER_EVENT_MODULE as FORM_BUILDER_EVENT_MODULE, __webpack_exports__FORM_BUILDER_MODULE_OPTIONS as FORM_BUILDER_MODULE_OPTIONS, __webpack_exports__FORM_MESSAGES as FORM_MESSAGES, __webpack_exports__FORM_RESULT_MESSAGES as FORM_RESULT_MESSAGES, __webpack_exports__Form as Form, __webpack_exports__FormAccessInfoResponseDto as FormAccessInfoResponseDto, __webpack_exports__FormAccessType as FormAccessType, __webpack_exports__FormBase as FormBase, __webpack_exports__FormBuilderConfigService as FormBuilderConfigService, __webpack_exports__FormBuilderDataSourceProvider as FormBuilderDataSourceProvider, __webpack_exports__FormBuilderModule as FormBuilderModule, __webpack_exports__FormCompanyEntities as FormCompanyEntities, __webpack_exports__FormController as FormController, __webpack_exports__FormCoreEntities as FormCoreEntities, __webpack_exports__FormEmailAuthController as FormEmailAuthController, __webpack_exports__FormEmailAuthService as FormEmailAuthService, __webpack_exports__FormEmailVerification as FormEmailVerification, __webpack_exports__FormResponseDto as FormResponseDto, __webpack_exports__FormResult as FormResult, __webpack_exports__FormResultController as FormResultController, __webpack_exports__FormResultResponseDto as FormResultResponseDto, __webpack_exports__FormResultService as FormResultService, __webpack_exports__FormService as FormService, __webpack_exports__FormWithCompany as FormWithCompany, __webpack_exports__GetMyDraftDto as GetMyDraftDto, __webpack_exports__GetResultsByFormDto as GetResultsByFormDto, __webpack_exports__HasSubmittedEmailDto as HasSubmittedEmailDto, __webpack_exports__LoadEmailVerifiedFormDto as LoadEmailVerifiedFormDto, __webpack_exports__PublicFormResponseDto as PublicFormResponseDto, __webpack_exports__RequestFormEmailOtpDto as RequestFormEmailOtpDto, __webpack_exports__SubmitFormDto as SubmitFormDto, __webpack_exports__UpdateDraftDto as UpdateDraftDto, __webpack_exports__UpdateFormDto as UpdateFormDto, __webpack_exports__UpdateFormResultDto as UpdateFormResultDto, __webpack_exports__VerifyFormEmailOtpDto as VerifyFormEmailOtpDto, __webpack_exports__VerifyOtpResponseDto as VerifyOtpResponseDto, __webpack_exports__calculateComputedFields as calculateComputedFields, __webpack_exports__findComputedFieldIssue as findComputedFieldIssue, __webpack_exports__formBuilderSwaggerConfig as formBuilderSwaggerConfig, __webpack_exports__getFormBuilderEntitiesByConfig as getFormBuilderEntitiesByConfig, __webpack_exports__hasFormPermission as hasFormPermission };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-form-builder",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.2",
|
|
4
4
|
"description": "Dynamic form builder module with schema versioning and access control",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./fesm/index.js",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"express": "^5.0.0"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@flusys/nestjs-core": "9.1.
|
|
79
|
-
"@flusys/nestjs-shared": "9.1.
|
|
78
|
+
"@flusys/nestjs-core": "9.1.2",
|
|
79
|
+
"@flusys/nestjs-shared": "9.1.2"
|
|
80
80
|
}
|
|
81
81
|
}
|
|
@@ -17,6 +17,7 @@ export declare class FormService extends ApiService<CreateFormDto, UpdateFormDto
|
|
|
17
17
|
private readonly permissionCache?;
|
|
18
18
|
constructor(cacheManager: HybridCache, utilsService: UtilsService, formBuilderConfig: FormBuilderConfigService, dataSourceProvider: FormBuilderDataSourceProvider, permissionResolver?: IPermissionResolver | undefined, permissionCache?: SharedPermissionCacheService | undefined);
|
|
19
19
|
convertSingleDtoToEntity(dto: CreateFormDto | UpdateFormDto, user: ILoggedUserInfo | null): Promise<Form>;
|
|
20
|
+
private assertValidComputedFields;
|
|
20
21
|
getSelectQuery(query: SelectQueryBuilder<Form>, _user: ILoggedUserInfo | null, select?: string[]): Promise<{
|
|
21
22
|
query: SelectQueryBuilder<Form>;
|
|
22
23
|
isRaw: boolean;
|
|
@@ -1,48 +1,24 @@
|
|
|
1
|
+
import type { Expression, IExpressionConditionGroup } from '@flusys/nestjs-shared/interfaces';
|
|
2
|
+
export type ComputedValueType = 'string' | 'number' | 'boolean';
|
|
1
3
|
export interface IComputedField {
|
|
2
4
|
id: string;
|
|
3
5
|
name: string;
|
|
4
6
|
key: string;
|
|
5
|
-
valueType:
|
|
7
|
+
valueType: ComputedValueType;
|
|
6
8
|
rules: IComputedRule[];
|
|
7
|
-
defaultValue?: string | number | null;
|
|
9
|
+
defaultValue?: string | number | boolean | null;
|
|
8
10
|
description?: string;
|
|
9
11
|
}
|
|
10
12
|
export interface IComputedRule {
|
|
11
13
|
id: string;
|
|
12
|
-
condition?:
|
|
13
|
-
|
|
14
|
+
condition?: IExpressionConditionGroup;
|
|
15
|
+
value: Expression;
|
|
14
16
|
}
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
export declare const COMPUTED_REF_PREFIX = "computed.";
|
|
18
|
+
export interface IComputedFieldIssue {
|
|
19
|
+
field: string;
|
|
20
|
+
code: string;
|
|
21
|
+
variables: Record<string, string | number>;
|
|
18
22
|
}
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
comparison: string;
|
|
22
|
-
value: unknown;
|
|
23
|
-
}
|
|
24
|
-
export interface IComputation {
|
|
25
|
-
type: ComputationType;
|
|
26
|
-
config: IDirectValueConfig | IFieldReferenceConfig | IArithmeticConfig;
|
|
27
|
-
}
|
|
28
|
-
export type ComputationType = 'direct' | 'field_reference' | 'arithmetic';
|
|
29
|
-
export interface IDirectValueConfig {
|
|
30
|
-
type: 'direct';
|
|
31
|
-
value: string | number;
|
|
32
|
-
}
|
|
33
|
-
export interface IFieldReferenceConfig {
|
|
34
|
-
type: 'field_reference';
|
|
35
|
-
fieldId: string;
|
|
36
|
-
}
|
|
37
|
-
export interface IArithmeticConfig {
|
|
38
|
-
type: 'arithmetic';
|
|
39
|
-
operation: ArithmeticOperation;
|
|
40
|
-
operands: IArithmeticOperand[];
|
|
41
|
-
}
|
|
42
|
-
export type ArithmeticOperation = 'sum' | 'subtract' | 'multiply' | 'divide' | 'average' | 'min' | 'max' | 'increment' | 'decrement';
|
|
43
|
-
export interface IArithmeticOperand {
|
|
44
|
-
type: 'field' | 'constant';
|
|
45
|
-
fieldId?: string;
|
|
46
|
-
value?: number;
|
|
47
|
-
}
|
|
48
|
-
export declare function calculateComputedFields(formData: Record<string, unknown>, computedFields: IComputedField[] | undefined): Record<string, unknown>;
|
|
23
|
+
export declare function calculateComputedFields(data: Record<string, unknown>, schema: unknown): Record<string, unknown>;
|
|
24
|
+
export declare function findComputedFieldIssue(schema: unknown): IComputedFieldIssue | null;
|