From 2c76ad0ce39bb6951c34d237910f477851221283 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Mon, 10 Jun 2024 11:27:10 -0600 Subject: [PATCH] [ML] AIOps Log Rate Analysis: adds controls for controlling which columns will be visible (#184262) ## Summary Related meta issue: https://github.com/elastic/kibana/issues/182714 This PR adds controls to the AIOps results table to show/hide columns. image ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...utton.tsx => item_filter_apply_button.tsx} | 2 +- ...er_popover.tsx => item_filter_popover.tsx} | 145 +++---- .../log_rate_analysis_results.tsx | 72 +++- .../log_rate_analysis_results_table/index.ts | 1 + .../log_rate_analysis_results_table.tsx | 309 +------------- ...log_rate_analysis_results_table_groups.tsx | 199 +++------ .../use_columns.tsx | 392 ++++++++++++++++++ .../translations/translations/fr-FR.json | 10 - .../translations/translations/ja-JP.json | 10 - .../translations/translations/zh-CN.json | 10 - .../apps/aiops/log_rate_analysis.ts | 30 +- .../artificial_log_data_view_test_data.ts | 2 + .../farequote_data_view_test_data.ts | 2 + ...arequote_data_view_test_data_with_query.ts | 2 + .../kibana_logs_data_view_test_data.ts | 2 + .../aiops/log_rate_analysis_anomaly_table.ts | 2 +- x-pack/test/functional/apps/aiops/types.ts | 4 +- .../services/aiops/log_rate_analysis_page.ts | 20 +- 18 files changed, 655 insertions(+), 559 deletions(-) rename x-pack/plugins/aiops/public/components/log_rate_analysis/{field_filter_apply_button.tsx => item_filter_apply_button.tsx} (93%) rename x-pack/plugins/aiops/public/components/log_rate_analysis/{field_filter_popover.tsx => item_filter_popover.tsx} (51%) create mode 100644 x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_columns.tsx diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_apply_button.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_apply_button.tsx similarity index 93% rename from x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_apply_button.tsx rename to x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_apply_button.tsx index 0243ce1877952b..0d3815da645067 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_apply_button.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_apply_button.tsx @@ -17,7 +17,7 @@ interface FieldFilterApplyButtonProps { tooltipContent?: string; } -export const FieldFilterApplyButton: FC = ({ +export const ItemFilterApplyButton: FC = ({ disabled, onClick, tooltipContent, diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_popover.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_popover.tsx similarity index 51% rename from x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_popover.tsx rename to x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_popover.tsx index 46f816c86543b3..25fb64def85506 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/field_filter_popover.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/item_filter_popover.tsx @@ -27,26 +27,40 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { FieldFilterApplyButton } from './field_filter_apply_button'; +import { ItemFilterApplyButton } from './item_filter_apply_button'; -interface FieldFilterPopoverProps { +interface ItemFilterPopoverProps { + dataTestSubj: string; disabled?: boolean; disabledApplyButton?: boolean; - uniqueFieldNames: string[]; - onChange: (skippedFields: string[]) => void; + disabledApplyTooltipContent?: string; + helpText: string; + itemSearchAriaLabel: string; + initialSkippedItems?: string[]; + popoverButtonTitle: string; + selectedItemLimit?: number; + uniqueItemNames: string[]; + onChange: (skippedItems: string[]) => void; } // This component is mostly inspired by EUI's Data Grid Column Selector // https://github.com/elastic/eui/blob/main/src/components/datagrid/controls/column_selector.tsx -export const FieldFilterPopover: FC = ({ +export const ItemFilterPopover: FC = ({ + dataTestSubj, disabled, disabledApplyButton, - uniqueFieldNames, + disabledApplyTooltipContent, + helpText, + itemSearchAriaLabel, + initialSkippedItems = [], + popoverButtonTitle, + selectedItemLimit = 2, + uniqueItemNames, onChange, }) => { const euiThemeContext = useEuiTheme(); // Inspired by https://github.com/elastic/eui/blob/main/src/components/datagrid/controls/_data_grid_column_selector.scss - const fieldSelectPopover = useMemo( + const itemSelectPopover = useMemo( () => css` ${euiYScrollWithShadows(euiThemeContext, {})} max-height: 400px; @@ -55,48 +69,49 @@ export const FieldFilterPopover: FC = ({ ); const [isTouched, setIsTouched] = useState(false); - const [fieldSearchText, setFieldSearchText] = useState(''); - const [skippedFields, setSkippedFields] = useState([]); - const setFieldsFilter = (fieldNames: string[], checked: boolean) => { - let updatedSkippedFields = [...skippedFields]; + const [itemSearchText, setItemSearchText] = useState(''); + const [skippedItems, setSkippedItems] = useState(initialSkippedItems); + const setItemsFilter = (itemNames: string[], checked: boolean) => { + let updatedSkippedItems = [...skippedItems]; if (!checked) { - updatedSkippedFields.push(...fieldNames); + updatedSkippedItems.push(...itemNames); } else { - updatedSkippedFields = skippedFields.filter((d) => !fieldNames.includes(d)); + updatedSkippedItems = skippedItems.filter((d) => !itemNames.includes(d)); } - setSkippedFields(updatedSkippedFields); + // Ensure there are no duplicates + setSkippedItems([...new Set(updatedSkippedItems)]); setIsTouched(true); }; - const [isFieldSelectionPopoverOpen, setIsFieldSelectionPopoverOpen] = useState(false); - const onFieldSelectionButtonClick = () => setIsFieldSelectionPopoverOpen((isOpen) => !isOpen); - const closePopover = () => setIsFieldSelectionPopoverOpen(false); + const [isItemSelectionPopoverOpen, setIsItemSelectionPopoverOpen] = useState(false); + const onItemSelectionButtonClick = () => setIsItemSelectionPopoverOpen((isOpen) => !isOpen); + const closePopover = () => setIsItemSelectionPopoverOpen(false); - const filteredUniqueFieldNames = useMemo(() => { - return uniqueFieldNames.filter( - (d) => d.toLowerCase().indexOf(fieldSearchText.toLowerCase()) !== -1 + const filteredUniqueItemNames = useMemo(() => { + return uniqueItemNames.filter( + (d) => d.toLowerCase().indexOf(itemSearchText.toLowerCase()) !== -1 ); - }, [fieldSearchText, uniqueFieldNames]); + }, [itemSearchText, uniqueItemNames]); // If the supplied list of unique field names changes, do a sanity check to only // keep field names in the list of skipped fields that still are in the list of unique fields. useEffect(() => { - setSkippedFields((previousSkippedFields) => - previousSkippedFields.filter((d) => uniqueFieldNames.includes(d)) + setSkippedItems((previousSkippedItems) => + previousSkippedItems.filter((d) => uniqueItemNames.includes(d)) ); - }, [uniqueFieldNames]); + }, [uniqueItemNames]); - const selectedFieldCount = uniqueFieldNames.length - skippedFields.length; + const selectedItemCount = uniqueItemNames.length - skippedItems.length; return ( = ({ iconSize="s" color="text" > - + {popoverButtonTitle} } - isOpen={isFieldSelectionPopoverOpen} + isOpen={isItemSelectionPopoverOpen} closePopover={closePopover} > - + {helpText} = ({ placeholder={i18n.translate('xpack.aiops.analysis.fieldSelectorPlaceholder', { defaultMessage: 'Search', })} - aria-label={i18n.translate('xpack.aiops.analysis.fieldSelectorAriaLabel', { - defaultMessage: 'Filter fields', - })} - value={fieldSearchText} - onChange={(e: ChangeEvent) => setFieldSearchText(e.currentTarget.value)} + aria-label={itemSearchAriaLabel} + value={itemSearchText} + onChange={(e: ChangeEvent) => setItemSearchText(e.currentTarget.value)} data-test-subj="aiopsFieldSelectorSearch" /> -
- {filteredUniqueFieldNames.map((fieldName) => ( +
+ {filteredUniqueItemNames.map((fieldName) => (
setFieldsFilter([fieldName], e.target.checked)} - checked={!skippedFields.includes(fieldName)} + onChange={(e) => setItemsFilter([fieldName], e.target.checked)} + checked={!skippedItems.includes(fieldName)} />
))} @@ -162,19 +169,19 @@ export const FieldFilterPopover: FC = ({ setFieldsFilter(filteredUniqueFieldNames, true)} - disabled={fieldSearchText.length > 0 && filteredUniqueFieldNames.length === 0} + onClick={() => setItemsFilter(filteredUniqueItemNames, true)} + disabled={itemSearchText.length > 0 && filteredUniqueItemNames.length === 0} data-test-subj="aiopsFieldSelectorSelectAllFieldsButton" > - {fieldSearchText.length > 0 ? ( + {itemSearchText.length > 0 ? ( ) : ( )} @@ -183,39 +190,35 @@ export const FieldFilterPopover: FC = ({ setFieldsFilter(filteredUniqueFieldNames, false)} - disabled={fieldSearchText.length > 0 && filteredUniqueFieldNames.length === 0} + onClick={() => setItemsFilter(filteredUniqueItemNames, false)} + disabled={itemSearchText.length > 0 && filteredUniqueItemNames.length === 0} data-test-subj="aiopsFieldSelectorDeselectAllFieldsButton" > - {fieldSearchText.length > 0 ? ( + {itemSearchText.length > 0 ? ( ) : ( )} - { - onChange(skippedFields); - setFieldSearchText(''); - setIsFieldSelectionPopoverOpen(false); + onChange(skippedItems); + setItemSearchText(''); + setIsItemSelectionPopoverOpen(false); closePopover(); }} - disabled={disabledApplyButton || selectedFieldCount < 2 || !isTouched} + disabled={disabledApplyButton || selectedItemCount < selectedItemLimit || !isTouched} tooltipContent={ - selectedFieldCount < 2 - ? i18n.translate('xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected', { - defaultMessage: 'Grouping requires at least 2 fields to be selected.', - }) - : undefined + selectedItemCount < selectedItemLimit ? disabledApplyTooltipContent : undefined } /> diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx index cee76add52fe94..8ff224b65f6783 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx @@ -41,6 +41,10 @@ import { useLogRateAnalysisStateContext } from '@kbn/aiops-components'; import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { useDataSource } from '../../hooks/use_data_source'; +import { + commonColumns, + significantItemColumns, +} from '../log_rate_analysis_results_table/use_columns'; import { getGroupTableItems, @@ -48,8 +52,10 @@ import { LogRateAnalysisResultsGroupsTable, } from '../log_rate_analysis_results_table'; -import { FieldFilterPopover } from './field_filter_popover'; +import { ItemFilterPopover as FieldFilterPopover } from './item_filter_popover'; +import { ItemFilterPopover as ColumnFilterPopover } from './item_filter_popover'; import { LogRateAnalysisTypeCallOut } from './log_rate_analysis_type_callout'; +import type { ColumnNames } from '../log_rate_analysis_results_table'; const groupResultsMessage = i18n.translate( 'xpack.aiops.logRateAnalysis.resultsTable.groupedSwitchLabel.groupResults', @@ -77,6 +83,37 @@ const groupResultsOnMessage = i18n.translate( ); const resultsGroupedOffId = 'aiopsLogRateAnalysisGroupingOff'; const resultsGroupedOnId = 'aiopsLogRateAnalysisGroupingOn'; +const fieldFilterHelpText = i18n.translate('xpack.aiops.logRateAnalysis.page.fieldFilterHelpText', { + defaultMessage: + 'Deselect non-relevant fields to remove them from groups and click the Apply button to rerun the grouping. Use the search bar to filter the list, then select/deselect multiple fields with the actions below.', +}); +const columnsFilterHelpText = i18n.translate( + 'xpack.aiops.logRateAnalysis.page.columnsFilterHelpText', + { + defaultMessage: 'Configure visible columns.', + } +); +const disabledFieldFilterApplyButtonTooltipContent = i18n.translate( + 'xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected', + { + defaultMessage: 'Grouping requires at least 2 fields to be selected.', + } +); +const disabledColumnFilterApplyButtonTooltipContent = i18n.translate( + 'xpack.aiops.analysis.columnSelectorNotEnoughColumnsSelected', + { + defaultMessage: 'At least one column must be selected.', + } +); +const columnSearchAriaLabel = i18n.translate('xpack.aiops.analysis.columnSelectorAriaLabel', { + defaultMessage: 'Filter columns', +}); +const columnsButton = i18n.translate('xpack.aiops.logRateAnalysis.page.columnsFilterButtonLabel', { + defaultMessage: 'Columns', +}); +const fieldsButton = i18n.translate('xpack.aiops.analysis.fieldFilterButtonLabel', { + defaultMessage: 'Filter fields', +}); /** * Interface for log rate analysis results data. @@ -157,6 +194,7 @@ export const LogRateAnalysisResults: FC = ({ ); const [shouldStart, setShouldStart] = useState(false); const [toggleIdSelected, setToggleIdSelected] = useState(resultsGroupedOffId); + const [skippedColumns, setSkippedColumns] = useState(['p-value']); const onGroupResultsToggle = (optionId: string) => { setToggleIdSelected(optionId); @@ -179,6 +217,10 @@ export const LogRateAnalysisResults: FC = ({ startHandler(true, false); }; + const onVisibleColumnsChange = (columns: ColumnNames[]) => { + setSkippedColumns(columns); + }; + const { cancel, start, @@ -378,12 +420,36 @@ export const LogRateAnalysisResults: FC = ({ + + void} + /> + {showLogRateAnalysisResultsTable && currentAnalysisType !== undefined && ( <> @@ -481,6 +547,7 @@ export const LogRateAnalysisResults: FC = ({ > {showLogRateAnalysisResultsTable && groupResults ? ( = ({ ) : null} {showLogRateAnalysisResultsTable && !groupResults ? ( = timeRangeMs, barColorOverride, barHighlightColorOverride, + skippedColumns, zeroDocsFallback = false, }) => { const euiTheme = useEuiTheme(); const primaryBackgroundColor = useEuiBackgroundColor('primary'); - const { dataView } = useDataSource(); - const dataViewId = dataView.id; const { pinnedGroup, @@ -100,263 +71,17 @@ export const LogRateAnalysisResultsTable: FC = zeroDocsFallback ? DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK : DEFAULT_SORT_DIRECTION ); - const { data, uiSettings, fieldFormats, charts } = useAiopsAppContext(); - - const fieldStatsServices: FieldStatsServices = useMemo(() => { - return { - uiSettings, - dataViews: data.dataViews, - data, - fieldFormats, - charts, - }; - }, [uiSettings, data, fieldFormats, charts]); - - const copyToClipBoardAction = useCopyToClipboardAction(); - const viewInDiscoverAction = useViewInDiscoverAction(dataViewId); - const viewInLogPatternAnalysisAction = useViewInLogPatternAnalysisAction(dataViewId); - - const columns: Array> = [ - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnFieldName', - field: 'fieldName', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.fieldNameLabel', { - defaultMessage: 'Field name', - }), - render: (_, { fieldName, fieldValue, key, type, doc_count: count }) => { - const dslQuery = - type === SIGNIFICANT_ITEM_TYPE.KEYWORD - ? searchQuery - : getCategoryQuery(fieldName, [ - { - key, - count, - examples: [], - regex: '', - }, - ]); - return ( - <> - {type === SIGNIFICANT_ITEM_TYPE.KEYWORD && ( - - )} - {type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN && ( - - )} - - - {fieldName} - - - ); - }, - sortable: true, - valign: 'middle', - }, - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnFieldValue', - field: 'fieldValue', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.fieldValueLabel', { - defaultMessage: 'Field value', - }), - render: (_, { fieldValue, type }) => ( - - {type === 'keyword' ? ( - String(fieldValue) - ) : ( - - - {String(fieldValue)} - - - )} - - ), - sortable: true, - textOnly: true, - truncateText: { lines: TRUNCATE_TEXT_LINES }, - valign: 'middle', - }, - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnLogRate', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - <> - -   - - - ), - render: (_, { histogram, fieldName, fieldValue }) => ( - - ), - sortable: false, - valign: 'middle', - }, - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnDocCount', - width: NARROW_COLUMN_WIDTH, - field: 'doc_count', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.docCountLabel', { - defaultMessage: 'Doc count', - }), - sortable: true, - valign: 'middle', - }, - ]; - - if (!zeroDocsFallback) { - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnPValue', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - <> - -   - - - ), - render: (pValue: number | null) => pValue?.toPrecision(3) ?? NOT_AVAILABLE, - sortable: true, - valign: 'middle', - }); - - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnImpact', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - <> - -   - - - ), - render: (_, { pValue }) => { - if (typeof pValue !== 'number') return NOT_AVAILABLE; - const label = getFailedTransactionsCorrelationImpactLabel(pValue); - return label ? {label.impact} : null; - }, - sortable: true, - valign: 'middle', - }); - } - - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnAction', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.actionsColumnName', { - defaultMessage: 'Actions', - }), - actions: [ - ...(viewInDiscoverAction ? [viewInDiscoverAction] : []), - ...(viewInLogPatternAnalysisAction ? [viewInLogPatternAnalysisAction] : []), - copyToClipBoardAction, - ], - width: ACTIONS_COLUMN_WIDTH, - valign: 'middle', - }); - - if (isExpandedRow === true) { - columns.unshift({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnUnique', - width: UNIQUE_COLUMN_WIDTH, - field: 'unique', - name: '', - render: (_, { unique }) => { - if (unique) { - return ( - - ); - } - return ''; - }, - sortable: false, - valign: 'middle', - }); - } + const columns = useColumns( + SIG_ITEMS_TABLE, + skippedColumns, + searchQuery, + timeRangeMs, + loading, + zeroDocsFallback, + barColorOverride, + barHighlightColorOverride, + isExpandedRow + ); const onChange = useCallback((tableSettings) => { if (tableSettings.page) { diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx index c388555bcf2caf..d0935ebb96ff0d 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/log_rate_analysis_results_table_groups.tsx @@ -32,20 +32,13 @@ import type { TimeRange as TimeRangeMs } from '@kbn/ml-date-picker'; import { stringHash } from '@kbn/ml-string-hash'; import { useLogRateAnalysisStateContext, type GroupTableItem } from '@kbn/aiops-components'; -import { useDataSource } from '../../hooks/use_data_source'; +import usePrevious from 'react-use/lib/usePrevious'; +import useMountedState from 'react-use/lib/useMountedState'; -import { MiniHistogram } from '../mini_histogram'; - -import { getFailedTransactionsCorrelationImpactLabel } from './get_failed_transactions_correlation_impact_label'; import { LogRateAnalysisResultsTable } from './log_rate_analysis_results_table'; -import { useCopyToClipboardAction } from './use_copy_to_clipboard_action'; -import { useViewInDiscoverAction } from './use_view_in_discover_action'; -import { useViewInLogPatternAnalysisAction } from './use_view_in_log_pattern_analysis_action'; +import { GROUPS_TABLE, useColumns } from './use_columns'; -const NARROW_COLUMN_WIDTH = '120px'; const EXPAND_COLUMN_WIDTH = '40px'; -const ACTIONS_COLUMN_WIDTH = '60px'; -const NOT_AVAILABLE = '--'; const MAX_GROUP_BADGES = 5; const PAGINATION_SIZE_OPTIONS = [5, 10, 20, 50]; @@ -55,6 +48,7 @@ const DEFAULT_SORT_DIRECTION = 'asc'; const DEFAULT_SORT_DIRECTION_ZERO_DOCS_FALLBACK = 'desc'; interface LogRateAnalysisResultsTableProps { + skippedColumns: string[]; significantItems: SignificantItem[]; groupTableItems: GroupTableItem[]; loading: boolean; @@ -68,6 +62,7 @@ interface LogRateAnalysisResultsTableProps { } export const LogRateAnalysisResultsGroupsTable: FC = ({ + skippedColumns, significantItems, groupTableItems, loading, @@ -77,7 +72,7 @@ export const LogRateAnalysisResultsGroupsTable: FC { - const { dataView } = useDataSource(); + const prevSkippedColumns = usePrevious(skippedColumns); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -97,7 +92,7 @@ export const LogRateAnalysisResultsGroupsTable: FC { const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; @@ -106,6 +101,7 @@ export const LogRateAnalysisResultsGroupsTable: FC( (p, groupItem) => { const st = significantItems.find( @@ -135,11 +131,7 @@ export const LogRateAnalysisResultsGroupsTable: FC> = [ + const groupColumns: Array> = [ { align: RIGHT_ALIGNMENT, width: EXPAND_COLUMN_WIDTH, @@ -199,7 +191,7 @@ export const LogRateAnalysisResultsGroupsTable: FC ), render: (_, { uniqueItemsCount, groupItemsSortedByUniqueness }) => { - const valuesBadges = []; + const valuesBadges: React.ReactNode[] = []; for (const groupItem of groupItemsSortedByUniqueness) { const { fieldName, fieldValue, duplicate } = groupItem; @@ -259,141 +251,20 @@ export const LogRateAnalysisResultsGroupsTable: FC - -   - - - ), - render: (_, { histogram, id }) => ( - - ), - sortable: false, - valign: 'top', - }, - { - 'data-test-subj': 'aiopsLogRateAnalysisResultsGroupsTableColumnDocCount', - width: NARROW_COLUMN_WIDTH, - field: 'docCount', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.docCountLabel', { - defaultMessage: 'Doc count', - }), - sortable: true, - valign: 'top', - }, ]; - if (!zeroDocsFallback) { - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsGroupsTableColumnPValue', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - <> - -   - - - ), - render: (pValue: number | null) => pValue?.toPrecision(3) ?? NOT_AVAILABLE, - sortable: true, - valign: 'top', - }); + const columns = useColumns( + GROUPS_TABLE, + skippedColumns, + searchQuery, + timeRangeMs, + loading, + zeroDocsFallback, + barColorOverride, + barHighlightColorOverride + ) as Array>; - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnImpact', - width: NARROW_COLUMN_WIDTH, - field: 'pValue', - name: ( - <> - -   - - - ), - render: (_, { pValue }) => { - if (!pValue) return NOT_AVAILABLE; - const label = getFailedTransactionsCorrelationImpactLabel(pValue); - return label ? {label.impact} : null; - }, - sortable: true, - valign: 'top', - }); - } - - columns.push({ - 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnAction', - name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.actionsColumnName', { - defaultMessage: 'Actions', - }), - actions: [ - ...(viewInDiscoverAction ? [viewInDiscoverAction] : []), - ...(viewInLogPatternAnalysisAction ? [viewInLogPatternAnalysisAction] : []), - copyToClipBoardAction, - ], - width: ACTIONS_COLUMN_WIDTH, - valign: 'top', - }); + groupColumns.push(...columns); const onChange = useCallback((tableSettings) => { if (tableSettings.page) { @@ -481,6 +352,32 @@ export const LogRateAnalysisResultsGroupsTable: FC 0 + ) { + const itemIdToExpandedRowMapValues = { ...itemIdToExpandedRowMap }; + for (const itemId in itemIdToExpandedRowMapValues) { + if (itemIdToExpandedRowMapValues.hasOwnProperty(itemId)) { + const component = itemIdToExpandedRowMapValues[itemId]; + itemIdToExpandedRowMapValues[itemId] = ( + + ); + } + } + setItemIdToExpandedRowMap(itemIdToExpandedRowMapValues); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [prevSkippedColumns, skippedColumns, itemIdToExpandedRowMap] + ); + const getRowStyle = (group: GroupTableItem) => { if (pinnedGroup && pinnedGroup.id === group.id) { return { @@ -503,7 +400,7 @@ export const LogRateAnalysisResultsGroupsTable: FC> => { + const { data, uiSettings, fieldFormats, charts } = useAiopsAppContext(); + const { dataView } = useDataSource(); + const euiTheme = useEuiTheme(); + const viewInDiscoverAction = useViewInDiscoverAction(dataView.id); + const viewInLogPatternAnalysisAction = useViewInLogPatternAnalysisAction(dataView.id); + const copyToClipBoardAction = useCopyToClipboardAction(); + + const isGroupsTable = tableType === GROUPS_TABLE; + + const fieldStatsServices: FieldStatsServices = useMemo(() => { + return { + uiSettings, + dataViews: data.dataViews, + data, + fieldFormats, + charts, + }; + }, [uiSettings, data, fieldFormats, charts]); + + const columnsMap: Record> = useMemo( + () => ({ + ['Field name']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnFieldName', + field: 'fieldName', + name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.fieldNameLabel', { + defaultMessage: 'Field name', + }), + render: (_, { fieldName, fieldValue, key, type, doc_count: count }) => { + const dslQuery = + type === SIGNIFICANT_ITEM_TYPE.KEYWORD + ? searchQuery + : getCategoryQuery(fieldName, [ + { + key, + count, + examples: [], + regex: '', + }, + ]); + return ( + <> + {type === SIGNIFICANT_ITEM_TYPE.KEYWORD && ( + + )} + {type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN && ( + + )} + + + {fieldName} + + + ); + }, + sortable: true, + valign: 'middle', + }, + ['Field value']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnFieldValue', + field: 'fieldValue', + name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.fieldValueLabel', { + defaultMessage: 'Field value', + }), + render: (_, { fieldValue, type }) => ( + + {type === 'keyword' ? ( + String(fieldValue) + ) : ( + + + {String(fieldValue)} + + + )} + + ), + sortable: true, + textOnly: true, + truncateText: { lines: TRUNCATE_TEXT_LINES }, + valign: 'middle', + }, + ['Log rate']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnLogRate', + width: NARROW_COLUMN_WIDTH, + field: 'pValue', + name: ( + <> + +   + + + ), + render: (_, { histogram, fieldName, fieldValue }) => ( + + ), + sortable: false, + valign: 'middle', + }, + ['Impact']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnImpact', + width: NARROW_COLUMN_WIDTH, + field: 'pValue', + name: ( + <> + +   + + + ), + render: (_, { pValue }) => { + if (typeof pValue !== 'number') return NOT_AVAILABLE; + const label = getFailedTransactionsCorrelationImpactLabel(pValue); + return label ? {label.impact} : null; + }, + sortable: true, + valign: 'middle', + }, + ['p-value']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnPValue', + width: NARROW_COLUMN_WIDTH, + field: 'pValue', + name: ( + <> + +   + + + ), + render: (pValue: number | null) => pValue?.toPrecision(3) ?? NOT_AVAILABLE, + sortable: true, + valign: 'middle', + }, + ['Doc count']: { + 'data-test-subj': isGroupsTable + ? 'aiopsLogRateAnalysisResultsGroupsTableColumnDocCount' + : 'aiopsLogRateAnalysisResultsTableColumnDocCount', + width: NARROW_COLUMN_WIDTH, + field: isGroupsTable ? 'docCount' : 'doc_count', + name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.docCountLabel', { + defaultMessage: 'Doc count', + }), + sortable: true, + valign: 'middle', + }, + ['Actions']: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnAction', + name: i18n.translate('xpack.aiops.logRateAnalysis.resultsTable.actionsColumnName', { + defaultMessage: 'Actions', + }), + actions: [ + ...(viewInDiscoverAction ? [viewInDiscoverAction] : []), + ...(viewInLogPatternAnalysisAction ? [viewInLogPatternAnalysisAction] : []), + copyToClipBoardAction, + ], + width: ACTIONS_COLUMN_WIDTH, + valign: 'middle', + }, + unique: { + 'data-test-subj': 'aiopsLogRateAnalysisResultsTableColumnUnique', + width: UNIQUE_COLUMN_WIDTH, + field: 'unique', + name: '', + render: (_, { unique }) => { + if (unique) { + return ( + + ); + } + return ''; + }, + sortable: false, + valign: 'middle', + }, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [ + barColorOverride, + barHighlightColorOverride, + copyToClipBoardAction, + dataView?.id, + euiTheme, + fieldStatsServices, + loading, + searchQuery, + timeRangeMs, + viewInDiscoverAction, + viewInLogPatternAnalysisAction, + ] + ); + + const columns = useMemo(() => { + const columnNamesToReturn: Partial> = isGroupsTable + ? commonColumns + : significantItemColumns; + const columnsToReturn = []; + + for (const columnName in columnNamesToReturn) { + if ( + columnNamesToReturn.hasOwnProperty(columnName) === false || + skippedColumns.includes(columnNamesToReturn[columnName as ColumnNames] as string) || + ((columnName === 'p-value' || columnName === 'Impact') && zeroDocsFallback) + ) + continue; + + columnsToReturn.push(columnsMap[columnName as ColumnNames]); + } + + if (isExpandedRow === true) { + columnsToReturn.unshift(columnsMap.unique); + } + + return columnsToReturn; + }, [isGroupsTable, skippedColumns, zeroDocsFallback, isExpandedRow, columnsMap]); + + return columns; +}; diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index f4067130e13462..59bdf5efef3e03 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -8200,7 +8200,6 @@ "xpack.aiops.analysis.analysisTypeSpikeCallOutContentFallback": "La plage temporelle de référence de base ne contient aucun document. Les résultats montrent donc les catégories de message des meilleurs logs et les valeurs des champs pour la plage temporelle de déviation.", "xpack.aiops.analysis.analysisTypeSpikeCallOutTitle": "Type d'analyse : Pic du taux de log", "xpack.aiops.analysis.analysisTypeSpikeFallbackCallOutTitle": "Type d'analyse : Meilleurs éléments pour la plage temporelle de déviation", - "xpack.aiops.analysis.fieldSelectorAriaLabel": "Champs de filtre", "xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected": "Le regroupement nécessite la sélection d'au moins 2 champs.", "xpack.aiops.analysis.fieldSelectorPlaceholder": "Recherche", "xpack.aiops.analysisCompleteLabel": "Analyse terminée", @@ -8336,12 +8335,7 @@ "xpack.aiops.logRateAnalysis.page.emptyPromptBody": "La fonction d'analyse des pics de taux de log identifie les combinaisons champ/valeur statistiquement significatives qui contribuent à un pic ou une baisse de taux de log.", "xpack.aiops.logRateAnalysis.page.emptyPromptTitle": "Cliquez sur un pic ou une baisse dans l'histogramme pour lancer l'analyse.", "xpack.aiops.logRateAnalysis.page.fieldFilterApplyButtonLabel": "Appliquer", - "xpack.aiops.logRateAnalysis.page.fieldFilterButtonLabel": "Champs de filtre", "xpack.aiops.logRateAnalysis.page.fieldFilterHelpText": "Désélectionnez les champs non pertinents pour les supprimer des groupes et cliquez sur le bouton Appliquer pour réexécuter le regroupement. Utilisez la barre de recherche pour filtrer la liste, puis sélectionnez/désélectionnez plusieurs champs avec les actions ci-dessous.", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllFields": "Désélectionner tous les champs", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllSearchedFields": "Désélectionner les champs filtrés", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllFields": "Sélectionner tous les champs", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllSearchedFields": "Sélectionner les champs filtrés", "xpack.aiops.logRateAnalysis.page.noResultsPromptBody": "Essayez d'ajuster la référence de base et les plages temporelles d'écart-type, et réexécutez l'analyse. Si vous n'obtenez toujours aucun résultat, il se peut qu'il n'y ait aucune entité statistiquement significative contribuant à cet écart dans les taux de log.", "xpack.aiops.logRateAnalysis.page.noResultsPromptTitle": "L'analyse n'a retourné aucun résultat.", "xpack.aiops.logRateAnalysis.page.tryToContinueAnalysisButtonText": "Essayer de continuer l'analyse", @@ -8375,12 +8369,8 @@ "xpack.aiops.logRateAnalysis.resultsTable.pValueLabel": "valeur-p", "xpack.aiops.logRateAnalysis.resultsTable.uniqueColumnTooltip": "Cette paire champ/valeur apparaît uniquement dans ce groupe", "xpack.aiops.logRateAnalysis.resultsTableGroups.groupLabel": "Regrouper", - "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabel": "Impact", "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabelColumnTooltip": "Niveau d'impact du groupe sur la différence de taux de messages", "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateColumnTooltip": "Représentation visuelle de l'impact du groupe sur la différence de taux de messages.", - "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateLabel": "Taux du log", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueColumnTooltip": "Une différence de fréquence des valeurs, surtout si celles-ci sont plus faibles, indique un changement important. Ordonner un tri de cette colonne entraînera automatiquement un tri secondaire sur la colonne \"nombre de documents\"..", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueLabel": "valeur-p", "xpack.aiops.logRateAnalysisTimeSeriesWarning.description": "L'analyse des taux de log ne fonctionne que sur des index temporels.", "xpack.aiops.miniHistogram.noDataLabel": "S. O.", "xpack.aiops.navMenu.mlAppNameText": "Machine Learning", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index f18f09518aa378..16c093425cc5a8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8188,7 +8188,6 @@ "xpack.aiops.analysis.analysisTypeSpikeCallOutContentFallback": "ベースライン時間範囲にはドキュメントが含まれていません。したがって、結果は、偏差時間範囲の上位のログメッセージカテゴリーとフィールド値を示しています。", "xpack.aiops.analysis.analysisTypeSpikeCallOutTitle": "分析タイプ:ログレートスパイク", "xpack.aiops.analysis.analysisTypeSpikeFallbackCallOutTitle": "分析タイプ:偏差時間範囲の上位のアイテム", - "xpack.aiops.analysis.fieldSelectorAriaLabel": "フィールドのフィルタリング", "xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected": "グループ化するには、2つ以上のフィールドを選択する必要があります。", "xpack.aiops.analysis.fieldSelectorPlaceholder": "検索", "xpack.aiops.analysisCompleteLabel": "分析完了", @@ -8324,12 +8323,7 @@ "xpack.aiops.logRateAnalysis.page.emptyPromptBody": "ログレート分析機能は、ログレートのスパイクまたはディップに寄与する統計的に有意なフィールド/値の組み合わせを特定します。", "xpack.aiops.logRateAnalysis.page.emptyPromptTitle": "ヒストグラム図のスパイクまたはディップをクリックすると、分析が開始します。", "xpack.aiops.logRateAnalysis.page.fieldFilterApplyButtonLabel": "適用", - "xpack.aiops.logRateAnalysis.page.fieldFilterButtonLabel": "フィールドのフィルタリング", "xpack.aiops.logRateAnalysis.page.fieldFilterHelpText": "関連しないフィールドを選択解除すると、グループから削除されます。[適用]ボタンをクリックすると、グループ化が再実行されます。 検索バーを使用してリストをフィルタリングしてから、下のアクションを使用して複数のフィールドを選択/選択解除します。", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllFields": "すべてのフィールドを選択解除", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllSearchedFields": "フィルタリングされたフィールドを選択解除", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllFields": "すべてのフィールドを選択", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllSearchedFields": "フィルタリングされたフィールドを選択", "xpack.aiops.logRateAnalysis.page.noResultsPromptBody": "ベースラインと時間範囲のずれを調整し、分析を再実行してください。結果が得られない場合は、このログレートの偏差に寄与する統計的に有意なエンティティが存在しない可能性があります。", "xpack.aiops.logRateAnalysis.page.noResultsPromptTitle": "分析の結果が返されませんでした。", "xpack.aiops.logRateAnalysis.page.tryToContinueAnalysisButtonText": "分析を続行してください", @@ -8363,12 +8357,8 @@ "xpack.aiops.logRateAnalysis.resultsTable.pValueLabel": "p値", "xpack.aiops.logRateAnalysis.resultsTable.uniqueColumnTooltip": "このフィールド/値の組み合わせはこのグループでのみ出現します", "xpack.aiops.logRateAnalysis.resultsTableGroups.groupLabel": "グループ", - "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabel": "インパクト", "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabelColumnTooltip": "メッセージレート差異に対するグループの影響のレベル", "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateColumnTooltip": "メッセージレート差異に対するグループの影響の視覚的な表示。", - "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateLabel": "ログレート", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueColumnTooltip": "値の頻度の変化の重要性。値が小さいほど変化が大きいことを示します。この列をソートすると、自動的にdoc count列が二次ソートされます。", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueLabel": "p値", "xpack.aiops.logRateAnalysisTimeSeriesWarning.description": "ログレートは、時間ベースのインデックスに対してのみ実行されます。", "xpack.aiops.miniHistogram.noDataLabel": "N/A", "xpack.aiops.navMenu.mlAppNameText": "機械学習", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 90699177a60b4e..a44779b8047d12 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8204,7 +8204,6 @@ "xpack.aiops.analysis.analysisTypeSpikeCallOutContentFallback": "基线时间范围不包含任何文档。因此,结果将显示偏差时间范围的主要日志消息类别和字段值。", "xpack.aiops.analysis.analysisTypeSpikeCallOutTitle": "分析类型:日志速率峰值", "xpack.aiops.analysis.analysisTypeSpikeFallbackCallOutTitle": "分析类型:偏差时间范围的主要项目", - "xpack.aiops.analysis.fieldSelectorAriaLabel": "筛选字段", "xpack.aiops.analysis.fieldSelectorNotEnoughFieldsSelected": "分组至少需要 2 个供选择的字段。", "xpack.aiops.analysis.fieldSelectorPlaceholder": "搜索", "xpack.aiops.analysisCompleteLabel": "分析已完成", @@ -8340,12 +8339,7 @@ "xpack.aiops.logRateAnalysis.page.emptyPromptBody": "“日志速率分析”功能会识别有助于达到日志速率峰值或谷值的具有统计意义的字段/值组合。", "xpack.aiops.logRateAnalysis.page.emptyPromptTitle": "单击直方图中的某个峰值或谷值可开始分析。", "xpack.aiops.logRateAnalysis.page.fieldFilterApplyButtonLabel": "应用", - "xpack.aiops.logRateAnalysis.page.fieldFilterButtonLabel": "筛选字段", "xpack.aiops.logRateAnalysis.page.fieldFilterHelpText": "取消选择非相关字段以将其从组中移除,然后单击“应用”按钮返回分组。 使用搜索栏筛选列表,然后通过以下操作选择/取消选择多个字段。", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllFields": "取消选择所有字段", - "xpack.aiops.logRateAnalysis.page.fieldSelector.deselectAllSearchedFields": "取消选择已筛选字段", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllFields": "选择所有字段", - "xpack.aiops.logRateAnalysis.page.fieldSelector.selectAllSearchedFields": "选择已筛选字段", "xpack.aiops.logRateAnalysis.page.noResultsPromptBody": "尝试调整基线和偏差时间范围,然后重新运行分析。如果仍然没有结果,可能没有具有统计意义的实体导致了该日志速率偏差。", "xpack.aiops.logRateAnalysis.page.noResultsPromptTitle": "分析未返回任何结果。", "xpack.aiops.logRateAnalysis.page.tryToContinueAnalysisButtonText": "尝试继续分析", @@ -8379,12 +8373,8 @@ "xpack.aiops.logRateAnalysis.resultsTable.pValueLabel": "p-value", "xpack.aiops.logRateAnalysis.resultsTable.uniqueColumnTooltip": "此字段/值对只在该分组中出现", "xpack.aiops.logRateAnalysis.resultsTableGroups.groupLabel": "组", - "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabel": "影响", "xpack.aiops.logRateAnalysis.resultsTableGroups.impactLabelColumnTooltip": "组对消息速率差异的影响水平", "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateColumnTooltip": "组对消息速率差异的影响的视觉表示形式。", - "xpack.aiops.logRateAnalysis.resultsTableGroups.logRateLabel": "日志速率", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueColumnTooltip": "值的频率更改的意义;值越小表示变化越大;对此列排序会自动在文档计数列上进行二次排序。", - "xpack.aiops.logRateAnalysis.resultsTableGroups.pValueLabel": "p-value", "xpack.aiops.logRateAnalysisTimeSeriesWarning.description": "日志速率分析仅在基于时间的索引上运行。", "xpack.aiops.miniHistogram.noDataLabel": "不可用", "xpack.aiops.navMenu.mlAppNameText": "Machine Learning", diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis.ts index 7308d561109bec..e9f245df275141 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis.ts @@ -215,6 +215,27 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await aiops.logRateAnalysisResultsGroupsTable.expandRow(); await aiops.logRateAnalysisResultsGroupsTable.scrollAnalysisTableIntoView(); + await ml.testExecution.logTestStep('open the column filter'); + await aiops.logRateAnalysisPage.assertFilterPopoverButtonExists( + 'aiopsColumnFilterButton', + false + ); + await aiops.logRateAnalysisPage.clickFilterPopoverButton('aiopsColumnFilterButton', true); + await aiops.logRateAnalysisPage.assertFieldSelectorFieldNameList( + testData.expected.columnSelectorPopover + ); + + await ml.testExecution.logTestStep('filter columns'); + await aiops.logRateAnalysisPage.setFieldSelectorSearch(testData.columnSelectorSearch); + await aiops.logRateAnalysisPage.assertFieldSelectorFieldNameList([ + testData.columnSelectorSearch, + ]); + await aiops.logRateAnalysisPage.clickFieldSelectorListItem( + 'aiopsFieldSelectorFieldNameListItem' + ); + await aiops.logRateAnalysisPage.assertFieldFilterApplyButtonExists(false); + await aiops.logRateAnalysisPage.clickFieldFilterApplyButton('aiopsColumnFilterButton'); + const analysisTable = await aiops.logRateAnalysisResultsTable.parseAnalysisTable(); const actualAnalysisTable = orderBy(analysisTable, ['fieldName', 'fieldValue']); @@ -231,8 +252,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ); await ml.testExecution.logTestStep('open the field filter'); - await aiops.logRateAnalysisPage.assertFieldFilterPopoverButtonExists(false); - await aiops.logRateAnalysisPage.clickFieldFilterPopoverButton(true); + await aiops.logRateAnalysisPage.assertFilterPopoverButtonExists( + 'aiopsFieldFilterButton', + false + ); + await aiops.logRateAnalysisPage.clickFilterPopoverButton('aiopsFieldFilterButton', true); await aiops.logRateAnalysisPage.assertFieldSelectorFieldNameList( testData.expected.fieldSelectorPopover ); @@ -249,7 +273,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { if (testData.fieldSelectorApplyAvailable) { await ml.testExecution.logTestStep('regroup results'); - await aiops.logRateAnalysisPage.clickFieldFilterApplyButton(); + await aiops.logRateAnalysisPage.clickFieldFilterApplyButton('aiopsFieldFilterButton'); const filteredAnalysisGroupsTable = await aiops.logRateAnalysisResultsGroupsTable.parseAnalysisTable(); diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts index ff6bfd4f9f19f4..d2c3f1987667b9 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/artificial_log_data_view_test_data.ts @@ -143,6 +143,7 @@ export const getArtificialLogDataViewTestData = ({ brushDeviationTargetTimestamp: getBrushDeviationTargetTimestamp(), brushIntervalFactor: zeroDocsFallback ? 1 : 10, chartClickCoordinates: [-200, 30], + columnSelectorSearch: 'p-value', fieldSelectorSearch: 'user', fieldSelectorApplyAvailable: true, expected: { @@ -150,6 +151,7 @@ export const getArtificialLogDataViewTestData = ({ analysisGroupsTable: getAnalysisGroupsTable(), filteredAnalysisGroupsTable: getFilteredAnalysisGroupsTable(), analysisTable: getAnalysisTable(), + columnSelectorPopover: ['Log rate', 'Doc count', 'p-value', 'Impact', 'Actions'], fieldSelectorPopover: getFieldSelectorPopover(), globalState: { refreshInterval: { pause: true, value: 60000 }, diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts index 07b116e544e20c..84e5cbed3e4001 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data.ts @@ -19,11 +19,13 @@ export const farequoteDataViewTestData: TestData = { brushDeviationTargetTimestamp: 1455033600000, brushIntervalFactor: 1, chartClickCoordinates: [0, 0], + columnSelectorSearch: 'p-value', fieldSelectorSearch: 'airline', fieldSelectorApplyAvailable: false, expected: { totalDocCountFormatted: '86,374', sampleProbabilityFormatted: '0.5', + columnSelectorPopover: ['Log rate', 'Doc count', 'p-value', 'Impact', 'Actions'], fieldSelectorPopover: ['airline', 'custom_field.keyword'], globalState: { refreshInterval: { pause: true, value: 60000 }, diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts index 14e754550f6082..42fddac191988a 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/farequote_data_view_test_data_with_query.ts @@ -19,6 +19,7 @@ export const farequoteDataViewTestDataWithQuery: TestData = { brushDeviationTargetTimestamp: 1455033600000, brushIntervalFactor: 1, chartClickCoordinates: [0, 0], + columnSelectorSearch: 'p-value', fieldSelectorSearch: 'airline', fieldSelectorApplyAvailable: false, query: 'NOT airline:("SWR" OR "ACA" OR "AWE" OR "BAW" OR "JAL" OR "JBU" OR "JZA" OR "KLM")', @@ -43,6 +44,7 @@ export const farequoteDataViewTestDataWithQuery: TestData = { impact: 'High', }, ], + columnSelectorPopover: ['Log rate', 'Doc count', 'p-value', 'Impact', 'Actions'], fieldSelectorPopover: ['airline', 'custom_field.keyword'], globalState: { refreshInterval: { pause: true, value: 60000 }, diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts index 4a5f9dddb6f1f8..9645863ed1e822 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis/test_data/kibana_logs_data_view_test_data.ts @@ -19,6 +19,7 @@ export const kibanaLogsDataViewTestData: TestData = { sourceIndexOrSavedSearch: 'kibana_sample_data_logstsdb', brushIntervalFactor: 1, chartClickCoordinates: [235, 0], + columnSelectorSearch: 'p-value', fieldSelectorSearch: 'referer', fieldSelectorApplyAvailable: true, action: { @@ -69,6 +70,7 @@ export const kibanaLogsDataViewTestData: TestData = { logRate: 'Chart type:bar chart', impact: 'High', })), + columnSelectorPopover: ['Log rate', 'Doc count', 'p-value', 'Impact', 'Actions'], fieldSelectorPopover: [ 'agent.keyword', 'clientip', diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis_anomaly_table.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis_anomaly_table.ts index 6ec612e6a66b2d..fe9904bce21dd2 100644 --- a/x-pack/test/functional/apps/aiops/log_rate_analysis_anomaly_table.ts +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis_anomaly_table.ts @@ -98,7 +98,7 @@ const testData: TestData[] = [ fieldValue: 'AAL', impact: 'High', logRate: 'Chart type:bar chart', - pValue: '8.96e-49', + pValue: '', }, ], }, diff --git a/x-pack/test/functional/apps/aiops/types.ts b/x-pack/test/functional/apps/aiops/types.ts index 0f8f4a4d07d222..aeac2ce33f7186 100644 --- a/x-pack/test/functional/apps/aiops/types.ts +++ b/x-pack/test/functional/apps/aiops/types.ts @@ -44,9 +44,10 @@ interface TestDataExpectedWithoutSampleProbability { fieldName: string; fieldValue: string; logRate: string; - pValue: string; + pValue?: string; impact: string; }>; + columnSelectorPopover: string[]; fieldSelectorPopover: string[]; prompt: 'empty' | 'change-point'; } @@ -63,6 +64,7 @@ export interface TestData { brushDeviationTargetTimestamp?: number; brushIntervalFactor: number; chartClickCoordinates: [number, number]; + columnSelectorSearch: string; fieldSelectorSearch: string; fieldSelectorApplyAvailable: boolean; query?: string; diff --git a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts index 1a33ede2e700c1..8ef2f02d4eb032 100644 --- a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts @@ -184,9 +184,9 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr }); }, - async assertFieldFilterPopoverButtonExists(isOpen: boolean) { + async assertFilterPopoverButtonExists(selector: string, isOpen: boolean) { await retry.tryForTime(5000, async () => { - await testSubjects.existOrFail('aiopsFieldFilterButton'); + await testSubjects.existOrFail(selector); if (isOpen) { await testSubjects.existOrFail('aiopsFieldSelectorSearch'); @@ -196,11 +196,11 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr }); }, - async clickFieldFilterPopoverButton(expectPopoverToBeOpen: boolean) { - await testSubjects.clickWhenNotDisabledWithoutRetry('aiopsFieldFilterButton'); + async clickFilterPopoverButton(selector: string, expectPopoverToBeOpen: boolean) { + await testSubjects.clickWhenNotDisabledWithoutRetry(selector); await retry.tryForTime(30 * 1000, async () => { - await this.assertFieldFilterPopoverButtonExists(expectPopoverToBeOpen); + await this.assertFilterPopoverButtonExists(selector, expectPopoverToBeOpen); }); }, @@ -246,11 +246,17 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr }); }, - async clickFieldFilterApplyButton() { + async clickFieldFilterApplyButton(selector: string) { await testSubjects.clickWhenNotDisabledWithoutRetry('aiopsFieldFilterApplyButton'); await retry.tryForTime(30 * 1000, async () => { - await this.assertFieldFilterPopoverButtonExists(false); + await this.assertFilterPopoverButtonExists(selector, false); + }); + }, + + async clickFieldSelectorListItem(selector: string) { + await retry.tryForTime(5 * 1000, async () => { + await testSubjects.click(selector); }); },