Skip to content

Commit 4d23bec

Browse files
committed
Dynamically display multiple errors if found
Signed-off-by: Tyler Ohlsen <ohltyler@amazon.com>
1 parent 67d8dad commit 4d23bec

File tree

1 file changed

+60
-17
lines changed

1 file changed

+60
-17
lines changed

public/pages/workflow_detail/workflow_inputs/input_fields/json_lines_field.tsx

+60-17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import React, { ReactNode, useEffect, useState } from 'react';
77
import { Field, FieldProps, getIn, useFormikContext } from 'formik';
8+
import { isEmpty } from 'lodash';
89
import {
910
EuiCodeEditor,
1011
EuiCompressedFormRow,
@@ -70,7 +71,19 @@ export function JsonLinesField(props: JsonLinesFieldProps) {
7071
) : undefined
7172
}
7273
helpText={props.helpText || undefined}
73-
error={validate ? customErrMsg : undefined}
74+
error={
75+
validate ? (
76+
<>
77+
{customErrMsg?.split('\n')?.map((errMsg, idx) => {
78+
return (
79+
<EuiText key={idx} color="danger" size="s">
80+
{errMsg}
81+
</EuiText>
82+
);
83+
})}
84+
</>
85+
) : undefined
86+
}
7487
isInvalid={
7588
validate
7689
? getIn(errors, field.name) && getIn(touched, field.name)
@@ -91,32 +104,37 @@ export function JsonLinesField(props: JsonLinesFieldProps) {
91104
onBlur={() => {
92105
form.setFieldTouched(field.name);
93106
let finalJsonStr = '';
94-
let curIdx = -1;
107+
let errs = [] as string[];
95108
try {
96109
const lines = jsonStr?.split('\n');
97110
lines.forEach((line: string, idx) => {
98-
curIdx = idx;
99111
if (line.trim() !== '') {
100-
finalJsonStr +=
101-
customStringifySingleLine(JSON.parse(line)) + '\n';
112+
let parsedLine = {};
113+
try {
114+
parsedLine = JSON.parse(line);
115+
} catch (error) {
116+
errs.push(
117+
getFormattedErrorMsg(error as Error, idx + 1)
118+
);
119+
}
120+
if (!isEmpty(parsedLine)) {
121+
finalJsonStr +=
122+
customStringifySingleLine(JSON.parse(line)) + '\n';
123+
}
102124
}
103125
});
104126
// remove trailing newline
105127
if (finalJsonStr !== '') {
106128
finalJsonStr = finalJsonStr.slice(0, -1);
107129
}
108-
form.setFieldValue(field.name, finalJsonStr);
109-
} catch (error) {
110-
setCustomErrMsg(
111-
`Error on line ${curIdx + 1}: ${getIn(
112-
error,
113-
'message',
114-
'Invalid JSON'
115-
)
116-
.replace(/^(.*?)\s+in JSON.*/, '$1')
117-
.replace(/^(.*?)\s+after JSON.*/, '$1')}`
118-
);
119-
}
130+
131+
if (errs?.length > 0) {
132+
setCustomErrMsg(getFormattedErrorMsgList(errs));
133+
} else {
134+
form.setFieldValue(field.name, finalJsonStr);
135+
setCustomErrMsg(undefined);
136+
}
137+
} catch (error) {}
120138
}}
121139
readOnly={props.readOnly || false}
122140
setOptions={{
@@ -135,3 +153,28 @@ export function JsonLinesField(props: JsonLinesFieldProps) {
135153
</Field>
136154
);
137155
}
156+
157+
function getFormattedErrorMsg(error: Error, idx: number): string {
158+
return `Error on line ${idx}: ${getIn(error, 'message', 'Invalid JSON')
159+
.replace(/^(.*?)\s+in JSON.*/, '$1')
160+
.replace(/^(.*?)\s+after JSON.*/, '$1')}`;
161+
}
162+
163+
// Verbosely display a few error messages, list the count of remaining ones.
164+
function getFormattedErrorMsgList(errors: string[]): string {
165+
let finalMsg = '';
166+
const verboseErrors = errors.slice(0, 3);
167+
const nonVerboseErrorCount = errors.length - 3;
168+
verboseErrors.forEach((error) => {
169+
finalMsg += error + '\n';
170+
});
171+
if (nonVerboseErrorCount > 0) {
172+
finalMsg += `${nonVerboseErrorCount} more error${
173+
nonVerboseErrorCount > 1 ? 's' : ''
174+
}`;
175+
} else if (finalMsg !== '') {
176+
// remove trailing newline
177+
finalMsg = finalMsg.slice(0, -1);
178+
}
179+
return finalMsg;
180+
}

0 commit comments

Comments
 (0)