fix current field candidates list

This commit is contained in:
Walter Rafelsberger 2024-10-11 20:15:37 +02:00
parent 26cd1a53df
commit 632b711ca1
4 changed files with 59 additions and 43 deletions

View file

@ -9,14 +9,16 @@ import { httpServiceMock } from '@kbn/core/public/mocks';
import type { FetchFieldCandidatesResponse } from '../queries/fetch_field_candidates';
import { fetchFieldCandidates } from './log_rate_analysis_field_candidates_slice';
import { fetchFieldCandidates, getDefaultState } from './log_rate_analysis_field_candidates_slice';
const mockHttp = httpServiceMock.createStartContract();
describe('fetchFieldCandidates', () => {
it('dispatches field candidates', async () => {
const mockDispatch = jest.fn();
const mockGetState = jest.fn();
const mockGetState = jest.fn().mockReturnValue({
logRateAnalysisFieldCandidates: getDefaultState(),
});
const mockResponse: FetchFieldCandidatesResponse = {
isECS: false,
@ -60,7 +62,12 @@ describe('fetchFieldCandidates', () => {
payload: {
fieldSelectionMessage:
'2 out of 5 fields were preselected for the analysis. Use the "Fields" dropdown to adjust the selection.',
fieldFilterSkippedItems: [
initialFieldFilterSkippedItems: [
'another-keyword-field',
'another-text-field',
'yet-another-text-field',
],
currentFieldFilterSkippedItems: [
'another-keyword-field',
'another-text-field',
'yet-another-text-field',

View file

@ -90,10 +90,14 @@ export const fetchFieldCandidates = createAsyncThunk(
...selectedKeywordFieldCandidates,
...selectedTextFieldCandidates,
];
const fieldFilterSkippedItems = fieldFilterUniqueItems.filter(
const initialFieldFilterSkippedItems = fieldFilterUniqueItems.filter(
(d) => !fieldFilterUniqueSelectedItems.includes(d)
);
const currentFieldFilterSkippedItems = (
thunkApi.getState() as { logRateAnalysisFieldCandidates: FieldCandidatesState }
).logRateAnalysisFieldCandidates.currentFieldFilterSkippedItems;
thunkApi.dispatch(
setAllFieldCandidates({
fieldSelectionMessage: getFieldSelectionMessage(
@ -102,7 +106,13 @@ export const fetchFieldCandidates = createAsyncThunk(
fieldFilterUniqueSelectedItems.length
),
fieldFilterUniqueItems,
fieldFilterSkippedItems,
initialFieldFilterSkippedItems,
// If the currentFieldFilterSkippedItems is null, we're on the first load,
// only then we set the current skipped fields to the initial skipped fields.
currentFieldFilterSkippedItems:
currentFieldFilterSkippedItems === null && initialFieldFilterSkippedItems.length > 0
? initialFieldFilterSkippedItems
: currentFieldFilterSkippedItems,
keywordFieldCandidates,
textFieldCandidates,
selectedKeywordFieldCandidates,
@ -116,18 +126,20 @@ export interface FieldCandidatesState {
isLoading: boolean;
fieldSelectionMessage?: string;
fieldFilterUniqueItems: string[];
fieldFilterSkippedItems: string[];
initialFieldFilterSkippedItems: string[];
currentFieldFilterSkippedItems: string[] | null;
keywordFieldCandidates: string[];
textFieldCandidates: string[];
selectedKeywordFieldCandidates: string[];
selectedTextFieldCandidates: string[];
}
function getDefaultState(): FieldCandidatesState {
export function getDefaultState(): FieldCandidatesState {
return {
isLoading: false,
fieldFilterUniqueItems: [],
fieldFilterSkippedItems: [],
initialFieldFilterSkippedItems: [],
currentFieldFilterSkippedItems: null,
keywordFieldCandidates: [],
textFieldCandidates: [],
selectedKeywordFieldCandidates: [],
@ -145,6 +157,12 @@ export const logRateAnalysisFieldCandidatesSlice = createSlice({
) => {
return { ...state, ...action.payload };
},
setCurrentFieldFilterSkippedItems: (
state: FieldCandidatesState,
action: PayloadAction<string[]>
) => {
return { ...state, currentFieldFilterSkippedItems: action.payload };
},
},
extraReducers: (builder) => {
builder.addCase(fetchFieldCandidates.pending, (state) => {
@ -157,4 +175,5 @@ export const logRateAnalysisFieldCandidatesSlice = createSlice({
});
// Action creators are generated for each case reducer function
export const { setAllFieldCandidates } = logRateAnalysisFieldCandidatesSlice.actions;
export const { setAllFieldCandidates, setCurrentFieldFilterSkippedItems } =
logRateAnalysisFieldCandidatesSlice.actions;

View file

@ -6,7 +6,7 @@
*/
import type { FC } from 'react';
import React, { useEffect, useState } from 'react';
import React from 'react';
import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
@ -23,6 +23,7 @@ import {
setSkippedColumns,
type LogRateAnalysisResultsTableColumnName,
} from '@kbn/aiops-log-rate-analysis/state/log_rate_analysis_table_slice';
import { setCurrentFieldFilterSkippedItems } from '@kbn/aiops-log-rate-analysis/state/log_rate_analysis_field_candidates_slice';
import { ItemFilterPopover as FieldFilterPopover } from './item_filter_popover';
import { ItemFilterPopover as ColumnFilterPopover } from './item_filter_popover';
@ -82,13 +83,11 @@ const resultsGroupedOnId = 'aiopsLogRateAnalysisGroupingOn';
export interface LogRateAnalysisOptionsProps {
foundGroups: boolean;
growFirstItem?: boolean;
onFieldsFilterChange: (skippedFieldsUpdate: string[]) => void;
}
export const LogRateAnalysisOptions: FC<LogRateAnalysisOptionsProps> = ({
foundGroups,
growFirstItem = false,
onFieldsFilterChange,
}) => {
const dispatch = useAppDispatch();
@ -96,20 +95,11 @@ export const LogRateAnalysisOptions: FC<LogRateAnalysisOptionsProps> = ({
const { isRunning } = useAppSelector((s) => s.logRateAnalysisStream);
const fieldCandidates = useAppSelector((s) => s.logRateAnalysisFieldCandidates);
const { skippedColumns } = useAppSelector((s) => s.logRateAnalysisTable);
const { fieldFilterUniqueItems, fieldFilterSkippedItems } = fieldCandidates;
const { fieldFilterUniqueItems, initialFieldFilterSkippedItems } = fieldCandidates;
const fieldFilterButtonDisabled =
isRunning || fieldCandidates.isLoading || fieldFilterUniqueItems.length === 0;
const toggleIdSelected = groupResults ? resultsGroupedOnId : resultsGroupedOffId;
// null is used as the uninitialized state to identify the first load.
const [skippedFields, setSkippedFields] = useState<string[] | null>(null);
// Set skipped fields only on first load, otherwise we'd overwrite the user's selection.
useEffect(() => {
if (skippedFields === null && fieldFilterSkippedItems.length > 0)
setSkippedFields(fieldFilterSkippedItems);
}, [fieldFilterSkippedItems, skippedFields]);
const onGroupResultsToggle = (optionId: string) => {
dispatch(setGroupResults(optionId === resultsGroupedOnId));
// When toggling the group switch, clear all row selections
@ -120,9 +110,8 @@ export const LogRateAnalysisOptions: FC<LogRateAnalysisOptionsProps> = ({
dispatch(setSkippedColumns(columns));
};
const onFieldsFilterChangeHandler = (skippedFieldsUpdate: string[]) => {
setSkippedFields(skippedFieldsUpdate);
onFieldsFilterChange(skippedFieldsUpdate);
const onFieldsFilterChange = (skippedFieldsUpdate: string[]) => {
dispatch(setCurrentFieldFilterSkippedItems(skippedFieldsUpdate));
};
// Disable the grouping switch toggle only if no groups were found,
@ -173,8 +162,8 @@ export const LogRateAnalysisOptions: FC<LogRateAnalysisOptionsProps> = ({
popoverButtonTitle={fieldsButton}
selectedItemLimit={1}
uniqueItemNames={fieldFilterUniqueItems}
initialSkippedItems={fieldFilterSkippedItems}
onChange={onFieldsFilterChangeHandler}
initialSkippedItems={initialFieldFilterSkippedItems}
onChange={onFieldsFilterChange}
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>

View file

@ -135,21 +135,27 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
setEmbeddableOptionsVisible((s) => !s);
};
const onFieldsFilterChange = (skippedFieldsUpdate: string[]) => {
const { currentFieldFilterSkippedItems, keywordFieldCandidates, textFieldCandidates } =
fieldCandidates;
useEffect(() => {
if (currentFieldFilterSkippedItems === null) return;
dispatch(resetResults());
setOverrides({
loaded: 0,
remainingKeywordFieldCandidates: keywordFieldCandidates.filter(
(d) => !skippedFieldsUpdate.includes(d)
(d) => !currentFieldFilterSkippedItems.includes(d)
),
remainingTextFieldCandidates: textFieldCandidates.filter(
(d) => !skippedFieldsUpdate.includes(d)
(d) => !currentFieldFilterSkippedItems.includes(d)
),
regroupOnly: false,
});
startHandler(true, false);
};
const { fieldFilterSkippedItems, keywordFieldCandidates, textFieldCandidates } = fieldCandidates;
// custom check to trigger on currentFieldFilterSkippedItems change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentFieldFilterSkippedItems]);
function cancelHandler() {
abortCtrl.current.abort();
@ -209,10 +215,12 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
dispatch(resetResults());
setOverrides({
remainingKeywordFieldCandidates: keywordFieldCandidates.filter(
(d) => fieldFilterSkippedItems !== null && fieldFilterSkippedItems.includes(d)
(d) =>
currentFieldFilterSkippedItems === null || !currentFieldFilterSkippedItems.includes(d)
),
remainingTextFieldCandidates: textFieldCandidates.filter(
(d) => fieldFilterSkippedItems !== null && fieldFilterSkippedItems.includes(d)
(d) =>
currentFieldFilterSkippedItems === null || !currentFieldFilterSkippedItems.includes(d)
),
});
}
@ -325,10 +333,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
>
<>
{embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD && (
<LogRateAnalysisOptions
foundGroups={foundGroups}
onFieldsFilterChange={onFieldsFilterChange}
/>
<LogRateAnalysisOptions foundGroups={foundGroups} />
)}
{embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD && (
<EuiFlexItem grow={false}>
@ -354,11 +359,7 @@ export const LogRateAnalysisResults: FC<LogRateAnalysisResultsProps> = ({
<>
<EuiSpacer size="m" />
<EuiFlexGroup alignItems="center" gutterSize="s">
<LogRateAnalysisOptions
foundGroups={foundGroups}
growFirstItem={true}
onFieldsFilterChange={onFieldsFilterChange}
/>
<LogRateAnalysisOptions foundGroups={foundGroups} growFirstItem={true} />
</EuiFlexGroup>
</>
)}