diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx
new file mode 100644
index 0000000000..373f2063ac
--- /dev/null
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx
@@ -0,0 +1,78 @@
+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';
+
+function ProcessorFieldInput({
+ fieldData,
+}: ProcessorFieldInputProps): JSX.Element | null {
+ const { t } = useTranslation('pipeline');
+
+ // Watch form values so we can evaluate shouldRender on
+ // conditional fields when form values are updated.
+ const form = Form.useFormInstance();
+ Form.useWatch(fieldData?.dependencies || [], form);
+
+ if (fieldData.shouldRender && !fieldData.shouldRender(form)) {
+ return null;
+ }
+
+ return (
+
+
+ {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}
+
+ ))}
+
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+interface ProcessorFieldInputProps {
+ fieldData: ProcessorFormField;
+}
+
+function ProcessorForm({ processorType }: ProcessorFormProps): JSX.Element {
+ return (
+
+ {processorFields[processorType]?.map((fieldData: ProcessorFormField) => (
+
+ ))}
+
+ );
+}
+
+interface ProcessorFormProps {
+ processorType: string;
+}
+
+export default ProcessorForm;
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
index d6337e2b5c..9dc4f1d1f8 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/config.ts
@@ -1,5 +1,7 @@
+import { FormInstance } from 'antd';
import { Rule, RuleRender } from 'antd/es/form';
import { NamePath } from 'antd/es/form/interface';
+import { ProcessorData } from 'types/api/pipeline/def';
type ProcessorType = {
key: string;
@@ -14,6 +16,7 @@ export const processorTypes: Array = [
{ key: 'regex_parser', value: 'regex_parser', label: 'Regex' },
{ 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: 'add', value: 'add', label: 'Add' },
{ key: 'remove', value: 'remove', label: 'Remove' },
// { key: 'retain', value: 'retain', label: 'Retain' }, @Chintan - Commented as per Nitya's suggestion
@@ -23,6 +26,11 @@ export const processorTypes: Array = [
export const DEFAULT_PROCESSOR_TYPE = processorTypes[0].value;
+export type ProcessorFieldOption = {
+ label: string;
+ value: string;
+};
+
export type ProcessorFormField = {
id: number;
fieldName: string;
@@ -31,6 +39,12 @@ export type ProcessorFormField = {
rules?: Array;
initialValue?: string;
dependencies?: Array;
+ options?: Array;
+ shouldRender?: (form: FormInstance) => boolean;
+ onFormValuesChanged?: (
+ changedValues: ProcessorData,
+ form: FormInstance,
+ ) => void;
};
const traceParserFieldValidator: RuleRender = (form) => ({
@@ -206,6 +220,103 @@ export const processorFields: { [key: string]: Array } = {
],
},
],
+ time_parser: [
+ {
+ id: 1,
+ fieldName: 'Name of Timestamp Parsing Processor',
+ placeholder: 'processor_name_placeholder',
+ name: 'name',
+ },
+ {
+ id: 2,
+ fieldName: 'Parse Timestamp Value From',
+ placeholder: 'processor_parsefrom_placeholder',
+ name: 'parse_from',
+ initialValue: 'attributes.timestamp',
+ },
+ {
+ id: 3,
+ fieldName: 'Timestamp Format Type',
+ placeholder: '',
+ name: 'layout_type',
+ initialValue: 'strptime',
+ options: [
+ {
+ label: 'Unix Epoch',
+ value: 'epoch',
+ },
+ {
+ label: 'strptime Format',
+ value: 'strptime',
+ },
+ ],
+ onFormValuesChanged: (
+ changedValues: ProcessorData,
+ form: FormInstance,
+ ): void => {
+ if (changedValues?.layout_type) {
+ const newLayoutValue =
+ changedValues.layout_type === 'strptime' ? '%Y-%m-%dT%H:%M:%S.%f%z' : 's';
+
+ form.setFieldValue('layout', newLayoutValue);
+ }
+ },
+ },
+ {
+ id: 4,
+ fieldName: 'Epoch Format',
+ placeholder: '',
+ name: 'layout',
+ dependencies: ['layout_type'],
+ shouldRender: (form: FormInstance): boolean => {
+ const layoutType = form.getFieldValue('layout_type');
+ return layoutType === 'epoch';
+ },
+ initialValue: 's',
+ options: [
+ {
+ label: 'seconds',
+ value: 's',
+ },
+ {
+ label: 'milliseconds',
+ value: 'ms',
+ },
+ {
+ label: 'microseconds',
+ value: 'us',
+ },
+ {
+ label: 'nanoseconds',
+ value: 'ns',
+ },
+ {
+ label: 'seconds.milliseconds (eg: 1136214245.123)',
+ value: 's.ms',
+ },
+ {
+ label: 'seconds.microseconds (eg: 1136214245.123456)',
+ value: 's.us',
+ },
+ {
+ label: 'seconds.nanoseconds (eg: 1136214245.123456789)',
+ value: 's.ns',
+ },
+ ],
+ },
+ {
+ id: 4,
+ fieldName: 'Timestamp Format',
+ placeholder: 'strptime directives based format. Eg: %Y-%m-%dT%H:%M:%S.%f%z',
+ name: 'layout',
+ dependencies: ['layout_type'],
+ shouldRender: (form: FormInstance): boolean => {
+ const layoutType = form.getFieldValue('layout_type');
+ return layoutType === 'strptime';
+ },
+ initialValue: '%Y-%m-%dT%H:%M:%S.%f%z',
+ },
+ ],
retain: [
{
id: 1,
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
index 8281655952..661fc4043a 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
+++ b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/index.tsx
@@ -11,9 +11,9 @@ import { v4 } from 'uuid';
import { ModalButtonWrapper, ModalTitle } from '../styles';
import { getEditedDataSource, getRecordIndex } from '../utils';
-import { DEFAULT_PROCESSOR_TYPE } from './config';
+import { DEFAULT_PROCESSOR_TYPE, processorFields } from './config';
import TypeSelect from './FormFields/TypeSelect';
-import { renderProcessorForm } from './utils';
+import ProcessorForm from './ProcessorForm';
function AddNewProcessor({
isActionType,
@@ -141,6 +141,17 @@ function AddNewProcessor({
const isOpen = useMemo(() => isEdit || isAdd, [isAdd, isEdit]);
+ const onFormValuesChanged = useCallback(
+ (changedValues: ProcessorData): void => {
+ processorFields[processorType].forEach((field) => {
+ if (field.onFormValuesChanged) {
+ field.onFormValuesChanged(changedValues, form);
+ }
+ });
+ },
+ [form, processorType],
+ );
+
return (
{modalTitle}}
@@ -157,9 +168,10 @@ function AddNewProcessor({
onFinish={onFinish}
autoComplete="off"
form={form}
+ onValuesChange={onFormValuesChanged}
>
- {renderProcessorForm(processorType)}
+
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/utils.tsx b/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/utils.tsx
deleted file mode 100644
index 1534b704ea..0000000000
--- a/frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/utils.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { processorFields, ProcessorFormField } from './config';
-import NameInput from './FormFields/NameInput';
-
-export const renderProcessorForm = (
- processorType: string,
-): Array =>
- processorFields[processorType]?.map((fieldData: ProcessorFormField) => (
-
- ));
diff --git a/frontend/src/container/PipelinePage/PipelineListsView/Preview/hooks/usePipelinePreview.ts b/frontend/src/container/PipelinePage/PipelineListsView/Preview/hooks/usePipelinePreview.ts
index ad875cdcd3..7e739fdf52 100644
--- a/frontend/src/container/PipelinePage/PipelineListsView/Preview/hooks/usePipelinePreview.ts
+++ b/frontend/src/container/PipelinePage/PipelineListsView/Preview/hooks/usePipelinePreview.ts
@@ -27,7 +27,8 @@ const usePipelinePreview = ({
// ILog allows both number and string while the API needs a number
const simulationInput = inputLogs.map((l) => ({
...l,
- timestamp: new Date(l.timestamp).getTime(),
+ // log timestamps in query service API are unix nanos
+ timestamp: new Date(l.timestamp).getTime() * 10 ** 6,
}));
const response = useQuery({
@@ -42,9 +43,15 @@ const usePipelinePreview = ({
const { isFetching, isError, data, error } = response;
+ const outputLogs = (data?.logs || []).map((l: ILog) => ({
+ ...l,
+ // log timestamps in query service API are unix nanos
+ timestamp: (l.timestamp as number) / 10 ** 6,
+ }));
+
return {
isLoading: isFetching,
- outputLogs: data?.logs || [],
+ outputLogs,
isError,
errorMsg: error?.response?.data?.error || '',
};
diff --git a/frontend/src/types/api/pipeline/def.ts b/frontend/src/types/api/pipeline/def.ts
index 5462dfe611..3aef70f1fd 100644
--- a/frontend/src/types/api/pipeline/def.ts
+++ b/frontend/src/types/api/pipeline/def.ts
@@ -27,6 +27,10 @@ export interface ProcessorData {
trace_flags?: {
parse_from: string;
};
+
+ // time parser fields
+ layout_type?: string;
+ layout?: string;
}
export interface PipelineData {