diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.styles.scss b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.styles.scss
new file mode 100644
index 000000000000..546b6d95eab6
--- /dev/null
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.styles.scss
@@ -0,0 +1,6 @@
+.json-flattening-form {
+ margin-top: 16px;
+ &__item {
+ margin-bottom: 12px;
+ }
+}
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.tsx
new file mode 100644
index 000000000000..cfdc16fe4362
--- /dev/null
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.tsx
@@ -0,0 +1,110 @@
+import './JsonFlattening.styles.scss';
+
+import { InfoCircleOutlined } from '@ant-design/icons';
+import { Form, Input, Space, Switch, Tooltip } from 'antd';
+import { useEffect, useState } from 'react';
+import { ProcessorData } from 'types/api/pipeline/def';
+
+import { PREDEFINED_MAPPING } from '../config';
+import KeyValueList from './KeyValueList';
+
+interface JsonFlatteningProps {
+ selectedProcessorData?: ProcessorData;
+ isAdd: boolean;
+}
+
+function JsonFlattening({
+ selectedProcessorData,
+ isAdd,
+}: JsonFlatteningProps): JSX.Element | null {
+ const form = Form.useFormInstance();
+ const mappingValue = selectedProcessorData?.mapping || {};
+ const enableFlattening = Form.useWatch('enable_flattening', form);
+ const enablePaths = Form.useWatch('enable_paths', form);
+
+ const [enableMapping, setEnableMapping] = useState(
+ !!mappingValue && Object.keys(mappingValue).length > 0,
+ );
+
+ const selectedMapping = selectedProcessorData?.mapping;
+ useEffect(() => {
+ if (!enableMapping) {
+ form.setFieldsValue({ mapping: undefined });
+ } else if (form.getFieldValue('mapping') === undefined) {
+ form.setFieldsValue({
+ mapping: selectedMapping || PREDEFINED_MAPPING,
+ });
+ }
+ }, [enableMapping, form, selectedMapping]);
+
+ const handleEnableMappingChange = (checked: boolean): void => {
+ setEnableMapping(checked);
+ };
+
+ const handleEnablePathsChange = (checked: boolean): void => {
+ form.setFieldValue('enable_paths', checked);
+ };
+
+ if (!enableFlattening) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ Enable Paths
+
+
+
+ {enablePaths && (
+
+
+
+ )}
+
+
+
+
+ Enable Mapping
+
+
+
+
+
+
+ {enableMapping && (
+
+
+
+ )}
+
+ );
+}
+
+JsonFlattening.defaultProps = {
+ selectedProcessorData: undefined,
+};
+
+export default JsonFlattening;
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/KeyValueList.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/KeyValueList.tsx
new file mode 100644
index 000000000000..b8a4c952ed1c
--- /dev/null
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/KeyValueList.tsx
@@ -0,0 +1,47 @@
+import { Form, Select } from 'antd';
+
+import { PREDEFINED_MAPPING } from '../config';
+
+interface KeyValueListProps {
+ value?: Record;
+ onChange?: (value: Record) => void;
+}
+
+function KeyValueList({
+ value = PREDEFINED_MAPPING,
+ onChange,
+}: KeyValueListProps): JSX.Element {
+ const handleValueChange = (key: string, newValue: string[]): void => {
+ const newMapping = {
+ ...value,
+ [key]: newValue,
+ };
+ if (onChange) {
+ onChange(newMapping);
+ }
+ };
+
+ return (
+
+ {Object.keys(value).map((key) => (
+
+
+ ))}
+
+ );
+}
+
+KeyValueList.defaultProps = {
+ value: PREDEFINED_MAPPING,
+ onChange: (): void => {},
+};
+
+export default KeyValueList;
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx
index 1d3b12e2c0c5..fbe0f98c5676 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx
@@ -1,16 +1,21 @@
import './styles.scss';
-import { Form, Input, Select } from 'antd';
+import { Form, Input, Select, Space, Switch } from 'antd';
import { ModalFooterTitle } from 'container/PipelinePage/styles';
import { useTranslation } from 'react-i18next';
+import { ProcessorData } from 'types/api/pipeline/def';
import { formValidationRules } from '../config';
import { processorFields, ProcessorFormField } from './config';
import CSVInput from './FormFields/CSVInput';
+import JsonFlattening from './FormFields/JsonFlattening';
import { FormWrapper, PipelineIndexIcon, StyledSelect } from './styles';
+// eslint-disable-next-line sonarjs/cognitive-complexity
function ProcessorFieldInput({
fieldData,
+ selectedProcessorData,
+ isAdd,
}: ProcessorFieldInputProps): JSX.Element | null {
const { t } = useTranslation('pipeline');
@@ -50,6 +55,13 @@ function ProcessorFieldInput({
);
} else if (Array.isArray(fieldData?.initialValue)) {
inputField = ;
+ } else if (fieldData?.name === 'enable_flattening') {
+ inputField = (
+
+ );
} else {
inputField = ;
}
@@ -68,40 +80,82 @@ function ProcessorFieldInput({
)}
- {fieldData.fieldName}}
- name={fieldData.name}
- initialValue={fieldData.initialValue}
- rules={fieldData.rules ? fieldData.rules : formValidationRules}
- dependencies={fieldData.dependencies || []}
- >
- {inputField}
-
+ {fieldData.name === 'enable_flattening' ? (
+
+
+ {
+ form.setFieldValue('enable_flattening', checked);
+ }}
+ />
+ {fieldData.fieldName}
+
+
+ ) : (
+ {fieldData.fieldName}}
+ name={fieldData.name}
+ initialValue={fieldData.initialValue}
+ rules={fieldData.rules ? fieldData.rules : formValidationRules}
+ dependencies={fieldData.dependencies || []}
+ >
+ {inputField}
+
+ )}
+ {fieldData.name === 'enable_flattening' && inputField}
);
}
+ProcessorFieldInput.defaultProps = {
+ selectedProcessorData: undefined,
+};
+
interface ProcessorFieldInputProps {
fieldData: ProcessorFormField;
+ selectedProcessorData?: ProcessorData;
+ isAdd: boolean;
}
-function ProcessorForm({ processorType }: ProcessorFormProps): JSX.Element {
+function ProcessorForm({
+ processorType,
+ selectedProcessorData,
+ isAdd,
+}: ProcessorFormProps): JSX.Element {
return (
{processorFields[processorType]?.map((fieldData: ProcessorFormField) => (
))}
);
}
+ProcessorForm.defaultProps = {
+ selectedProcessorData: undefined,
+};
+
interface ProcessorFormProps {
processorType: string;
+ selectedProcessorData?: ProcessorData;
+ isAdd: boolean;
}
export default ProcessorForm;
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
index 2c9a67689849..4205de722e4f 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
@@ -136,6 +136,13 @@ export const processorFields: { [key: string]: Array } = {
name: 'parse_to',
initialValue: 'attributes',
},
+ {
+ id: 4,
+ fieldName: 'Enable Flattening',
+ placeholder: '',
+ name: 'enable_flattening',
+ initialValue: false,
+ },
],
regex_parser: [
{
@@ -458,3 +465,14 @@ export const processorFields: { [key: string]: Array } = {
},
],
};
+
+export const PREDEFINED_MAPPING = {
+ environment: ['service.env', 'environment', 'env'],
+ host: ['host', 'hostname', 'host.name'],
+ message: ['message', 'msg', 'log'],
+ service: ['service', 'appname'],
+ severity: ['status', 'severity', 'level'],
+ span_id: ['span_id', 'span.id'],
+ trace_flags: ['flags'],
+ trace_id: ['trace_id', 'trace.id'],
+};
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
index 661fc4043ae9..7d9edbc48bec 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
@@ -160,6 +160,7 @@ function AddNewProcessor({
width={800}
footer={null}
onCancel={onCancelModal}
+ destroyOnClose
>
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss
index ef6acfe83813..20af7b763a0d 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/styles.scss
@@ -24,3 +24,7 @@
flex-grow: 1;
margin-left: 2.5rem;
}
+
+.enable-flattening-switch .ant-form-item-control-input {
+ min-height: unset !important;
+}
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx b/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx
index 17761ad99f9f..d00f3fad830a 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx
+++ b/frontend/src/container/PipelinePage/PipelineListsView/PipelineExpandView.tsx
@@ -219,21 +219,6 @@ function PipelineExpandView({
moveRow: moveProcessorRow,
} as React.HTMLAttributes);
- const processorData = useMemo(
- () =>
- expandedPipelineData?.config &&
- expandedPipelineData?.config.map(
- (item: ProcessorData): ProcessorData => ({
- id: item.id,
- orderId: item.orderId,
- type: item.type,
- name: item.name,
- enabled: item.enabled,
- }),
- ),
- [expandedPipelineData],
- );
-
const getLocales = (): TableLocale => ({
emptyText: ,
});
@@ -248,7 +233,7 @@ function PipelineExpandView({
rowKey="id"
size="small"
components={tableComponents}
- dataSource={processorData}
+ dataSource={expandedPipelineData?.config}
pagination={false}
onRow={onRowHandler}
footer={footer}
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx b/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx
index 71b353defec6..d3d8739a874e 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx
+++ b/frontend/src/container/PipelinePage/PipelineListsView/PipelineListsView.tsx
@@ -6,7 +6,7 @@ import { ExpandableConfig } from 'antd/es/table/interface';
import logEvent from 'api/common/logEvent';
import savePipeline from 'api/pipeline/post';
import { useNotifications } from 'hooks/useNotifications';
-import { isUndefined } from 'lodash-es';
+import { isEqual, isUndefined } from 'lodash-es';
import cloneDeep from 'lodash-es/cloneDeep';
import React, {
useCallback,
@@ -75,7 +75,7 @@ function PipelinesListEmptyState(): JSX.Element {
here
@@ -407,15 +407,46 @@ function PipelineListsView({
return undefined;
}, [isEditingActionMode, addNewPipelineHandler, t]);
+ const getModifiedJsonFlatteningConfigs = useCallback(
+ () =>
+ currPipelineData.flatMap((pipeline) => {
+ const prevPipeline = prevPipelineData.find((p) => p.name === pipeline.name);
+
+ return (pipeline.config || [])
+ .filter((processor) => {
+ const prevProcessor = prevPipeline?.config?.find(
+ (p) => p.name === processor.name,
+ );
+ return (
+ processor.type === 'json_parser' &&
+ (!prevProcessor ||
+ prevProcessor.enable_flattening !== processor.enable_flattening ||
+ prevProcessor.enable_paths !== processor.enable_paths ||
+ prevProcessor.path_prefix !== processor.path_prefix ||
+ !isEqual(prevProcessor.mapping, processor.mapping))
+ );
+ })
+ .map((processor) => ({
+ enableFlattening: !!processor.enable_flattening,
+ enablePaths: !!processor.enable_paths,
+ pathPrefix: processor.path_prefix || '',
+ mapping: processor.mapping || {},
+ }));
+ }),
+ [currPipelineData, prevPipelineData],
+ );
+
const onSaveConfigurationHandler = useCallback(async () => {
const modifiedPipelineData = currPipelineData.map((item: PipelineData) => {
const pipelineData = { ...item };
delete pipelineData?.id;
return pipelineData;
});
+
const response = await savePipeline({
data: { pipelines: modifiedPipelineData },
});
+
if (response.statusCode === 200) {
refetchPipelineLists();
setActionMode(ActionMode.Viewing);
@@ -425,6 +456,15 @@ function PipelineListsView({
setCurrPipelineData(pipelinesInDB);
setPrevPipelineData(pipelinesInDB);
+ // Log modified JSON flattening configurations
+ const modifiedConfigs = getModifiedJsonFlatteningConfigs();
+ if (modifiedConfigs.length > 0) {
+ logEvent('Logs pipeline: Saved JSON Flattening Configuration', {
+ count: modifiedConfigs.length,
+ configurations: modifiedConfigs,
+ });
+ }
+
logEvent('Logs: Pipelines: Saved Pipelines', {
count: pipelinesInDB.length,
enabled: pipelinesInDB.filter((p) => p.enabled).length,
@@ -446,7 +486,14 @@ function PipelineListsView({
setPrevPipelineData(modifiedPipelineData);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [currPipelineData, notifications, refetchPipelineLists, setActionMode, t]);
+ }, [
+ currPipelineData,
+ notifications,
+ refetchPipelineLists,
+ setActionMode,
+ t,
+ getModifiedJsonFlatteningConfigs,
+ ]);
const onCancelConfigurationHandler = useCallback((): void => {
setActionMode(ActionMode.Viewing);
diff --git a/frontend/src/container/PipelinePage/mocks/pipeline.ts b/frontend/src/container/PipelinePage/mocks/pipeline.ts
index db309b0e50f4..5dd7b37a8489 100644
--- a/frontend/src/container/PipelinePage/mocks/pipeline.ts
+++ b/frontend/src/container/PipelinePage/mocks/pipeline.ts
@@ -58,6 +58,15 @@ export const pipelineMockData: Array = [
from: 'attributes.auth',
to: 'attributes.username',
},
+ {
+ orderId: 3,
+ enabled: true,
+ type: 'json_parser',
+ id: 'jsonparser',
+ name: 'json parser',
+ from: 'attributes.auth',
+ to: 'attributes.username',
+ },
],
createdBy: 'nityananda@signoz.io',
createdAt: '2023-03-07T16:56:53.36071141Z',
diff --git a/frontend/src/container/PipelinePage/tests/AddNewProcessor.test.tsx b/frontend/src/container/PipelinePage/tests/AddNewProcessor.test.tsx
index 8a226861bf83..e1e961e125aa 100644
--- a/frontend/src/container/PipelinePage/tests/AddNewProcessor.test.tsx
+++ b/frontend/src/container/PipelinePage/tests/AddNewProcessor.test.tsx
@@ -1,8 +1,16 @@
-import { render } from 'tests/test-utils';
+import { fireEvent, screen, waitFor } from '@testing-library/react';
+import { render as customRender } from 'tests/test-utils';
+import { ProcessorData } from 'types/api/pipeline/def';
import { pipelineMockData } from '../mocks/pipeline';
import AddNewProcessor from '../PipelineListsView/AddNewProcessor';
+// Mock the config module to set JSON parser as default
+jest.mock('../PipelineListsView/AddNewProcessor/config', () => ({
+ ...jest.requireActual('../PipelineListsView/AddNewProcessor/config'),
+ DEFAULT_PROCESSOR_TYPE: 'json_parser',
+}));
+
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
@@ -17,44 +25,233 @@ jest.mock('uplot', () => {
};
});
-beforeAll(() => {
- Object.defineProperty(window, 'matchMedia', {
- writable: true,
- value: jest.fn().mockImplementation((query) => ({
- matches: false,
- media: query,
- onchange: null,
- addListener: jest.fn(),
- removeListener: jest.fn(),
- addEventListener: jest.fn(),
- removeEventListener: jest.fn(),
- dispatchEvent: jest.fn(),
- })),
- });
-});
-
const selectedProcessorData = {
id: '1',
orderId: 1,
- type: 'grok_parser',
- name: 'grok use common',
- output: 'grokusecommon',
+ type: 'json_parser',
+ name: 'json parser',
+ output: 'jsonparser',
};
-describe('PipelinePage container test', () => {
- it('should render AddNewProcessor section', () => {
- const setActionType = jest.fn();
- const isActionType = 'add-processor';
- const { asFragment } = render(
- ,
- );
- expect(asFragment()).toMatchSnapshot();
+// Constants for repeated text
+const ENABLE_PATHS_TEXT = 'Enable Paths';
+const ENABLE_MAPPING_TEXT = 'Enable Mapping';
+const PATH_PREFIX_LABEL = 'Path Prefix';
+
+// Helper function to render AddNewProcessor with JSON parser type
+const renderJsonProcessor = ({
+ selectedProcessorData: processorData = selectedProcessorData,
+ isActionType = 'add-processor',
+}: {
+ selectedProcessorData?: ProcessorData;
+ isActionType?: 'add-processor' | 'edit-processor';
+}): ReturnType => {
+ const defaultProps = {
+ isActionType,
+ setActionType: jest.fn(),
+ selectedProcessorData: processorData,
+ setShowSaveButton: jest.fn(),
+ expandedPipelineData: pipelineMockData[2],
+ setExpandedPipelineData: jest.fn(),
+ };
+
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ return customRender();
+};
+
+describe('JSON Flattening Processor Tests', () => {
+ describe('Enable/Disable Flattening', () => {
+ it('should display the form when enable flattening is turned on', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: true,
+ },
+ });
+
+ // Verify the JSON flattening form is displayed
+ expect(screen.queryByText(ENABLE_PATHS_TEXT)).toBeInTheDocument();
+ expect(screen.queryByText(ENABLE_MAPPING_TEXT)).toBeInTheDocument();
+ });
+ it('should not display the form when enable flattening is turned off', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: false,
+ },
+ });
+
+ // Verify the JSON flattening form is not displayed
+ expect(screen.queryByText(ENABLE_PATHS_TEXT)).not.toBeInTheDocument();
+ expect(screen.queryByText(ENABLE_MAPPING_TEXT)).not.toBeInTheDocument();
+ });
+ it('should display the form when enable flattening switch is toggled on', async () => {
+ renderJsonProcessor({});
+
+ // Wait for the component to render and find the enable flattening switch
+ await waitFor(() => {
+ expect(screen.getByRole('switch')).toBeInTheDocument();
+ });
+
+ // Find the enable flattening switch
+ const enableFlatteningSwitch = screen.getByRole('switch');
+ // Turn on the switch
+ fireEvent.click(enableFlatteningSwitch);
+
+ // Verify the JSON flattening form is displayed
+ await waitFor(() => {
+ expect(screen.getByText(ENABLE_PATHS_TEXT)).toBeInTheDocument();
+ expect(screen.getByText(ENABLE_MAPPING_TEXT)).toBeInTheDocument();
+ });
+ });
+ it('should hide the form when enable flattening switch is toggled off', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: true,
+ },
+ });
+
+ // Wait for the component to render and find the switches
+ await waitFor(() => {
+ expect(screen.getAllByRole('switch')[0]).toBeInTheDocument();
+ });
+
+ // Find the enable flattening switch
+ const enableFlatteningSwitch = screen.getAllByRole('switch')[0];
+ // Turn off the switch
+ fireEvent.click(enableFlatteningSwitch);
+ await waitFor(() => {
+ expect(screen.queryByText(ENABLE_PATHS_TEXT)).not.toBeInTheDocument();
+ expect(screen.queryByText(ENABLE_MAPPING_TEXT)).not.toBeInTheDocument();
+ });
+ });
+ });
+
+ describe('Enable/Disable Paths', () => {
+ it('should toggle path prefix visibility when enable paths switch is toggled', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: true,
+ enable_paths: false,
+ },
+ });
+
+ // Wait for the component to render and find the switches
+ await waitFor(() => {
+ expect(screen.getAllByRole('switch')[1]).toBeInTheDocument();
+ });
+
+ // In add mode, enable_paths is always true initially, so the path prefix should be visible
+ await waitFor(() => {
+ expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
+ });
+
+ // Find the enable paths switch (second switch in the form) and turn it off
+ const enablePathsSwitch = screen.getAllByRole('switch')[1];
+ fireEvent.click(enablePathsSwitch);
+
+ // Verify the path prefix field is now hidden
+ await waitFor(() => {
+ expect(screen.queryByLabelText(PATH_PREFIX_LABEL)).not.toBeInTheDocument();
+ });
+
+ // Turn the paths switch back on
+ fireEvent.click(enablePathsSwitch);
+
+ // Verify the path prefix field is displayed again
+ await waitFor(() => {
+ expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
+ });
+ });
+ it('should hide path prefix when enable paths switch is turned off', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: true,
+ enable_paths: true,
+ },
+ });
+
+ // Wait for the component to render and find the switches
+ await waitFor(() => {
+ expect(screen.getAllByRole('switch')[1]).toBeInTheDocument();
+ });
+
+ // Verify the path prefix is initially visible
+ await waitFor(() => {
+ expect(screen.getByLabelText(PATH_PREFIX_LABEL)).toBeInTheDocument();
+ });
+
+ // Find the enable paths switch and turn it off
+ const enablePathsSwitch = screen.getAllByRole('switch')[1];
+ fireEvent.click(enablePathsSwitch);
+
+ // Verify the path prefix field is now hidden
+ await waitFor(() => {
+ expect(screen.queryByLabelText(PATH_PREFIX_LABEL)).not.toBeInTheDocument();
+ });
+ });
+ });
+
+ describe('Enable/Disable Mapping', () => {
+ it('should display the mapping fields when enable mapping is turned on', async () => {
+ renderJsonProcessor({
+ selectedProcessorData: {
+ ...selectedProcessorData,
+ enable_flattening: true,
+ enable_paths: true,
+ mapping: {
+ environment: ['existing.env'],
+ host: ['existing.host'],
+ },
+ },
+ });
+
+ // Verify the mapping fields are displayed
+ await waitFor(() => {
+ expect(screen.getByText('environment')).toBeInTheDocument();
+ expect(screen.getByText('host')).toBeInTheDocument();
+ });
+ });
+ });
+
+ describe('Edit Processor Flow', () => {
+ it('should load existing processor data correctly when editing', async () => {
+ const existingProcessorData = {
+ id: '1',
+ orderId: 1,
+ type: 'json_parser',
+ name: 'test json parser',
+ output: 'testoutput',
+ enable_flattening: true,
+ enable_paths: true,
+ path_prefix: 'existing.prefix',
+ enable_mapping: true,
+ mapping: {
+ environment: ['existing.env'],
+ host: ['existing.host'],
+ },
+ };
+
+ renderJsonProcessor({
+ selectedProcessorData: existingProcessorData,
+ isActionType: 'edit-processor',
+ });
+
+ // Verify the form is displayed with existing data
+ await waitFor(() => {
+ expect(screen.getByDisplayValue('existing.prefix')).toBeInTheDocument();
+ });
+
+ // Verify flattening is enabled
+ const enableFlatteningSwitch = screen.getAllByRole('switch')[0];
+ expect(enableFlatteningSwitch).toBeChecked();
+
+ // Verify paths is enabled
+ const enablePathsSwitch = screen.getAllByRole('switch')[1];
+ expect(enablePathsSwitch).toBeChecked();
+ });
});
});
diff --git a/frontend/src/container/PipelinePage/tests/PipelineListsView.test.tsx b/frontend/src/container/PipelinePage/tests/PipelineListsView.test.tsx
index 003e0ac63e69..3542e0b3165c 100644
--- a/frontend/src/container/PipelinePage/tests/PipelineListsView.test.tsx
+++ b/frontend/src/container/PipelinePage/tests/PipelineListsView.test.tsx
@@ -192,7 +192,7 @@ describe('PipelinePage container test', () => {
'.ant-table-expanded-row [data-icon="delete"]',
);
- expect(deleteBtns.length).toBe(2);
+ expect(deleteBtns.length).toBe(3);
// delete pipeline
await fireEvent.click(deleteBtns[0] as HTMLElement);
@@ -213,7 +213,7 @@ describe('PipelinePage container test', () => {
expect(
document.querySelectorAll('.ant-table-expanded-row [data-icon="delete"]')
.length,
- ).toBe(1);
+ ).toBe(2);
});
it('should be able to toggle and delete pipeline', async () => {
diff --git a/frontend/src/container/PipelinePage/tests/__snapshots__/AddNewProcessor.test.tsx.snap b/frontend/src/container/PipelinePage/tests/__snapshots__/AddNewProcessor.test.tsx.snap
deleted file mode 100644
index 1a91dcb17c9e..000000000000
--- a/frontend/src/container/PipelinePage/tests/__snapshots__/AddNewProcessor.test.tsx.snap
+++ /dev/null
@@ -1,3 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`PipelinePage container test should render AddNewProcessor section 1`] = ``;
diff --git a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelineExpandView.test.tsx.snap b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelineExpandView.test.tsx.snap
index 6e27fbea9759..13b89bec4355 100644
--- a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelineExpandView.test.tsx.snap
+++ b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelineExpandView.test.tsx.snap
@@ -124,6 +124,37 @@ exports[`PipelinePage should render PipelineExpandView section 1`] = `
+
+ |
+
+
+ 3
+
+
+ |
+
+
+ json parser
+
+ |
+
diff --git a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap
index 1261f7282c83..de2cf63c5f4a 100644
--- a/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap
+++ b/frontend/src/container/PipelinePage/tests/__snapshots__/PipelinePageLayout.test.tsx.snap
@@ -118,7 +118,7 @@ exports[`PipelinePage container test should render PipelinePageLayout section 1`
learn_moreĀ
here
diff --git a/frontend/src/types/api/pipeline/def.ts b/frontend/src/types/api/pipeline/def.ts
index 3aef70f1fdbc..956954cf3212 100644
--- a/frontend/src/types/api/pipeline/def.ts
+++ b/frontend/src/types/api/pipeline/def.ts
@@ -31,6 +31,13 @@ export interface ProcessorData {
// time parser fields
layout_type?: string;
layout?: string;
+
+ // json flattening fields
+ enable_flattening?: boolean;
+ enable_paths?: boolean;
+ path_prefix?: string;
+ enable_mapping?: boolean;
+ mapping?: Record;
}
export interface PipelineData {