From d3cf524d364ee90f69577265a4b83e31935a0a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 30 Apr 2020 20:35:25 +0200 Subject: [PATCH] Ensure disappering datasets get removed from filter --- .../common/log_analysis/job_parameters.ts | 22 +++ .../log_analysis/log_analysis_setup_state.ts | 167 ++++++++---------- 2 files changed, 96 insertions(+), 93 deletions(-) diff --git a/x-pack/plugins/infra/common/log_analysis/job_parameters.ts b/x-pack/plugins/infra/common/log_analysis/job_parameters.ts index 171d7fb0b4928..7e10e45bbae4d 100644 --- a/x-pack/plugins/infra/common/log_analysis/job_parameters.ts +++ b/x-pack/plugins/infra/common/log_analysis/job_parameters.ts @@ -69,3 +69,25 @@ export const combineDatasetFilters = ( datasets: [...includedDatasets], }; }; + +export const filterDatasetFilter = ( + datasetFilter: DatasetFilter, + predicate: (dataset: string) => boolean +): DatasetFilter => { + if (datasetFilter.type === 'includeAll') { + return datasetFilter; + } else { + const newDatasets = datasetFilter.datasets.filter(predicate); + + if (newDatasets.length > 0) { + return { + type: 'includeSome', + datasets: newDatasets, + }; + } else { + return { + type: 'includeAll', + }; + } + } +}; diff --git a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts index c92aaab0de739..d46e8bc2485f6 100644 --- a/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts +++ b/x-pack/plugins/infra/public/containers/logs/log_analysis/log_analysis_setup_state.ts @@ -5,11 +5,12 @@ */ import { isEqual } from 'lodash'; -import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { usePrevious } from 'react-use'; import { combineDatasetFilters, DatasetFilter, + filterDatasetFilter, isExampleDataIndex, } from '../../../../common/log_analysis'; import { @@ -45,14 +46,82 @@ export const useAnalysisSetupState = ({ const [startTime, setStartTime] = useState(Date.now() - fourWeeksInMs); const [endTime, setEndTime] = useState(undefined); - const [validatedIndices, dispatchAvailableIndexAction] = useReducer( - reduceAvailableIndicesState, + const [validatedIndices, setValidatedIndices] = useState( sourceConfiguration.indices.map(indexName => ({ name: indexName, validity: 'unknown' as const, })) ); + const updateIndicesWithValidationErrors = useCallback( + (validationErrors: ValidationIndicesError[]) => + setValidatedIndices(availableIndices => + availableIndices.map(previousAvailableIndex => { + const indexValiationErrors = validationErrors.filter( + ({ index }) => index === previousAvailableIndex.name + ); + + if (indexValiationErrors.length > 0) { + return { + validity: 'invalid', + name: previousAvailableIndex.name, + errors: indexValiationErrors, + }; + } else if (previousAvailableIndex.validity === 'valid') { + return { + ...previousAvailableIndex, + validity: 'valid', + errors: [], + }; + } else { + return { + validity: 'valid', + name: previousAvailableIndex.name, + isSelected: !isExampleDataIndex(previousAvailableIndex.name), + availableDatasets: [], + datasetFilter: { + type: 'includeAll' as const, + }, + }; + } + }) + ), + [] + ); + + const updateIndicesWithAvailableDatasets = useCallback( + (availableDatasets: Array<{ indexName: string; datasets: string[] }>) => + setValidatedIndices(availableIndices => + availableIndices.map(previousAvailableIndex => { + if (previousAvailableIndex.validity !== 'valid') { + return previousAvailableIndex; + } + + const availableDatasetsForIndex = availableDatasets.filter( + ({ indexName }) => indexName === previousAvailableIndex.name + ); + const newAvailableDatasets = availableDatasetsForIndex.flatMap( + ({ datasets }) => datasets + ); + + // filter out datasets that have disappeared if this index' datasets were updated + const newDatasetFilter: DatasetFilter = + availableDatasetsForIndex.length > 0 + ? filterDatasetFilter(previousAvailableIndex.datasetFilter, dataset => + newAvailableDatasets.includes(dataset) + ) + : previousAvailableIndex.datasetFilter; + + return { + ...previousAvailableIndex, + availableDatasets: newAvailableDatasets, + datasetFilter: newDatasetFilter, + }; + }) + ), + [] + ); + const validIndexNames = useMemo( () => validatedIndices.filter(index => index.validity === 'valid').map(index => index.name), [validatedIndices] @@ -78,15 +147,6 @@ export const useAnalysisSetupState = ({ [validatedIndices] ); - const setValidatedIndices = useCallback( - (valueOrFunc: AvailableIndex[] | ((validateIndices: AvailableIndex[]) => AvailableIndex[])) => - dispatchAvailableIndexAction({ - type: 'legacySet', - valueOrFunc, - }), - [] - ); - const [validateIndicesRequest, validateIndices] = useTrackedPromise( { cancelPreviousOn: 'resolution', @@ -97,10 +157,7 @@ export const useAnalysisSetupState = ({ ); }, onResolve: ({ data: { errors } }) => { - dispatchAvailableIndexAction({ - type: 'updateWithValidationErrors', - validationErrors: errors, - }); + updateIndicesWithValidationErrors(errors); }, onReject: () => { setValidatedIndices([]); @@ -125,10 +182,7 @@ export const useAnalysisSetupState = ({ ); }, onResolve: ({ data: { datasets } }) => { - dispatchAvailableIndexAction({ - type: 'updateWithAvailableDatasets', - availableDatasets: datasets, - }); + updateIndicesWithAvailableDatasets(datasets); }, }, [validIndexNames, sourceConfiguration.timestampField, startTime, endTime] @@ -208,76 +262,3 @@ export const useAnalysisSetupState = ({ validationErrors, }; }; - -type AvailableIndicesAction = - | { - type: 'legacySet'; - valueOrFunc: AvailableIndex[] | ((i: AvailableIndex[]) => AvailableIndex[]); - } - | { type: 'updateWithValidationErrors'; validationErrors: ValidationIndicesError[] } - | { type: 'select'; indexName: string } - | { - type: 'updateWithAvailableDatasets'; - availableDatasets: Array<{ indexName: string; datasets: string[] }>; - }; - -const reduceAvailableIndicesState = ( - state: AvailableIndex[], - action: AvailableIndicesAction -): AvailableIndex[] => { - switch (action.type) { - case 'legacySet': - if (typeof action.valueOrFunc === 'function') { - return action.valueOrFunc(state); - } else { - return action.valueOrFunc; - } - case 'updateWithValidationErrors': - return state.map(previousAvailableIndex => { - const indexValiationErrors = action.validationErrors.filter( - ({ index }) => index === previousAvailableIndex.name - ); - - if (indexValiationErrors.length > 0) { - return { - validity: 'invalid', - name: previousAvailableIndex.name, - errors: indexValiationErrors, - }; - } else if (previousAvailableIndex.validity === 'valid') { - return { - ...previousAvailableIndex, - validity: 'valid', - errors: [], - }; - } else { - return { - validity: 'valid', - name: previousAvailableIndex.name, - isSelected: !isExampleDataIndex(previousAvailableIndex.name), - availableDatasets: [], - datasetFilter: { - type: 'includeAll' as const, - }, - }; - } - }); - case 'updateWithAvailableDatasets': - return state.map(previousAvailableIndex => { - if (previousAvailableIndex.validity !== 'valid') { - return previousAvailableIndex; - } - - const datasetsForIndex = action.availableDatasets - .filter(({ indexName }) => indexName === previousAvailableIndex.name) - .flatMap(({ datasets }) => datasets); - - return { - ...previousAvailableIndex, - availableDatasets: datasetsForIndex, - }; - }); - case 'select': - return state; - } -};