diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/CSVInput.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/CSVInput.tsx new file mode 100644 index 0000000000..81050c1ba9 --- /dev/null +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/CSVInput.tsx @@ -0,0 +1,25 @@ +import { Input, InputProps } from 'antd'; +import { ChangeEventHandler, useState } from 'react'; + +function CSVInput({ value, onChange, ...otherProps }: InputProps): JSX.Element { + const [inputValue, setInputValue] = useState( + ((value as string[]) || []).join(', '), + ); + + const onChangeHandler = (onChange as unknown) as (v: string[]) => void; + + const onInputChange: ChangeEventHandler = (e) => { + const newValue = e.target.value; + setInputValue(newValue); + + if (onChangeHandler) { + const splitValues = newValue.split(',').map((v) => v.trim()); + onChangeHandler(splitValues); + } + }; + + // eslint-disable-next-line react/jsx-props-no-spreading + return ; +} + +export default CSVInput; diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx index 373f2063ac..1d3b12e2c0 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx @@ -1,15 +1,13 @@ +import './styles.scss'; + import { Form, Input, Select } from 'antd'; import { ModalFooterTitle } from 'container/PipelinePage/styles'; import { useTranslation } from 'react-i18next'; import { formValidationRules } from '../config'; import { processorFields, ProcessorFormField } from './config'; -import { - Container, - FormWrapper, - PipelineIndexIcon, - StyledSelect, -} from './styles'; +import CSVInput from './FormFields/CSVInput'; +import { FormWrapper, PipelineIndexIcon, StyledSelect } from './styles'; function ProcessorFieldInput({ fieldData, @@ -25,35 +23,63 @@ function ProcessorFieldInput({ return null; } + // Do not render display elements for hidden inputs. + if (fieldData?.hidden) { + return ( + + + + ); + } + + let inputField; + if (fieldData?.options) { + inputField = ( + + {fieldData.options.map(({ value, label }) => ( + + {label} + + ))} + + ); + } else if (Array.isArray(fieldData?.initialValue)) { + inputField = ; + } else { + inputField = ; + } + return ( - - - {Number(fieldData.id) + 1} - +
+ {!fieldData?.compact && ( + + {Number(fieldData.id) + 1} + + )} {fieldData.fieldName}} - key={fieldData.id} name={fieldData.name} initialValue={fieldData.initialValue} rules={fieldData.rules ? fieldData.rules : formValidationRules} dependencies={fieldData.dependencies || []} > - {fieldData?.options ? ( - - {fieldData.options.map(({ value, label }) => ( - - {label} - - ))} - - ) : ( - - )} + {inputField} - +
); } @@ -63,9 +89,12 @@ interface ProcessorFieldInputProps { function ProcessorForm({ processorType }: ProcessorFormProps): JSX.Element { return ( -
+
{processorFields[processorType]?.map((fieldData: ProcessorFormField) => ( - + ))}
); diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts index 9dc4f1d1f8..2c9a676898 100644 --- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts @@ -17,6 +17,7 @@ export const processorTypes: Array = [ { key: 'json_parser', value: 'json_parser', label: 'Json Parser' }, { key: 'trace_parser', value: 'trace_parser', label: 'Trace Parser' }, { key: 'time_parser', value: 'time_parser', label: 'Timestamp Parser' }, + { key: 'severity_parser', value: 'severity_parser', label: 'Severity Parser' }, { key: 'add', value: 'add', label: 'Add' }, { key: 'remove', value: 'remove', label: 'Remove' }, // { key: 'retain', value: 'retain', label: 'Retain' }, @Chintan - Commented as per Nitya's suggestion @@ -31,13 +32,15 @@ export type ProcessorFieldOption = { value: string; }; +// TODO(Raj): Refactor Processor Form code after putting e2e UI tests in place. export type ProcessorFormField = { id: number; fieldName: string; placeholder: string; name: string | NamePath; rules?: Array; - initialValue?: string; + hidden?: boolean; + initialValue?: boolean | string | Array; dependencies?: Array; options?: Array; shouldRender?: (form: FormInstance) => boolean; @@ -45,6 +48,10 @@ export type ProcessorFormField = { changedValues: ProcessorData, form: FormInstance, ) => void; + + // Should this field have its own row or should it + // be packed with other compact fields. + compact?: boolean; }; const traceParserFieldValidator: RuleRender = (form) => ({ @@ -317,6 +324,85 @@ export const processorFields: { [key: string]: Array } = { initialValue: '%Y-%m-%dT%H:%M:%S.%f%z', }, ], + severity_parser: [ + { + id: 1, + fieldName: 'Name of Severity Parsing Processor', + placeholder: 'processor_name_placeholder', + name: 'name', + }, + { + id: 2, + fieldName: 'Parse Severity Value From', + placeholder: 'processor_parsefrom_placeholder', + name: 'parse_from', + initialValue: 'attributes.logLevel', + }, + { + id: 3, + fieldName: 'Values for level TRACE', + placeholder: 'Specify comma separated values. Eg: trace, 0', + name: ['mapping', 'trace'], + rules: [], + initialValue: ['trace'], + compact: true, + }, + { + id: 4, + fieldName: 'Values for level DEBUG', + placeholder: 'Specify comma separated values. Eg: debug, 2xx', + name: ['mapping', 'debug'], + rules: [], + initialValue: ['debug'], + compact: true, + }, + { + id: 5, + fieldName: 'Values for level INFO', + placeholder: 'Specify comma separated values. Eg: info, 3xx', + name: ['mapping', 'info'], + rules: [], + initialValue: ['info'], + compact: true, + }, + { + id: 6, + fieldName: 'Values for level WARN', + placeholder: 'Specify comma separated values. Eg: warning, 4xx', + name: ['mapping', 'warn'], + rules: [], + initialValue: ['warn'], + compact: true, + }, + { + id: 7, + fieldName: 'Values for level ERROR', + placeholder: 'Specify comma separated values. Eg: error, 5xx', + name: ['mapping', 'error'], + rules: [], + initialValue: ['error'], + compact: true, + }, + { + id: 8, + fieldName: 'Values for level FATAL', + placeholder: 'Specify comma separated values. Eg: fatal, panic', + name: ['mapping', 'fatal'], + rules: [], + initialValue: ['fatal'], + compact: true, + }, + { + id: 9, + fieldName: 'Override Severity Text', + placeholder: + 'Should the parsed severity set both severity and severityText?', + name: ['overwrite_text'], + rules: [], + initialValue: true, + hidden: true, + }, + ], retain: [ { id: 1, diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss new file mode 100644 index 0000000000..1fabdd233f --- /dev/null +++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss @@ -0,0 +1,27 @@ + +.processor-form-container { + position: relative; + width: 100%; + + display: flex; + flex-wrap: wrap +} + +.processor-field-container { + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 0rem; + gap: 1rem; + width: 100%; +} + +.compact-processor-field-container { + display: flex; + flex-direction: row; + align-items: flex-start; + padding: 0rem; + min-width: 40%; + flex-grow: 1; + margin-left: 2.5rem; +} diff --git a/frontend/src/pages/Pipelines/index.tsx b/frontend/src/pages/Pipelines/index.tsx index dd9ea1d185..1a05a4010a 100644 --- a/frontend/src/pages/Pipelines/index.tsx +++ b/frontend/src/pages/Pipelines/index.tsx @@ -5,7 +5,9 @@ import Spinner from 'components/Spinner'; import ChangeHistory from 'container/PipelinePage/Layouts/ChangeHistory'; import PipelinePage from 'container/PipelinePage/Layouts/Pipeline'; import { useNotifications } from 'hooks/useNotifications'; +import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback'; import { useEffect, useMemo } from 'react'; +import { ErrorBoundary } from 'react-error-boundary'; import { useTranslation } from 'react-i18next'; import { useQuery } from 'react-query'; import { SuccessResponse } from 'types/api'; @@ -77,7 +79,11 @@ function Pipelines(): JSX.Element { return ; } - return ; + return ( + + ; + + ); } export default Pipelines;