Skip to content

Commit 12b2932

Browse files
author
Gene Hynson
authored
feat(subs): jsonpath and regex form validation (#4734)
1 parent 99e4a67 commit 12b2932

File tree

10 files changed

+803
-635
lines changed

10 files changed

+803
-635
lines changed

cypress/e2e/cloud/subscriptions.test.ts

Lines changed: 531 additions & 509 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
"immer": "^9.0.6",
187187
"intersection-observer": "^0.7.0",
188188
"jsonlint-mod": "^1.7.5",
189+
"jsonpath": "^1.1.1",
189190
"jspdf": "^2.4.0",
190191
"lodash": "^4.17.21",
191192
"luxon": "^2.0.2",

src/writeData/subscriptions/components/CreateSubscriptionPage.tsx

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ import {
4747
getDataLayerIdentity,
4848
getExperimentVariantId,
4949
} from 'src/cloud/utils/experiments'
50+
import {
51+
checkRequiredJsonFields,
52+
checkRequiredStringFields,
53+
} from 'src/writeData/subscriptions/utils/form'
5054

5155
// Constants
5256
import {CREDIT_250_EXPERIMENT_ID} from 'src/shared/constants'
@@ -103,26 +107,6 @@ const CreateSubscriptionPage: FC = () => {
103107
)
104108
}, [])
105109

106-
const isParsingFormCompleted = (): boolean => {
107-
if (formContent.dataFormat === 'json') {
108-
return (
109-
formContent.jsonMeasurementKey.path &&
110-
formContent.jsonFieldKeys.length &&
111-
formContent.jsonFieldKeys[0].name &&
112-
!!formContent.jsonFieldKeys[0].path
113-
)
114-
} else if (formContent.dataFormat === 'string') {
115-
return (
116-
formContent.stringMeasurement.pattern &&
117-
formContent.stringFields.length &&
118-
formContent.stringFields[0].name &&
119-
!!formContent.stringFields[0].pattern
120-
)
121-
} else {
122-
return true
123-
}
124-
}
125-
126110
const handleClick = (step: number) => {
127111
event(
128112
'subway navigation clicked',
@@ -136,7 +120,11 @@ const CreateSubscriptionPage: FC = () => {
136120
subscriptionStepCompleted:
137121
formContent.topic && formContent.bucket ? 'true' : 'false',
138122
parsingStepCompleted:
139-
formContent.dataFormat && isParsingFormCompleted() ? 'true' : 'false',
123+
formContent.dataFormat &&
124+
checkRequiredJsonFields(formContent) &&
125+
checkRequiredStringFields(formContent)
126+
? 'true'
127+
: 'false',
140128
dataFormat: formContent.dataFormat ?? 'not chosen yet',
141129
},
142130
{feature: 'subscriptions'}

src/writeData/subscriptions/components/JsonParsingForm.tsx

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {Subscription} from 'src/types/subscriptions'
2828
import {
2929
sanitizeType,
3030
handleValidation,
31+
handleJsonPathValidation,
3132
} from 'src/writeData/subscriptions/utils/form'
3233

3334
// Styles
@@ -71,32 +72,44 @@ const JsonParsingForm: FC<Props> = ({formContent, updateForm, edit}) => {
7172
return (
7273
<div className="json-parsing-form">
7374
<Grid.Column>
74-
<Form.Label label="JSON Path to Timestamp" />
75-
<Input
76-
type={InputType.Text}
77-
placeholder="eg. $.myJSON.myObject[0].timestampKey"
78-
name="timestamp"
79-
autoFocus={true}
75+
<Form.ValidationElement
76+
label="JSON Path to Timestmap"
8077
value={formContent.jsonTimestamp?.path}
81-
onChange={e => {
82-
updateForm({
83-
...formContent,
84-
jsonTimestamp: {
85-
...formContent.jsonTimestamp,
86-
path: e.target.value,
87-
},
88-
})
89-
}}
90-
onBlur={() =>
91-
event(
92-
'completed form field',
93-
{formField: 'jsonTimestamp.path'},
94-
{feature: 'subscriptions'}
95-
)
78+
required={false}
79+
validationFunc={() =>
80+
!!formContent.jsonTimestamp?.path
81+
? handleJsonPathValidation(formContent.jsonTimestamp?.path)
82+
: null
9683
}
97-
testID="timestamp-json-parsing"
98-
status={edit ? ComponentStatus.Default : ComponentStatus.Disabled}
99-
/>
84+
>
85+
{status => (
86+
<Input
87+
type={InputType.Text}
88+
placeholder="eg. $.myJSON.myObject[0].timestampKey"
89+
name="timestamp"
90+
autoFocus={true}
91+
value={formContent.jsonTimestamp?.path}
92+
onChange={e => {
93+
updateForm({
94+
...formContent,
95+
jsonTimestamp: {
96+
...formContent.jsonTimestamp,
97+
path: e.target.value,
98+
},
99+
})
100+
}}
101+
onBlur={() =>
102+
event(
103+
'completed form field',
104+
{formField: 'jsonTimestamp.path'},
105+
{feature: 'subscriptions'}
106+
)
107+
}
108+
testID="timestamp-json-parsing"
109+
status={edit ? status : ComponentStatus.Disabled}
110+
/>
111+
)}
112+
</Form.ValidationElement>
100113
</Grid.Column>
101114
<Grid.Column>
102115
<FlexBox
@@ -123,12 +136,13 @@ const JsonParsingForm: FC<Props> = ({formContent, updateForm, edit}) => {
123136
label="JSON Path"
124137
value={formContent.jsonMeasurementKey.path}
125138
required={true}
126-
validationFunc={() =>
127-
handleValidation(
128-
'Measurement Path',
129-
formContent.jsonMeasurementKey.path
139+
validationFunc={() => {
140+
const path = formContent.jsonMeasurementKey.path
141+
return (
142+
handleValidation('Measurement Path', path) ??
143+
handleJsonPathValidation(path)
130144
)
131-
}
145+
}}
132146
>
133147
{status => (
134148
<Input

src/writeData/subscriptions/components/JsonPathInput.tsx

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {Subscription} from 'src/types/subscriptions'
2727

2828
// Utils
2929
import {
30+
handleJsonPathValidation,
3031
handleValidation,
3132
sanitizeType,
3233
} from 'src/writeData/subscriptions/utils/form'
@@ -53,7 +54,12 @@ const JsonPathInput: FC<Props> = ({
5354
return (
5455
<div>
5556
<Grid.Column>
56-
<div className="json-parsing-form__header-wrap">
57+
<FlexBox
58+
alignItems={AlignItems.Center}
59+
direction={FlexDirection.Row}
60+
margin={ComponentSize.Medium}
61+
className="header-wrap"
62+
>
5763
<Heading
5864
element={HeadingElement.H3}
5965
weight={FontWeight.Bold}
@@ -62,7 +68,7 @@ const JsonPathInput: FC<Props> = ({
6268
{name}
6369
</Heading>
6470
{(tagType
65-
? !(formContent.jsonTagKeys.length === 1)
71+
? !(formContent.jsonTagKeys.length === 0)
6672
: !(formContent.jsonFieldKeys.length === 1)) && (
6773
<ConfirmationButton
6874
color={ComponentColor.Colorless}
@@ -89,7 +95,7 @@ const JsonPathInput: FC<Props> = ({
8995
testID={`${tagType}-json-delete-label`}
9096
/>
9197
)}
92-
</div>
98+
</FlexBox>
9399
<FlexBox
94100
alignItems={AlignItems.FlexStart}
95101
direction={FlexDirection.Row}
@@ -227,14 +233,15 @@ const JsonPathInput: FC<Props> = ({
227233
: formContent.jsonFieldKeys[itemNum].path
228234
}
229235
required={true}
230-
validationFunc={() =>
231-
handleValidation(
232-
`${name} Path`,
233-
tagType
234-
? formContent.jsonTagKeys[itemNum].path
235-
: formContent.jsonFieldKeys[itemNum].path
236+
validationFunc={() => {
237+
const path = tagType
238+
? formContent.jsonTagKeys[itemNum].path
239+
: formContent.jsonFieldKeys[itemNum].path
240+
return (
241+
handleValidation(`${name} Path`, path) ??
242+
handleJsonPathValidation(path)
236243
)
237-
}
244+
}}
238245
>
239246
{status => (
240247
<Input

src/writeData/subscriptions/components/StringParsingForm.tsx

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ import StringPatternInput from 'src/writeData/subscriptions/components/StringPat
2424
import {Subscription} from 'src/types/subscriptions'
2525

2626
// Utils
27-
import {handleValidation} from 'src/writeData/subscriptions/utils/form'
27+
import {
28+
handleRegexValidation,
29+
handleValidation,
30+
} from 'src/writeData/subscriptions/utils/form'
2831

2932
// Styles
3033
import 'src/writeData/subscriptions/components/StringParsingForm.scss'
@@ -63,35 +66,47 @@ const StringParsingForm: FC<Props> = ({formContent, updateForm, edit}) => {
6366
return (
6467
<div className="string-parsing-form">
6568
<Grid.Column>
66-
<Form.Label label="Regex to find Timestamp" />
67-
<Input
68-
type={InputType.Text}
69-
placeholder="eg. regexExample"
70-
name="timestamp"
71-
autoFocus={true}
69+
<Form.ValidationElement
70+
label="Regex Pattern to find Timestamp"
7271
value={formContent.stringTimestamp.pattern}
73-
onChange={e => {
74-
updateForm({
75-
...formContent,
76-
stringTimestamp: {
77-
...formContent.stringTimestamp,
78-
pattern: e.target.value,
79-
},
80-
})
81-
}}
82-
onBlur={() =>
83-
event(
84-
'completed form field',
85-
{
86-
formField: 'stringTimestamp.pattern',
87-
},
88-
{feature: 'subscriptions'}
89-
)
72+
required={false}
73+
validationFunc={() =>
74+
!!formContent.stringTimestamp.pattern
75+
? handleRegexValidation(formContent.stringTimestamp.pattern)
76+
: null
9077
}
91-
maxLength={255}
92-
testID="timestamp-string-parsing"
93-
status={edit ? ComponentStatus.Default : ComponentStatus.Disabled}
94-
/>
78+
>
79+
{status => (
80+
<Input
81+
type={InputType.Text}
82+
placeholder="eg. regexExample"
83+
name="timestamp"
84+
autoFocus={true}
85+
value={formContent.stringTimestamp.pattern}
86+
onChange={e => {
87+
updateForm({
88+
...formContent,
89+
stringTimestamp: {
90+
...formContent.stringTimestamp,
91+
pattern: e.target.value,
92+
},
93+
})
94+
}}
95+
onBlur={() =>
96+
event(
97+
'completed form field',
98+
{
99+
formField: 'stringTimestamp.pattern',
100+
},
101+
{feature: 'subscriptions'}
102+
)
103+
}
104+
maxLength={255}
105+
testID="timestamp-string-parsing"
106+
status={edit ? status : ComponentStatus.Disabled}
107+
/>
108+
)}
109+
</Form.ValidationElement>
95110
</Grid.Column>
96111
<Grid.Column>
97112
<FlexBox
@@ -112,9 +127,13 @@ const StringParsingForm: FC<Props> = ({formContent, updateForm, edit}) => {
112127
label="Regex Pattern to find Measurement"
113128
value={formContent.stringMeasurement.pattern}
114129
required={true}
115-
validationFunc={() =>
116-
handleValidation('Pattern', formContent.stringMeasurement.pattern)
117-
}
130+
validationFunc={() => {
131+
const pattern = formContent.stringMeasurement.pattern
132+
return (
133+
handleValidation('Pattern', pattern) ??
134+
handleRegexValidation(pattern)
135+
)
136+
}}
118137
>
119138
{status => (
120139
<Input

src/writeData/subscriptions/components/StringPatternInput.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ import {
2525
import {Subscription} from 'src/types/subscriptions'
2626

2727
// Utils
28-
import {handleValidation} from 'src/writeData/subscriptions/utils/form'
28+
import {
29+
handleRegexValidation,
30+
handleValidation,
31+
} from 'src/writeData/subscriptions/utils/form'
2932
import {event} from 'src/cloud/utils/reporting'
3033

3134
interface Props {
@@ -61,7 +64,7 @@ const StringPatternInput: FC<Props> = ({
6164
{name}
6265
</Heading>
6366
{(tagType
64-
? !(formContent.stringTags.length === 1)
67+
? !(formContent.stringTags.length === 0)
6568
: !(formContent.stringFields.length === 1)) && (
6669
<ConfirmationButton
6770
color={ComponentColor.Colorless}
@@ -162,14 +165,15 @@ const StringPatternInput: FC<Props> = ({
162165
: formContent.stringFields[itemNum].pattern
163166
}
164167
required={true}
165-
validationFunc={() =>
166-
handleValidation(
167-
'Pattern',
168-
tagType
169-
? formContent.stringTags[itemNum].pattern
170-
: formContent.stringFields[itemNum].pattern
168+
validationFunc={() => {
169+
const pattern = tagType
170+
? formContent.stringTags[itemNum].pattern
171+
: formContent.stringFields[itemNum].pattern
172+
return (
173+
handleValidation('Pattern', pattern) ??
174+
handleRegexValidation(pattern)
171175
)
172-
}
176+
}}
173177
>
174178
{status => (
175179
<Input

src/writeData/subscriptions/context/subscription.create.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,7 @@ export const DEFAULT_CONTEXT: SubscriptionCreateContextType = {
5050
type: 'string',
5151
},
5252
],
53-
jsonTagKeys: [
54-
{
55-
name: '',
56-
path: '',
57-
type: 'string',
58-
},
59-
],
53+
jsonTagKeys: [],
6054
jsonTimestamp: {
6155
name: 'timestamp',
6256
path: '',
@@ -72,12 +66,7 @@ export const DEFAULT_CONTEXT: SubscriptionCreateContextType = {
7266
name: '',
7367
},
7468
],
75-
stringTags: [
76-
{
77-
pattern: '',
78-
name: '',
79-
},
80-
],
69+
stringTags: [],
8170
stringTimestamp: {
8271
pattern: '',
8372
name: '',

0 commit comments

Comments
 (0)