Skip to content

Commit

Permalink
Required Fields V2 - Conditionally Required Fields (#2099)
Browse files Browse the repository at this point in the history
* PoC for direct builder defined JSON Schema with working unit test

* Adds more unit tests

* Renames definition.validSchema to definition.groupConditions and restricts them to anyOf, allOf, oneOf which are all a list of fieldKeys

* WIP - implementation of DependsOnConditions conversion to JsonSchema

* Generates a basic schema. Passes basic test case

* More unit tests, non-passing

* Able to generate schema when there are multiple conditions on one field defined for one field.

* WIP - unit tests

* WIP - two cases failing, not from an incorrectly created schema

* All test cases for multiple conditions on same field passing

* Can validate a basic object dependency

* Can validate a basic object dependency with an is_not operator

* Adds more object test cases

* Adds unit tests for different value data types

* Can validate simple conditions with undefined values

* Adds new unit tests for multiple conditions with an undefined value. Adds a new unit test for multiple object dependant conditions

* Some helper methods and DRYing

* WIP - only test object case

* WIP - renames helper method to be more descriptive

* WIP - enable all unit tests

* WIP - factors out singleConditionSingleDependency case

* WIP - factors out singleConditionSingleDependency case

* WIP - simplifies multiple non-object case

* WIP - simplifies multiple object case. actually passes multiple: true parameter which fixes 3 unit tests

* Removes commented out code

* Fixed incorrect test case, all test cases passing

* Removes 3 year old todo unit test

* Removes groupConditions as they'll be implemented in a separate PR

* Renames fields-to-jsonschema file to indicate it only contains snapshot tests. generates snapshots

* Removes dedicated snapshot tests and just makes all existing tests also a snapshot test

* Skips conditions when generating types for the stored file

* WIP - unit test for null values

* Adds conditional requirement to Lead V2 action as well

* Handles explicitly null values as if they were undefined fields

* Removes conditionally required from Lead V2 since that action relies on syncMode

* Consolidates two test cases into one since they share a schema. Removes a console log

* WIP - conditionally required object sub-property unit test

* WIP - working on conditionally required object properties

* Can validate conditionally required object properties

* Unit test for when two fields depend on each other

* Updates readme and the description for the required property with info on how conditional fields work

* Adds dot notation example in readme
  • Loading branch information
nick-Ag authored Jan 29, 2025
1 parent 2f37138 commit 6be90dc
Show file tree
Hide file tree
Showing 7 changed files with 3,266 additions and 13 deletions.
122 changes: 121 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ interface InputField {
dynamic?: boolean

/** Whether or not the field is required */
required?: boolean
required?: boolean | DependsOnConditions

/**
* Optional definition for the properties of `type: 'object'` fields
Expand Down Expand Up @@ -358,6 +358,126 @@ const destination = {

In addition to default values for input fields, you can also specify the defaultSubscription for a given action – this is the FQL query that will be automatically populated when a customer configures a new subscription triggering a given action.

## Required Fields

You may configure a field to either be always required, not required, or conditionally required. Validation for required fields is performed both when a user is configuring a mapping in the UI and when an event payload is delivered through a `perform` block.

**An example of each possible value for `required`**

```js
const destination = {
actions: {
readmeAction: {
fields: {
operation: {
label: 'An operation for the readme action',
required: true // This field is always required and any payloads omitting it will fail
},
creationName: {
label: "The name of the resource to create, required when operation = 'create'",
required: {
// This field is required only when the 'operation' field has the value 'create'
match: 'all',
conditions: [
{
fieldKey: 'operation',
operator: 'is',
value: 'create'
}
]
}
},
email: {
label: 'The customer email',
required: false // This field is not required. This is the same as not including the 'required' property at all
},
userIdentifiers: {
phone: {
label: 'The customer phone number',
required: {
// If email is not provided then a phone number is required
conditions: [{ fieldKey: 'email', operator: 'is', value: undefined }]
}
},
countryCode: {
label: 'The country code for the customer phone number',
required: {
// If a userIdentifiers.phone is provided then the country code is also required
conditions: [
{
fieldKey: 'userIdentifiers.phone', // Dot notation may be used to address object fields.
operator: 'is_not',
value: undefined
}
]
}
}
}
}
}
}
}
```

**Examples of valid and invalid payloads for the fields above**

```json
// This payload is valid since the only required field, 'operation', is defined.
{
"operation": "update",
"email": "[email protected]"
}
```

```json
// This payload is invalid since 'creationName' is required because 'operation' is 'create'
{
"operation": "create",
"email": "[email protected]"
}
// This error will be thrown:
"message": "The root value is missing the required field 'creationName'. The root value must match \"then\" schema."
```

```json
// This payload is valid since the two required fields, 'operation' and 'creationName' are defined.
{
"operation": "create",
"creationName": "readme",
"email": "[email protected]"
}
```

```json
// This payload is invalid since 'phone' is required when 'email' is missing.
{
"operation": "update",
}
// This error will be thrown:
"message": "The root value is missing the required field 'phone'. The root value must match \"then\" schema."
```

```json
// This payload is invalid since 'countryCode' is required when 'phone' is defined
{
"operation": "update",
"userIdentifiers": { "phone": "619-555-5555" }
}
// This error will be thrown:
"message": "The root value is missing the required field 'countryCode'. The root value must match \"then\" schema."
```

```json
// This payload is valid since all conditionally required fields are included
{
"operation": "update",
"userIdentifiers": {
"phone": "619-555-5555",
"countryCode": "+1"
}
}
```

## Dynamic Fields

You can setup a field which dynamically fetches inputs from your destination. These dynamic fields can be used to populate a dropdown menu of options for your users to select.
Expand Down
Loading

0 comments on commit 6be90dc

Please sign in to comment.