Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
932 changes: 842 additions & 90 deletions oas_docs/bundle.json

Large diffs are not rendered by default.

932 changes: 842 additions & 90 deletions oas_docs/bundle.serverless.json

Large diffs are not rendered by default.

766 changes: 619 additions & 147 deletions oas_docs/output/kibana.serverless.yaml

Large diffs are not rendered by default.

766 changes: 619 additions & 147 deletions oas_docs/output/kibana.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,37 @@ export const dissectProcessorDefinitionSchema = z.strictObject({
),
}) satisfies z.Schema<DissectProcessorDefinition>;

export type ProcessorDefinition = DissectProcessorDefinition | GrokProcessorDefinition;
export interface DateProcessorConfig extends ProcessorBase {
field: string;
formats: string[];
locale?: string;
target_field?: string;
timezone?: string;
output_format?: string;
}

export interface DateProcessorDefinition {
date: DateProcessorConfig;
}

export const dateProcessorDefinitionSchema = z.strictObject({
date: z.intersection(
processorBaseSchema,
z.object({
field: NonEmptyString,
formats: z.array(NonEmptyString),
locale: z.optional(NonEmptyString),
target_field: z.optional(NonEmptyString),
timezone: z.optional(NonEmptyString),
output_format: z.optional(NonEmptyString),
})
),
}) satisfies z.Schema<DateProcessorDefinition>;

export type ProcessorDefinition =
| DateProcessorDefinition
| DissectProcessorDefinition
| GrokProcessorDefinition;
export type ProcessorDefinitionWithId = ProcessorDefinition & { id: string };

type UnionKeysOf<T extends Record<string, any>> = T extends T ? keyof T : never;
Expand All @@ -82,13 +112,15 @@ export type ProcessorTypeOf<TProcessorDefinition extends ProcessorDefinition> =
UnionKeysOf<TProcessorDefinition> & ProcessorType;

export const processorDefinitionSchema: z.ZodType<ProcessorDefinition> = z.union([
grokProcessorDefinitionSchema,
dateProcessorDefinitionSchema,
dissectProcessorDefinitionSchema,
grokProcessorDefinitionSchema,
]);

export const processorWithIdDefinitionSchema: z.ZodType<ProcessorDefinitionWithId> = z.union([
grokProcessorDefinitionSchema.merge(z.object({ id: z.string() })),
dateProcessorDefinitionSchema.merge(z.object({ id: z.string() })),
dissectProcessorDefinitionSchema.merge(z.object({ id: z.string() })),
grokProcessorDefinitionSchema.merge(z.object({ id: z.string() })),
]);

export const isGrokProcessorDefinition = createIsNarrowSchema(
Expand All @@ -101,6 +133,11 @@ export const isDissectProcessorDefinition = createIsNarrowSchema(
dissectProcessorDefinitionSchema
);

export const isDateProcessorDefinition = createIsNarrowSchema(
processorDefinitionSchema,
dateProcessorDefinitionSchema
);

const processorTypes: ProcessorType[] = (processorDefinitionSchema as z.ZodUnion<any>).options.map(
(option: z.ZodUnion<any>['options'][number]) => Object.keys(option.shape)[0]
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { useController } from 'react-hook-form';
import { EuiFieldText, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import { ProcessorFormState } from '../../types';

export const DateFormatsField = () => {
const { field, fieldState } = useController<ProcessorFormState, 'formats'>({
name: 'formats',
rules: {
required: i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateFormatsRequiredError',
{ defaultMessage: 'A value for format is required.' }
),
},
});

const { invalid, error } = fieldState;
const { ref, ...inputProps } = field;

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
field.onChange([e.target.value]);
};

return (
<EuiFormRow
label={i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateFormatsLabel',
{ defaultMessage: 'Format' }
)}
helpText={
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateFormatsHelpText"
defaultMessage="Expected date format. Accepts a Java time pattern, ISO8601, UNIX, UNIX_MS, or TAI64N format."
/>
}
fullWidth
isInvalid={invalid}
error={error?.message}
>
<EuiFieldText {...inputProps} inputRef={ref} isInvalid={invalid} onChange={handleChange} />
</EuiFormRow>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { useFormContext } from 'react-hook-form';
import { EuiCode, EuiFieldText, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';

export const DateTargetField = () => {
const { register } = useFormContext();
const { ref, ...inputProps } = register('target_field');

return (
<EuiFormRow
label={i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateTargetLabel',
{ defaultMessage: 'Target field' }
)}
helpText={
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateTargetHelpText"
defaultMessage="The field that will hold the parsed date. Defaults to {target}."
values={{ target: <EuiCode>@timestamp</EuiCode> }}
/>
}
fullWidth
>
<EuiFieldText {...inputProps} inputRef={ref} />
</EuiFormRow>
);
};

export const DateTimezoneField = () => {
const { register } = useFormContext();
const { ref, ...inputProps } = register('timezone');

return (
<EuiFormRow
label={i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateTimezoneLabel',
{ defaultMessage: 'Timezone' }
)}
helpText={
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateTimezoneHelpText"
defaultMessage="The timezone to use when parsing the date. Supports template snippets. Defaults to {timezone}"
values={{ timezone: <EuiCode>UTC</EuiCode> }}
/>
}
fullWidth
>
<EuiFieldText {...inputProps} inputRef={ref} />
</EuiFormRow>
);
};

export const DateLocaleField = () => {
const { register } = useFormContext();
const { ref, ...inputProps } = register('locale');

return (
<EuiFormRow
label={i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateLocaleLabel',
{ defaultMessage: 'Locale' }
)}
helpText={
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateLocaleHelpText"
defaultMessage="The locale to use when parsing the date, relevant when parsing month names or week days. Supports template snippets. Defaults to {locale}."
values={{ locale: <EuiCode>ENGLISH</EuiCode> }}
/>
}
fullWidth
>
<EuiFieldText {...inputProps} inputRef={ref} />
</EuiFormRow>
);
};

export const DateOutputFormatField = () => {
const { register } = useFormContext();
const { ref, ...inputProps } = register('output_format');

return (
<EuiFormRow
label={i18n.translate(
'xpack.streams.streamDetailView.managementTab.enrichment.processor.dateOutputFormatLabel',
{ defaultMessage: 'Output format' }
)}
helpText={
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateOutputFormatHelpText"
defaultMessage="The format to use when writing the date to {field}. Must be a valid java time pattern. Defaults to {outputFormat}."
values={{
field: <EuiCode>target_field</EuiCode>,
outputFormat: <EuiCode>yyyy-MM-dd&apos;T&apos;HH:mm:ss.SSSXXX</EuiCode>,
}}
/>
}
fullWidth
>
<EuiFieldText {...inputProps} inputRef={ref} />
</EuiFormRow>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { EuiSpacer } from '@elastic/eui';

import { ProcessorFieldSelector } from '../processor_field_selector';
import { OptionalFieldsAccordion } from '../optional_fields_accordion';
import { ProcessorConditionEditor } from '../processor_condition_editor';
import { IgnoreFailureToggle } from '../ignore_toggles';
import {
DateTargetField,
DateTimezoneField,
DateOutputFormatField,
DateLocaleField,
} from './date_optional_fields';
import { DateFormatsField } from './date_formats_field';

export const DateProcessorForm = () => {
return (
<>
<ProcessorFieldSelector />
<DateFormatsField />
<EuiSpacer size="m" />
<OptionalFieldsAccordion>
<DateTargetField />
<DateTimezoneField />
<DateLocaleField />
<DateOutputFormatField />
<EuiSpacer size="m" />
<ProcessorConditionEditor />
</OptionalFieldsAccordion>
<EuiSpacer size="m" />
<IgnoreFailureToggle />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
isGrokProcessor,
isDissectProcessor,
getDefaultFormStateByType,
isDateProcessor,
} from '../utils';
import { ProcessorErrors, ProcessorMetricBadges } from './processor_metrics';
import {
Expand All @@ -46,6 +47,7 @@ import {
StreamEnrichmentContext,
} from '../state_management/stream_enrichment_state_machine';
import { ProcessorMetrics } from '../state_management/simulation_state_machine';
import { DateProcessorForm } from './date';

export function AddProcessorPanel() {
const { euiTheme } = useEuiTheme();
Expand Down Expand Up @@ -166,8 +168,9 @@ export function AddProcessorPanel() {
<EuiForm component="form" fullWidth onSubmit={methods.handleSubmit(handleSubmit)}>
<ProcessorTypeSelector />
<EuiSpacer size="m" />
{type === 'grok' && <GrokProcessorForm />}
{type === 'date' && <DateProcessorForm />}
{type === 'dissect' && <DissectProcessorForm />}
{type === 'grok' && <GrokProcessorForm />}
</EuiForm>
{processorMetrics && !isEmpty(processorMetrics.errors) && (
<ProcessorErrors metrics={processorMetrics} />
Expand Down Expand Up @@ -351,6 +354,7 @@ export function EditProcessorPanel({ processorRef, processorMetrics }: EditProce
<EuiForm component="form" fullWidth onSubmit={methods.handleSubmit(handleSubmit)}>
<ProcessorTypeSelector disabled />
<EuiSpacer size="m" />
{type === 'date' && <DateProcessorForm />}
{type === 'grok' && <GrokProcessorForm />}
{type === 'dissect' && <DissectProcessorForm />}
</EuiForm>
Expand Down Expand Up @@ -392,6 +396,8 @@ const getProcessorDescription = (processor: ProcessorDefinitionWithUIAttributes)
return processor.grok.patterns.join(' • ');
} else if (isDissectProcessor(processor)) {
return processor.dissect.pattern;
} else if (isDateProcessor(processor)) {
return `${processor.date.field} • ${processor.date.formats.join(' - ')}`;
}

return '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ export const ProcessorTypeSelector = ({
};

const availableProcessors: TAvailableProcessors = {
date: {
value: 'date',
inputDisplay: 'Date',
getDocUrl: () => (
<FormattedMessage
id="xpack.streams.streamDetailView.managementTab.enrichment.processor.dateHelpText"
defaultMessage="Converts a date to a document timestamp."
/>
),
},
dissect: {
value: 'dissect',
inputDisplay: 'Dissect',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { EuiFormRow, EuiFormRowProps, EuiSwitch, htmlIdGenerator } from '@elasti
import { ProcessorFormState } from '../types';

type ExtractBooleanFields<TInput> = NonNullable<
{
[K in keyof TInput]: boolean extends TInput[K] ? K : never;
}[keyof TInput]
TInput extends Record<string, unknown>
? {
[K in keyof TInput]: boolean extends TInput[K] ? K : never;
}[keyof TInput]
: never
>;

interface ToggleFieldProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import {
DateProcessorConfig,
DissectProcessorConfig,
FieldDefinitionType,
GrokProcessorConfig,
Expand All @@ -25,16 +26,13 @@ export interface DetectedField {
type?: FieldDefinitionType | 'system';
}

interface BaseFormState {
detected_fields?: DetectedField[];
}
export type GrokFormState = Omit<GrokProcessorConfig, 'patterns'> & {
type: 'grok';
patterns: Array<{ value: string }>;
};

export type GrokFormState = BaseFormState &
Omit<GrokProcessorConfig, 'patterns'> & {
type: 'grok';
patterns: Array<{ value: string }>;
};
export type DissectFormState = DissectProcessorConfig & { type: 'dissect' };

export type DissectFormState = BaseFormState & DissectProcessorConfig & { type: 'dissect' };
export type DateFormState = DateProcessorConfig & { type: 'date' };

export type ProcessorFormState = GrokFormState | DissectFormState;
export type ProcessorFormState = GrokFormState | DissectFormState | DateFormState;
Loading