@remoteoss/json-schema-form 0.7.2-beta.0 → 0.7.3-beta.0
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/CHANGELOG.md +6 -0
- package/dist/index.cjs +62 -26
- package/dist/index.js +62 -26
- package/dist/standalone.js +62 -26
- package/package.json +1 -1
- package/src/tests/conditions.test.js +309 -6
- package/src/tests/createHeadlessForm.test.js +48 -6
- package/src/tests/jsonLogic.fixtures.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
#### 0.7.3-beta.0 (2023-11-07)
|
|
2
|
+
|
|
3
|
+
##### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* Remove conditional attributes after the condition is unmatched ([#57](https://github.com/remoteoss/json-schema-form/pull/57)) ([8bac7145](https://github.com/remoteoss/json-schema-form/commit/8bac7145dfdd4136c0613044389666a614eb12f7))
|
|
6
|
+
|
|
1
7
|
#### 0.7.2-beta.0 (2023-11-06)
|
|
2
8
|
|
|
3
9
|
##### Bug Fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2023 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.7.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.7.3-beta.0
|
|
5
|
+
Generated: Tue, 07 Nov 2023 09:29:14 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -1061,6 +1061,33 @@ function processJSONLogicNode({
|
|
|
1061
1061
|
}
|
|
1062
1062
|
|
|
1063
1063
|
// src/helpers.js
|
|
1064
|
+
var dynamicInternalJsfAttrs = [
|
|
1065
|
+
"isVisible",
|
|
1066
|
+
// Driven from conditionals state
|
|
1067
|
+
"fields",
|
|
1068
|
+
// driven from group-array
|
|
1069
|
+
"getComputedAttributes",
|
|
1070
|
+
// From json-logic
|
|
1071
|
+
"computedAttributes",
|
|
1072
|
+
// From json-logic
|
|
1073
|
+
"calculateConditionalProperties",
|
|
1074
|
+
// driven from conditionals
|
|
1075
|
+
"calculateCustomValidationProperties",
|
|
1076
|
+
// To be deprecated in favor of json-logic
|
|
1077
|
+
"scopedJsonSchema"
|
|
1078
|
+
// The respective JSON Schema
|
|
1079
|
+
];
|
|
1080
|
+
var dynamicInternalJsfAttrsObj = Object.fromEntries(
|
|
1081
|
+
dynamicInternalJsfAttrs.map((k) => [k, true])
|
|
1082
|
+
);
|
|
1083
|
+
function removeConditionalStaleAttributes(field, conditionalAttrs, rootAttrs) {
|
|
1084
|
+
Object.keys(field).forEach((key) => {
|
|
1085
|
+
if (conditionalAttrs[key] === void 0 && rootAttrs[key] === void 0 && // Don't remove attrs that were declared in the root field.
|
|
1086
|
+
dynamicInternalJsfAttrsObj[key] === void 0) {
|
|
1087
|
+
field[key] = void 0;
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1064
1091
|
function hasType(type, typeName) {
|
|
1065
1092
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
1066
1093
|
}
|
|
@@ -1153,19 +1180,21 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1153
1180
|
if (fieldIsRequired) {
|
|
1154
1181
|
field.isVisible = true;
|
|
1155
1182
|
}
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
field.
|
|
1183
|
+
const updateAttributes = (fieldAttrs) => {
|
|
1184
|
+
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
1185
|
+
field[key] = typeof value === "function" ? value() : value;
|
|
1186
|
+
if (key === "value") {
|
|
1187
|
+
const readOnlyPropertyWasUpdated = typeof fieldAttrs.readOnly !== "undefined";
|
|
1188
|
+
const isReadonlyByDefault = field.readOnly;
|
|
1189
|
+
const isReadonly = readOnlyPropertyWasUpdated ? fieldAttrs.readOnly : isReadonlyByDefault;
|
|
1190
|
+
if (!isReadonly && (value === null || field.inputType === "checkbox")) {
|
|
1191
|
+
field.value = void 0;
|
|
1192
|
+
}
|
|
1164
1193
|
}
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1194
|
+
});
|
|
1195
|
+
};
|
|
1167
1196
|
if (field.getComputedAttributes) {
|
|
1168
|
-
const
|
|
1197
|
+
const newAttributes = field.getComputedAttributes({
|
|
1169
1198
|
field,
|
|
1170
1199
|
isRequired: fieldIsRequired,
|
|
1171
1200
|
node,
|
|
@@ -1173,23 +1202,24 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1173
1202
|
config,
|
|
1174
1203
|
logic
|
|
1175
1204
|
});
|
|
1176
|
-
|
|
1205
|
+
updateAttributes(newAttributes);
|
|
1177
1206
|
}
|
|
1178
1207
|
if (field.calculateConditionalProperties) {
|
|
1179
|
-
const
|
|
1208
|
+
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
1180
1209
|
isRequired: fieldIsRequired,
|
|
1181
1210
|
conditionBranch: node,
|
|
1182
1211
|
formValues
|
|
1183
1212
|
});
|
|
1184
|
-
|
|
1213
|
+
updateAttributes(newAttributes);
|
|
1214
|
+
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
1185
1215
|
}
|
|
1186
1216
|
if (field.calculateCustomValidationProperties) {
|
|
1187
|
-
const
|
|
1217
|
+
const newAttributes = field.calculateCustomValidationProperties(
|
|
1188
1218
|
fieldIsRequired,
|
|
1189
1219
|
node,
|
|
1190
1220
|
formValues
|
|
1191
1221
|
);
|
|
1192
|
-
|
|
1222
|
+
updateAttributes(newAttributes);
|
|
1193
1223
|
}
|
|
1194
1224
|
}
|
|
1195
1225
|
function processNode({
|
|
@@ -1531,17 +1561,23 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
1531
1561
|
logic
|
|
1532
1562
|
)
|
|
1533
1563
|
};
|
|
1534
|
-
return
|
|
1564
|
+
return {
|
|
1565
|
+
rootFieldAttrs: fieldParams,
|
|
1566
|
+
newAttributes: (0, import_omit2.default)((0, import_merge2.default)(base, presentation, newFieldParams), ["inputType"])
|
|
1567
|
+
};
|
|
1535
1568
|
}
|
|
1536
1569
|
const isVisible = isRequired;
|
|
1537
1570
|
return {
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1571
|
+
rootFieldAttrs: fieldParams,
|
|
1572
|
+
newAttributes: {
|
|
1573
|
+
isVisible,
|
|
1574
|
+
required: isRequired,
|
|
1575
|
+
schema: buildYupSchema({
|
|
1576
|
+
...fieldParams,
|
|
1577
|
+
...extractParametersFromNode(conditionBranch),
|
|
1578
|
+
required: isRequired
|
|
1579
|
+
})
|
|
1580
|
+
}
|
|
1545
1581
|
};
|
|
1546
1582
|
};
|
|
1547
1583
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2023 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.7.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.7.3-beta.0
|
|
5
|
+
Generated: Tue, 07 Nov 2023 09:29:14 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -1025,6 +1025,33 @@ function processJSONLogicNode({
|
|
|
1025
1025
|
}
|
|
1026
1026
|
|
|
1027
1027
|
// src/helpers.js
|
|
1028
|
+
var dynamicInternalJsfAttrs = [
|
|
1029
|
+
"isVisible",
|
|
1030
|
+
// Driven from conditionals state
|
|
1031
|
+
"fields",
|
|
1032
|
+
// driven from group-array
|
|
1033
|
+
"getComputedAttributes",
|
|
1034
|
+
// From json-logic
|
|
1035
|
+
"computedAttributes",
|
|
1036
|
+
// From json-logic
|
|
1037
|
+
"calculateConditionalProperties",
|
|
1038
|
+
// driven from conditionals
|
|
1039
|
+
"calculateCustomValidationProperties",
|
|
1040
|
+
// To be deprecated in favor of json-logic
|
|
1041
|
+
"scopedJsonSchema"
|
|
1042
|
+
// The respective JSON Schema
|
|
1043
|
+
];
|
|
1044
|
+
var dynamicInternalJsfAttrsObj = Object.fromEntries(
|
|
1045
|
+
dynamicInternalJsfAttrs.map((k) => [k, true])
|
|
1046
|
+
);
|
|
1047
|
+
function removeConditionalStaleAttributes(field, conditionalAttrs, rootAttrs) {
|
|
1048
|
+
Object.keys(field).forEach((key) => {
|
|
1049
|
+
if (conditionalAttrs[key] === void 0 && rootAttrs[key] === void 0 && // Don't remove attrs that were declared in the root field.
|
|
1050
|
+
dynamicInternalJsfAttrsObj[key] === void 0) {
|
|
1051
|
+
field[key] = void 0;
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1028
1055
|
function hasType(type, typeName) {
|
|
1029
1056
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
1030
1057
|
}
|
|
@@ -1117,19 +1144,21 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1117
1144
|
if (fieldIsRequired) {
|
|
1118
1145
|
field.isVisible = true;
|
|
1119
1146
|
}
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
field.
|
|
1147
|
+
const updateAttributes = (fieldAttrs) => {
|
|
1148
|
+
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
1149
|
+
field[key] = typeof value === "function" ? value() : value;
|
|
1150
|
+
if (key === "value") {
|
|
1151
|
+
const readOnlyPropertyWasUpdated = typeof fieldAttrs.readOnly !== "undefined";
|
|
1152
|
+
const isReadonlyByDefault = field.readOnly;
|
|
1153
|
+
const isReadonly = readOnlyPropertyWasUpdated ? fieldAttrs.readOnly : isReadonlyByDefault;
|
|
1154
|
+
if (!isReadonly && (value === null || field.inputType === "checkbox")) {
|
|
1155
|
+
field.value = void 0;
|
|
1156
|
+
}
|
|
1128
1157
|
}
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1158
|
+
});
|
|
1159
|
+
};
|
|
1131
1160
|
if (field.getComputedAttributes) {
|
|
1132
|
-
const
|
|
1161
|
+
const newAttributes = field.getComputedAttributes({
|
|
1133
1162
|
field,
|
|
1134
1163
|
isRequired: fieldIsRequired,
|
|
1135
1164
|
node,
|
|
@@ -1137,23 +1166,24 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
1137
1166
|
config,
|
|
1138
1167
|
logic
|
|
1139
1168
|
});
|
|
1140
|
-
|
|
1169
|
+
updateAttributes(newAttributes);
|
|
1141
1170
|
}
|
|
1142
1171
|
if (field.calculateConditionalProperties) {
|
|
1143
|
-
const
|
|
1172
|
+
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
1144
1173
|
isRequired: fieldIsRequired,
|
|
1145
1174
|
conditionBranch: node,
|
|
1146
1175
|
formValues
|
|
1147
1176
|
});
|
|
1148
|
-
|
|
1177
|
+
updateAttributes(newAttributes);
|
|
1178
|
+
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
1149
1179
|
}
|
|
1150
1180
|
if (field.calculateCustomValidationProperties) {
|
|
1151
|
-
const
|
|
1181
|
+
const newAttributes = field.calculateCustomValidationProperties(
|
|
1152
1182
|
fieldIsRequired,
|
|
1153
1183
|
node,
|
|
1154
1184
|
formValues
|
|
1155
1185
|
);
|
|
1156
|
-
|
|
1186
|
+
updateAttributes(newAttributes);
|
|
1157
1187
|
}
|
|
1158
1188
|
}
|
|
1159
1189
|
function processNode({
|
|
@@ -1495,17 +1525,23 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
1495
1525
|
logic
|
|
1496
1526
|
)
|
|
1497
1527
|
};
|
|
1498
|
-
return
|
|
1528
|
+
return {
|
|
1529
|
+
rootFieldAttrs: fieldParams,
|
|
1530
|
+
newAttributes: omit2(merge2(base, presentation, newFieldParams), ["inputType"])
|
|
1531
|
+
};
|
|
1499
1532
|
}
|
|
1500
1533
|
const isVisible = isRequired;
|
|
1501
1534
|
return {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1535
|
+
rootFieldAttrs: fieldParams,
|
|
1536
|
+
newAttributes: {
|
|
1537
|
+
isVisible,
|
|
1538
|
+
required: isRequired,
|
|
1539
|
+
schema: buildYupSchema({
|
|
1540
|
+
...fieldParams,
|
|
1541
|
+
...extractParametersFromNode(conditionBranch),
|
|
1542
|
+
required: isRequired
|
|
1543
|
+
})
|
|
1544
|
+
}
|
|
1509
1545
|
};
|
|
1510
1546
|
};
|
|
1511
1547
|
}
|
package/dist/standalone.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
3
|
Copyright (c) 2023 Remote Technology, Inc.
|
|
4
|
-
NPM Package: @remoteoss/json-schema-form@0.7.
|
|
5
|
-
Generated:
|
|
4
|
+
NPM Package: @remoteoss/json-schema-form@0.7.3-beta.0
|
|
5
|
+
Generated: Tue, 07 Nov 2023 09:29:14 GMT
|
|
6
6
|
|
|
7
7
|
MIT License
|
|
8
8
|
|
|
@@ -12379,6 +12379,33 @@ function processJSONLogicNode({
|
|
|
12379
12379
|
}
|
|
12380
12380
|
|
|
12381
12381
|
// src/helpers.js
|
|
12382
|
+
var dynamicInternalJsfAttrs = [
|
|
12383
|
+
"isVisible",
|
|
12384
|
+
// Driven from conditionals state
|
|
12385
|
+
"fields",
|
|
12386
|
+
// driven from group-array
|
|
12387
|
+
"getComputedAttributes",
|
|
12388
|
+
// From json-logic
|
|
12389
|
+
"computedAttributes",
|
|
12390
|
+
// From json-logic
|
|
12391
|
+
"calculateConditionalProperties",
|
|
12392
|
+
// driven from conditionals
|
|
12393
|
+
"calculateCustomValidationProperties",
|
|
12394
|
+
// To be deprecated in favor of json-logic
|
|
12395
|
+
"scopedJsonSchema"
|
|
12396
|
+
// The respective JSON Schema
|
|
12397
|
+
];
|
|
12398
|
+
var dynamicInternalJsfAttrsObj = Object.fromEntries(
|
|
12399
|
+
dynamicInternalJsfAttrs.map((k) => [k, true])
|
|
12400
|
+
);
|
|
12401
|
+
function removeConditionalStaleAttributes(field, conditionalAttrs, rootAttrs) {
|
|
12402
|
+
Object.keys(field).forEach((key) => {
|
|
12403
|
+
if (conditionalAttrs[key] === void 0 && rootAttrs[key] === void 0 && // Don't remove attrs that were declared in the root field.
|
|
12404
|
+
dynamicInternalJsfAttrsObj[key] === void 0) {
|
|
12405
|
+
field[key] = void 0;
|
|
12406
|
+
}
|
|
12407
|
+
});
|
|
12408
|
+
}
|
|
12382
12409
|
function hasType(type, typeName) {
|
|
12383
12410
|
return Array.isArray(type) ? type.includes(typeName) : type === typeName;
|
|
12384
12411
|
}
|
|
@@ -12471,19 +12498,21 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12471
12498
|
if (fieldIsRequired) {
|
|
12472
12499
|
field.isVisible = true;
|
|
12473
12500
|
}
|
|
12474
|
-
const
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
field.
|
|
12501
|
+
const updateAttributes = (fieldAttrs) => {
|
|
12502
|
+
Object.entries(fieldAttrs).forEach(([key, value]) => {
|
|
12503
|
+
field[key] = typeof value === "function" ? value() : value;
|
|
12504
|
+
if (key === "value") {
|
|
12505
|
+
const readOnlyPropertyWasUpdated = typeof fieldAttrs.readOnly !== "undefined";
|
|
12506
|
+
const isReadonlyByDefault = field.readOnly;
|
|
12507
|
+
const isReadonly = readOnlyPropertyWasUpdated ? fieldAttrs.readOnly : isReadonlyByDefault;
|
|
12508
|
+
if (!isReadonly && (value === null || field.inputType === "checkbox")) {
|
|
12509
|
+
field.value = void 0;
|
|
12510
|
+
}
|
|
12482
12511
|
}
|
|
12483
|
-
}
|
|
12484
|
-
}
|
|
12512
|
+
});
|
|
12513
|
+
};
|
|
12485
12514
|
if (field.getComputedAttributes) {
|
|
12486
|
-
const
|
|
12515
|
+
const newAttributes = field.getComputedAttributes({
|
|
12487
12516
|
field,
|
|
12488
12517
|
isRequired: fieldIsRequired,
|
|
12489
12518
|
node,
|
|
@@ -12491,23 +12520,24 @@ function updateField(field, requiredFields, node, formValues, logic, config) {
|
|
|
12491
12520
|
config,
|
|
12492
12521
|
logic
|
|
12493
12522
|
});
|
|
12494
|
-
|
|
12523
|
+
updateAttributes(newAttributes);
|
|
12495
12524
|
}
|
|
12496
12525
|
if (field.calculateConditionalProperties) {
|
|
12497
|
-
const
|
|
12526
|
+
const { rootFieldAttrs, newAttributes } = field.calculateConditionalProperties({
|
|
12498
12527
|
isRequired: fieldIsRequired,
|
|
12499
12528
|
conditionBranch: node,
|
|
12500
12529
|
formValues
|
|
12501
12530
|
});
|
|
12502
|
-
|
|
12531
|
+
updateAttributes(newAttributes);
|
|
12532
|
+
removeConditionalStaleAttributes(field, newAttributes, rootFieldAttrs);
|
|
12503
12533
|
}
|
|
12504
12534
|
if (field.calculateCustomValidationProperties) {
|
|
12505
|
-
const
|
|
12535
|
+
const newAttributes = field.calculateCustomValidationProperties(
|
|
12506
12536
|
fieldIsRequired,
|
|
12507
12537
|
node,
|
|
12508
12538
|
formValues
|
|
12509
12539
|
);
|
|
12510
|
-
|
|
12540
|
+
updateAttributes(newAttributes);
|
|
12511
12541
|
}
|
|
12512
12542
|
}
|
|
12513
12543
|
function processNode({
|
|
@@ -12849,17 +12879,23 @@ function calculateConditionalProperties({ fieldParams, customProperties, logic,
|
|
|
12849
12879
|
logic
|
|
12850
12880
|
)
|
|
12851
12881
|
};
|
|
12852
|
-
return
|
|
12882
|
+
return {
|
|
12883
|
+
rootFieldAttrs: fieldParams,
|
|
12884
|
+
newAttributes: (0, import_omit2.default)((0, import_merge2.default)(base, presentation, newFieldParams), ["inputType"])
|
|
12885
|
+
};
|
|
12853
12886
|
}
|
|
12854
12887
|
const isVisible = isRequired;
|
|
12855
12888
|
return {
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
|
|
12859
|
-
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12889
|
+
rootFieldAttrs: fieldParams,
|
|
12890
|
+
newAttributes: {
|
|
12891
|
+
isVisible,
|
|
12892
|
+
required: isRequired,
|
|
12893
|
+
schema: buildYupSchema({
|
|
12894
|
+
...fieldParams,
|
|
12895
|
+
...extractParametersFromNode(conditionBranch),
|
|
12896
|
+
required: isRequired
|
|
12897
|
+
})
|
|
12898
|
+
}
|
|
12863
12899
|
};
|
|
12864
12900
|
};
|
|
12865
12901
|
}
|
package/package.json
CHANGED
|
@@ -27,12 +27,7 @@ it('Should allow check of a nested property in a conditional', () => {
|
|
|
27
27
|
additionalProperties: false,
|
|
28
28
|
properties: {
|
|
29
29
|
child: {
|
|
30
|
-
oneOf: [
|
|
31
|
-
{
|
|
32
|
-
const: 'yes',
|
|
33
|
-
},
|
|
34
|
-
{ const: 'no' },
|
|
35
|
-
],
|
|
30
|
+
oneOf: [{ const: 'yes' }, { const: 'no' }],
|
|
36
31
|
type: 'string',
|
|
37
32
|
},
|
|
38
33
|
},
|
|
@@ -56,3 +51,311 @@ it('Should allow check of a nested property in a conditional', () => {
|
|
|
56
51
|
undefined
|
|
57
52
|
);
|
|
58
53
|
});
|
|
54
|
+
|
|
55
|
+
describe('Conditional attributes updated', () => {
|
|
56
|
+
it('Update basic case with const, default, maximum', () => {
|
|
57
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
58
|
+
{
|
|
59
|
+
properties: {
|
|
60
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
61
|
+
hours: { type: 'number' },
|
|
62
|
+
},
|
|
63
|
+
allOf: [
|
|
64
|
+
{
|
|
65
|
+
if: {
|
|
66
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
67
|
+
required: ['is_full_time'],
|
|
68
|
+
},
|
|
69
|
+
then: {
|
|
70
|
+
properties: {
|
|
71
|
+
hours: {
|
|
72
|
+
const: 8,
|
|
73
|
+
default: 8,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
else: {
|
|
78
|
+
properties: {
|
|
79
|
+
hours: {
|
|
80
|
+
maximum: 4,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
{ strictInputType: false }
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Given "Yes" it applies "const" and "default"
|
|
91
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 4 }).formErrors).toEqual({
|
|
92
|
+
hours: 'The only accepted value is 8.',
|
|
93
|
+
});
|
|
94
|
+
expect(fields[1]).toMatchObject({ const: 8, default: 8 });
|
|
95
|
+
expect(fields[1].maximum).toBeUndefined();
|
|
96
|
+
|
|
97
|
+
// Changing to "No", applies the "maximum" and cleans "const" and "default"
|
|
98
|
+
expect(handleValidation({ is_full_time: 'no', hours: 4 }).formErrors).toBeUndefined();
|
|
99
|
+
expect(fields[1]).toMatchObject({ maximum: 4 });
|
|
100
|
+
expect(fields[1].const).toBeUndefined();
|
|
101
|
+
expect(fields[1].default).toBeUndefined();
|
|
102
|
+
|
|
103
|
+
// Changing back to "Yes", it removes "maximum", and applies "const" and "default"
|
|
104
|
+
expect(handleValidation({}).formErrors).toBeUndefined();
|
|
105
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 8 }).formErrors).toBeUndefined();
|
|
106
|
+
expect(fields[1].maximum).toBeUndefined();
|
|
107
|
+
expect(fields[1]).toMatchObject({ const: 8, default: 8 });
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('Update a new attribute (eg description)', () => {
|
|
111
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
112
|
+
{
|
|
113
|
+
properties: {
|
|
114
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
115
|
+
hours: {
|
|
116
|
+
type: 'number',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
allOf: [
|
|
120
|
+
{
|
|
121
|
+
if: {
|
|
122
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
123
|
+
required: ['is_full_time'],
|
|
124
|
+
},
|
|
125
|
+
then: {
|
|
126
|
+
properties: {
|
|
127
|
+
hours: {
|
|
128
|
+
description: 'We recommend 8 hours.',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{ strictInputType: false }
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// By default the attribute is not set.
|
|
139
|
+
expect(fields[1].description).toBeUndefined();
|
|
140
|
+
|
|
141
|
+
// Given "Yes" it applies the conditional attribute
|
|
142
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
143
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
144
|
+
|
|
145
|
+
// Changing to "No", removes the description
|
|
146
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
147
|
+
expect(fields[1].description).toBeUndefined();
|
|
148
|
+
|
|
149
|
+
// Changing back to "Yes", it sets the attribute again
|
|
150
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
151
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('Update an existing attribute (eg description)', () => {
|
|
155
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
156
|
+
{
|
|
157
|
+
properties: {
|
|
158
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
159
|
+
hours: {
|
|
160
|
+
type: 'number',
|
|
161
|
+
description: 'Any value works.',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
allOf: [
|
|
165
|
+
{
|
|
166
|
+
if: {
|
|
167
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
168
|
+
required: ['is_full_time'],
|
|
169
|
+
},
|
|
170
|
+
then: {
|
|
171
|
+
properties: {
|
|
172
|
+
hours: {
|
|
173
|
+
description: 'We recommend 8 hours.',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
{ strictInputType: false }
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// By default the attribute is set the base value.
|
|
184
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
185
|
+
|
|
186
|
+
// Given "Yes" it applies the conditional attribute
|
|
187
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 4 }).formErrors).toBeUndefined();
|
|
188
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
189
|
+
|
|
190
|
+
// Changing to "No", it applies the base value again.
|
|
191
|
+
expect(handleValidation({ is_full_time: 'no', hours: 4 }).formErrors).toBeUndefined();
|
|
192
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
193
|
+
|
|
194
|
+
// Changing back to "Yes", it sets the attribute again
|
|
195
|
+
expect(handleValidation({ is_full_time: 'yes', hours: 8 }).formErrors).toBeUndefined();
|
|
196
|
+
expect(fields[1].description).toBe('We recommend 8 hours.');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('Update a nested attribute', () => {
|
|
200
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
201
|
+
{
|
|
202
|
+
properties: {
|
|
203
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
204
|
+
hours: {
|
|
205
|
+
type: 'number',
|
|
206
|
+
presentation: {
|
|
207
|
+
inputType: 'number',
|
|
208
|
+
anything: 'info',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
allOf: [
|
|
213
|
+
{
|
|
214
|
+
if: {
|
|
215
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
216
|
+
required: ['is_full_time'],
|
|
217
|
+
},
|
|
218
|
+
then: {
|
|
219
|
+
properties: {
|
|
220
|
+
hours: {
|
|
221
|
+
presentation: {
|
|
222
|
+
anything: 'danger',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
],
|
|
229
|
+
},
|
|
230
|
+
{ strictInputType: false }
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// By default the attribute is set the base value.
|
|
234
|
+
expect(fields[1].anything).toBe('info');
|
|
235
|
+
|
|
236
|
+
// Given "Yes" it applies the conditional attribute
|
|
237
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
238
|
+
expect(fields[1].anything).toBe('danger');
|
|
239
|
+
|
|
240
|
+
// Changing to "No", it applies the base value again.
|
|
241
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
242
|
+
expect(fields[1].anything).toBe('info');
|
|
243
|
+
|
|
244
|
+
// Changing back to "Yes", it sets the attribute again
|
|
245
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toBeUndefined();
|
|
246
|
+
expect(fields[1].anything).toBe('danger');
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('Keeps existing attributes in matches that dont change the attr', () => {
|
|
250
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
251
|
+
{
|
|
252
|
+
properties: {
|
|
253
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
254
|
+
hours: {
|
|
255
|
+
type: 'number',
|
|
256
|
+
description: 'Any value works.',
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
allOf: [
|
|
260
|
+
{
|
|
261
|
+
if: {
|
|
262
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
263
|
+
required: ['is_full_time'],
|
|
264
|
+
},
|
|
265
|
+
then: {
|
|
266
|
+
required: ['hours'],
|
|
267
|
+
},
|
|
268
|
+
else: {
|
|
269
|
+
properties: {
|
|
270
|
+
hours: false,
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
{ strictInputType: false }
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
// By default the attribute is set the base value, even though the field is invisible.
|
|
280
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
281
|
+
expect(fields[1].isVisible).toBe(false);
|
|
282
|
+
|
|
283
|
+
// Given "Yes" it keeps the base value
|
|
284
|
+
expect(handleValidation({ is_full_time: 'yes' }).formErrors).toEqual({
|
|
285
|
+
hours: 'Required field',
|
|
286
|
+
});
|
|
287
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
288
|
+
expect(fields[1].isVisible).toBe(true);
|
|
289
|
+
|
|
290
|
+
// Changing to "No" it keeps the base value
|
|
291
|
+
expect(handleValidation({ is_full_time: 'no' }).formErrors).toBeUndefined();
|
|
292
|
+
expect(fields[1].description).toBe('Any value works.');
|
|
293
|
+
expect(fields[1].isVisible).toBe(false);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('Keeps internal attributes (fieldAttrsFromJsf)', () => {
|
|
297
|
+
// This is necessary while we keep supporting "type", even if deprecated
|
|
298
|
+
// otherwise our Remote app will break because it didn't migrate
|
|
299
|
+
// from "type" to "inputType" yet.
|
|
300
|
+
const { fields, handleValidation } = createHeadlessForm(
|
|
301
|
+
{
|
|
302
|
+
properties: {
|
|
303
|
+
is_full_time: { type: 'string', oneOf: [{ const: 'yes' }, { const: 'no' }] },
|
|
304
|
+
salary_period: {
|
|
305
|
+
type: 'string',
|
|
306
|
+
title: 'Salary period',
|
|
307
|
+
oneOf: [
|
|
308
|
+
{ title: 'Weekly', const: 'weekly' },
|
|
309
|
+
{ title: 'Monthly', const: 'monthly' },
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
allOf: [
|
|
314
|
+
{
|
|
315
|
+
if: {
|
|
316
|
+
properties: { is_full_time: { const: 'yes' } },
|
|
317
|
+
required: ['is_full_time'],
|
|
318
|
+
},
|
|
319
|
+
then: {
|
|
320
|
+
properties: {
|
|
321
|
+
salary_period: {
|
|
322
|
+
description: 'We recommend montlhy.',
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
{ strictInputType: false }
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
// Given "Yes" it keeps the "type"
|
|
333
|
+
handleValidation({ is_full_time: 'yes' });
|
|
334
|
+
|
|
335
|
+
// All the following attrs are never removed
|
|
336
|
+
// during conditionals because they are core.
|
|
337
|
+
expect(fields[1]).toMatchObject({
|
|
338
|
+
name: 'salary_period',
|
|
339
|
+
label: 'Salary period',
|
|
340
|
+
required: false,
|
|
341
|
+
type: 'radio',
|
|
342
|
+
inputType: 'radio',
|
|
343
|
+
jsonType: 'string',
|
|
344
|
+
computedAttributes: {},
|
|
345
|
+
calculateConditionalProperties: expect.any(Function),
|
|
346
|
+
schema: expect.any(Object),
|
|
347
|
+
scopedJsonSchema: expect.any(Object),
|
|
348
|
+
isVisible: true,
|
|
349
|
+
options: [
|
|
350
|
+
{
|
|
351
|
+
label: 'Weekly',
|
|
352
|
+
value: 'weekly',
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
label: 'Monthly',
|
|
356
|
+
value: 'monthly',
|
|
357
|
+
},
|
|
358
|
+
],
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
});
|
|
@@ -446,7 +446,7 @@ describe('createHeadlessForm', () => {
|
|
|
446
446
|
[fieldName]: 'The option "blah-blah" is not valid.',
|
|
447
447
|
});
|
|
448
448
|
|
|
449
|
-
// Given undefined, it says it's a
|
|
449
|
+
// Given undefined, it says it's a required field.
|
|
450
450
|
expect(validateForm({})).toEqual({
|
|
451
451
|
[fieldName]: 'Required field',
|
|
452
452
|
});
|
|
@@ -856,6 +856,7 @@ describe('createHeadlessForm', () => {
|
|
|
856
856
|
has_car: 'yes',
|
|
857
857
|
})
|
|
858
858
|
).toBeUndefined();
|
|
859
|
+
|
|
859
860
|
expect(validateForm({})).toEqual({
|
|
860
861
|
has_siblings: 'Required field',
|
|
861
862
|
});
|
|
@@ -1419,6 +1420,50 @@ describe('createHeadlessForm', () => {
|
|
|
1419
1420
|
],
|
|
1420
1421
|
});
|
|
1421
1422
|
});
|
|
1423
|
+
|
|
1424
|
+
it('can be a conditional field', () => {
|
|
1425
|
+
const { fields, handleValidation } = createHeadlessForm({
|
|
1426
|
+
properties: {
|
|
1427
|
+
yes_or_no: {
|
|
1428
|
+
title: 'Show the dependents or not?',
|
|
1429
|
+
oneOf: [{ const: 'yes' }, { const: 'no' }],
|
|
1430
|
+
'x-jsf-presentation': { inputType: 'radio' },
|
|
1431
|
+
},
|
|
1432
|
+
dependent_details: mockGroupArrayInput,
|
|
1433
|
+
},
|
|
1434
|
+
allOf: [
|
|
1435
|
+
{
|
|
1436
|
+
if: {
|
|
1437
|
+
properties: {
|
|
1438
|
+
yes_or_no: { const: 'yes' },
|
|
1439
|
+
},
|
|
1440
|
+
required: ['yes_or_no'],
|
|
1441
|
+
},
|
|
1442
|
+
then: {
|
|
1443
|
+
required: ['dependent_details'],
|
|
1444
|
+
},
|
|
1445
|
+
else: {
|
|
1446
|
+
properties: {
|
|
1447
|
+
dependent_details: false,
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
],
|
|
1452
|
+
});
|
|
1453
|
+
|
|
1454
|
+
// By default is hidden but the fields are accessible
|
|
1455
|
+
expect(getField(fields, 'dependent_details').isVisible).toBe(false);
|
|
1456
|
+
expect(getField(fields, 'dependent_details').fields).toEqual(expect.any(Function));
|
|
1457
|
+
|
|
1458
|
+
// When the condition matches...
|
|
1459
|
+
const { formErrors } = handleValidation({ yes_or_no: 'yes' });
|
|
1460
|
+
expect(formErrors).toEqual({
|
|
1461
|
+
dependent_details: 'Required field',
|
|
1462
|
+
});
|
|
1463
|
+
// it gets visible with its inner fields.
|
|
1464
|
+
expect(getField(fields, 'dependent_details').isVisible).toBe(true);
|
|
1465
|
+
expect(getField(fields, 'dependent_details').fields).toEqual(expect.any(Function));
|
|
1466
|
+
});
|
|
1422
1467
|
});
|
|
1423
1468
|
|
|
1424
1469
|
it('supports "radio" field type with its "card" and "card-expandable" variants', () => {
|
|
@@ -1808,11 +1853,8 @@ describe('createHeadlessForm', () => {
|
|
|
1808
1853
|
expect(foodField.options).toHaveLength(4);
|
|
1809
1854
|
// ...Food description was back to the original
|
|
1810
1855
|
expect(foodField.description).toBeUndefined();
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
expect(getField(fields, 'pto').description).toBe(
|
|
1814
|
-
'Above 30 hours, the PTO needs to be at least 20 days.'
|
|
1815
|
-
);
|
|
1856
|
+
// ...PTO Description is removed too.
|
|
1857
|
+
expect(getField(fields, 'pto').description).toBeUndefined();
|
|
1816
1858
|
|
|
1817
1859
|
// Given again "low perks", the form valid.
|
|
1818
1860
|
expect(
|