mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
🌊 Streams: Use better default field (#217478)
This PR passes the current sample documents to the default form state generation for new processors to pick a good default field. The logic that's actually employed for `dissect` and `grok` is the following: * Go through all docs and order string fields occurring by how many values they have * Pick the top one from a list of "well known" fields that probably make sense (in case of a tie, go by a the ordering of the well known fields) * If no field is found this way, just leave it empty - this still shows the full table and the user can pick the field they care about Especially for otel this should be helpful.
This commit is contained in:
parent
dee4dfbe59
commit
e6cdba65ed
6 changed files with 233 additions and 28 deletions
|
@ -23,7 +23,7 @@ import {
|
||||||
import { useSelector } from '@xstate5/react';
|
import { useSelector } from '@xstate5/react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useEffect, useMemo, useCallback } from 'react';
|
||||||
import { useForm, SubmitHandler, FormProvider, useWatch } from 'react-hook-form';
|
import { useForm, SubmitHandler, FormProvider, useWatch } from 'react-hook-form';
|
||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
import { DiscardPromptOptions, useDiscardConfirm } from '../../../../hooks/use_discard_confirm';
|
import { DiscardPromptOptions, useDiscardConfirm } from '../../../../hooks/use_discard_confirm';
|
||||||
|
@ -46,11 +46,13 @@ import {
|
||||||
useStreamsEnrichmentSelector,
|
useStreamsEnrichmentSelector,
|
||||||
useSimulatorSelector,
|
useSimulatorSelector,
|
||||||
StreamEnrichmentContextType,
|
StreamEnrichmentContextType,
|
||||||
|
useGetStreamEnrichmentState,
|
||||||
} from '../state_management/stream_enrichment_state_machine';
|
} from '../state_management/stream_enrichment_state_machine';
|
||||||
import { ProcessorMetrics } from '../state_management/simulation_state_machine';
|
import { ProcessorMetrics } from '../state_management/simulation_state_machine';
|
||||||
import { DateProcessorForm } from './date';
|
import { DateProcessorForm } from './date';
|
||||||
import { ConfigDrivenProcessorFields } from './config_driven/components/fields';
|
import { ConfigDrivenProcessorFields } from './config_driven/components/fields';
|
||||||
import { ConfigDrivenProcessorType } from './config_driven/types';
|
import { ConfigDrivenProcessorType } from './config_driven/types';
|
||||||
|
import { selectPreviewDocuments } from '../state_management/simulation_state_machine/selectors';
|
||||||
|
|
||||||
export function AddProcessorPanel() {
|
export function AddProcessorPanel() {
|
||||||
const { euiTheme } = useEuiTheme();
|
const { euiTheme } = useEuiTheme();
|
||||||
|
@ -63,20 +65,31 @@ export function AddProcessorPanel() {
|
||||||
const processorMetrics = useSimulatorSelector(
|
const processorMetrics = useSimulatorSelector(
|
||||||
(state) => processorRef && state.context.simulation?.processors_metrics[processorRef.id]
|
(state) => processorRef && state.context.simulation?.processors_metrics[processorRef.id]
|
||||||
);
|
);
|
||||||
|
const getEnrichmentState = useGetStreamEnrichmentState();
|
||||||
|
|
||||||
const isOpen = Boolean(processorRef);
|
const isOpen = Boolean(processorRef);
|
||||||
|
const defaultValuesGetter = useCallback(
|
||||||
|
() =>
|
||||||
|
getDefaultFormStateByType(
|
||||||
|
'grok',
|
||||||
|
selectPreviewDocuments(getEnrichmentState().context.simulatorRef?.getSnapshot().context)
|
||||||
|
),
|
||||||
|
[getEnrichmentState]
|
||||||
|
);
|
||||||
|
const initialDefaultValues = useMemo(() => defaultValuesGetter(), [defaultValuesGetter]);
|
||||||
|
|
||||||
const defaultValues = useMemo(() => getDefaultFormStateByType('grok'), []);
|
const methods = useForm<ProcessorFormState>({
|
||||||
|
defaultValues: initialDefaultValues,
|
||||||
const methods = useForm<ProcessorFormState>({ defaultValues, mode: 'onChange' });
|
mode: 'onChange',
|
||||||
|
});
|
||||||
|
|
||||||
const type = useWatch({ control: methods.control, name: 'type' });
|
const type = useWatch({ control: methods.control, name: 'type' });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!processorRef) {
|
if (!processorRef) {
|
||||||
methods.reset(defaultValues);
|
methods.reset(defaultValuesGetter());
|
||||||
}
|
}
|
||||||
}, [defaultValues, methods, processorRef]);
|
}, [defaultValuesGetter, methods, processorRef]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (processorRef) {
|
if (processorRef) {
|
||||||
|
@ -99,6 +112,8 @@ export function AddProcessorPanel() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
|
const defaultValues = defaultValuesGetter();
|
||||||
|
methods.reset(defaultValues);
|
||||||
const draftProcessor = createDraftProcessorFromForm(defaultValues);
|
const draftProcessor = createDraftProcessorFromForm(defaultValues);
|
||||||
addProcessor(draftProcessor);
|
addProcessor(draftProcessor);
|
||||||
};
|
};
|
||||||
|
@ -207,6 +222,7 @@ export interface EditProcessorPanelProps {
|
||||||
export function EditProcessorPanel({ processorRef, processorMetrics }: EditProcessorPanelProps) {
|
export function EditProcessorPanel({ processorRef, processorMetrics }: EditProcessorPanelProps) {
|
||||||
const { euiTheme } = useEuiTheme();
|
const { euiTheme } = useEuiTheme();
|
||||||
const state = useSelector(processorRef, (s) => s);
|
const state = useSelector(processorRef, (s) => s);
|
||||||
|
const getEnrichmentState = useGetStreamEnrichmentState();
|
||||||
const canEdit = useStreamsEnrichmentSelector((s) => s.context.definition.privileges.simulate);
|
const canEdit = useStreamsEnrichmentSelector((s) => s.context.definition.privileges.simulate);
|
||||||
const previousProcessor = state.context.previousProcessor;
|
const previousProcessor = state.context.previousProcessor;
|
||||||
const processor = state.context.processor;
|
const processor = state.context.processor;
|
||||||
|
@ -217,7 +233,14 @@ export function EditProcessorPanel({ processorRef, processorMetrics }: EditProce
|
||||||
const isNew = state.context.isNew;
|
const isNew = state.context.isNew;
|
||||||
const isUnsaved = isNew || state.context.isUpdated;
|
const isUnsaved = isNew || state.context.isUpdated;
|
||||||
|
|
||||||
const defaultValues = useMemo(() => getFormStateFrom(processor), [processor]);
|
const defaultValues = useMemo(
|
||||||
|
() =>
|
||||||
|
getFormStateFrom(
|
||||||
|
selectPreviewDocuments(getEnrichmentState().context.simulatorRef?.getSnapshot().context),
|
||||||
|
processor
|
||||||
|
),
|
||||||
|
[getEnrichmentState, processor]
|
||||||
|
);
|
||||||
|
|
||||||
const methods = useForm<ProcessorFormState>({
|
const methods = useForm<ProcessorFormState>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
|
@ -239,11 +262,16 @@ export function EditProcessorPanel({ processorRef, processorMetrics }: EditProce
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const subscription = processorRef.on('processor.changesDiscarded', () => {
|
const subscription = processorRef.on('processor.changesDiscarded', () => {
|
||||||
methods.reset(getFormStateFrom(previousProcessor));
|
methods.reset(
|
||||||
|
getFormStateFrom(
|
||||||
|
selectPreviewDocuments(getEnrichmentState().context.simulatorRef?.getSnapshot().context),
|
||||||
|
previousProcessor
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => subscription.unsubscribe();
|
return () => subscription.unsubscribe();
|
||||||
}, [methods, previousProcessor, processorRef]);
|
}, [getEnrichmentState, methods, previousProcessor, processorRef]);
|
||||||
|
|
||||||
const handleCancel = useDiscardConfirm(
|
const handleCancel = useDiscardConfirm(
|
||||||
() => processorRef?.send({ type: 'processor.cancel' }),
|
() => processorRef?.send({ type: 'processor.cancel' }),
|
||||||
|
|
|
@ -15,6 +15,8 @@ import { useKibana } from '../../../../hooks/use_kibana';
|
||||||
import { getDefaultFormStateByType } from '../utils';
|
import { getDefaultFormStateByType } from '../utils';
|
||||||
import { ProcessorFormState } from '../types';
|
import { ProcessorFormState } from '../types';
|
||||||
import { configDrivenProcessors } from './config_driven';
|
import { configDrivenProcessors } from './config_driven';
|
||||||
|
import { useGetStreamEnrichmentState } from '../state_management/stream_enrichment_state_machine';
|
||||||
|
import { selectPreviewDocuments } from '../state_management/simulation_state_machine/selectors';
|
||||||
|
|
||||||
interface TAvailableProcessor {
|
interface TAvailableProcessor {
|
||||||
type: ProcessorType;
|
type: ProcessorType;
|
||||||
|
@ -29,6 +31,7 @@ export const ProcessorTypeSelector = ({
|
||||||
}: Pick<EuiSuperSelectProps, 'disabled'>) => {
|
}: Pick<EuiSuperSelectProps, 'disabled'>) => {
|
||||||
const { core } = useKibana();
|
const { core } = useKibana();
|
||||||
const esDocUrl = core.docLinks.links.elasticsearch.docsBase;
|
const esDocUrl = core.docLinks.links.elasticsearch.docsBase;
|
||||||
|
const getEnrichmentState = useGetStreamEnrichmentState();
|
||||||
|
|
||||||
const { reset } = useFormContext();
|
const { reset } = useFormContext();
|
||||||
const { field, fieldState } = useController<ProcessorFormState, 'type'>({
|
const { field, fieldState } = useController<ProcessorFormState, 'type'>({
|
||||||
|
@ -39,7 +42,10 @@ export const ProcessorTypeSelector = ({
|
||||||
const processorType = useWatch<{ type: ProcessorType }>({ name: 'type' });
|
const processorType = useWatch<{ type: ProcessorType }>({ name: 'type' });
|
||||||
|
|
||||||
const handleChange = (type: ProcessorType) => {
|
const handleChange = (type: ProcessorType) => {
|
||||||
const formState = getDefaultFormStateByType(type);
|
const formState = getDefaultFormStateByType(
|
||||||
|
type,
|
||||||
|
selectPreviewDocuments(getEnrichmentState().context.simulatorRef?.getSnapshot().context)
|
||||||
|
);
|
||||||
reset(formState);
|
reset(formState);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,15 @@ const EMPTY_ARRAY: [] = [];
|
||||||
*/
|
*/
|
||||||
export const selectPreviewDocuments = createSelector(
|
export const selectPreviewDocuments = createSelector(
|
||||||
[
|
[
|
||||||
(context: SimulationContext) => context.samples,
|
(context: SimulationContext | undefined) => context?.samples,
|
||||||
(context: SimulationContext) => context.previewDocsFilter,
|
(context: SimulationContext | undefined) => context?.previewDocsFilter,
|
||||||
(context: SimulationContext) => context.simulation?.documents,
|
(context: SimulationContext | undefined) => context?.simulation?.documents,
|
||||||
],
|
],
|
||||||
(samples, previewDocsFilter, documents) => {
|
(samples, previewDocsFilter, documents) => {
|
||||||
return (
|
return (
|
||||||
((previewDocsFilter && documents
|
((previewDocsFilter && documents
|
||||||
? filterSimulationDocuments(documents, previewDocsFilter)
|
? filterSimulationDocuments(documents, previewDocsFilter)
|
||||||
: samples.map(flattenObjectNestedLast)) as FlattenRecord[]) || EMPTY_ARRAY
|
: samples?.map(flattenObjectNestedLast)) as FlattenRecord[]) || EMPTY_ARRAY
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||||
import { createActorContext, useSelector } from '@xstate5/react';
|
import { createActorContext, useSelector } from '@xstate5/react';
|
||||||
import { createConsoleInspector } from '@kbn/xstate-utils';
|
import { createConsoleInspector } from '@kbn/xstate-utils';
|
||||||
import {
|
import {
|
||||||
|
@ -26,6 +26,11 @@ export const useStreamsEnrichmentSelector = StreamEnrichmentContext.useSelector;
|
||||||
|
|
||||||
export type StreamEnrichmentEvents = ReturnType<typeof useStreamEnrichmentEvents>;
|
export type StreamEnrichmentEvents = ReturnType<typeof useStreamEnrichmentEvents>;
|
||||||
|
|
||||||
|
export const useGetStreamEnrichmentState = () => {
|
||||||
|
const service = StreamEnrichmentContext.useActorRef();
|
||||||
|
return useCallback(() => service.getSnapshot(), [service]);
|
||||||
|
};
|
||||||
|
|
||||||
export const useStreamEnrichmentEvents = () => {
|
export const useStreamEnrichmentEvents = () => {
|
||||||
const service = StreamEnrichmentContext.useActorRef();
|
const service = StreamEnrichmentContext.useActorRef();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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 { FlattenRecord } from '@kbn/streams-schema';
|
||||||
|
import { getDefaultFormStateByType } from './utils';
|
||||||
|
import { ALWAYS_CONDITION } from '../../../util/condition';
|
||||||
|
|
||||||
|
describe('utils', () => {
|
||||||
|
describe('defaultGrokProcessorFormState', () => {
|
||||||
|
it('should return default form state with empty field when no well known text fields are present', () => {
|
||||||
|
const sampleDocs: FlattenRecord[] = [
|
||||||
|
{
|
||||||
|
'unknown.field': 'some value',
|
||||||
|
'another.field': 'another value',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'random.field': 'random value',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = getDefaultFormStateByType('grok', sampleDocs);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
type: 'grok',
|
||||||
|
field: '',
|
||||||
|
patterns: [{ value: '' }],
|
||||||
|
pattern_definitions: {},
|
||||||
|
ignore_failure: true,
|
||||||
|
ignore_missing: true,
|
||||||
|
if: ALWAYS_CONDITION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select the only well known text field present', () => {
|
||||||
|
const sampleDocs: FlattenRecord[] = [
|
||||||
|
{
|
||||||
|
'error.message': 'This is an error',
|
||||||
|
'another.field': 'another value',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'error.message': 'Another error',
|
||||||
|
'random.field': 'random value',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = getDefaultFormStateByType('grok', sampleDocs);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
type: 'grok',
|
||||||
|
field: 'error.message',
|
||||||
|
patterns: [{ value: '' }],
|
||||||
|
pattern_definitions: {},
|
||||||
|
ignore_failure: true,
|
||||||
|
ignore_missing: true,
|
||||||
|
if: ALWAYS_CONDITION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select the most common well known text field when multiple are present', () => {
|
||||||
|
const sampleDocs: FlattenRecord[] = [
|
||||||
|
{
|
||||||
|
message: 'Log message 1',
|
||||||
|
'error.message': 'Error message 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: 'Log message 2',
|
||||||
|
'error.message': 'Error message 2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'error.message': 'Error message 3',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = getDefaultFormStateByType('grok', sampleDocs);
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
type: 'grok',
|
||||||
|
field: 'error.message', // 'error.message' appears 3 times vs 'message' 2 times
|
||||||
|
patterns: [{ value: '' }],
|
||||||
|
pattern_definitions: {},
|
||||||
|
ignore_failure: true,
|
||||||
|
ignore_missing: true,
|
||||||
|
if: ALWAYS_CONDITION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should select based on WELL_KNOWN_TEXT_FIELDS order when frequencies are equal', () => {
|
||||||
|
const sampleDocs: FlattenRecord[] = [
|
||||||
|
{
|
||||||
|
message: 'Log message 1',
|
||||||
|
'error.message': 'Error message 1',
|
||||||
|
'event.original': 'Original event 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: 'Log message 2',
|
||||||
|
'error.message': 'Error message 2',
|
||||||
|
'event.original': 'Original event 2',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = getDefaultFormStateByType('grok', sampleDocs);
|
||||||
|
|
||||||
|
// In WELL_KNOWN_TEXT_FIELDS, 'message' comes before 'error.message' and 'event.original'
|
||||||
|
expect(result).toEqual({
|
||||||
|
type: 'grok',
|
||||||
|
field: 'message',
|
||||||
|
patterns: [{ value: '' }],
|
||||||
|
pattern_definitions: {},
|
||||||
|
ignore_failure: true,
|
||||||
|
ignore_missing: true,
|
||||||
|
if: ALWAYS_CONDITION,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,6 +8,7 @@
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
FlattenRecord,
|
||||||
ProcessorDefinition,
|
ProcessorDefinition,
|
||||||
ProcessorDefinitionWithId,
|
ProcessorDefinitionWithId,
|
||||||
ProcessorType,
|
ProcessorType,
|
||||||
|
@ -35,7 +36,7 @@ import {
|
||||||
*/
|
*/
|
||||||
export const SPECIALISED_TYPES = ['date', 'dissect', 'grok'];
|
export const SPECIALISED_TYPES = ['date', 'dissect', 'grok'];
|
||||||
|
|
||||||
const defaultDateProcessorFormState: DateFormState = {
|
const defaultDateProcessorFormState: () => DateFormState = () => ({
|
||||||
type: 'date',
|
type: 'date',
|
||||||
field: '',
|
field: '',
|
||||||
formats: [],
|
formats: [],
|
||||||
|
@ -45,48 +46,94 @@ const defaultDateProcessorFormState: DateFormState = {
|
||||||
output_format: '',
|
output_format: '',
|
||||||
ignore_failure: true,
|
ignore_failure: true,
|
||||||
if: ALWAYS_CONDITION,
|
if: ALWAYS_CONDITION,
|
||||||
|
});
|
||||||
|
|
||||||
|
const WELL_KNOWN_TEXT_FIELDS = [
|
||||||
|
'message',
|
||||||
|
'body.text',
|
||||||
|
'error.message',
|
||||||
|
'event.original',
|
||||||
|
'attributes.exception.message',
|
||||||
|
];
|
||||||
|
|
||||||
|
const getDefaultTextField = (sampleDocs: FlattenRecord[]) => {
|
||||||
|
const stringFieldCounts = sampleDocs
|
||||||
|
.map((doc) =>
|
||||||
|
Object.keys(doc).filter(
|
||||||
|
(key) => doc[key] && typeof doc[key] === 'string' && WELL_KNOWN_TEXT_FIELDS.includes(key)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.reduce((acc, keys) => {
|
||||||
|
keys.forEach((key) => {
|
||||||
|
acc[key] = (acc[key] || 0) + 1;
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, number>);
|
||||||
|
|
||||||
|
// sort by count descending first, then by order of field in WELL_KNOWN_TEXT_FIELDS
|
||||||
|
const sortedFields = Object.entries(stringFieldCounts).sort(
|
||||||
|
([fieldA, countA], [fieldB, countB]) => {
|
||||||
|
const countSorting = countB - countA;
|
||||||
|
if (countSorting !== 0) {
|
||||||
|
return countSorting;
|
||||||
|
}
|
||||||
|
const indexA = WELL_KNOWN_TEXT_FIELDS.indexOf(fieldA);
|
||||||
|
const indexB = WELL_KNOWN_TEXT_FIELDS.indexOf(fieldB);
|
||||||
|
return indexA - indexB;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const mostCommonField = sortedFields[0];
|
||||||
|
return mostCommonField ? mostCommonField[0] : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultDissectProcessorFormState: DissectFormState = {
|
const defaultDissectProcessorFormState: (sampleDocs: FlattenRecord[]) => DissectFormState = (
|
||||||
|
sampleDocs: FlattenRecord[]
|
||||||
|
) => ({
|
||||||
type: 'dissect',
|
type: 'dissect',
|
||||||
field: 'message',
|
field: getDefaultTextField(sampleDocs),
|
||||||
pattern: '',
|
pattern: '',
|
||||||
ignore_failure: true,
|
ignore_failure: true,
|
||||||
ignore_missing: true,
|
ignore_missing: true,
|
||||||
if: ALWAYS_CONDITION,
|
if: ALWAYS_CONDITION,
|
||||||
};
|
});
|
||||||
|
|
||||||
const defaultGrokProcessorFormState: GrokFormState = {
|
const defaultGrokProcessorFormState: (sampleDocs: FlattenRecord[]) => GrokFormState = (
|
||||||
|
sampleDocs: FlattenRecord[]
|
||||||
|
) => ({
|
||||||
type: 'grok',
|
type: 'grok',
|
||||||
field: 'message',
|
field: getDefaultTextField(sampleDocs),
|
||||||
patterns: [{ value: '' }],
|
patterns: [{ value: '' }],
|
||||||
pattern_definitions: {},
|
pattern_definitions: {},
|
||||||
ignore_failure: true,
|
ignore_failure: true,
|
||||||
ignore_missing: true,
|
ignore_missing: true,
|
||||||
if: ALWAYS_CONDITION,
|
if: ALWAYS_CONDITION,
|
||||||
};
|
});
|
||||||
|
|
||||||
const configDrivenDefaultFormStates = mapValues(
|
const configDrivenDefaultFormStates = mapValues(
|
||||||
configDrivenProcessors,
|
configDrivenProcessors,
|
||||||
(config) => config.defaultFormState
|
(config) => () => config.defaultFormState
|
||||||
) as {
|
) as {
|
||||||
[TKey in ConfigDrivenProcessorType]: ConfigDrivenProcessors[TKey]['defaultFormState'];
|
[TKey in ConfigDrivenProcessorType]: () => ConfigDrivenProcessors[TKey]['defaultFormState'];
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProcessorFormStateByType: Record<ProcessorType, ProcessorFormState> = {
|
const defaultProcessorFormStateByType: Record<
|
||||||
|
ProcessorType,
|
||||||
|
(sampleDocs: FlattenRecord[]) => ProcessorFormState
|
||||||
|
> = {
|
||||||
date: defaultDateProcessorFormState,
|
date: defaultDateProcessorFormState,
|
||||||
dissect: defaultDissectProcessorFormState,
|
dissect: defaultDissectProcessorFormState,
|
||||||
grok: defaultGrokProcessorFormState,
|
grok: defaultGrokProcessorFormState,
|
||||||
...configDrivenDefaultFormStates,
|
...configDrivenDefaultFormStates,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultFormStateByType = (type: ProcessorType) =>
|
export const getDefaultFormStateByType = (type: ProcessorType, sampleDocuments: FlattenRecord[]) =>
|
||||||
defaultProcessorFormStateByType[type];
|
defaultProcessorFormStateByType[type](sampleDocuments);
|
||||||
|
|
||||||
export const getFormStateFrom = (
|
export const getFormStateFrom = (
|
||||||
|
sampleDocuments: FlattenRecord[],
|
||||||
processor?: ProcessorDefinitionWithUIAttributes
|
processor?: ProcessorDefinitionWithUIAttributes
|
||||||
): ProcessorFormState => {
|
): ProcessorFormState => {
|
||||||
if (!processor) return defaultGrokProcessorFormState;
|
if (!processor) return defaultGrokProcessorFormState(sampleDocuments);
|
||||||
|
|
||||||
if (isGrokProcessor(processor)) {
|
if (isGrokProcessor(processor)) {
|
||||||
const { grok } = processor;
|
const { grok } = processor;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue