export function DataStreamNotFoundPrompt({ dataStream }: { dataStream: string }) {
const promptTitle = {emptyPromptTitle}
;
- const promptBody = {emptyPromptBody(dataStream)}
;
+ const promptBody = (
+
+ {emptyPromptBody(dataStream)}
+
+ );
- return ;
+ return (
+
+ );
}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx
index ff311032fe69..3040e81f0e58 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart.tsx
@@ -14,7 +14,7 @@ import { KibanaErrorBoundary } from '@kbn/shared-ux-error-boundary';
import { flyoutDegradedDocsTrendText } from '../../../../../../common/translations';
import { useKibanaContextForPlugin } from '../../../../../utils';
import { TimeRangeConfig } from '../../../../../../common/types';
-import { useDegradedDocs } from '../../../../../hooks/use_degraded_docs';
+import { useDegradedDocsChart } from '../../../../../hooks';
const CHART_HEIGHT = 180;
const DISABLED_ACTIONS = [
@@ -26,7 +26,7 @@ const DISABLED_ACTIONS = [
interface DegradedDocsChartProps
extends Pick<
- ReturnType,
+ ReturnType,
'attributes' | 'isChartLoading' | 'onChartLoading' | 'extraActions'
> {
timeRange: TimeRangeConfig;
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx
index 985a748e792b..7c3aea15a6cf 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx
@@ -29,13 +29,15 @@ import {
openInLogsExplorerText,
overviewDegradedDocsText,
} from '../../../../../../common/translations';
-import { useDegradedDocs } from '../../../../../hooks/use_degraded_docs';
import { DegradedDocsChart } from './degraded_docs_chart';
import {
- useDatasetQualityDetailsRedirectLink,
+ useDatasetDetailsRedirectLinkTelemetry,
useDatasetQualityDetailsState,
+ useDegradedDocsChart,
+ useRedirectLink,
} from '../../../../../hooks';
import { _IGNORED } from '../../../../../../common/es_fields';
+import { NavigationSource } from '../../../../../services/telemetry';
const degradedDocsTooltip = (
{
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx
index b40f563a4dff..e03e0957b5a5 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/summary/panel.tsx
@@ -10,6 +10,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSkeletonTitle, EuiText } from '
import { css } from '@emotion/react';
import { euiThemeVars } from '@kbn/ui-theme';
import { PrivilegesWarningIconWrapper } from '../../../common';
+import { notAvailableLabel } from '../../../../../common/translations';
const verticalRule = css`
width: 1px;
@@ -95,8 +96,8 @@ export function PanelIndicator({
<>>
{userHasPrivilege && (
-
- {value}
+
+ {userHasPrivilege ? value : notAvailableLabel}
)}
>
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx
deleted file mode 100644
index cb35e9c74d33..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/dataset_summary.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
-import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types';
-import { DataStreamDetails, DataStreamSettings } from '../../../common/data_streams_stats';
-import {
- datasetCreatedOnText,
- flyoutDatasetDetailsText,
- datasetLastActivityText,
-} from '../../../common/translations';
-import { FieldsList, FieldsListLoading } from './fields_list';
-
-interface DatasetSummaryProps {
- fieldFormats: FieldFormatsStart;
- dataStreamSettings?: DataStreamSettings;
- dataStreamSettingsLoading: boolean;
- dataStreamDetails?: DataStreamDetails;
- dataStreamDetailsLoading: boolean;
-}
-
-export function DatasetSummary({
- dataStreamSettings,
- dataStreamSettingsLoading,
- dataStreamDetails,
- dataStreamDetailsLoading,
- fieldFormats,
-}: DatasetSummaryProps) {
- const dataFormatter = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE, [
- ES_FIELD_TYPES.DATE,
- ]);
- const formattedLastActivity = dataStreamDetails?.lastActivity
- ? dataFormatter.convert(dataStreamDetails?.lastActivity)
- : '-';
- const formattedCreatedOn = dataStreamSettings?.createdOn
- ? dataFormatter.convert(dataStreamSettings.createdOn)
- : '-';
-
- return (
-
- );
-}
-
-export function DatasetSummaryLoading() {
- return ;
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx
deleted file mode 100644
index 5335d5de8692..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_docs_trend/degraded_docs.tsx
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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, { useEffect, useState } from 'react';
-import { css } from '@emotion/react';
-import { FormattedMessage } from '@kbn/i18n-react';
-import {
- EuiFlexGroup,
- EuiFlexItem,
- EuiPanel,
- EuiSpacer,
- EuiTitle,
- EuiToolTip,
- EuiIcon,
- EuiCode,
- OnTimeChangeProps,
- EuiSkeletonRectangle,
-} from '@elastic/eui';
-import { UnifiedBreakdownFieldSelector } from '@kbn/unified-histogram-plugin/public';
-import type { DataViewField } from '@kbn/data-views-plugin/common';
-import { useDegradedDocsChart } from '../../../hooks';
-
-import { DEFAULT_TIME_RANGE, DEFAULT_DATEPICKER_REFRESH } from '../../../../common/constants';
-import { overviewDegradedDocsText } from '../../../../common/translations';
-import { DegradedDocsChart } from '../../dataset_quality_details/overview/document_trends/degraded_docs/degraded_docs_chart';
-import { TimeRangeConfig } from '../../../../common/types';
-
-export function DegradedDocs({
- dataStream,
- timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH },
- lastReloadTime,
- onTimeRangeChange,
-}: {
- dataStream?: string;
- timeRange?: TimeRangeConfig;
- lastReloadTime: number;
- onTimeRangeChange: (props: Pick) => void;
-}) {
- const { dataView, breakdown, ...chartProps } = useDegradedDocsChart({ dataStream });
-
- const [breakdownDataViewField, setBreakdownDataViewField] = useState(
- undefined
- );
-
- useEffect(() => {
- if (breakdown.dataViewField && breakdown.fieldSupportsBreakdown) {
- setBreakdownDataViewField(breakdown.dataViewField);
- } else {
- setBreakdownDataViewField(undefined);
- }
-
- if (breakdown.dataViewField && !breakdown.fieldSupportsBreakdown) {
- // TODO: If needed, notify user that the field is not breakable
- }
- }, [setBreakdownDataViewField, breakdown]);
-
- return (
-
-
-
-
- {overviewDegradedDocsText}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-const degradedDocsTooltip = (
-
- _ignored
-
- ),
- }}
- />
-);
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx
deleted file mode 100644
index 1d7e79b3c0b3..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/columns.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 { i18n } from '@kbn/i18n';
-import { EuiBasicTableColumn } from '@elastic/eui';
-import { FieldFormat } from '@kbn/field-formats-plugin/common';
-import { formatNumber } from '@elastic/eui';
-
-import { DegradedField } from '../../../../common/api_types';
-import { SparkPlot } from './spark_plot';
-import { NUMBER_FORMAT } from '../../../../common/constants';
-
-const fieldColumnName = i18n.translate('xpack.datasetQuality.flyout.degradedField.field', {
- defaultMessage: 'Field',
-});
-
-const countColumnName = i18n.translate('xpack.datasetQuality.flyout.degradedField.count', {
- defaultMessage: 'Docs count',
-});
-
-const lastOccurrenceColumnName = i18n.translate(
- 'xpack.datasetQuality.flyout.degradedField.lastOccurrence',
- {
- defaultMessage: 'Last occurrence',
- }
-);
-
-export const getDegradedFieldsColumns = ({
- dateFormatter,
- isLoading,
-}: {
- dateFormatter: FieldFormat;
- isLoading: boolean;
-}): Array> => [
- {
- name: fieldColumnName,
- field: 'name',
- },
- {
- name: countColumnName,
- sortable: true,
- field: 'count',
- render: (_, { count, timeSeries }) => {
- const countValue = formatNumber(count, NUMBER_FORMAT);
- return ;
- },
- },
- {
- name: lastOccurrenceColumnName,
- sortable: true,
- field: 'lastOccurrence',
- render: (lastOccurrence: number) => {
- return dateFormatter.convert(lastOccurrence);
- },
- },
-];
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx
deleted file mode 100644
index bd2c20b24171..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/degraded_fields.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 { EuiFlexGroup, EuiPanel, EuiTitle, EuiIconTip } from '@elastic/eui';
-import { flyoutImprovementText, flyoutImprovementTooltip } from '../../../../common/translations';
-import { DegradedFieldTable } from './table';
-
-export function DegradedFields() {
- return (
-
-
-
- {flyoutImprovementText}
-
-
-
-
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx
deleted file mode 100644
index 964c3ee434f4..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/spark_plot.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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 {
- EuiFlexGroup,
- EuiFlexItem,
- EuiIcon,
- EuiLoadingChart,
- euiPaletteColorBlind,
- useEuiTheme,
-} from '@elastic/eui';
-import React from 'react';
-import { ScaleType, Settings, Tooltip, Chart, BarSeries } from '@elastic/charts';
-import { i18n } from '@kbn/i18n';
-import { Coordinate } from '../../../../common/types';
-
-export function SparkPlot({
- valueLabel,
- isLoading,
- series,
-}: {
- valueLabel: React.ReactNode;
- isLoading: boolean;
- series?: Coordinate[] | null;
-}) {
- return (
-
-
-
-
- {valueLabel}
-
- );
-}
-
-function SparkPlotItem({
- isLoading,
- series,
-}: {
- isLoading: boolean;
- series?: Coordinate[] | null;
-}) {
- const { euiTheme } = useEuiTheme();
- const chartSize = {
- height: euiTheme.size.l,
- width: '80px',
- };
-
- const commonStyle = {
- ...chartSize,
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- };
- const palette = euiPaletteColorBlind({ rotations: 2 });
-
- if (isLoading) {
- return (
-
-
-
- );
- }
-
- if (hasValidTimeSeries(series)) {
- return (
-
-
-
-
-
-
-
- );
- }
-
- return (
-
-
-
- );
-}
-
-function hasValidTimeSeries(series?: Coordinate[] | null): series is Coordinate[] {
- return !!series?.some((point) => point.y !== 0);
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx
deleted file mode 100644
index 1a1baa8aae7c..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/degraded_fields/table.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 { EuiBasicTable, EuiEmptyPrompt } from '@elastic/eui';
-import React from 'react';
-import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types';
-import { useDatasetQualityDegradedField } from '../../../hooks';
-import { getDegradedFieldsColumns } from './columns';
-import {
- overviewDegradedFieldsTableLoadingText,
- overviewDegradedFieldsTableNoData,
-} from '../../../../common/translations';
-
-export const DegradedFieldTable = () => {
- const { isLoading, pagination, renderedItems, onTableChange, sort, fieldFormats } =
- useDatasetQualityDegradedField();
- const dateFormatter = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.DATE, [
- ES_FIELD_TYPES.DATE,
- ]);
- const columns = getDegradedFieldsColumns({ dateFormatter, isLoading });
-
- return (
- {overviewDegradedFieldsTableNoData}}
- hasBorder={false}
- titleSize="m"
- />
- )
- }
- />
- );
-};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx
deleted file mode 100644
index 1861d23b69a4..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/fields_list.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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, { ReactNode, Fragment } from 'react';
-import {
- EuiFlexGroup,
- EuiPanel,
- EuiFlexItem,
- EuiSpacer,
- EuiTitle,
- EuiHorizontalRule,
- EuiSkeletonTitle,
- EuiSkeletonText,
- EuiSkeletonRectangle,
-} from '@elastic/eui';
-
-export function FieldsList({
- title,
- fields,
- actionsMenu: ActionsMenu,
- dataTestSubj = `datasetQualityFlyoutFieldsList-${title.toLowerCase().split(' ').join('_')}`,
-}: {
- title: string;
- fields: Array<{ fieldTitle: string; fieldValue: ReactNode; isLoading: boolean }>;
- actionsMenu?: ReactNode;
- dataTestSubj?: string;
-}) {
- return (
-
-
-
- {title}
-
- {ActionsMenu}
-
-
-
- {fields.map(({ fieldTitle, fieldValue, isLoading: isFieldLoading }, index) => (
-
-
-
-
- {fieldTitle}
-
-
-
-
- {fieldValue}
-
-
-
-
- {index < fields.length - 1 ? : null}
-
- ))}
-
-
- );
-}
-
-export function FieldsListLoading() {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx
deleted file mode 100644
index cb6944057a2d..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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, { Fragment, useEffect } from 'react';
-import { css } from '@emotion/react';
-import {
- EuiButtonEmpty,
- EuiFlexGroup,
- EuiFlexItem,
- EuiFlyout,
- EuiFlyoutBody,
- EuiFlyoutFooter,
- EuiSpacer,
- EuiHorizontalRule,
- EuiPanel,
- EuiSkeletonRectangle,
-} from '@elastic/eui';
-import { dynamic } from '@kbn/shared-ux-utility';
-import { flyoutCancelText } from '../../../common/translations';
-import { useDatasetQualityFlyout, useDatasetDetailsTelemetry } from '../../hooks';
-import { DatasetSummary, DatasetSummaryLoading } from './dataset_summary';
-import { Header } from './header';
-import { FlyoutProps } from './types';
-import { BasicDataStream } from '../../../common/types';
-
-const FlyoutSummary = dynamic(() => import('./flyout_summary/flyout_summary'));
-const IntegrationSummary = dynamic(() => import('./integration_summary'));
-
-// Allow for lazy loading
-// eslint-disable-next-line import/no-default-export
-export default function Flyout({ dataset, closeFlyout }: FlyoutProps) {
- const {
- dataStreamStat,
- dataStreamSettings,
- dataStreamDetails,
- isNonAggregatable,
- fieldFormats,
- timeRange,
- loadingState,
- flyoutLoading,
- integration,
- } = useDatasetQualityFlyout();
-
- const linkDetails: BasicDataStream = {
- name: dataset.name,
- rawName: dataset.rawName,
- integration: integration?.integrationDetails,
- type: dataset.type,
- namespace: dataset.namespace,
- };
-
- const title = integration?.integrationDetails?.datasets?.[dataset.name] ?? dataset.name;
-
- const { startTracking } = useDatasetDetailsTelemetry();
-
- useEffect(() => {
- startTracking();
- }, [startTracking]);
-
- return (
-
- {flyoutLoading ? (
-
- ) : (
- <>
-
-
-
-
-
-
-
-
-
- {loadingState.dataStreamDetailsLoading && loadingState.dataStreamSettingsLoading ? (
-
- ) : dataStreamStat ? (
-
-
-
- {integration?.integrationDetails && (
- <>
-
-
- >
- )}
-
- ) : null}
-
-
-
-
-
-
-
- {flyoutCancelText}
-
-
-
-
- >
- )}
-
- );
-}
-
-const flyoutBodyStyles = css`
- .euiFlyoutBody__overflowContent {
- padding: 0;
- }
-`;
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx
deleted file mode 100644
index 5b89c43ad92d..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary.tsx
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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, { useCallback, useState } from 'react';
-import { i18n } from '@kbn/i18n';
-import {
- OnRefreshProps,
- OnTimeChangeProps,
- EuiSpacer,
- EuiFlexGroup,
- EuiFlexItem,
- EuiCallOut,
- EuiLink,
- EuiCode,
-} from '@elastic/eui';
-
-import { FormattedMessage } from '@kbn/i18n-react';
-import { DegradedDocs } from '../degraded_docs_trend/degraded_docs';
-import { DataStreamDetails } from '../../../../common/api_types';
-import { DEFAULT_TIME_RANGE, DEFAULT_DATEPICKER_REFRESH } from '../../../../common/constants';
-import { useDatasetQualityContext } from '../../dataset_quality/context';
-import { FlyoutSummaryHeader } from './flyout_summary_header';
-import { FlyoutSummaryKpis, FlyoutSummaryKpisLoading } from './flyout_summary_kpis';
-import { DegradedFields } from '../degraded_fields/degraded_fields';
-import { TimeRangeConfig } from '../../../../common/types';
-import { FlyoutDataset } from '../../../state_machines/dataset_quality_controller';
-
-const nonAggregatableWarningTitle = i18n.translate('xpack.datasetQuality.nonAggregatable.title', {
- defaultMessage: 'Your request may take longer to complete',
-});
-
-const nonAggregatableWarningDescription = (dataset: string) => (
-
- {dataset}
-
- ),
- howToFixIt: (
-
- {i18n.translate(
- 'xpack.datasetQuality.flyout.nonAggregatableDatasets.link.title',
- {
- defaultMessage: 'rollover',
- }
- )}
-
- ),
- }}
- />
- ),
- }}
- />
- ),
- }}
- />
-);
-
-// Allow for lazy loading
-// eslint-disable-next-line import/no-default-export
-export default function FlyoutSummary({
- dataStream,
- dataStreamStat,
- dataStreamDetails,
- isNonAggregatable,
- dataStreamDetailsLoading,
- timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH },
-}: {
- dataStream: string;
- dataStreamStat?: FlyoutDataset;
- dataStreamDetails?: DataStreamDetails;
- dataStreamDetailsLoading: boolean;
- timeRange?: TimeRangeConfig;
- isNonAggregatable?: boolean;
-}) {
- const { service } = useDatasetQualityContext();
- const [lastReloadTime, setLastReloadTime] = useState(Date.now());
-
- const updateTimeRange = useCallback(
- ({ start, end, refreshInterval }: OnRefreshProps) => {
- service.send({
- type: 'UPDATE_INSIGHTS_TIME_RANGE',
- timeRange: {
- from: start,
- to: end,
- refresh: { ...DEFAULT_DATEPICKER_REFRESH, value: refreshInterval },
- },
- });
- },
- [service]
- );
-
- const handleTimeChange = useCallback(
- ({ isInvalid, ...timeRangeProps }: OnTimeChangeProps) => {
- if (!isInvalid) {
- updateTimeRange({ refreshInterval: timeRange.refresh.value, ...timeRangeProps });
- }
- },
- [updateTimeRange, timeRange.refresh]
- );
-
- const handleTimeRangeChange = useCallback(
- ({ start, end }: Pick) => {
- updateTimeRange({ start, end, refreshInterval: timeRange.refresh.value });
- },
- [updateTimeRange, timeRange.refresh]
- );
-
- const handleRefresh = useCallback(
- (refreshProps: OnRefreshProps) => {
- updateTimeRange(refreshProps);
- setLastReloadTime(Date.now());
- },
- [updateTimeRange]
- );
-
- return (
- <>
- {isNonAggregatable && (
-
-
-
- {nonAggregatableWarningDescription(dataStream)}
-
-
-
- )}
-
-
-
-
- {dataStreamStat ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
- >
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx
deleted file mode 100644
index c0ee7303b51a..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_header.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 { css } from '@emotion/react';
-import {
- EuiFlexGroup,
- EuiIcon,
- EuiSuperDatePicker,
- EuiTitle,
- EuiToolTip,
- OnRefreshProps,
- OnTimeChangeProps,
-} from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n-react';
-
-import { flyoutSummaryText } from '../../../../common/translations';
-import { TimeRangeConfig } from '../../../../common/types';
-
-export function FlyoutSummaryHeader({
- timeRange,
- onTimeChange,
- onRefresh,
-}: {
- timeRange: TimeRangeConfig;
- onTimeChange: (timeChangeProps: OnTimeChangeProps) => void;
- onRefresh: (refreshProps: OnRefreshProps) => void;
-}) {
- return (
-
-
-
- {flyoutSummaryText}
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-const flyoutSummaryTooltip = (
-
-);
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx
deleted file mode 100644
index 767cd8ec41f4..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpi_item.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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 {
- EuiFlexGroup,
- EuiFlexItem,
- EuiPanel,
- EuiTitle,
- EuiText,
- EuiLink,
- useEuiTheme,
- EuiSkeletonTitle,
- EuiSkeletonRectangle,
-} from '@elastic/eui';
-
-import { PrivilegesWarningIconWrapper } from '../../common';
-import { notAvailableLabel } from '../../../../common/translations';
-import type { getSummaryKpis } from './get_summary_kpis';
-
-export function FlyoutSummaryKpiItem({
- title,
- value,
- link,
- isLoading,
- userHasPrivilege,
-}: ReturnType[number] & { isLoading: boolean }) {
- const { euiTheme } = useEuiTheme();
-
- return (
-
-
-
-
-
- {title}
-
-
-
- <>>
-
-
- {link ? (
-
-
- {link.label}
-
-
- ) : null}
-
-
-
-
- {userHasPrivilege ? value : notAvailableLabel}
-
-
-
-
-
- );
-}
-
-export function FlyoutSummaryKpiItemLoading({ title }: { title: string }) {
- return (
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx
deleted file mode 100644
index 47b41712dc7f..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/flyout_summary_kpis.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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, { useMemo } from 'react';
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
-
-import { _IGNORED } from '../../../../common/es_fields';
-
-import { DataStreamDetails } from '../../../../common/api_types';
-import { useKibanaContextForPlugin } from '../../../utils';
-import { NavigationSource } from '../../../services/telemetry';
-import { useDatasetDetailsTelemetry, useRedirectLink } from '../../../hooks';
-import { FlyoutDataset } from '../../../state_machines/dataset_quality_controller';
-import { FlyoutSummaryKpiItem, FlyoutSummaryKpiItemLoading } from './flyout_summary_kpi_item';
-import { getSummaryKpis } from './get_summary_kpis';
-import { TimeRangeConfig } from '../../../../common/types';
-
-export function FlyoutSummaryKpis({
- dataStreamStat,
- dataStreamDetails,
- isLoading,
- timeRange,
-}: {
- dataStreamStat: FlyoutDataset;
- dataStreamDetails?: DataStreamDetails;
- isLoading: boolean;
- timeRange: TimeRangeConfig;
-}) {
- const {
- services: { observabilityShared },
- } = useKibanaContextForPlugin();
- const telemetry = useDatasetDetailsTelemetry();
- const hostsLocator = observabilityShared.locators.infra.hostsLocator;
-
- const degradedDocsLinkProps = useRedirectLink({
- dataStreamStat,
- query: { language: 'kuery', query: `${_IGNORED}: *` },
- timeRangeConfig: timeRange,
- telemetry: {
- page: 'details',
- navigationSource: NavigationSource.Summary,
- },
- });
-
- const kpis = useMemo(
- () =>
- getSummaryKpis({
- dataStreamDetails,
- timeRange,
- degradedDocsLinkProps,
- hostsLocator,
- telemetry,
- }),
- [dataStreamDetails, degradedDocsLinkProps, hostsLocator, telemetry, timeRange]
- );
-
- return (
-
-
- {kpis.map((kpi) => (
-
-
-
- ))}
-
-
- );
-}
-
-export function FlyoutSummaryKpisLoading() {
- const telemetry = useDatasetDetailsTelemetry();
-
- return (
-
-
- {getSummaryKpis({ telemetry }).map(({ title }) => (
-
-
-
- ))}
-
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts
deleted file mode 100644
index 28f5334e2f19..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.test.ts
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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 { formatNumber } from '@elastic/eui';
-import type { useKibanaContextForPlugin } from '../../../utils';
-import type { useDatasetDetailsTelemetry } from '../../../hooks';
-
-import {
- BYTE_NUMBER_FORMAT,
- DEFAULT_DATEPICKER_REFRESH,
- DEFAULT_TIME_RANGE,
- MAX_HOSTS_METRIC_VALUE,
-} from '../../../../common/constants';
-import {
- overviewDegradedDocsText,
- flyoutDocsCountTotalText,
- flyoutHostsText,
- flyoutServicesText,
- flyoutShowAllText,
- flyoutSizeText,
-} from '../../../../common/translations';
-import { getSummaryKpis } from './get_summary_kpis';
-import { TimeRangeConfig } from '../../../../common/types';
-
-const dataStreamDetails = {
- services: {
- service1: ['service1Instance1', 'service1Instance2'],
- service2: ['service2Instance1'],
- },
- docsCount: 1000,
- sizeBytes: 5000,
- hosts: {
- host1: ['host1Instance1', 'host1Instance2'],
- host2: ['host2Instance1'],
- },
- degradedDocsCount: 200,
-};
-
-const timeRange: TimeRangeConfig = {
- ...DEFAULT_TIME_RANGE,
- refresh: DEFAULT_DATEPICKER_REFRESH,
- from: 'now-15m',
- to: 'now',
-};
-
-const degradedDocsLinkProps = {
- linkProps: { href: 'http://exploratory-view/degraded-docs', onClick: () => {} },
- navigate: () => {},
- isLogsExplorerAvailable: true,
-};
-const hostsRedirectUrl = 'http://hosts/metric/';
-
-const hostsLocator = {
- getRedirectUrl: () => hostsRedirectUrl,
-} as unknown as ReturnType<
- typeof useKibanaContextForPlugin
->['services']['observabilityShared']['locators']['infra']['hostsLocator'];
-
-const telemetry = {
- trackDetailsNavigated: () => {},
-} as unknown as ReturnType;
-
-describe('getSummaryKpis', () => {
- it('should return the correct KPIs', () => {
- const result = getSummaryKpis({
- dataStreamDetails,
- timeRange,
- degradedDocsLinkProps,
- hostsLocator,
- telemetry,
- });
-
- expect(result).toEqual([
- {
- title: flyoutDocsCountTotalText,
- value: '1,000',
- userHasPrivilege: true,
- },
- {
- title: flyoutSizeText,
- value: formatNumber(dataStreamDetails.sizeBytes ?? 0, BYTE_NUMBER_FORMAT),
- userHasPrivilege: false,
- },
- {
- title: flyoutServicesText,
- value: '3',
- link: undefined,
- userHasPrivilege: true,
- },
- {
- title: flyoutHostsText,
- value: '3',
- link: undefined,
- userHasPrivilege: true,
- },
- {
- title: overviewDegradedDocsText,
- value: '200',
- link: {
- label: flyoutShowAllText,
- props: degradedDocsLinkProps.linkProps,
- },
- userHasPrivilege: true,
- },
- ]);
- });
-
- it('show X+ if number of hosts or services exceed MAX_HOSTS_METRIC_VALUE', () => {
- const services = {
- service1: new Array(MAX_HOSTS_METRIC_VALUE + 1)
- .fill('service1Instance')
- .map((_, i) => `service1Instance${i}`),
- };
-
- const host3 = new Array(MAX_HOSTS_METRIC_VALUE + 1)
- .fill('host3Instance')
- .map((_, i) => `host3Instance${i}`);
-
- const detailsWithMaxPlusHosts = {
- ...dataStreamDetails,
- services,
- hosts: { ...dataStreamDetails.hosts, host3 },
- };
-
- const result = getSummaryKpis({
- dataStreamDetails: detailsWithMaxPlusHosts,
- timeRange,
- degradedDocsLinkProps,
- hostsLocator,
- telemetry,
- });
-
- expect(result).toEqual([
- {
- title: flyoutDocsCountTotalText,
- value: '1,000',
- userHasPrivilege: true,
- },
- {
- title: flyoutSizeText,
- value: formatNumber(dataStreamDetails.sizeBytes ?? 0, BYTE_NUMBER_FORMAT),
- userHasPrivilege: false,
- },
- {
- title: flyoutServicesText,
- value: '50+',
- link: undefined,
- userHasPrivilege: true,
- },
- {
- title: flyoutHostsText,
- value: '54+',
- link: undefined,
- userHasPrivilege: true,
- },
- {
- title: overviewDegradedDocsText,
- value: '200',
- link: {
- label: flyoutShowAllText,
- props: degradedDocsLinkProps.linkProps,
- },
- userHasPrivilege: true,
- },
- ]);
- });
-});
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts
deleted file mode 100644
index b574e1e8a816..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/flyout_summary/get_summary_kpis.ts
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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 { formatNumber } from '@elastic/eui';
-import { getRouterLinkProps, RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
-import {
- BYTE_NUMBER_FORMAT,
- DEFAULT_DATEPICKER_REFRESH,
- DEFAULT_TIME_RANGE,
- MAX_HOSTS_METRIC_VALUE,
- NUMBER_FORMAT,
-} from '../../../../common/constants';
-import {
- overviewDegradedDocsText,
- flyoutDocsCountTotalText,
- flyoutHostsText,
- flyoutServicesText,
- flyoutShowAllText,
- flyoutSizeText,
-} from '../../../../common/translations';
-import { DataStreamDetails } from '../../../../common/api_types';
-import { NavigationTarget, NavigationSource } from '../../../services/telemetry';
-import { useKibanaContextForPlugin } from '../../../utils';
-import type { useRedirectLink, useDatasetDetailsTelemetry } from '../../../hooks';
-import { TimeRangeConfig } from '../../../../common/types';
-
-export function getSummaryKpis({
- dataStreamDetails,
- timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_DATEPICKER_REFRESH },
- degradedDocsLinkProps,
- hostsLocator,
- telemetry,
-}: {
- dataStreamDetails?: DataStreamDetails;
- timeRange?: TimeRangeConfig;
- degradedDocsLinkProps?: ReturnType;
- hostsLocator?: ReturnType<
- typeof useKibanaContextForPlugin
- >['services']['observabilityShared']['locators']['infra']['hostsLocator'];
- telemetry: ReturnType;
-}): Array<{
- title: string;
- value: string;
- link?: { label: string; props: RouterLinkProps };
- userHasPrivilege: boolean;
-}> {
- const services = dataStreamDetails?.services ?? {};
- const serviceKeys = Object.keys(services);
- const countOfServices = serviceKeys
- .map((key: string) => services[key].length)
- .reduce((a, b) => a + b, 0);
-
- // @ts-ignore // TODO: Add link to APM services page when possible - https://github.com/elastic/kibana/issues/179904
- const servicesLink = {
- label: flyoutShowAllText,
- props: getRouterLinkProps({
- href: undefined,
- onClick: () => {
- telemetry.trackDetailsNavigated(NavigationTarget.Services, NavigationSource.Summary);
- },
- }),
- };
-
- return [
- {
- title: flyoutDocsCountTotalText,
- value: formatNumber(dataStreamDetails?.docsCount ?? 0, NUMBER_FORMAT),
- userHasPrivilege: true,
- },
- // dataStreamDetails.sizeBytes = null indicates it's Serverless where `_stats` API isn't available
- ...(dataStreamDetails?.sizeBytes !== null // Only show when not in Serverless
- ? [
- {
- title: flyoutSizeText,
- value: formatNumber(dataStreamDetails?.sizeBytes ?? 0, BYTE_NUMBER_FORMAT),
- userHasPrivilege: Boolean(dataStreamDetails?.userPrivileges?.canMonitor),
- },
- ]
- : []),
- {
- title: flyoutServicesText,
- value: formatMetricValueForMax(countOfServices, MAX_HOSTS_METRIC_VALUE, NUMBER_FORMAT),
- link: undefined,
- userHasPrivilege: true,
- },
- getHostsKpi(dataStreamDetails?.hosts, timeRange, telemetry, hostsLocator),
- {
- title: overviewDegradedDocsText,
- value: formatNumber(dataStreamDetails?.degradedDocsCount ?? 0, NUMBER_FORMAT),
- link:
- degradedDocsLinkProps && degradedDocsLinkProps.linkProps.href
- ? {
- label: flyoutShowAllText,
- props: degradedDocsLinkProps.linkProps,
- }
- : undefined,
- userHasPrivilege: true,
- },
- ];
-}
-
-function getHostsKpi(
- dataStreamHosts: DataStreamDetails['hosts'],
- timeRange: TimeRangeConfig,
- telemetry: ReturnType,
- hostsLocator?: ReturnType<
- typeof useKibanaContextForPlugin
- >['services']['observabilityShared']['locators']['infra']['hostsLocator']
-) {
- const hosts = dataStreamHosts ?? {};
- const hostKeys = Object.keys(hosts);
- const countOfHosts = hostKeys
- .map((key: string) => hosts[key].length)
- .reduce(
- ({ count, anyHostExceedsMax }, hostCount) => ({
- count: count + hostCount,
- anyHostExceedsMax: anyHostExceedsMax || hostCount > MAX_HOSTS_METRIC_VALUE,
- }),
- { count: 0, anyHostExceedsMax: false }
- );
-
- // Create a query so from hostKeys so that (key: value OR key: value2)
- const hostsKuery = hostKeys
- .filter((key) => hosts[key].length > 0)
- .map((key) => hosts[key].map((value) => `${key}: "${value}"`).join(' OR '))
- .join(' OR ');
- const hostsUrl = hostsLocator?.getRedirectUrl({
- query: { language: 'kuery', query: hostsKuery },
- dateRange: { from: timeRange.from, to: timeRange.to },
- limit: countOfHosts.count,
- });
-
- // @ts-ignore // TODO: Add link to Infra Hosts page when possible
- const hostsLink = {
- label: flyoutShowAllText,
- props: getRouterLinkProps({
- href: hostsUrl,
- onClick: () => {
- telemetry.trackDetailsNavigated(NavigationTarget.Hosts, NavigationSource.Summary);
- },
- }),
- };
-
- return {
- title: flyoutHostsText,
- value: formatMetricValueForMax(
- countOfHosts.anyHostExceedsMax ? countOfHosts.count + 1 : countOfHosts.count,
- countOfHosts.count,
- NUMBER_FORMAT
- ),
- link: undefined,
- userHasPrivilege: true,
- };
-}
-
-/**
- * Formats a metric value to show a '+' sign if it's above a max value e.g. 50+
- */
-function formatMetricValueForMax(value: number, max: number, numberFormat: string): string {
- const exceedsMax = value > max;
- const valueToShow = exceedsMax ? max : value;
- return `${formatNumber(valueToShow, numberFormat)}${exceedsMax ? '+' : ''}`;
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx
deleted file mode 100644
index 1117c7da12a1..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/header.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 {
- EuiButton,
- EuiFlexGroup,
- EuiFlexItem,
- EuiFlyoutHeader,
- EuiSkeletonTitle,
- EuiTitle,
- useEuiShadow,
- useEuiTheme,
-} from '@elastic/eui';
-import { css } from '@emotion/react';
-import React from 'react';
-import { openInDiscoverText, openInLogsExplorerText } from '../../../common/translations';
-import { NavigationSource } from '../../services/telemetry';
-import { useRedirectLink } from '../../hooks';
-import { IntegrationIcon } from '../common';
-import { BasicDataStream, TimeRangeConfig } from '../../../common/types';
-
-export function Header({
- linkDetails,
- loading,
- title,
- timeRange,
-}: {
- linkDetails: BasicDataStream;
- loading: boolean;
- title: string;
- timeRange: TimeRangeConfig;
-}) {
- const { integration } = linkDetails;
- const euiShadow = useEuiShadow('s');
- const { euiTheme } = useEuiTheme();
- const redirectLinkProps = useRedirectLink({
- dataStreamStat: linkDetails,
- telemetry: {
- page: 'details',
- navigationSource: NavigationSource.Header,
- },
- timeRangeConfig: timeRange,
- });
-
- return (
-
- {loading ? (
-
- ) : (
-
-
-
-
- {title}
-
-
-
-
-
-
-
-
-
- {redirectLinkProps.isLogsExplorerAvailable
- ? openInLogsExplorerText
- : openInDiscoverText}
-
-
-
-
- )}
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx
deleted file mode 100644
index 6a2c75f0054a..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * 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.
- */
-
-export * from './flyout';
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx
deleted file mode 100644
index 99afb7f269df..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_actions_menu.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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, { useMemo } from 'react';
-import { i18n } from '@kbn/i18n';
-import {
- EuiButtonEmpty,
- EuiButtonIcon,
- EuiContextMenu,
- EuiContextMenuPanelDescriptor,
- EuiContextMenuPanelItemDescriptor,
- EuiPopover,
- EuiSkeletonRectangle,
-} from '@elastic/eui';
-import { css } from '@emotion/react';
-import { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
-import { useDatasetQualityFlyout } from '../../hooks';
-import { useFlyoutIntegrationActions } from '../../hooks/use_flyout_integration_actions';
-import { Integration } from '../../../common/data_streams_stats/integration';
-import { Dashboard } from '../../../common/api_types';
-
-const integrationActionsText = i18n.translate('xpack.datasetQuality.flyoutIntegrationActionsText', {
- defaultMessage: 'Integration actions',
-});
-
-const seeIntegrationText = i18n.translate('xpack.datasetQuality.flyoutSeeIntegrationActionText', {
- defaultMessage: 'See integration',
-});
-
-const indexTemplateText = i18n.translate('xpack.datasetQuality.flyoutIndexTemplateActionText', {
- defaultMessage: 'Index template',
-});
-
-const viewDashboardsText = i18n.translate('xpack.datasetQuality.flyoutViewDashboardsActionText', {
- defaultMessage: 'View dashboards',
-});
-
-export function IntegrationActionsMenu({
- integration,
- dashboards,
- dashboardsLoading,
-}: {
- integration: Integration;
- dashboards: Dashboard[];
- dashboardsLoading: boolean;
-}) {
- const { dataStreamStat, canUserAccessDashboards, canUserViewIntegrations } =
- useDatasetQualityFlyout();
- const { version, name: integrationName } = integration;
- const { type, name } = dataStreamStat!;
- const {
- isOpen,
- handleCloseMenu,
- handleToggleMenu,
- getIntegrationOverviewLinkProps,
- getIndexManagementLinkProps,
- getDashboardLinkProps,
- } = useFlyoutIntegrationActions();
-
- const actionButton = (
-
- );
-
- const MenuActionItem = ({
- dataTestSubject,
- buttonText,
- routerLinkProps,
- iconType,
- disabled = false,
- }: {
- dataTestSubject: string;
- buttonText: string | React.ReactNode;
- routerLinkProps: RouterLinkProps;
- iconType: string;
- disabled?: boolean;
- }) => (
-
- {buttonText}
-
- );
-
- const panelItems = useMemo(() => {
- const firstLevelItems: EuiContextMenuPanelItemDescriptor[] = [
- ...(canUserViewIntegrations
- ? [
- {
- renderItem: () => (
-
- ),
- },
- ]
- : []),
- {
- renderItem: () => (
-
- ),
- },
- {
- isSeparator: true,
- key: 'sep',
- },
- ];
-
- if (dashboards.length && canUserAccessDashboards) {
- firstLevelItems.push({
- icon: 'dashboardApp',
- panel: 1,
- name: viewDashboardsText,
- 'data-test-subj': 'datasetQualityFlyoutIntegrationActionViewDashboards',
- disabled: false,
- });
- } else if (dashboardsLoading) {
- firstLevelItems.push({
- icon: 'dashboardApp',
- name: ,
- 'data-test-subj': 'datasetQualityFlyoutIntegrationActionDashboardsLoading',
- disabled: true,
- });
- }
-
- const panel: EuiContextMenuPanelDescriptor[] = [
- {
- id: 0,
- items: firstLevelItems,
- },
- {
- id: 1,
- title: viewDashboardsText,
- items: dashboards.map((dashboard) => {
- return {
- renderItem: () => (
-
- ),
- };
- }),
- },
- ];
-
- return panel;
- }, [
- dashboards,
- getDashboardLinkProps,
- getIndexManagementLinkProps,
- getIntegrationOverviewLinkProps,
- integrationName,
- name,
- type,
- version,
- dashboardsLoading,
- canUserAccessDashboards,
- canUserViewIntegrations,
- ]);
-
- return (
-
-
-
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx
deleted file mode 100644
index 53262c7821ce..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/integration_summary.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 { EuiFlexGroup, EuiBadge, EuiText } from '@elastic/eui';
-import React from 'react';
-import { css } from '@emotion/react';
-import {
- flyoutIntegrationDetailsText,
- flyoutIntegrationNameText,
- integrationVersionText,
-} from '../../../common/translations';
-import { IntegrationIcon } from '../common';
-import { FieldsList } from './fields_list';
-import { IntegrationActionsMenu } from './integration_actions_menu';
-import { Integration } from '../../../common/data_streams_stats/integration';
-import { Dashboard } from '../../../common/api_types';
-
-// Allow for lazy loading
-// eslint-disable-next-line import/no-default-export
-export default function IntegrationSummary({
- integration,
- dashboards,
- dashboardsLoading,
-}: {
- integration: Integration;
- dashboards: Dashboard[];
- dashboardsLoading: boolean;
-}) {
- const { name, version } = integration;
-
- const integrationActionsMenu = (
-
- );
- return (
-
-
-
- {name}
-
-
- ),
- isLoading: false,
- },
- {
- fieldTitle: integrationVersionText,
- fieldValue: version,
- isLoading: false,
- },
- ]}
- />
- );
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts
deleted file mode 100644
index 97d82b862428..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/components/flyout/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * 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 { FlyoutDataset } from '../../state_machines/dataset_quality_controller';
-
-export interface FlyoutProps {
- dataset: FlyoutDataset;
- closeFlyout: () => void;
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts
index 7424e13b0f93..ea4443a61a8f 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/create_controller.ts
@@ -11,12 +11,10 @@ import equal from 'fast-deep-equal';
import { distinctUntilChanged, from, map } from 'rxjs';
import { interpret } from 'xstate';
import { IDataStreamsStatsClient } from '../../services/data_streams_stats';
-import { IDataStreamDetailsClient } from '../../services/data_stream_details';
import {
createDatasetQualityControllerStateMachine,
DEFAULT_CONTEXT,
} from '../../state_machines/dataset_quality_controller';
-import { DatasetQualityStartDeps } from '../../types';
import { getContextFromPublicState, getPublicStateFromContext } from './public_state';
import { DatasetQualityController, DatasetQualityPublicStateUpdate } from './types';
@@ -24,13 +22,11 @@ type InitialState = DatasetQualityPublicStateUpdate;
interface Dependencies {
core: CoreStart;
- plugins: DatasetQualityStartDeps;
dataStreamStatsClient: IDataStreamsStatsClient;
- dataStreamDetailsClient: IDataStreamDetailsClient;
}
export const createDatasetQualityControllerFactory =
- ({ core, plugins, dataStreamStatsClient, dataStreamDetailsClient }: Dependencies) =>
+ ({ core, dataStreamStatsClient }: Dependencies) =>
async ({
initialState = DEFAULT_CONTEXT,
}: {
@@ -40,10 +36,8 @@ export const createDatasetQualityControllerFactory =
const machine = createDatasetQualityControllerStateMachine({
initialContext,
- plugins,
toasts: core.notifications.toasts,
dataStreamStatsClient,
- dataStreamDetailsClient,
});
const service = interpret(machine, {
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts
index 1bf0088bc7a4..ea5ae63f9707 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/public_state.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { DatasetTableSortField, DegradedFieldSortField } from '../../hooks';
+import { DatasetTableSortField } from '../../hooks';
import {
DatasetQualityControllerContext,
DEFAULT_CONTEXT,
@@ -17,7 +17,6 @@ export const getPublicStateFromContext = (
): DatasetQualityPublicState => {
return {
table: context.table,
- flyout: context.flyout,
filters: context.filters,
};
};
@@ -36,22 +35,6 @@ export const getContextFromPublicState = (
}
: DEFAULT_CONTEXT.table.sort,
},
- flyout: {
- ...DEFAULT_CONTEXT.flyout,
- ...publicState.flyout,
- degradedFields: {
- table: {
- ...DEFAULT_CONTEXT.flyout.degradedFields.table,
- ...publicState.flyout?.degradedFields?.table,
- sort: publicState.flyout?.degradedFields?.table?.sort
- ? {
- ...publicState.flyout.degradedFields.table.sort,
- field: publicState.flyout.degradedFields.table.sort.field as DegradedFieldSortField,
- }
- : DEFAULT_CONTEXT.flyout.degradedFields.table.sort,
- },
- },
- },
filters: {
...DEFAULT_CONTEXT.filters,
...publicState.filters,
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts
index decb7454bd19..81b2de0088a5 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality/types.ts
@@ -9,9 +9,7 @@ import { Observable } from 'rxjs';
import {
DatasetQualityControllerStateService,
WithFilters,
- WithFlyoutOptions,
WithTableOptions,
- DegradedFields,
} from '../../state_machines/dataset_quality_controller';
export interface DatasetQualityController {
@@ -25,25 +23,10 @@ export type DatasetQualityTableOptions = Partial<
Omit & { sort: TableSortOptions }
>;
-type DegradedFieldSortOptions = Omit & { field: string };
-
-export type DatasetQualityDegradedFieldTableOptions = Partial<
- Omit & {
- sort: DegradedFieldSortOptions;
- }
->;
-
-export type DatasetQualityFlyoutOptions = Partial<
- Omit & {
- degradedFields: { table?: DatasetQualityDegradedFieldTableOptions };
- }
->;
-
export type DatasetQualityFilterOptions = Partial;
export interface DatasetQualityPublicState {
table: DatasetQualityTableOptions;
- flyout: DatasetQualityFlyoutOptions;
filters: DatasetQualityFilterOptions;
}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts
index 65ca53c073d4..b5a295a897bd 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/controller/dataset_quality_details/types.ts
@@ -28,7 +28,7 @@ export type DatasetQualityDetailsPublicState = WithDefaultControllerState;
// a must and everything else can be optional. The table inside the
// degradedFields must accept field property as string
export type DatasetQualityDetailsPublicStateUpdate = Partial<
- Pick
+ Pick
> & {
dataStream: string;
} & {
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts
index 5c746e2f1177..ad588fd0b673 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/index.ts
@@ -6,14 +6,13 @@
*/
export * from './use_dataset_quality_table';
-export * from './use_dataset_quality_flyout';
export * from './use_degraded_docs_chart';
export * from './use_redirect_link';
export * from './use_summary_panel';
export * from './use_create_dataview';
-export * from './use_dataset_quality_degraded_field';
-export * from './use_telemetry';
+export * from './use_redirect_link_telemetry';
export * from './use_dataset_quality_details_state';
-export * from './use_dataset_quality_details_redirect_link';
export * from './use_degraded_fields';
export * from './use_integration_actions';
+export * from './use_dataset_telemetry';
+export * from './use_dataset_details_telemetry';
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts
new file mode 100644
index 000000000000..f613d3af7fdc
--- /dev/null
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts
@@ -0,0 +1,200 @@
+/*
+ * 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 { useCallback, useEffect, useMemo } from 'react';
+import { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
+import { getDateISORange } from '@kbn/timerange';
+import { useDatasetQualityDetailsState } from './use_dataset_quality_details_state';
+import { DatasetDetailsEbtProps, NavigationSource, NavigationTarget } from '../services/telemetry';
+import { BasicDataStream, TimeRangeConfig } from '../../common/types';
+import { DataStreamDetails } from '../../common/api_types';
+import { Integration } from '../../common/data_streams_stats/integration';
+import { mapPercentageToQuality } from '../../common/utils';
+import { MASKED_FIELD_PLACEHOLDER, UNKOWN_FIELD_PLACEHOLDER } from '../../common/constants';
+
+export function useDatasetDetailsTelemetry() {
+ const {
+ telemetryClient,
+ datasetDetails,
+ dataStreamDetails,
+ timeRange,
+ canUserViewIntegrations,
+ canUserAccessDashboards,
+ breakdownField,
+ isNonAggregatable,
+ isBreakdownFieldEcs,
+ integrationDetails,
+ loadingState,
+ } = useDatasetQualityDetailsState();
+
+ const ebtProps = useMemo(() => {
+ if (dataStreamDetails && timeRange && !loadingState.dataStreamDetailsLoading) {
+ return getDatasetDetailsEbtProps({
+ datasetDetails,
+ dataStreamDetails,
+ timeRange,
+ canUserViewIntegrations,
+ canUserAccessDashboards,
+ breakdownField,
+ isNonAggregatable,
+ isBreakdownFieldEcs,
+ integration: integrationDetails.integration,
+ });
+ }
+
+ return undefined;
+ }, [
+ dataStreamDetails,
+ timeRange,
+ loadingState.dataStreamDetailsLoading,
+ datasetDetails,
+ canUserViewIntegrations,
+ canUserAccessDashboards,
+ breakdownField,
+ isNonAggregatable,
+ isBreakdownFieldEcs,
+ integrationDetails.integration,
+ ]);
+
+ const startTracking = useCallback(() => {
+ telemetryClient.startDatasetDetailsTracking();
+ }, [telemetryClient]);
+
+ // Report opening dataset details
+ useEffect(() => {
+ const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
+ if (datasetDetailsTrackingState === 'started' && ebtProps) {
+ telemetryClient.trackDatasetDetailsOpened(ebtProps);
+ }
+ }, [ebtProps, telemetryClient]);
+
+ const trackDetailsNavigated = useCallback(
+ (target: NavigationTarget, source: NavigationSource, isDegraded = false) => {
+ const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
+ if (
+ (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') &&
+ ebtProps
+ ) {
+ telemetryClient.trackDatasetDetailsNavigated({
+ ...ebtProps,
+ filters: {
+ is_degraded: isDegraded,
+ },
+ target,
+ source,
+ });
+ } else {
+ throw new Error(
+ 'Cannot report dataset details navigation telemetry without required data and state'
+ );
+ }
+ },
+ [ebtProps, telemetryClient]
+ );
+
+ const trackDatasetDetailsBreakdownFieldChanged = useCallback(() => {
+ const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
+ if (
+ (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') &&
+ ebtProps
+ ) {
+ telemetryClient.trackDatasetDetailsBreakdownFieldChanged({
+ ...ebtProps,
+ breakdown_field: ebtProps.breakdown_field,
+ });
+ }
+ }, [ebtProps, telemetryClient]);
+
+ const wrapLinkPropsForTelemetry = useCallback(
+ (
+ props: RouterLinkProps,
+ target: NavigationTarget,
+ source: NavigationSource,
+ isDegraded = false
+ ) => {
+ return {
+ ...props,
+ onClick: (event: Parameters[0]) => {
+ trackDetailsNavigated(target, source, isDegraded);
+ if (props.onClick) {
+ props.onClick(event);
+ }
+ },
+ };
+ },
+ [trackDetailsNavigated]
+ );
+
+ return {
+ startTracking,
+ trackDetailsNavigated,
+ wrapLinkPropsForTelemetry,
+ navigationTargets: NavigationTarget,
+ navigationSources: NavigationSource,
+ trackDatasetDetailsBreakdownFieldChanged,
+ };
+}
+
+function getDatasetDetailsEbtProps({
+ datasetDetails,
+ dataStreamDetails,
+ timeRange,
+ canUserViewIntegrations,
+ canUserAccessDashboards,
+ breakdownField,
+ isNonAggregatable,
+ isBreakdownFieldEcs,
+ integration,
+}: {
+ datasetDetails: BasicDataStream;
+ dataStreamDetails: DataStreamDetails;
+ timeRange: TimeRangeConfig;
+ canUserViewIntegrations: boolean;
+ canUserAccessDashboards: boolean;
+ breakdownField?: string;
+ isNonAggregatable: boolean;
+ isBreakdownFieldEcs: boolean;
+ integration?: Integration;
+}): DatasetDetailsEbtProps {
+ const indexName = datasetDetails.rawName;
+ const dataStream = {
+ dataset: datasetDetails.name,
+ namespace: datasetDetails.namespace,
+ type: datasetDetails.type,
+ };
+ const degradedDocs = dataStreamDetails?.degradedDocsCount ?? 0;
+ const totalDocs = dataStreamDetails?.docsCount ?? 0;
+ const degradedPercentage =
+ totalDocs > 0 ? Number(((degradedDocs / totalDocs) * 100).toFixed(2)) : 0;
+ const health = mapPercentageToQuality(degradedPercentage);
+ const { startDate: from, endDate: to } = getDateISORange(timeRange);
+
+ return {
+ index_name: indexName,
+ data_stream: dataStream,
+ privileges: {
+ can_monitor_data_stream: true,
+ can_view_integrations: canUserViewIntegrations,
+ can_view_dashboards: canUserAccessDashboards,
+ },
+ data_stream_aggregatable: !isNonAggregatable,
+ data_stream_health: health,
+ from,
+ to,
+ degraded_percentage: degradedPercentage,
+ integration: integration?.name,
+ breakdown_field: breakdownField
+ ? isBreakdownFieldEcs === null
+ ? UNKOWN_FIELD_PLACEHOLDER
+ : getMaskedBreakdownField(breakdownField, isBreakdownFieldEcs)
+ : breakdownField,
+ };
+}
+
+function getMaskedBreakdownField(breakdownField: string, isBreakdownFieldEcs: boolean) {
+ return isBreakdownFieldEcs ? breakdownField : MASKED_FIELD_PLACEHOLDER;
+}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts
deleted file mode 100644
index d92aa5be153f..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_degraded_field.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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 { useSelector } from '@xstate/react';
-import { useCallback, useMemo } from 'react';
-import { orderBy } from 'lodash';
-import { useDatasetQualityContext } from '../components/dataset_quality/context';
-import { DegradedField } from '../../common/data_streams_stats';
-import { SortDirection } from '../../common/types';
-import {
- DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
- DEFAULT_DEGRADED_FIELD_SORT_FIELD,
-} from '../../common/constants';
-import { useKibanaContextForPlugin } from '../utils';
-
-type DegradedFieldSortField = keyof DegradedField;
-
-// TODO: DELETE this hook in favour of new hook post migration
-export function useDatasetQualityDegradedField() {
- const { service } = useDatasetQualityContext();
- const {
- services: { fieldFormats },
- } = useKibanaContextForPlugin();
-
- const degradedFields = useSelector(service, (state) => state.context.flyout.degradedFields) ?? {};
- const { data, table } = degradedFields;
- const { page, rowsPerPage, sort } = table;
-
- const pagination = {
- pageIndex: page,
- pageSize: rowsPerPage,
- totalItemCount: data?.length ?? 0,
- hidePerPageOptions: true,
- };
-
- const onTableChange = useCallback(
- (options: {
- page: { index: number; size: number };
- sort?: { field: DegradedFieldSortField; direction: SortDirection };
- }) => {
- service.send({
- type: 'UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA',
- degraded_field_criteria: {
- page: options.page.index,
- rowsPerPage: options.page.size,
- sort: {
- field: options.sort?.field || DEFAULT_DEGRADED_FIELD_SORT_FIELD,
- direction: options.sort?.direction || DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
- },
- },
- });
- },
- [service]
- );
-
- const renderedItems = useMemo(() => {
- const sortedItems = orderBy(data, sort.field, sort.direction);
- return sortedItems.slice(page * rowsPerPage, (page + 1) * rowsPerPage);
- }, [data, sort.field, sort.direction, page, rowsPerPage]);
-
- const isLoading = useSelector(service, (state) =>
- state.matches('flyout.initializing.dataStreamDegradedFields.fetching')
- );
-
- return {
- isLoading,
- pagination,
- onTableChange,
- renderedItems,
- sort: { sort },
- fieldFormats,
- };
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts
deleted file mode 100644
index 3000d05aa34d..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_redirect_link.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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 {
- SINGLE_DATASET_LOCATOR_ID,
- type SingleDatasetLocatorParams,
-} from '@kbn/deeplinks-observability';
-import { type DiscoverAppLocatorParams, DISCOVER_APP_LOCATOR } from '@kbn/discover-plugin/common';
-import { type Query, type AggregateQuery, buildPhraseFilter } from '@kbn/es-query';
-import { getRouterLinkProps } from '@kbn/router-utils';
-import type { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
-import type { LocatorPublic } from '@kbn/share-plugin/common';
-import type { LocatorClient } from '@kbn/shared-ux-prompt-no-data-views-types';
-import { useKibanaContextForPlugin } from '../utils';
-import { BasicDataStream, TimeRangeConfig } from '../../common/types';
-
-export const useDatasetQualityDetailsRedirectLink = ({
- dataStreamStat,
- query,
- timeRangeConfig,
- breakdownField,
-}: {
- dataStreamStat: T;
- query?: Query | AggregateQuery;
- timeRangeConfig: TimeRangeConfig;
- breakdownField?: string;
-}) => {
- const {
- services: { share },
- } = useKibanaContextForPlugin();
-
- const { from, to } = timeRangeConfig;
-
- const logsExplorerLocator =
- share.url.locators.get(SINGLE_DATASET_LOCATOR_ID);
-
- const config = logsExplorerLocator
- ? buildLogsExplorerConfig({
- locator: logsExplorerLocator,
- dataStreamStat,
- query,
- from,
- to,
- breakdownField,
- })
- : buildDiscoverConfig({
- locatorClient: share.url.locators,
- dataStreamStat,
- query,
- from,
- to,
- breakdownField,
- });
-
- return {
- linkProps: {
- ...config.routerLinkProps,
- },
- navigate: config.navigate,
- isLogsExplorerAvailable: !!logsExplorerLocator,
- };
-};
-
-const buildLogsExplorerConfig = ({
- locator,
- dataStreamStat,
- query,
- from,
- to,
- breakdownField,
-}: {
- locator: LocatorPublic;
- dataStreamStat: T;
- query?: Query | AggregateQuery;
- from: string;
- to: string;
- breakdownField?: string;
-}): {
- navigate: () => void;
- routerLinkProps: RouterLinkProps;
-} => {
- const params: SingleDatasetLocatorParams = {
- dataset: dataStreamStat.name,
- timeRange: {
- from,
- to,
- },
- integration: dataStreamStat.integration?.name,
- query,
- filterControls: {
- namespace: {
- mode: 'include',
- values: [dataStreamStat.namespace],
- },
- },
- breakdownField,
- };
-
- const urlToLogsExplorer = locator.getRedirectUrl(params);
-
- const navigateToLogsExplorer = () => {
- locator.navigate(params) as Promise;
- };
-
- const logsExplorerLinkProps = getRouterLinkProps({
- href: urlToLogsExplorer,
- onClick: navigateToLogsExplorer,
- });
-
- return { routerLinkProps: logsExplorerLinkProps, navigate: navigateToLogsExplorer };
-};
-
-const buildDiscoverConfig = ({
- locatorClient,
- dataStreamStat,
- query,
- from,
- to,
- breakdownField,
-}: {
- locatorClient: LocatorClient;
- dataStreamStat: T;
- query?: Query | AggregateQuery;
- from: string;
- to: string;
- breakdownField?: string;
-}): {
- navigate: () => void;
- routerLinkProps: RouterLinkProps;
-} => {
- const dataViewId = `${dataStreamStat.type}-${dataStreamStat.name}-*`;
- const dataViewTitle = dataStreamStat.integration
- ? `[${dataStreamStat.integration.title}] ${dataStreamStat.name}`
- : `${dataViewId}`;
-
- const params: DiscoverAppLocatorParams = {
- timeRange: {
- from,
- to,
- },
- refreshInterval: {
- pause: true,
- value: 60000,
- },
- dataViewId,
- dataViewSpec: {
- id: dataViewId,
- title: dataViewTitle,
- },
- query,
- breakdownField,
- columns: ['@timestamp', 'message'],
- filters: [
- buildPhraseFilter(
- {
- name: 'data_stream.namespace',
- type: 'string',
- },
- dataStreamStat.namespace,
- {
- id: dataViewId,
- title: dataViewTitle,
- }
- ),
- ],
- interval: 'auto',
- sort: [['@timestamp', 'desc']],
- };
-
- const locator = locatorClient.get(DISCOVER_APP_LOCATOR);
-
- const urlToDiscover = locator?.getRedirectUrl(params);
-
- const navigateToDiscover = () => {
- locator?.navigate(params) as Promise;
- };
-
- const discoverLinkProps = getRouterLinkProps({
- href: urlToDiscover,
- onClick: navigateToDiscover,
- });
-
- return { routerLinkProps: discoverLinkProps, navigate: navigateToDiscover };
-};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts
index 4b0626f95158..146ff9e5aa41 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts
@@ -15,7 +15,7 @@ import { BasicDataStream } from '../../common/types';
import { useKibanaContextForPlugin } from '../utils';
export const useDatasetQualityDetailsState = () => {
- const { service } = useDatasetQualityDetailsContext();
+ const { service, telemetryClient } = useDatasetQualityDetailsContext();
const {
services: { fieldFormats },
@@ -36,6 +36,14 @@ export const useDatasetQualityDetailsState = () => {
: false
);
+ const isBreakdownFieldAsserted = useSelector(
+ service,
+ (state) =>
+ state.matches('initializing.checkBreakdownFieldIsEcs.done') &&
+ breakdownField &&
+ isBreakdownFieldEcs
+ );
+
const dataStreamSettings = useSelector(service, (state) =>
state.matches('initializing.dataStreamSettings.initializeIntegrations')
? state.context.dataStreamSettings
@@ -67,7 +75,9 @@ export const useDatasetQualityDetailsState = () => {
)
);
- const canUserViewIntegrations = dataStreamSettings?.datasetUserPrivileges?.canViewIntegrations;
+ const canUserViewIntegrations = Boolean(
+ dataStreamSettings?.datasetUserPrivileges?.canViewIntegrations
+ );
const dataStreamDetails = useSelector(service, (state) =>
state.matches('initializing.dataStreamDetails.done')
@@ -115,6 +125,7 @@ export const useDatasetQualityDetailsState = () => {
return {
service,
+ telemetryClient,
fieldFormats,
isIndexNotFoundError,
dataStream,
@@ -123,6 +134,7 @@ export const useDatasetQualityDetailsState = () => {
dataStreamDetails,
breakdownField,
isBreakdownFieldEcs,
+ isBreakdownFieldAsserted,
isNonAggregatable,
timeRange,
loadingState,
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.ts
similarity index 100%
rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.tsx
rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_filters.ts
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx
deleted file mode 100644
index 0f9d7981e619..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_flyout.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 { useSelector } from '@xstate/react';
-import { useDatasetQualityContext } from '../components/dataset_quality/context';
-import { useKibanaContextForPlugin } from '../utils';
-
-export const useDatasetQualityFlyout = () => {
- const {
- services: { fieldFormats },
- } = useKibanaContextForPlugin();
-
- const { service } = useDatasetQualityContext();
-
- const {
- dataset: dataStreamStat,
- dataStreamSettings,
- datasetDetails: dataStreamDetails,
- insightsTimeRange,
- breakdownField,
- isNonAggregatable,
- integration,
- } = useSelector(service, (state) => state.context.flyout) ?? {};
-
- const { timeRange } = useSelector(service, (state) => state.context.filters);
-
- const loadingState = useSelector(service, (state) => ({
- dataStreamDetailsLoading: state.matches('flyout.initializing.dataStreamDetails.fetching'),
- dataStreamSettingsLoading: state.matches('flyout.initializing.dataStreamSettings.fetching'),
- datasetIntegrationDashboardLoading: state.matches(
- 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.fetching'
- ),
- datasetIntegrationDone: state.matches(
- 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDetails.done'
- ),
- }));
-
- const canUserAccessDashboards = useSelector(
- service,
- (state) =>
- !state.matches(
- 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.unauthorized'
- )
- );
-
- const canUserViewIntegrations = useSelector(
- service,
- (state) => state.context.datasetUserPrivileges.canViewIntegrations
- );
-
- return {
- dataStreamStat,
- dataStreamSettings,
- dataStreamDetails,
- isNonAggregatable,
- integration,
- fieldFormats,
- timeRange: insightsTimeRange ?? timeRange,
- breakdownField,
- loadingState,
- flyoutLoading: !dataStreamStat,
- canUserAccessDashboards,
- canUserViewIntegrations,
- };
-};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx
index b205a58dfb98..3a3475eabeed 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_table.tsx
@@ -14,7 +14,6 @@ import { DataStreamStat } from '../../common/data_streams_stats/data_stream_stat
import { tableSummaryAllText, tableSummaryOfText } from '../../common/translations';
import { getDatasetQualityTableColumns } from '../components/dataset_quality/table/columns';
import { useDatasetQualityContext } from '../components/dataset_quality/context';
-import { FlyoutDataset } from '../state_machines/dataset_quality_controller';
import { useKibanaContextForPlugin } from '../utils';
import { filterInactiveDatasets, isActiveDataset } from '../utils/filter_inactive_datasets';
import { SortDirection } from '../../common/types';
@@ -30,7 +29,10 @@ const sortingOverrides: Partial<{
export const useDatasetQualityTable = () => {
const {
- services: { fieldFormats },
+ services: {
+ fieldFormats,
+ share: { url },
+ },
} = useKibanaContextForPlugin();
const { service } = useDatasetQualityContext();
@@ -61,8 +63,6 @@ export const useDatasetQualityTable = () => {
} = useSelector(service, (state) => state.context.filters);
const showInactiveDatasets = inactive || !canUserMonitorDataset;
- const flyout = useSelector(service, (state) => state.context.flyout);
-
const loading = useSelector(
service,
(state) =>
@@ -89,33 +89,6 @@ export const useDatasetQualityTable = () => {
[service]
);
- const closeFlyout = useCallback(() => service.send({ type: 'CLOSE_FLYOUT' }), [service]);
- const openFlyout = useCallback(
- (selectedDataset: FlyoutDataset) => {
- if (flyout?.dataset?.rawName === selectedDataset.rawName) {
- service.send({
- type: 'CLOSE_FLYOUT',
- });
-
- return;
- }
-
- if (!flyout?.insightsTimeRange) {
- service.send({
- type: 'OPEN_FLYOUT',
- dataset: selectedDataset,
- });
- return;
- }
-
- service.send({
- type: 'SELECT_NEW_DATASET',
- dataset: selectedDataset,
- });
- },
- [flyout?.dataset?.rawName, flyout?.insightsTimeRange, service]
- );
-
const isActive = useCallback(
(lastActivity: number) => isActiveDataset({ lastActivity, timeRange }),
[timeRange]
@@ -127,27 +100,25 @@ export const useDatasetQualityTable = () => {
fieldFormats,
canUserMonitorDataset,
canUserMonitorAnyDataStream,
- selectedDataset: flyout?.dataset,
- openFlyout,
loadingDataStreamStats,
loadingDegradedStats,
showFullDatasetNames,
isSizeStatsAvailable,
isActiveDataset: isActive,
timeRange,
+ urlService: url,
}),
[
fieldFormats,
canUserMonitorDataset,
canUserMonitorAnyDataStream,
- flyout?.dataset,
- openFlyout,
loadingDataStreamStats,
loadingDegradedStats,
showFullDatasetNames,
isSizeStatsAvailable,
isActive,
timeRange,
+ url,
]
);
@@ -235,8 +206,6 @@ export const useDatasetQualityTable = () => {
columns,
loading,
resultsCount,
- closeFlyout,
- selectedDataset: flyout?.dataset,
showInactiveDatasets,
showFullDatasetNames,
canUserMonitorDataset,
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.ts
new file mode 100644
index 000000000000..167ebd37fe81
--- /dev/null
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_telemetry.ts
@@ -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 { useSelector } from '@xstate/react';
+import { useCallback } from 'react';
+import { getDateISORange } from '@kbn/timerange';
+import { useDatasetQualityContext } from '../components/dataset_quality/context';
+import { useDatasetQualityFilters } from './use_dataset_quality_filters';
+import { DataStreamStat } from '../../common/data_streams_stats';
+import { DatasetEbtProps, DatasetNavigatedEbtProps } from '../services/telemetry';
+
+export function useDatasetTelemetry() {
+ const { service, telemetryClient } = useDatasetQualityContext();
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const datasets = useSelector(service, (state) => state.context.datasets) ?? {};
+ const nonAggregatableDatasets = useSelector(
+ service,
+ (state) => state.context.nonAggregatableDatasets
+ );
+ const canUserViewIntegrations = useSelector(
+ service,
+ (state) => state.context.datasetUserPrivileges.canViewIntegrations
+ );
+ const sort = useSelector(service, (state) => state.context.table.sort);
+ const appliedFilters = useDatasetQualityFilters();
+
+ const trackDatasetNavigated = useCallback<(rawName: string, isIgnoredFilter: boolean) => void>(
+ (rawName: string, isIgnoredFilter: boolean) => {
+ const foundDataset = datasets.find((dataset) => dataset.rawName === rawName);
+ if (foundDataset) {
+ const ebtProps = getDatasetEbtProps(
+ foundDataset,
+ sort,
+ appliedFilters,
+ nonAggregatableDatasets,
+ isIgnoredFilter,
+ canUserViewIntegrations
+ );
+ telemetryClient.trackDatasetNavigated(ebtProps);
+ } else {
+ throw new Error(
+ `Cannot report dataset navigation telemetry for unknown dataset ${rawName}`
+ );
+ }
+ },
+ [
+ sort,
+ appliedFilters,
+ canUserViewIntegrations,
+ datasets,
+ nonAggregatableDatasets,
+ telemetryClient,
+ ]
+ );
+
+ return { trackDatasetNavigated };
+}
+
+function getDatasetEbtProps(
+ dataset: DataStreamStat,
+ sort: { field: string; direction: 'asc' | 'desc' },
+ filters: ReturnType,
+ nonAggregatableDatasets: string[],
+ isIgnoredFilter: boolean,
+ canUserViewIntegrations: boolean
+): DatasetNavigatedEbtProps {
+ const { startDate: from, endDate: to } = getDateISORange(filters.timeRange);
+ const datasetEbtProps: DatasetEbtProps = {
+ index_name: dataset.rawName,
+ data_stream: {
+ dataset: dataset.name,
+ namespace: dataset.namespace,
+ type: dataset.type,
+ },
+ data_stream_health: dataset.degradedDocs.quality,
+ data_stream_aggregatable: nonAggregatableDatasets.some(
+ (indexName) => indexName === dataset.rawName
+ ),
+ from,
+ to,
+ degraded_percentage: dataset.degradedDocs.percentage,
+ integration: dataset.integration?.name,
+ privileges: {
+ can_monitor_data_stream: dataset.userPrivileges?.canMonitor ?? true,
+ can_view_integrations: canUserViewIntegrations,
+ },
+ };
+
+ const ebtFilters: DatasetNavigatedEbtProps['filters'] = {
+ is_degraded: isIgnoredFilter,
+ query_length: filters.selectedQuery?.length ?? 0,
+ integrations: {
+ total: filters.integrations.filter((item) => item.name !== 'none').length,
+ included: filters.integrations.filter((item) => item?.checked === 'on').length,
+ excluded: filters.integrations.filter((item) => item?.checked === 'off').length,
+ },
+ namespaces: {
+ total: filters.namespaces.length,
+ included: filters.namespaces.filter((item) => item?.checked === 'on').length,
+ excluded: filters.namespaces.filter((item) => item?.checked === 'off').length,
+ },
+ qualities: {
+ total: filters.qualities.length,
+ included: filters.qualities.filter((item) => item?.checked === 'on').length,
+ excluded: filters.qualities.filter((item) => item?.checked === 'off').length,
+ },
+ };
+
+ return {
+ ...datasetEbtProps,
+ sort,
+ filters: ebtFilters,
+ };
+}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts
similarity index 80%
rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts
rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts
index 7842fe81966f..795700bfc944 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { useCallback, useState, useMemo, useEffect } from 'react';
+import { useCallback, useEffect, useMemo, useState } from 'react';
import type { Action } from '@kbn/ui-actions-plugin/public';
import { fieldSupportsBreakdown } from '@kbn/unified-histogram-plugin/public';
import { i18n } from '@kbn/i18n';
@@ -16,7 +16,9 @@ import { useCreateDataView } from './use_create_dataview';
import { useKibanaContextForPlugin } from '../utils';
import { useDatasetQualityDetailsState } from './use_dataset_quality_details_state';
import { getLensAttributes } from '../components/dataset_quality_details/overview/document_trends/degraded_docs/lens_attributes';
-import { useDatasetQualityDetailsRedirectLink } from './use_dataset_quality_details_redirect_link';
+import { useRedirectLink } from './use_redirect_link';
+import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry';
+import { useDatasetDetailsRedirectLinkTelemetry } from './use_redirect_link_telemetry';
const exploreDataInLogsExplorerText = i18n.translate(
'xpack.datasetQuality.details.chartExploreDataInLogsExplorerText',
@@ -39,13 +41,27 @@ const openInLensText = i18n.translate('xpack.datasetQuality.details.chartOpenInL
const ACTION_EXPLORE_IN_LOGS_EXPLORER = 'ACTION_EXPLORE_IN_LOGS_EXPLORER';
const ACTION_OPEN_IN_LENS = 'ACTION_OPEN_IN_LENS';
-export const useDegradedDocs = () => {
+export const useDegradedDocsChart = () => {
const { euiTheme } = useEuiTheme();
const {
services: { lens },
} = useKibanaContextForPlugin();
- const { service, dataStream, datasetDetails, timeRange, breakdownField, integrationDetails } =
- useDatasetQualityDetailsState();
+ const {
+ service,
+ dataStream,
+ datasetDetails,
+ timeRange,
+ breakdownField,
+ integrationDetails,
+ isBreakdownFieldAsserted,
+ } = useDatasetQualityDetailsState();
+
+ const {
+ trackDatasetDetailsBreakdownFieldChanged,
+ trackDetailsNavigated,
+ navigationTargets,
+ navigationSources,
+ } = useDatasetDetailsTelemetry();
const [isChartLoading, setIsChartLoading] = useState(undefined);
const [attributes, setAttributes] = useState | undefined>(
@@ -75,6 +91,10 @@ export const useDegradedDocs = () => {
[service]
);
+ useEffect(() => {
+ if (isBreakdownFieldAsserted) trackDatasetDetailsBreakdownFieldChanged();
+ }, [trackDatasetDetailsBreakdownFieldChanged, isBreakdownFieldAsserted]);
+
useEffect(() => {
const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW;
const datasetTitle =
@@ -98,13 +118,21 @@ export const useDegradedDocs = () => {
const openInLensCallback = useCallback(() => {
if (attributes) {
+ trackDetailsNavigated(navigationTargets.Lens, navigationSources.Chart);
lens.navigateToPrefilledEditor({
id: '',
timeRange,
attributes,
});
}
- }, [attributes, lens, timeRange]);
+ }, [
+ attributes,
+ lens,
+ navigationSources.Chart,
+ navigationTargets.Lens,
+ timeRange,
+ trackDetailsNavigated,
+ ]);
const getOpenInLensAction = useMemo(() => {
return {
@@ -126,11 +154,17 @@ export const useDegradedDocs = () => {
};
}, [openInLensCallback]);
- const redirectLinkProps = useDatasetQualityDetailsRedirectLink({
+ const { sendTelemetry } = useDatasetDetailsRedirectLinkTelemetry({
+ query: { language: 'kuery', query: '_ignored:*' },
+ navigationSource: navigationSources.Chart,
+ });
+
+ const redirectLinkProps = useRedirectLink({
dataStreamStat: datasetDetails,
query: { language: 'kuery', query: '_ignored:*' },
timeRangeConfig: timeRange,
breakdownField: breakdownDataViewField?.name,
+ sendTelemetry,
});
const getOpenInLogsExplorerAction = useMemo(() => {
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx
deleted file mode 100644
index 6840f2a4088a..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * 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 { useCallback, useState, useMemo, useEffect } from 'react';
-import { Action } from '@kbn/ui-actions-plugin/public';
-import { fieldSupportsBreakdown } from '@kbn/unified-histogram-plugin/public';
-import { useSelector } from '@xstate/react';
-import { i18n } from '@kbn/i18n';
-import { useEuiTheme } from '@elastic/eui';
-import { type DataView, DataViewField } from '@kbn/data-views-plugin/common';
-import { useDatasetQualityContext } from '../components/dataset_quality/context';
-import { DEFAULT_LOGS_DATA_VIEW } from '../../common/constants';
-import { useCreateDataView } from './use_create_dataview';
-import { useRedirectLink } from './use_redirect_link';
-import { useDatasetQualityFlyout } from './use_dataset_quality_flyout';
-import { useKibanaContextForPlugin } from '../utils';
-import { useDatasetDetailsTelemetry } from './use_telemetry';
-import { getLensAttributes } from '../components/dataset_quality_details/overview/document_trends/degraded_docs/lens_attributes';
-
-const exploreDataInLogsExplorerText = i18n.translate(
- 'xpack.datasetQuality.flyoutChartExploreDataInLogsExplorerText',
- {
- defaultMessage: 'Explore data in Logs Explorer',
- }
-);
-
-const exploreDataInDiscoverText = i18n.translate(
- 'xpack.datasetQuality.flyoutChartExploreDataInDiscoverText',
- {
- defaultMessage: 'Explore data in Discover',
- }
-);
-
-const openInLensText = i18n.translate('xpack.datasetQuality.flyoutChartOpenInLensText', {
- defaultMessage: 'Open in Lens',
-});
-
-const ACTION_EXPLORE_IN_LOGS_EXPLORER = 'ACTION_EXPLORE_IN_LOGS_EXPLORER';
-const ACTION_OPEN_IN_LENS = 'ACTION_OPEN_IN_LENS';
-
-interface DegradedDocsChartDeps {
- dataStream?: string;
- breakdownField?: string;
-}
-
-export const useDegradedDocsChart = ({ dataStream }: DegradedDocsChartDeps) => {
- const { euiTheme } = useEuiTheme();
- const {
- services: { lens },
- } = useKibanaContextForPlugin();
- const { service } = useDatasetQualityContext();
-
- const {
- trackDatasetDetailsBreakdownFieldChanged,
- trackDetailsNavigated,
- navigationTargets,
- navigationSources,
- } = useDatasetDetailsTelemetry();
-
- const { dataStreamStat, timeRange, breakdownField } = useDatasetQualityFlyout();
-
- const isBreakdownFieldEcs = useSelector(
- service,
- (state) => state.context.flyout.isBreakdownFieldEcs
- );
-
- const isBreakdownFieldEcsAsserted = useSelector(service, (state) => {
- return (
- state.matches('flyout.initializing.assertBreakdownFieldIsEcs.done') &&
- state.history?.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching') &&
- isBreakdownFieldEcs !== null
- );
- });
-
- const [isChartLoading, setIsChartLoading] = useState(undefined);
- const [attributes, setAttributes] = useState | undefined>(
- undefined
- );
-
- const { dataView } = useCreateDataView({
- indexPatternString: getDataViewIndexPattern(dataStream),
- });
-
- const breakdownDataViewField = useMemo(
- () => getDataViewField(dataView, breakdownField),
- [breakdownField, dataView]
- );
-
- const handleChartLoading = (isLoading: boolean) => {
- setIsChartLoading(isLoading);
- };
-
- const handleBreakdownFieldChange = useCallback(
- (field: DataViewField | undefined) => {
- service.send({
- type: 'BREAKDOWN_FIELD_CHANGE',
- breakdownField: field?.name ?? null,
- });
- },
- [service]
- );
-
- useEffect(() => {
- if (isBreakdownFieldEcsAsserted) trackDatasetDetailsBreakdownFieldChanged();
- }, [trackDatasetDetailsBreakdownFieldChanged, isBreakdownFieldEcsAsserted]);
-
- useEffect(() => {
- const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW;
-
- const lensAttributes = getLensAttributes({
- color: euiTheme.colors.danger,
- dataStream: dataStreamName,
- datasetTitle: dataStreamStat?.title ?? dataStreamName,
- breakdownFieldName: breakdownDataViewField?.name,
- });
- setAttributes(lensAttributes);
- }, [
- breakdownDataViewField?.name,
- euiTheme.colors.danger,
- setAttributes,
- dataStream,
- dataStreamStat?.title,
- ]);
-
- const openInLensCallback = useCallback(() => {
- if (attributes) {
- trackDetailsNavigated(navigationTargets.Lens, navigationSources.Chart);
- lens.navigateToPrefilledEditor({
- id: '',
- timeRange,
- attributes,
- });
- }
- }, [attributes, trackDetailsNavigated, navigationTargets, navigationSources, lens, timeRange]);
-
- const getOpenInLensAction = useMemo(() => {
- return {
- id: ACTION_OPEN_IN_LENS,
- type: 'link',
- order: 17,
- getDisplayName(): string {
- return openInLensText;
- },
- getIconType(): string {
- return 'visArea';
- },
- async isCompatible(): Promise {
- return true;
- },
- async execute(): Promise {
- return openInLensCallback();
- },
- };
- }, [openInLensCallback]);
-
- const redirectLinkProps = useRedirectLink({
- dataStreamStat: dataStreamStat!,
- query: { language: 'kuery', query: '_ignored:*' },
- timeRangeConfig: timeRange,
- breakdownField: breakdownDataViewField?.name,
- telemetry: {
- page: 'details',
- navigationSource: navigationSources.Chart,
- },
- });
-
- const getOpenInLogsExplorerAction = useMemo(() => {
- return {
- id: ACTION_EXPLORE_IN_LOGS_EXPLORER,
- type: 'link',
- getDisplayName(): string {
- return redirectLinkProps?.isLogsExplorerAvailable
- ? exploreDataInLogsExplorerText
- : exploreDataInDiscoverText;
- },
- getHref: async () => {
- return redirectLinkProps.linkProps.href;
- },
- getIconType(): string | undefined {
- return 'visTable';
- },
- async isCompatible(): Promise {
- return true;
- },
- async execute(): Promise {
- return redirectLinkProps.navigate();
- },
- order: 18,
- };
- }, [redirectLinkProps]);
-
- const extraActions: Action[] = [getOpenInLensAction, getOpenInLogsExplorerAction];
-
- return {
- attributes,
- dataView,
- breakdown: {
- dataViewField: breakdownDataViewField,
- fieldSupportsBreakdown: breakdownDataViewField
- ? fieldSupportsBreakdown(breakdownDataViewField)
- : true,
- onChange: handleBreakdownFieldChange,
- },
- extraActions,
- isChartLoading,
- onChartLoading: handleChartLoading,
- setAttributes,
- setIsChartLoading,
- };
-};
-
-function getDataViewIndexPattern(dataStream: string | undefined) {
- return dataStream ?? DEFAULT_LOGS_DATA_VIEW;
-}
-
-function getDataViewField(dataView: DataView | undefined, fieldName: string | undefined) {
- return fieldName && dataView
- ? dataView.fields.find((field) => field.name === fieldName)
- : undefined;
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx
deleted file mode 100644
index b0f47716100b..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_flyout_integration_actions.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 { getRouterLinkProps } from '@kbn/router-utils';
-import { useMemo, useCallback } from 'react';
-import useToggle from 'react-use/lib/useToggle';
-import { MANAGEMENT_APP_LOCATOR } from '@kbn/deeplinks-management/constants';
-import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
-import { useKibanaContextForPlugin } from '../utils';
-import { Dashboard } from '../../common/api_types';
-import { useDatasetDetailsTelemetry } from './use_telemetry';
-
-export const useFlyoutIntegrationActions = () => {
- const {
- services: {
- application: { navigateToUrl },
- http: { basePath },
- share,
- },
- } = useKibanaContextForPlugin();
- const { wrapLinkPropsForTelemetry, navigationSources, navigationTargets } =
- useDatasetDetailsTelemetry();
-
- const [isOpen, toggleIsOpen] = useToggle(false);
-
- const dashboardLocator = useMemo(
- () => share.url.locators.get(DASHBOARD_APP_LOCATOR),
- [share.url.locators]
- );
- const indexManagementLocator = useMemo(
- () => share.url.locators.get(MANAGEMENT_APP_LOCATOR),
- [share.url.locators]
- );
-
- const handleCloseMenu = useCallback(() => {
- toggleIsOpen();
- }, [toggleIsOpen]);
- const handleToggleMenu = useCallback(() => {
- toggleIsOpen();
- }, [toggleIsOpen]);
-
- const getIntegrationOverviewLinkProps = useCallback(
- (name: string, version: string) => {
- const href = basePath.prepend(`/app/integrations/detail/${name}-${version}/overview`);
- return wrapLinkPropsForTelemetry(
- getRouterLinkProps({
- href,
- onClick: () => {
- return navigateToUrl(href);
- },
- }),
- navigationTargets.Integration,
- navigationSources.ActionMenu
- );
- },
- [basePath, navigateToUrl, navigationSources, navigationTargets, wrapLinkPropsForTelemetry]
- );
- const getIndexManagementLinkProps = useCallback(
- (params: { sectionId: string; appId: string }) =>
- wrapLinkPropsForTelemetry(
- getRouterLinkProps({
- href: indexManagementLocator?.getRedirectUrl(params),
- onClick: () => {
- return indexManagementLocator?.navigate(params);
- },
- }),
- navigationTargets.IndexTemplate,
- navigationSources.ActionMenu
- ),
- [
- indexManagementLocator,
- navigationSources.ActionMenu,
- navigationTargets.IndexTemplate,
- wrapLinkPropsForTelemetry,
- ]
- );
- const getDashboardLinkProps = useCallback(
- (dashboard: Dashboard) =>
- wrapLinkPropsForTelemetry(
- getRouterLinkProps({
- href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''),
- onClick: () => {
- return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || '');
- },
- }),
- navigationTargets.Dashboard,
- navigationSources.ActionMenu
- ),
- [dashboardLocator, navigationSources, navigationTargets, wrapLinkPropsForTelemetry]
- );
-
- return {
- isOpen,
- handleCloseMenu,
- handleToggleMenu,
- getIntegrationOverviewLinkProps,
- getIndexManagementLinkProps,
- getDashboardLinkProps,
- };
-};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts
index 0fce743875a6..165ac2a65180 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_integration_actions.ts
@@ -12,6 +12,7 @@ import { MANAGEMENT_APP_LOCATOR } from '@kbn/deeplinks-management/constants';
import { DASHBOARD_APP_LOCATOR } from '@kbn/deeplinks-analytics';
import { useKibanaContextForPlugin } from '../utils';
import { Dashboard } from '../../common/api_types';
+import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry';
export const useIntegrationActions = () => {
const {
@@ -21,6 +22,8 @@ export const useIntegrationActions = () => {
share,
},
} = useKibanaContextForPlugin();
+ const { wrapLinkPropsForTelemetry, navigationSources, navigationTargets } =
+ useDatasetDetailsTelemetry();
const [isOpen, toggleIsOpen] = useToggle(false);
@@ -43,34 +46,51 @@ export const useIntegrationActions = () => {
const getIntegrationOverviewLinkProps = useCallback(
(name: string, version: string) => {
const href = basePath.prepend(`/app/integrations/detail/${name}-${version}/overview`);
- return getRouterLinkProps({
- href,
- onClick: () => {
- return navigateToUrl(href);
- },
- });
+ return wrapLinkPropsForTelemetry(
+ getRouterLinkProps({
+ href,
+ onClick: () => {
+ return navigateToUrl(href);
+ },
+ }),
+ navigationTargets.Integration,
+ navigationSources.ActionMenu
+ );
},
- [basePath, navigateToUrl]
+ [basePath, navigateToUrl, navigationSources, navigationTargets, wrapLinkPropsForTelemetry]
);
const getIndexManagementLinkProps = useCallback(
(params: { sectionId: string; appId: string }) =>
- getRouterLinkProps({
- href: indexManagementLocator?.getRedirectUrl(params),
- onClick: () => {
- return indexManagementLocator?.navigate(params);
- },
- }),
- [indexManagementLocator]
+ wrapLinkPropsForTelemetry(
+ getRouterLinkProps({
+ href: indexManagementLocator?.getRedirectUrl(params),
+ onClick: () => {
+ return indexManagementLocator?.navigate(params);
+ },
+ }),
+ navigationTargets.IndexTemplate,
+ navigationSources.ActionMenu
+ ),
+ [
+ indexManagementLocator,
+ navigationSources.ActionMenu,
+ navigationTargets.IndexTemplate,
+ wrapLinkPropsForTelemetry,
+ ]
);
const getDashboardLinkProps = useCallback(
(dashboard: Dashboard) =>
- getRouterLinkProps({
- href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''),
- onClick: () => {
- return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || '');
- },
- }),
- [dashboardLocator]
+ wrapLinkPropsForTelemetry(
+ getRouterLinkProps({
+ href: dashboardLocator?.getRedirectUrl({ dashboardId: dashboard?.id } || ''),
+ onClick: () => {
+ return dashboardLocator?.navigate({ dashboardId: dashboard?.id } || '');
+ },
+ }),
+ navigationTargets.Dashboard,
+ navigationSources.ActionMenu
+ ),
+ [dashboardLocator, navigationSources, navigationTargets, wrapLinkPropsForTelemetry]
);
return {
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts
index e4fbf0771ee1..d83ad8299e26 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link.ts
@@ -18,20 +18,20 @@ import { LocatorPublic } from '@kbn/share-plugin/common';
import { LocatorClient } from '@kbn/shared-ux-prompt-no-data-views-types';
import { useKibanaContextForPlugin } from '../utils';
import { BasicDataStream, TimeRangeConfig } from '../../common/types';
-import { useRedirectLinkTelemetry } from './use_telemetry';
+import { SendTelemetryFn } from './use_redirect_link_telemetry';
export const useRedirectLink = ({
dataStreamStat,
query,
timeRangeConfig,
breakdownField,
- telemetry,
+ sendTelemetry,
}: {
dataStreamStat: T;
query?: Query | AggregateQuery;
timeRangeConfig: TimeRangeConfig;
breakdownField?: string;
- telemetry?: Parameters[0]['telemetry'];
+ sendTelemetry: SendTelemetryFn;
}) => {
const {
services: { share },
@@ -42,13 +42,6 @@ export const useRedirectLink = ({
const logsExplorerLocator =
share.url.locators.get(SINGLE_DATASET_LOCATOR_ID);
- const { sendTelemetry } = useRedirectLinkTelemetry({
- rawName: dataStreamStat.rawName,
- isLogsExplorer: !!logsExplorerLocator,
- telemetry,
- query,
- });
-
return useMemo<{
linkProps: RouterLinkProps;
navigate: () => void;
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.ts
new file mode 100644
index 000000000000..a70de0bd2029
--- /dev/null
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_redirect_link_telemetry.ts
@@ -0,0 +1,75 @@
+/*
+ * 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 { useCallback } from 'react';
+import { AggregateQuery, Query } from '@kbn/es-query';
+import {
+ SINGLE_DATASET_LOCATOR_ID,
+ SingleDatasetLocatorParams,
+} from '@kbn/deeplinks-observability';
+import { NavigationSource } from '../services/telemetry';
+import { useDatasetTelemetry } from './use_dataset_telemetry';
+import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry';
+import { useKibanaContextForPlugin } from '../utils';
+
+export type SendTelemetryFn =
+ | ReturnType['sendTelemetry']
+ | ReturnType['sendTelemetry'];
+
+export const useDatasetRedirectLinkTelemetry = ({
+ rawName,
+ query,
+}: {
+ rawName: string;
+ query?: Query | AggregateQuery;
+}) => {
+ const { trackDatasetNavigated } = useDatasetTelemetry();
+
+ const sendTelemetry = useCallback(() => {
+ const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false;
+
+ trackDatasetNavigated(rawName, isIgnoredFilter);
+ }, [query, rawName, trackDatasetNavigated]);
+
+ return {
+ sendTelemetry,
+ };
+};
+
+export const useDatasetDetailsRedirectLinkTelemetry = ({
+ query,
+ navigationSource,
+}: {
+ navigationSource: NavigationSource;
+ query?: Query | AggregateQuery;
+}) => {
+ const {
+ services: { share },
+ } = useKibanaContextForPlugin();
+ const logsExplorerLocator =
+ share.url.locators.get(SINGLE_DATASET_LOCATOR_ID);
+ const isLogsExplorer = !!logsExplorerLocator;
+ const { trackDetailsNavigated, navigationTargets } = useDatasetDetailsTelemetry();
+
+ const sendTelemetry = useCallback(() => {
+ const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false;
+ const target = isLogsExplorer ? navigationTargets.LogsExplorer : navigationTargets.Discover;
+
+ trackDetailsNavigated(target, navigationSource, isIgnoredFilter);
+ }, [
+ query,
+ isLogsExplorer,
+ navigationTargets.LogsExplorer,
+ navigationTargets.Discover,
+ trackDetailsNavigated,
+ navigationSource,
+ ]);
+
+ return {
+ sendTelemetry,
+ };
+};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts
similarity index 100%
rename from x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.tsx
rename to x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx
deleted file mode 100644
index c473495c0a66..000000000000
--- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_telemetry.tsx
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * 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 { RouterLinkProps } from '@kbn/router-utils/src/get_router_link_props';
-import { useCallback, useEffect, useMemo } from 'react';
-import { useSelector } from '@xstate/react';
-import { getDateISORange } from '@kbn/timerange';
-import { AggregateQuery, Query } from '@kbn/es-query';
-
-import { MASKED_FIELD_PLACEHOLDER, UNKOWN_FIELD_PLACEHOLDER } from '../../common/constants';
-import { DataStreamStat } from '../../common/data_streams_stats';
-import { DataStreamDetails } from '../../common/api_types';
-import { mapPercentageToQuality } from '../../common/utils';
-import {
- NavigationTarget,
- NavigationSource,
- DatasetDetailsEbtProps,
- DatasetNavigatedEbtProps,
- DatasetEbtProps,
-} from '../services/telemetry';
-import { FlyoutDataset } from '../state_machines/dataset_quality_controller';
-import { useDatasetQualityContext } from '../components/dataset_quality/context';
-import { useDatasetQualityFilters } from './use_dataset_quality_filters';
-import { TimeRangeConfig } from '../../common/types';
-
-export const useRedirectLinkTelemetry = ({
- rawName,
- isLogsExplorer,
- telemetry,
- query,
-}: {
- rawName: string;
- isLogsExplorer: boolean;
- telemetry?: {
- page: 'main' | 'details';
- navigationSource: NavigationSource;
- };
- query?: Query | AggregateQuery;
-}) => {
- const { trackDatasetNavigated } = useDatasetTelemetry();
- const { trackDetailsNavigated, navigationTargets } = useDatasetDetailsTelemetry();
-
- const sendTelemetry = useCallback(() => {
- if (telemetry) {
- const isIgnoredFilter = query ? JSON.stringify(query).includes('_ignored') : false;
- if (telemetry.page === 'main') {
- trackDatasetNavigated(rawName, isIgnoredFilter);
- } else {
- trackDetailsNavigated(
- isLogsExplorer ? navigationTargets.LogsExplorer : navigationTargets.Discover,
- telemetry.navigationSource,
- isIgnoredFilter
- );
- }
- }
- }, [
- isLogsExplorer,
- trackDetailsNavigated,
- navigationTargets,
- query,
- rawName,
- telemetry,
- trackDatasetNavigated,
- ]);
-
- const wrapLinkPropsForTelemetry = useCallback(
- (props: RouterLinkProps) => {
- return {
- ...props,
- onClick: (event: Parameters[0]) => {
- sendTelemetry();
- if (props.onClick) {
- props.onClick(event);
- }
- },
- };
- },
- [sendTelemetry]
- );
-
- return {
- wrapLinkPropsForTelemetry,
- sendTelemetry,
- };
-};
-
-export const useDatasetTelemetry = () => {
- const { service, telemetryClient } = useDatasetQualityContext();
-
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const datasets = useSelector(service, (state) => state.context.datasets) ?? {};
- const nonAggregatableDatasets = useSelector(
- service,
- (state) => state.context.nonAggregatableDatasets
- );
- const canUserViewIntegrations = useSelector(
- service,
- (state) => state.context.datasetUserPrivileges.canViewIntegrations
- );
- const sort = useSelector(service, (state) => state.context.table.sort);
- const appliedFilters = useDatasetQualityFilters();
-
- const trackDatasetNavigated = useCallback<(rawName: string, isIgnoredFilter: boolean) => void>(
- (rawName: string, isIgnoredFilter: boolean) => {
- const foundDataset = datasets.find((dataset) => dataset.rawName === rawName);
- if (foundDataset) {
- const ebtProps = getDatasetEbtProps(
- foundDataset,
- sort,
- appliedFilters,
- nonAggregatableDatasets,
- isIgnoredFilter,
- canUserViewIntegrations
- );
- telemetryClient.trackDatasetNavigated(ebtProps);
- } else {
- throw new Error(
- `Cannot report dataset navigation telemetry for unknown dataset ${rawName}`
- );
- }
- },
- [
- sort,
- appliedFilters,
- canUserViewIntegrations,
- datasets,
- nonAggregatableDatasets,
- telemetryClient,
- ]
- );
-
- return { trackDatasetNavigated };
-};
-
-export const useDatasetDetailsTelemetry = () => {
- const { service, telemetryClient } = useDatasetQualityContext();
-
- const {
- dataset: dataStreamStat,
- datasetDetails: dataStreamDetails,
- insightsTimeRange,
- breakdownField,
- isNonAggregatable,
- isBreakdownFieldEcs,
- } = useSelector(service, (state) => state.context.flyout) ?? {};
-
- const loadingState = useSelector(service, (state) => ({
- dataStreamDetailsLoading:
- state.matches('flyout.initializing.dataStreamDetails.fetching') ||
- state.matches('flyout.initializing.assertBreakdownFieldIsEcs.fetching'),
- }));
-
- const canUserAccessDashboards = useSelector(
- service,
- (state) => !state.matches('flyout.initializing.integrationDashboards.unauthorized')
- );
-
- const canUserViewIntegrations = useSelector(
- service,
- (state) => state.context.datasetUserPrivileges.canViewIntegrations
- );
-
- const ebtProps = useMemo(() => {
- if (
- dataStreamDetails &&
- insightsTimeRange &&
- dataStreamStat &&
- !loadingState.dataStreamDetailsLoading
- ) {
- return getDatasetDetailsEbtProps(
- insightsTimeRange,
- dataStreamStat,
- dataStreamDetails,
- isNonAggregatable ?? false,
- canUserViewIntegrations,
- canUserAccessDashboards,
- isBreakdownFieldEcs,
- breakdownField
- );
- }
-
- return undefined;
- }, [
- insightsTimeRange,
- dataStreamStat,
- dataStreamDetails,
- loadingState.dataStreamDetailsLoading,
- isNonAggregatable,
- canUserViewIntegrations,
- canUserAccessDashboards,
- isBreakdownFieldEcs,
- breakdownField,
- ]);
-
- const startTracking = useCallback(() => {
- telemetryClient.startDatasetDetailsTracking();
- }, [telemetryClient]);
-
- // Report opening dataset details
- useEffect(() => {
- const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
- if (datasetDetailsTrackingState === 'started' && ebtProps) {
- telemetryClient.trackDatasetDetailsOpened(ebtProps);
- }
- }, [ebtProps, telemetryClient]);
-
- const trackDetailsNavigated = useCallback(
- (target: NavigationTarget, source: NavigationSource, isDegraded = false) => {
- const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
- if (
- (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') &&
- ebtProps
- ) {
- telemetryClient.trackDatasetDetailsNavigated({
- ...ebtProps,
- filters: {
- is_degraded: isDegraded,
- },
- target,
- source,
- });
- } else {
- throw new Error(
- 'Cannot report dataset details navigation telemetry without required data and state'
- );
- }
- },
- [ebtProps, telemetryClient]
- );
-
- const trackDatasetDetailsBreakdownFieldChanged = useCallback(() => {
- const datasetDetailsTrackingState = telemetryClient.getDatasetDetailsTrackingState();
- if (
- (datasetDetailsTrackingState === 'opened' || datasetDetailsTrackingState === 'navigated') &&
- ebtProps
- ) {
- telemetryClient.trackDatasetDetailsBreakdownFieldChanged({
- ...ebtProps,
- breakdown_field: ebtProps.breakdown_field,
- });
- }
- }, [ebtProps, telemetryClient]);
-
- const wrapLinkPropsForTelemetry = useCallback(
- (
- props: RouterLinkProps,
- target: NavigationTarget,
- source: NavigationSource,
- isDegraded = false
- ) => {
- return {
- ...props,
- onClick: (event: Parameters[0]) => {
- trackDetailsNavigated(target, source, isDegraded);
- if (props.onClick) {
- props.onClick(event);
- }
- },
- };
- },
- [trackDetailsNavigated]
- );
-
- return {
- startTracking,
- trackDetailsNavigated,
- wrapLinkPropsForTelemetry,
- navigationTargets: NavigationTarget,
- navigationSources: NavigationSource,
- trackDatasetDetailsBreakdownFieldChanged,
- };
-};
-
-function getDatasetEbtProps(
- dataset: DataStreamStat,
- sort: { field: string; direction: 'asc' | 'desc' },
- filters: ReturnType,
- nonAggregatableDatasets: string[],
- isIgnoredFilter: boolean,
- canUserViewIntegrations: boolean
-): DatasetNavigatedEbtProps {
- const { startDate: from, endDate: to } = getDateISORange(filters.timeRange);
- const datasetEbtProps: DatasetEbtProps = {
- index_name: dataset.rawName,
- data_stream: {
- dataset: dataset.name,
- namespace: dataset.namespace,
- type: dataset.type,
- },
- data_stream_health: dataset.degradedDocs.quality,
- data_stream_aggregatable: nonAggregatableDatasets.some(
- (indexName) => indexName === dataset.rawName
- ),
- from,
- to,
- degraded_percentage: dataset.degradedDocs.percentage,
- integration: dataset.integration?.name,
- privileges: {
- can_monitor_data_stream: dataset.userPrivileges?.canMonitor ?? true,
- can_view_integrations: canUserViewIntegrations,
- },
- };
-
- const ebtFilters: DatasetNavigatedEbtProps['filters'] = {
- is_degraded: isIgnoredFilter,
- query_length: filters.selectedQuery?.length ?? 0,
- integrations: {
- total: filters.integrations.filter((item) => item.name !== 'none').length,
- included: filters.integrations.filter((item) => item?.checked === 'on').length,
- excluded: filters.integrations.filter((item) => item?.checked === 'off').length,
- },
- namespaces: {
- total: filters.namespaces.length,
- included: filters.namespaces.filter((item) => item?.checked === 'on').length,
- excluded: filters.namespaces.filter((item) => item?.checked === 'off').length,
- },
- qualities: {
- total: filters.qualities.length,
- included: filters.qualities.filter((item) => item?.checked === 'on').length,
- excluded: filters.qualities.filter((item) => item?.checked === 'off').length,
- },
- };
-
- return {
- ...datasetEbtProps,
- sort,
- filters: ebtFilters,
- };
-}
-
-function getDatasetDetailsEbtProps(
- insightsTimeRange: TimeRangeConfig,
- flyoutDataset: FlyoutDataset,
- details: DataStreamDetails,
- isNonAggregatable: boolean,
- canUserViewIntegrations: boolean,
- canUserAccessDashboards: boolean,
- isBreakdownFieldEcs: boolean | null,
- breakdownField?: string
-): DatasetDetailsEbtProps {
- const indexName = flyoutDataset.rawName;
- const dataStream = {
- dataset: flyoutDataset.name,
- namespace: flyoutDataset.namespace,
- type: flyoutDataset.type,
- };
- const degradedDocs = details?.degradedDocsCount ?? 0;
- const totalDocs = details?.docsCount ?? 0;
- const degradedPercentage =
- totalDocs > 0 ? Number(((degradedDocs / totalDocs) * 100).toFixed(2)) : 0;
- const health = mapPercentageToQuality(degradedPercentage);
- const { startDate: from, endDate: to } = getDateISORange(insightsTimeRange);
-
- return {
- index_name: indexName,
- data_stream: dataStream,
- privileges: {
- can_monitor_data_stream: true,
- can_view_integrations: canUserViewIntegrations,
- can_view_dashboards: canUserAccessDashboards,
- },
- data_stream_aggregatable: !isNonAggregatable,
- data_stream_health: health,
- from,
- to,
- degraded_percentage: degradedPercentage,
- integration: flyoutDataset.integration?.name,
- breakdown_field: breakdownField
- ? isBreakdownFieldEcs === null
- ? UNKOWN_FIELD_PLACEHOLDER
- : getMaskedBreakdownField(breakdownField, isBreakdownFieldEcs)
- : breakdownField,
- };
-}
-
-function getMaskedBreakdownField(breakdownField: string, isBreakdownFieldEcs: boolean) {
- return isBreakdownFieldEcs ? breakdownField : MASKED_FIELD_PLACEHOLDER;
-}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx
index 6cb4c1297541..84dbabe1d254 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/plugin.tsx
@@ -52,9 +52,7 @@ export class DatasetQualityPlugin
const createDatasetQualityController = createDatasetQualityControllerLazyFactory({
core,
- plugins,
dataStreamStatsClient,
- dataStreamDetailsClient,
});
const DatasetQualityDetails = createDatasetQualityDetails({
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts
index e4b5e07c8df9..f1a41ffc666c 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/telemetry/types.ts
@@ -34,6 +34,7 @@ export enum NavigationSource {
Footer = 'footer',
Summary = 'summary',
Chart = 'chart',
+ Trend = 'trend',
Table = 'table',
ActionMenu = 'action_menu',
}
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts
index 62ec47632c24..87a6a398df8f 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/defaults.ts
@@ -7,8 +7,6 @@
import {
DEFAULT_DATASET_TYPE,
- DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
- DEFAULT_DEGRADED_FIELD_SORT_FIELD,
DEFAULT_SORT_DIRECTION,
DEFAULT_SORT_FIELD,
} from '../../../../common/constants';
@@ -47,19 +45,6 @@ export const DEFAULT_CONTEXT: DefaultDatasetQualityControllerState = {
namespaces: [],
qualities: [],
},
- flyout: {
- degradedFields: {
- table: {
- page: 0,
- rowsPerPage: 10,
- sort: {
- field: DEFAULT_DEGRADED_FIELD_SORT_FIELD,
- direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
- },
- },
- },
- isBreakdownFieldEcs: null,
- },
datasets: [],
isSizeStatsAvailable: true,
nonAggregatableDatasets: [],
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts
index f10ea32da3af..a21cc85aac44 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/notifications.ts
@@ -17,15 +17,6 @@ export const fetchDatasetStatsFailedNotifier = (toasts: IToasts, error: Error) =
});
};
-export const fetchDatasetDetailsFailedNotifier = (toasts: IToasts, error: Error) => {
- toasts.addDanger({
- title: i18n.translate('xpack.datasetQuality.fetchDatasetDetailsFailed', {
- defaultMessage: "We couldn't get your data set details.",
- }),
- text: error.message,
- });
-};
-
export const fetchDegradedStatsFailedNotifier = (toasts: IToasts, error: Error) => {
toasts.addDanger({
title: i18n.translate('xpack.datasetQuality.fetchDegradedStatsFailed', {
@@ -35,15 +26,6 @@ export const fetchDegradedStatsFailedNotifier = (toasts: IToasts, error: Error)
});
};
-export const fetchNonAggregatableDatasetsFailedNotifier = (toasts: IToasts, error: Error) => {
- toasts.addDanger({
- title: i18n.translate('xpack.datasetQuality.fetchNonAggregatableDatasetsFailed', {
- defaultMessage: "We couldn't get non aggregatable datasets information.",
- }),
- text: error.message,
- });
-};
-
export const fetchIntegrationsFailedNotifier = (toasts: IToasts, error: Error) => {
toasts.addDanger({
title: i18n.translate('xpack.datasetQuality.fetchIntegrationsFailed', {
@@ -52,19 +34,3 @@ export const fetchIntegrationsFailedNotifier = (toasts: IToasts, error: Error) =
text: error.message,
});
};
-
-export const noDatasetSelected = i18n.translate(
- 'xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected',
- {
- defaultMessage: 'No data set have been selected',
- }
-);
-
-export const assertBreakdownFieldEcsFailedNotifier = (toasts: IToasts, error: Error) => {
- toasts.addDanger({
- title: i18n.translate('xpack.datasetQuality.assertBreakdownFieldEcsFailed', {
- defaultMessage: "We couldn't retrieve breakdown field metadata.",
- }),
- text: error.message,
- });
-};
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts
index fb6c03fae153..7ce3c5b5d8f6 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/state_machine.ts
@@ -8,36 +8,22 @@
import { IToasts } from '@kbn/core/public';
import { getDateISORange } from '@kbn/timerange';
import { assign, createMachine, DoneInvokeEvent, InterpreterFrom } from 'xstate';
-import { DatasetQualityStartDeps } from '../../../types';
-import {
- Dashboard,
- DataStreamStat,
- DegradedFieldResponse,
- NonAggregatableDatasets,
-} from '../../../../common/api_types';
+import { DataStreamStat, NonAggregatableDatasets } from '../../../../common/api_types';
import { Integration } from '../../../../common/data_streams_stats/integration';
-import { IDataStreamDetailsClient } from '../../../services/data_stream_details';
import {
- DataStreamSettings,
- DataStreamDetails,
GetDataStreamsStatsQuery,
GetIntegrationsParams,
GetNonAggregatableDataStreamsParams,
DataStreamStatServiceResponse,
} from '../../../../common/data_streams_stats';
import { DegradedDocsStat } from '../../../../common/data_streams_stats/malformed_docs_stat';
-import { DataStreamType } from '../../../../common/types';
-import { dataStreamPartsToIndexName } from '../../../../common/utils';
import { IDataStreamsStatsClient } from '../../../services/data_streams_stats';
import { generateDatasets } from '../../../utils';
import { DEFAULT_CONTEXT } from './defaults';
import {
- fetchDatasetDetailsFailedNotifier,
fetchDatasetStatsFailedNotifier,
fetchDegradedStatsFailedNotifier,
fetchIntegrationsFailedNotifier,
- noDatasetSelected,
- assertBreakdownFieldEcsFailedNotifier,
} from './notifications';
import { fetchNonAggregatableDatasetsFailedNotifier } from '../../common/notifications';
import {
@@ -45,13 +31,7 @@ import {
DatasetQualityControllerEvent,
DatasetQualityControllerTypeState,
DefaultDatasetQualityControllerState,
- FlyoutDataset,
} from './types';
-import {
- fetchDataStreamSettingsFailedNotifier,
- fetchIntegrationDashboardsFailedNotifier,
- fetchDataStreamIntegrationFailedNotifier,
-} from '../../dataset_quality_details_controller/notifications';
export const createPureDatasetQualityControllerStateMachine = (
initialContext: DatasetQualityControllerContext
@@ -227,231 +207,6 @@ export const createPureDatasetQualityControllerStateMachine = (
},
},
},
- flyout: {
- initial: 'closed',
- states: {
- initializing: {
- type: 'parallel',
- states: {
- nonAggregatableDataset: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadDatasetIsNonAggregatable',
- onDone: {
- target: 'done',
- actions: ['storeDatasetIsNonAggregatable'],
- },
- onError: {
- target: 'done',
- actions: ['notifyFetchNonAggregatableDatasetsFailed'],
- },
- },
- },
- done: {
- on: {
- UPDATE_INSIGHTS_TIME_RANGE: {
- target: 'fetching',
- actions: ['storeFlyoutOptions'],
- },
- SELECT_DATASET: {
- target: 'fetching',
- actions: ['storeFlyoutOptions'],
- },
- },
- },
- },
- },
- dataStreamSettings: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadDataStreamSettings',
- onDone: {
- target: 'initializeIntegrations',
- actions: ['storeDataStreamSettings'],
- },
- onError: {
- target: 'done',
- actions: ['notifyFetchDataStreamSettingsFailed'],
- },
- },
- },
- initializeIntegrations: {
- type: 'parallel',
- states: {
- integrationDetails: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadDataStreamIntegration',
- onDone: {
- target: 'done',
- actions: ['storeDataStreamIntegration'],
- },
- onError: {
- target: 'done',
- actions: ['notifyFetchDatasetIntegrationsFailed'],
- },
- },
- },
- done: {
- type: 'final',
- },
- },
- },
- integrationDashboards: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadIntegrationDashboards',
- onDone: {
- target: 'done',
- actions: ['storeIntegrationDashboards'],
- },
- onError: [
- {
- target: 'unauthorized',
- cond: 'checkIfActionForbidden',
- },
- {
- target: 'done',
- actions: ['notifyFetchIntegrationDashboardsFailed'],
- },
- ],
- },
- },
- done: {
- type: 'final',
- },
- unauthorized: {
- type: 'final',
- },
- },
- },
- },
- },
- done: {
- type: 'final',
- },
- },
- },
- dataStreamDetails: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadDataStreamDetails',
- onDone: {
- target: 'done',
- actions: ['storeDatasetDetails'],
- },
- onError: {
- target: 'done',
- actions: ['notifyFetchDatasetDetailsFailed'],
- },
- },
- },
- done: {
- on: {
- UPDATE_INSIGHTS_TIME_RANGE: {
- target: 'fetching',
- actions: ['storeFlyoutOptions'],
- },
- BREAKDOWN_FIELD_CHANGE: {
- target:
- '#DatasetQualityController.flyout.initializing.assertBreakdownFieldIsEcs.fetching',
- actions: ['storeFlyoutOptions'],
- },
- },
- },
- },
- },
- dataStreamDegradedFields: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'loadDegradedFieldsPerDataStream',
- onDone: {
- target: 'done',
- actions: ['storeDegradedFields'],
- },
- onError: {
- target: 'done',
- },
- },
- },
- done: {
- on: {
- UPDATE_INSIGHTS_TIME_RANGE: {
- target: 'fetching',
- actions: ['resetDegradedFieldPage'],
- },
- UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: {
- target: 'done',
- actions: ['storeDegradedFieldTableOptions'],
- },
- },
- },
- },
- },
- assertBreakdownFieldIsEcs: {
- initial: 'fetching',
- states: {
- fetching: {
- invoke: {
- src: 'assertBreakdownFieldIsEcs',
- onDone: {
- target: 'done',
- actions: ['storeBreakdownFieldIsEcs'],
- },
- onError: {
- target: 'done',
- actions: ['notifyAssertBreakdownFieldEcsFailed'],
- },
- },
- },
- done: {},
- },
- },
- },
- onDone: {
- target: '#DatasetQualityController.flyout.loaded',
- },
- },
- loaded: {
- on: {
- CLOSE_FLYOUT: {
- target: 'closed',
- actions: ['resetFlyoutOptions'],
- },
- },
- },
- closed: {
- on: {
- OPEN_FLYOUT: {
- target: '#DatasetQualityController.flyout.initializing',
- actions: ['storeFlyoutOptions'],
- },
- },
- },
- },
- on: {
- SELECT_NEW_DATASET: {
- target: '#DatasetQualityController.flyout.initializing',
- actions: ['storeFlyoutOptions'],
- },
- CLOSE_FLYOUT: {
- target: '#DatasetQualityController.flyout.closed',
- actions: ['resetFlyoutOptions'],
- },
- },
- },
},
},
{
@@ -463,38 +218,12 @@ export const createPureDatasetQualityControllerStateMachine = (
}
: {};
}),
- storeDegradedFieldTableOptions: assign((context, event) => {
- return 'degraded_field_criteria' in event
- ? {
- flyout: {
- ...context.flyout,
- degradedFields: {
- ...context.flyout.degradedFields,
- table: event.degraded_field_criteria,
- },
- },
- }
- : {};
- }),
resetPage: assign((context, _event) => ({
table: {
...context.table,
page: 0,
},
})),
- resetDegradedFieldPage: assign((context, _event) => ({
- flyout: {
- ...context.flyout,
- degradedFields: {
- ...context.flyout.degradedFields,
- table: {
- ...context.flyout.degradedFields.table,
- page: 0,
- rowsPerPage: 10,
- },
- },
- },
- })),
storeInactiveDatasetsVisibility: assign((context, _event) => {
return {
filters: {
@@ -561,37 +290,6 @@ export const createPureDatasetQualityControllerStateMachine = (
}
: {};
}),
- storeFlyoutOptions: assign((context, event) => {
- const insightsTimeRange =
- 'timeRange' in event
- ? event.timeRange
- : context.flyout?.insightsTimeRange ?? context.filters?.timeRange;
- const dataset =
- 'dataset' in event ? (event.dataset as FlyoutDataset) : context.flyout?.dataset;
- const breakdownField =
- 'breakdownField' in event
- ? event.breakdownField ?? undefined
- : context.flyout?.breakdownField;
-
- return {
- flyout: {
- ...context.flyout,
- dataset,
- insightsTimeRange,
- breakdownField,
- },
- };
- }),
- storeBreakdownFieldIsEcs: assign((context, event: DoneInvokeEvent) => {
- return {
- flyout: {
- ...context.flyout,
- isBreakdownFieldEcs:
- 'data' in event && typeof event.data === 'boolean' ? event.data : null,
- },
- };
- }),
- resetFlyoutOptions: assign((_context, _event) => ({ flyout: DEFAULT_CONTEXT.flyout })),
storeDataStreamStats: assign(
(_context, event: DoneInvokeEvent) => {
if ('data' in event && 'dataStreamsStats' in event.data) {
@@ -618,19 +316,6 @@ export const createPureDatasetQualityControllerStateMachine = (
}
: {};
}),
- storeDegradedFields: assign((context, event: DoneInvokeEvent) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- degradedFields: {
- ...context.flyout.degradedFields,
- data: event.data.degradedFields,
- },
- },
- }
- : {};
- }),
storeNonAggregatableDatasets: assign(
(
_context: DefaultDatasetQualityControllerState,
@@ -643,41 +328,6 @@ export const createPureDatasetQualityControllerStateMachine = (
: {};
}
),
- storeDataStreamSettings: assign((context, event) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- dataStreamSettings: (event.data ?? {}) as DataStreamSettings,
- },
- }
- : {};
- }),
- storeDatasetDetails: assign((context, event) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- datasetDetails: event.data as DataStreamDetails,
- },
- }
- : {};
- }),
- storeDatasetIsNonAggregatable: assign(
- (
- context: DefaultDatasetQualityControllerState,
- event: DoneInvokeEvent
- ) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- isNonAggregatable: !event.data.aggregatable,
- },
- }
- : {};
- }
- ),
storeIntegrations: assign((_context, event) => {
return 'data' in event
? {
@@ -690,32 +340,6 @@ export const createPureDatasetQualityControllerStateMachine = (
integrations: [],
};
}),
- storeDataStreamIntegration: assign((context, event: DoneInvokeEvent) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- integration: {
- ...context.flyout.integration,
- integrationDetails: event.data,
- },
- },
- }
- : {};
- }),
- storeIntegrationDashboards: assign((context, event: DoneInvokeEvent) => {
- return 'data' in event
- ? {
- flyout: {
- ...context.flyout,
- integration: {
- ...context.flyout.integration,
- dashboards: event.data,
- },
- },
- }
- : {};
- }),
storeDatasets: assign((context, _event) => {
return context.integrations && (context.dataStreamStats || context.degradedDocStats)
? {
@@ -743,18 +367,14 @@ export const createPureDatasetQualityControllerStateMachine = (
export interface DatasetQualityControllerStateMachineDependencies {
initialContext?: DatasetQualityControllerContext;
- plugins: DatasetQualityStartDeps;
toasts: IToasts;
dataStreamStatsClient: IDataStreamsStatsClient;
- dataStreamDetailsClient: IDataStreamDetailsClient;
}
export const createDatasetQualityControllerStateMachine = ({
initialContext = DEFAULT_CONTEXT,
- plugins,
toasts,
dataStreamStatsClient,
- dataStreamDetailsClient,
}: DatasetQualityControllerStateMachineDependencies) =>
createPureDatasetQualityControllerStateMachine(initialContext).withConfig({
actions: {
@@ -764,20 +384,8 @@ export const createDatasetQualityControllerStateMachine = ({
fetchDegradedStatsFailedNotifier(toasts, event.data),
notifyFetchNonAggregatableDatasetsFailed: (_context, event: DoneInvokeEvent) =>
fetchNonAggregatableDatasetsFailedNotifier(toasts, event.data),
- notifyFetchDataStreamSettingsFailed: (_context, event: DoneInvokeEvent) =>
- fetchDataStreamSettingsFailedNotifier(toasts, event.data),
- notifyFetchDatasetDetailsFailed: (_context, event: DoneInvokeEvent) =>
- fetchDatasetDetailsFailedNotifier(toasts, event.data),
- notifyFetchIntegrationDashboardsFailed: (_context, event: DoneInvokeEvent) =>
- fetchIntegrationDashboardsFailedNotifier(toasts, event.data),
notifyFetchIntegrationsFailed: (_context, event: DoneInvokeEvent) =>
fetchIntegrationsFailedNotifier(toasts, event.data),
- notifyFetchDatasetIntegrationsFailed: (context, event: DoneInvokeEvent) => {
- const integrationName = context.flyout.dataStreamSettings?.integration;
- return fetchDataStreamIntegrationFailedNotifier(toasts, event.data, integrationName);
- },
- notifyAssertBreakdownFieldEcsFailed: (_context, event: DoneInvokeEvent) =>
- assertBreakdownFieldEcsFailedNotifier(toasts, event.data),
},
services: {
loadDataStreamStats: (context) =>
@@ -795,27 +403,6 @@ export const createDatasetQualityControllerStateMachine = ({
end,
});
},
-
- loadDegradedFieldsPerDataStream: (context) => {
- if (!context.flyout.dataset || !context.flyout.insightsTimeRange) {
- return Promise.resolve({});
- }
-
- const { startDate: start, endDate: end } = getDateISORange(
- context.flyout.insightsTimeRange
- );
- const { type, name: dataset, namespace } = context.flyout.dataset;
-
- return dataStreamDetailsClient.getDataStreamDegradedFields({
- dataStream: dataStreamPartsToIndexName({
- type: type as DataStreamType,
- dataset,
- namespace,
- }),
- start,
- end,
- });
- },
loadIntegrations: (context) => {
return dataStreamStatsClient.getIntegrations({
type: context.type as GetIntegrationsParams['query']['type'],
@@ -830,108 +417,6 @@ export const createDatasetQualityControllerStateMachine = ({
end,
});
},
- loadDataStreamSettings: (context) => {
- if (!context.flyout.dataset) {
- fetchDataStreamSettingsFailedNotifier(toasts, new Error(noDatasetSelected));
-
- return Promise.resolve({});
- }
-
- const { type, name: dataset, namespace } = context.flyout.dataset;
-
- return dataStreamDetailsClient.getDataStreamSettings({
- dataStream: dataStreamPartsToIndexName({
- type: type as DataStreamType,
- dataset,
- namespace,
- }),
- });
- },
- loadDataStreamIntegration: (context) => {
- if (context.flyout.dataStreamSettings?.integration && context.flyout.dataset) {
- const { type } = context.flyout.dataset;
- return dataStreamDetailsClient.getDataStreamIntegration({
- type: type as DataStreamType,
- integrationName: context.flyout.dataStreamSettings.integration,
- });
- }
- return Promise.resolve();
- },
- loadDataStreamDetails: (context) => {
- if (!context.flyout.dataset || !context.flyout.insightsTimeRange) {
- fetchDatasetDetailsFailedNotifier(toasts, new Error(noDatasetSelected));
-
- return Promise.resolve({});
- }
-
- const { type, name: dataset, namespace } = context.flyout.dataset;
- const { startDate: start, endDate: end } = getDateISORange(
- context.flyout.insightsTimeRange
- );
-
- return dataStreamDetailsClient.getDataStreamDetails({
- dataStream: dataStreamPartsToIndexName({
- type: type as DataStreamType,
- dataset,
- namespace,
- }),
- start,
- end,
- });
- },
- loadIntegrationDashboards: (context) => {
- if (context.flyout.dataStreamSettings?.integration) {
- return dataStreamDetailsClient.getIntegrationDashboards({
- integration: context.flyout.dataStreamSettings.integration,
- });
- }
-
- return Promise.resolve();
- },
- loadDatasetIsNonAggregatable: async (context) => {
- if (!context.flyout.dataset || !context.flyout.insightsTimeRange) {
- fetchDatasetDetailsFailedNotifier(toasts, new Error(noDatasetSelected));
-
- return Promise.resolve({});
- }
-
- const { type, name: dataset, namespace } = context.flyout.dataset;
- const { startDate: start, endDate: end } = getDateISORange(
- context.flyout.insightsTimeRange
- );
-
- return dataStreamStatsClient.getNonAggregatableDatasets({
- type: context.type as GetNonAggregatableDataStreamsParams['type'],
- start,
- end,
- dataStream: dataStreamPartsToIndexName({
- type: type as DataStreamType,
- dataset,
- namespace,
- }),
- });
- },
- assertBreakdownFieldIsEcs: async (context) => {
- if (context.flyout.breakdownField) {
- const allowedFieldSources = ['ecs', 'metadata'];
-
- // This timeout is to avoid a runtime error that randomly happens on breakdown field change
- // TypeError: Cannot read properties of undefined (reading 'timeFieldName')
- await new Promise((res) => setTimeout(res, 300));
-
- const client = await plugins.fieldsMetadata.getClient();
- const { fields } = await client.find({
- attributes: ['source'],
- fieldNames: [context.flyout.breakdownField],
- });
-
- const breakdownFieldSource = fields[context.flyout.breakdownField]?.source;
-
- return !!(breakdownFieldSource && allowedFieldSources.includes(breakdownFieldSource));
- }
-
- return null;
- },
},
});
diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts
index d6bfaaad216b..a03bddcc9e93 100644
--- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts
+++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_controller/src/types.ts
@@ -7,35 +7,18 @@
import { DoneInvokeEvent } from 'xstate';
import { QualityIndicators, TableCriteria, TimeRangeConfig } from '../../../../common/types';
-import {
- Dashboard,
- DatasetUserPrivileges,
- NonAggregatableDatasets,
-} from '../../../../common/api_types';
+import { DatasetUserPrivileges, NonAggregatableDatasets } from '../../../../common/api_types';
import { Integration } from '../../../../common/data_streams_stats/integration';
-import { DatasetTableSortField, DegradedFieldSortField } from '../../../hooks';
+import { DatasetTableSortField } from '../../../hooks';
import { DegradedDocsStat } from '../../../../common/data_streams_stats/malformed_docs_stat';
import {
DataStreamDegradedDocsStatServiceResponse,
- DataStreamSettings,
DataStreamDetails,
DataStreamStatServiceResponse,
DataStreamStat,
DataStreamStatType,
- DegradedField,
- DegradedFieldResponse,
} from '../../../../common/data_streams_stats';
-export type FlyoutDataset = Omit<
- DataStreamStat,
- 'type' | 'size' | 'sizeBytes' | 'lastActivity' | 'degradedDocs'
-> & { type: string };
-
-export interface DegradedFields {
- table: TableCriteria;
- data?: DegradedField[];
-}
-
interface FiltersCriteria {
inactive: boolean;
fullNames: boolean;
@@ -46,29 +29,10 @@ interface FiltersCriteria {
query?: string;
}
-export interface DataStreamIntegrations {
- integrationDetails?: Integration;
- dashboards?: Dashboard[];
-}
-
export interface WithTableOptions {
table: TableCriteria;
}
-export interface WithFlyoutOptions {
- flyout: {
- dataset?: FlyoutDataset;
- dataStreamSettings?: DataStreamSettings;
- datasetDetails?: DataStreamDetails;
- insightsTimeRange?: TimeRangeConfig;
- breakdownField?: string;
- degradedFields: DegradedFields;
- isNonAggregatable?: boolean;
- integration?: DataStreamIntegrations;
- isBreakdownFieldEcs: boolean | null;
- };
-}
-
export interface WithFilters {
filters: FiltersCriteria;
}
@@ -98,14 +62,12 @@ export interface WithIntegrations {
export type DefaultDatasetQualityControllerState = { type: string } & WithTableOptions &
WithDataStreamStats &
Partial &
- WithFlyoutOptions &
WithDatasets &
WithFilters &
WithNonAggregatableDatasets &
Partial;
-type DefaultDatasetQualityStateContext = DefaultDatasetQualityControllerState &
- Partial;
+type DefaultDatasetQualityStateContext = DefaultDatasetQualityControllerState;
export type DatasetQualityControllerTypeState =
| {
@@ -131,48 +93,6 @@ export type DatasetQualityControllerTypeState =
| {
value: 'nonAggregatableDatasets.fetching';
context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamSettings.fetching';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.fetching';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDashboards.unauthorized';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamSettings.initializeIntegrations.integrationDetails.done';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamDetails.fetching';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamDetails.done';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.assertBreakdownFieldIsEcs.fetching';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.assertBreakdownFieldIsEcs.done';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value: 'flyout.initializing.dataStreamDegradedFields.fetching';
- context: DefaultDatasetQualityStateContext;
- }
- | {
- value:
- | 'flyout.initializing.integrationDashboards.fetching'
- | 'flyout.initializing.integrationDashboards.unauthorized';
- context: DefaultDatasetQualityStateContext;
};
export type DatasetQualityControllerContext = DatasetQualityControllerTypeState['context'];
@@ -182,29 +102,10 @@ export type DatasetQualityControllerEvent =
type: 'UPDATE_TABLE_CRITERIA';
dataset_criteria: TableCriteria;
}
- | {
- type: 'UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA';
- degraded_field_criteria: TableCriteria;
- }
- | {
- type: 'OPEN_FLYOUT';
- dataset: FlyoutDataset;
- }
- | {
- type: 'SELECT_NEW_DATASET';
- dataset: FlyoutDataset;
- }
| {
type: 'UPDATE_INSIGHTS_TIME_RANGE';
timeRange: TimeRangeConfig;
}
- | {
- type: 'BREAKDOWN_FIELD_CHANGE';
- breakdownField: string | null;
- }
- | {
- type: 'CLOSE_FLYOUT';
- }
| {
type: 'TOGGLE_INACTIVE_DATASETS';
}
@@ -236,10 +137,7 @@ export type DatasetQualityControllerEvent =
}
| DoneInvokeEvent
| DoneInvokeEvent
- | DoneInvokeEvent
| DoneInvokeEvent
- | DoneInvokeEvent
- | DoneInvokeEvent
| DoneInvokeEvent
| DoneInvokeEvent
| DoneInvokeEvent
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json
index 53dcc0869d47..86e3e5702baa 100644
--- a/x-pack/plugins/translations/translations/fr-FR.json
+++ b/x-pack/plugins/translations/translations/fr-FR.json
@@ -14613,7 +14613,6 @@
"xpack.datasetQuality.appTitle": "Qualité de l’ensemble de données",
"xpack.datasetQuality.betaBadgeDescription": "Cette fonctionnalité est actuellement en version bêta. Nous aimerions beaucoup savoir si vous avez des commentaires ou si vous rencontrez des bugs. Veuillez ouvrir un dossier d'assistance et/ou consulter notre forum de discussion.",
"xpack.datasetQuality.betaBadgeLabel": "Bêta",
- "xpack.datasetQuality.collapseLabel": "Réduire",
"xpack.datasetQuality.datasetQualityColumnName": "Qualité de l’ensemble de données",
"xpack.datasetQuality.datasetQualityColumnTooltip": "La qualité est basée sur le pourcentage de documents dégradés dans un ensemble de données. {visualQueue}",
"xpack.datasetQuality.datasetQualityIdicator": "{quality}",
@@ -14624,9 +14623,6 @@
"xpack.datasetQuality.emptyState.noData.title": "Aucun ensemble de données trouvé",
"xpack.datasetQuality.emptyState.noPrivileges.message": "Vous ne disposez pas des autorisations requises pour voir les données de logs. Assurez-vous d'avoir les autorisations requises pour voir {datasetPattern}.",
"xpack.datasetQuality.emptyState.noPrivileges.title": "Impossible de charger les ensembles de données",
- "xpack.datasetQuality.expandLabel": "Développer",
- "xpack.datasetQuality.fetchDatasetDetailsFailed": "Nous n'avons pas pu obtenir les détails de votre ensemble de données.",
- "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "Vous n'avez sélectionné aucun ensemble de données",
"xpack.datasetQuality.fetchDatasetStatsFailed": "Nous n'avons pas pu obtenir vos ensembles de données.",
"xpack.datasetQuality.fetchDegradedStatsFailed": "Nous n'avons pas pu obtenir d'informations sur vos documents dégradés.",
"xpack.datasetQuality.fetchIntegrationsFailed": "Nous n'avons pas pu obtenir vos intégrations.",
@@ -14634,9 +14630,6 @@
"xpack.datasetQuality.fewDegradedDocsTooltip": "{degradedDocsCount} documents dégradés dans cet ensemble de données.",
"xpack.datasetQuality.filterBar.placeholder": "Filtrer les ensembles de données",
"xpack.datasetQuality.flyout.degradedDocsTitle": "Documents dégradés",
- "xpack.datasetQuality.flyout.degradedField.count": "Nombre de documents",
- "xpack.datasetQuality.flyout.degradedField.field": "Champ",
- "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "Dernière occurrence",
"xpack.datasetQuality.flyout.nonAggregatable.description": "{description}",
"xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "{rolloverLink} manuellement cet ensemble de données pour empêcher des délais à l'avenir.",
"xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset} est incompatible avec l'agrégation _ignored, ce qui peut entraîner des délais lors de la recherche de données. {howToFixIt}",
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index e89e452923f3..0ab34991b457 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -14602,7 +14602,6 @@
"xpack.datasetQuality.appTitle": "データセット品質",
"xpack.datasetQuality.betaBadgeDescription": "現在、この機能はベータです。バグが発生した場合やフィードバックがある場合は、お問い合わせください。サポート問題をオープンするか、ディスカッションフォーラムをご覧ください。",
"xpack.datasetQuality.betaBadgeLabel": "ベータ",
- "xpack.datasetQuality.collapseLabel": "縮小",
"xpack.datasetQuality.datasetQualityColumnName": "データセット品質",
"xpack.datasetQuality.datasetQualityColumnTooltip": "品質は、データセットの劣化したドキュメントの割合に基づきます。{visualQueue}",
"xpack.datasetQuality.datasetQualityIdicator": "{quality}",
@@ -14613,9 +14612,6 @@
"xpack.datasetQuality.emptyState.noData.title": "データセットが見つかりません",
"xpack.datasetQuality.emptyState.noPrivileges.message": "ログデータを表示するために必要な権限がありません。{datasetPattern}を表示するための十分な権限があることを確認してください。",
"xpack.datasetQuality.emptyState.noPrivileges.title": "データセットを読み込めませんでした",
- "xpack.datasetQuality.expandLabel": "拡張",
- "xpack.datasetQuality.fetchDatasetDetailsFailed": "データセット詳細を取得できませんでした。",
- "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "データセットが選択されていません",
"xpack.datasetQuality.fetchDatasetStatsFailed": "データセットを取得できませんでした。",
"xpack.datasetQuality.fetchDegradedStatsFailed": "劣化したドキュメント情報を取得できませんでした。",
"xpack.datasetQuality.fetchIntegrationsFailed": "統合を取得できませんでした。",
@@ -14623,9 +14619,6 @@
"xpack.datasetQuality.fewDegradedDocsTooltip": "このデータセットの{degradedDocsCount}個の劣化したドキュメント。",
"xpack.datasetQuality.filterBar.placeholder": "データセットのフィルタリング",
"xpack.datasetQuality.flyout.degradedDocsTitle": "劣化したドキュメント",
- "xpack.datasetQuality.flyout.degradedField.count": "ドキュメント数",
- "xpack.datasetQuality.flyout.degradedField.field": "フィールド",
- "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "前回の発生",
"xpack.datasetQuality.flyout.nonAggregatable.description": "{description}",
"xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "今後の遅れを防止するには、手動でこのデータを{rolloverLink}してください。",
"xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset}は_ignored集約をサポートしていません。データのクエリを実行するときに遅延が生じる可能性があります。{howToFixIt}",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 30cfd990ff4e..9698931c132f 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -14625,7 +14625,6 @@
"xpack.datasetQuality.appTitle": "数据集质量",
"xpack.datasetQuality.betaBadgeDescription": "此功能当前为公测版。如果遇到任何错误或有任何反馈,我们乐于倾听您的意见。请报告支持问题和/或访问我们的讨论论坛。",
"xpack.datasetQuality.betaBadgeLabel": "公测版",
- "xpack.datasetQuality.collapseLabel": "折叠",
"xpack.datasetQuality.datasetQualityColumnName": "数据集质量",
"xpack.datasetQuality.datasetQualityColumnTooltip": "质量基于数据集中的已降级文档的百分比。{visualQueue}",
"xpack.datasetQuality.datasetQualityIdicator": "{quality}",
@@ -14636,9 +14635,6 @@
"xpack.datasetQuality.emptyState.noData.title": "找不到数据集",
"xpack.datasetQuality.emptyState.noPrivileges.message": "您没有查看日志数据所需的权限。请确保您具有足够的权限,可以查看 {datasetPattern}。",
"xpack.datasetQuality.emptyState.noPrivileges.title": "无法加载数据集",
- "xpack.datasetQuality.expandLabel": "展开",
- "xpack.datasetQuality.fetchDatasetDetailsFailed": "无法获取数据集详情。",
- "xpack.datasetQuality.fetchDatasetDetailsFailed.noDatasetSelected": "尚未选择任何数据集",
"xpack.datasetQuality.fetchDatasetStatsFailed": "无法获取数据集。",
"xpack.datasetQuality.fetchDegradedStatsFailed": "无法获取已降级文档信息。",
"xpack.datasetQuality.fetchIntegrationsFailed": "无法获取集成。",
@@ -14646,9 +14642,6 @@
"xpack.datasetQuality.fewDegradedDocsTooltip": "此数据集中的 {degradedDocsCount} 个已降级文档。",
"xpack.datasetQuality.filterBar.placeholder": "筛选数据集",
"xpack.datasetQuality.flyout.degradedDocsTitle": "已降级文档",
- "xpack.datasetQuality.flyout.degradedField.count": "文档计数",
- "xpack.datasetQuality.flyout.degradedField.field": "字段",
- "xpack.datasetQuality.flyout.degradedField.lastOccurrence": "最后一次发生",
"xpack.datasetQuality.flyout.nonAggregatable.description": "{description}",
"xpack.datasetQuality.flyout.nonAggregatable.howToFixIt": "手动 {rolloverLink} 此数据集以防止未来出现延迟。",
"xpack.datasetQuality.flyout.nonAggregatable.warning": "{dataset} 不支持 _ignored 聚合,在查询数据时可能会导致延迟。{howToFixIt}",
diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts
similarity index 69%
rename from x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts
rename to x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts
index 52ccfad201a5..3ac6cf8b4694 100644
--- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_flyout.ts
+++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts
@@ -10,6 +10,7 @@ import { DatasetQualityFtrProviderContext } from './config';
import {
createDegradedFieldsRecord,
datasetNames,
+ defaultNamespace,
getInitialTestLogs,
getLogsForDataset,
productionNamespace,
@@ -33,8 +34,9 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const retry = getService('retry');
const browser = getService('browser');
const to = '2024-01-01T12:00:00.000Z';
+
const apacheAccessDatasetName = 'apache.access';
- const apacheAccessDatasetHumanName = 'Apache access logs';
+ const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${productionNamespace}`;
const apacheIntegrationId = 'apache';
const apachePkg = {
name: 'apache',
@@ -42,15 +44,18 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
};
const bitbucketDatasetName = 'atlassian_bitbucket.audit';
- const bitbucketDatasetHumanName = 'Bitbucket Audit Logs';
+ const bitbucketAuditDataStreamName = `logs-${bitbucketDatasetName}-${defaultNamespace}`;
const bitbucketPkg = {
name: 'atlassian_bitbucket',
version: '1.14.0',
};
+ const regularDatasetName = datasetNames[0];
+ const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`;
const degradedDatasetName = datasetNames[2];
+ const degradedDataStreamName = `logs-${degradedDatasetName}-${defaultNamespace}`;
- describe('Flyout', () => {
+ describe('Dataset Quality Details', () => {
before(async () => {
// Install Apache Integration and ingest logs for it
await PageObjects.observabilityLogsExplorer.installPackage(apachePkg);
@@ -85,8 +90,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
// Index logs for Bitbucket integration
getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName }),
]);
-
- await PageObjects.datasetQuality.navigateTo();
});
after(async () => {
@@ -95,21 +98,49 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
await synthtrace.clean();
});
- describe('open flyout', () => {
- it('should open the flyout for the right dataset', async () => {
- const testDatasetName = datasetNames[1];
+ describe('navigate to dataset details', () => {
+ it('should navigate to right dataset', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({ dataStream: regularDataStreamName });
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle
+ );
+ });
+
+ it('should navigate to details page from a main page', async () => {
+ await PageObjects.datasetQuality.navigateTo();
+
+ const synthDataset = await testSubjects.find(
+ 'datasetQualityTableDetailsLink-logs-synth.1-default',
+ 20 * 1000
+ );
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ await synthDataset.click();
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle
);
+ });
- await PageObjects.datasetQuality.closeFlyout();
+ it('should show an empty prompt with error message when the dataset is not found', async () => {
+ const nonExistentDataStreamName = 'logs-non.existent-production';
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: nonExistentDataStreamName,
+ });
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPrompt
+ );
+
+ const emptyPromptBody = await testSubjects.getVisibleText(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPromptBody
+ );
+
+ expect(emptyPromptBody).to.contain(nonExistentDataStreamName);
});
it('reflects the breakdown field state in url', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName });
const breakdownField = 'service.name';
await PageObjects.datasetQuality.selectBreakdownField(breakdownField);
@@ -128,46 +159,72 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const currentUrl = await browser.getCurrentUrl();
expect(currentUrl).to.not.contain('breakdownField');
});
- await PageObjects.datasetQuality.closeFlyout();
});
});
- describe('integrations', () => {
- it('should hide the integration section for non integrations', async () => {
- const testDatasetName = datasetNames[1];
+ describe('overview summary panel', () => {
+ it('should show summary KPIs', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ const { docsCountTotal, degradedDocs, services, hosts, size } =
+ await PageObjects.datasetQuality.parseOverviewSummaryPanelKpis();
+ expect(parseInt(docsCountTotal, 10)).to.be(226);
+ expect(parseInt(degradedDocs, 10)).to.be(1);
+ expect(parseInt(services, 10)).to.be(3);
+ expect(parseInt(hosts, 10)).to.be(52);
+ expect(parseInt(size, 10)).to.be.greaterThan(0);
+ });
+ });
+ describe('overview integrations', () => {
+ it('should hide the integration section for non integrations', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
+
+ // The Integration row should not be present
await testSubjects.missingOrFail(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails
+ .datasetQualityDetailsIntegrationRowIntegration
);
- await PageObjects.datasetQuality.closeFlyout();
+ // The Version row should not be present
+ await testSubjects.missingOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion
+ );
});
it('should shows the integration section for integrations', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await testSubjects.existOrFail(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails
+ .datasetQualityDetailsIntegrationRowIntegration
+ );
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion
);
await retry.tryForTime(5000, async () => {
const integrationNameExists = await PageObjects.datasetQuality.doesTextExist(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails,
+ .datasetQualityDetailsIntegrationRowIntegration,
apacheIntegrationId
);
expect(integrationNameExists).to.be(true);
});
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should show the integration actions menu with correct actions', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
+
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const actions = await Promise.all(
@@ -177,23 +234,26 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
);
expect(actions.length).to.eql(3);
- await PageObjects.datasetQuality.closeFlyout();
});
it('should hide integration dashboard for integrations without dashboards', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: bitbucketAuditDataStreamName,
+ });
+
await PageObjects.datasetQuality.openIntegrationActionsMenu();
await testSubjects.missingOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction(
integrationActions.viewDashboards
)
);
- await PageObjects.datasetQuality.closeFlyout();
});
it('Should navigate to integration overview page on clicking integration overview action', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: bitbucketAuditDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -208,12 +268,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket');
});
-
- await PageObjects.datasetQuality.navigateTo();
});
it('should navigate to index template page in clicking Integration template', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -229,11 +289,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
`/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}`
);
});
- await PageObjects.datasetQuality.navigateTo();
});
it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -251,119 +312,87 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last');
expect(breadcrumbText).to.eql(dashboardText);
-
- await PageObjects.datasetQuality.navigateTo();
- });
- });
-
- describe('summary panel', () => {
- it('should show summary KPIs', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
-
- const { docsCountTotal, degradedDocs, services, hosts, size } =
- await PageObjects.datasetQuality.parseFlyoutKpis();
- expect(parseInt(docsCountTotal, 10)).to.be(226);
- expect(parseInt(degradedDocs, 10)).to.be(1);
- expect(parseInt(services, 10)).to.be(3);
- expect(parseInt(hosts, 10)).to.be(52);
- expect(parseInt(size, 10)).to.be.greaterThan(0);
-
- await PageObjects.datasetQuality.closeFlyout();
});
});
describe('navigation', () => {
- afterEach(async () => {
- // Navigate back to dataset quality page after each test
- await PageObjects.datasetQuality.navigateTo();
- });
-
it('should go to log explorer page when the open in log explorer button is clicked', async () => {
- const testDatasetName = datasetNames[2];
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
- const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton();
+ const logExplorerButton =
+ await PageObjects.datasetQuality.getDatasetQualityDetailsHeaderButton();
await logExplorerButton.click();
// Confirm dataset selector text in observability logs explorer
const datasetSelectorText =
await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText();
- expect(datasetSelectorText).to.eql(testDatasetName);
+ expect(datasetSelectorText).to.eql(regularDatasetName);
});
- it('should go log explorer for degraded docs when the show all button is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ it('should go log explorer for degraded docs when the button next to breakdown selector is clicked', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
- const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`;
- await testSubjects.click(degradedDocsShowAllSelector);
+ await testSubjects.click(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsLinkToDiscover
+ );
// Confirm dataset selector text in observability logs explorer
const datasetSelectorText =
await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText();
expect(datasetSelectorText).to.contain(apacheAccessDatasetName);
});
-
- // Blocked by https://github.com/elastic/kibana/issues/181705
- // Its a test written ahead of its time.
- it.skip('goes to infra hosts for hosts when show all is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
-
- const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`;
- await testSubjects.click(hostsShowAllSelector);
-
- // Confirm url contains metrics/hosts
- await retry.tryForTime(5000, async () => {
- const currentUrl = await browser.getCurrentUrl();
- const parsedUrl = new URL(currentUrl);
- expect(parsedUrl.pathname).to.contain('/app/metrics/hosts');
- });
- });
});
describe('degraded fields table', () => {
it(' should show empty degraded fields table when no degraded fields are present', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedTableNoData
);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should show the degraded fields table with data when present', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedFieldTable
);
const rows =
- await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows();
+ await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows();
expect(rows.length).to.eql(2);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should display Spark Plot for every row of degraded fields', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const rows =
- await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows();
+ await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows();
const sparkPlots = await testSubjects.findAll(
PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot
);
expect(rows.length).to.be(sparkPlots.length);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should sort the table when the count table header is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
@@ -374,12 +403,12 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const sortedCellTexts = await countColumn.getCellTexts();
expect(cellTexts.reverse()).to.eql(sortedCellTexts);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should update the URL when the table is sorted', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
const countColumn = table['Docs count'];
@@ -405,8 +434,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
'sort:(direction:asc,field:count)'
);
});
-
- await PageObjects.datasetQuality.closeFlyout();
});
// This is the only test which ingest data during the test.
@@ -414,7 +441,9 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
// Even though this test ingest data, it can also be freely moved inside
// this describe block, and it won't affect any of the existing tests
it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
@@ -429,7 +458,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
}),
]);
- await PageObjects.datasetQuality.refreshFlyout();
+ await PageObjects.datasetQuality.refreshDetailsPageData();
const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable();
const updatedCountColumn = updatedTable['Docs count'];
@@ -440,8 +469,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const singleValueNow = parseInt(updatedCellTexts[0], 10);
expect(singleValueNow).to.be.greaterThan(singleValuePreviously);
-
- await PageObjects.datasetQuality.closeFlyout();
});
});
});
diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts
index c7c3cbf70993..c94a08394606 100644
--- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts
+++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_privileges.ts
@@ -7,7 +7,7 @@
import expect from '@kbn/expect';
import { DatasetQualityFtrProviderContext } from './config';
-import { getInitialTestLogs, getLogsForDataset } from './data';
+import { datasetNames, defaultNamespace, getInitialTestLogs, getLogsForDataset } from './data';
export default function ({ getService, getPageObjects }: DatasetQualityFtrProviderContext) {
const PageObjects = getPageObjects([
@@ -25,6 +25,8 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
const apacheAccessDatasetName = 'apache.access';
const apacheAccessDatasetHumanName = 'Apache access logs';
+ const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`;
+ const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${defaultNamespace}`;
describe('Dataset quality handles user privileges', () => {
before(async () => {
@@ -170,35 +172,39 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid
);
});
- it('flyout shows insufficient privileges warning for underprivileged data stream', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout('synth.1');
+ it('Details page shows insufficient privileges warning for underprivileged data stream', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
await testSubjects.existOrFail(
`${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityInsufficientPrivileges}-Size`
);
- await PageObjects.datasetQuality.closeFlyout();
+ await PageObjects.datasetQuality.navigateTo();
});
it('"View dashboards" and "See integration" are hidden for underprivileged user', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
// "See Integration" is hidden
await testSubjects.missingOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction(
'Overview'
)
);
// "View Dashboards" is hidden
await testSubjects.missingOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction(
'ViewDashboards'
)
);
- await PageObjects.datasetQuality.closeFlyout();
+ await PageObjects.datasetQuality.navigateTo();
});
});
});
diff --git a/x-pack/test/functional/apps/dataset_quality/index.ts b/x-pack/test/functional/apps/dataset_quality/index.ts
index f22af151ca6c..ec975f6cafff 100644
--- a/x-pack/test/functional/apps/dataset_quality/index.ts
+++ b/x-pack/test/functional/apps/dataset_quality/index.ts
@@ -13,7 +13,7 @@ export default function ({ loadTestFile }: DatasetQualityFtrProviderContext) {
loadTestFile(require.resolve('./dataset_quality_summary'));
loadTestFile(require.resolve('./dataset_quality_table'));
loadTestFile(require.resolve('./dataset_quality_table_filters'));
- loadTestFile(require.resolve('./dataset_quality_flyout'));
loadTestFile(require.resolve('./dataset_quality_privileges'));
+ loadTestFile(require.resolve('./dataset_quality_details'));
});
}
diff --git a/x-pack/test/functional/page_objects/dataset_quality.ts b/x-pack/test/functional/page_objects/dataset_quality.ts
index b2d07161ddba..8fdc021af79f 100644
--- a/x-pack/test/functional/page_objects/dataset_quality.ts
+++ b/x-pack/test/functional/page_objects/dataset_quality.ts
@@ -7,12 +7,11 @@
import querystring from 'querystring';
import rison from '@kbn/rison';
-import expect from '@kbn/expect';
-import { TimeUnitId } from '@elastic/eui';
import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services';
import {
DATA_QUALITY_URL_STATE_KEY,
datasetQualityUrlSchemaV1,
+ datasetQualityDetailsUrlSchemaV1,
} from '@kbn/data-quality-plugin/common';
import {
DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
@@ -26,15 +25,18 @@ const defaultPageState: datasetQualityUrlSchemaV1.UrlSchema = {
page: 0,
},
filters: {},
- flyout: {
- degradedFields: {
- table: {
- page: 0,
- rowsPerPage: 10,
- sort: {
- field: DEFAULT_DEGRADED_FIELD_SORT_FIELD,
- direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
- },
+};
+
+const defaultDetailsPageState: datasetQualityDetailsUrlSchemaV1.UrlSchema = {
+ v: 1,
+ dataStream: 'logs-synth.1-default',
+ degradedFields: {
+ table: {
+ page: 0,
+ rowsPerPage: 10,
+ sort: {
+ field: DEFAULT_DEGRADED_FIELD_SORT_FIELD,
+ direction: DEFAULT_DEGRADED_FIELD_SORT_DIRECTION,
},
},
},
@@ -49,7 +51,10 @@ type SummaryPanelKpi = Record<
string
>;
-type FlyoutKpi = Record<'docsCountTotal' | 'size' | 'services' | 'hosts' | 'degradedDocs', string>;
+type SummaryPanelKPI = Record<
+ 'docsCountTotal' | 'size' | 'services' | 'hosts' | 'degradedDocs',
+ string
+>;
const texts = {
noActivityText: 'No activity in the selected timeframe',
@@ -58,7 +63,7 @@ const texts = {
datasetHealthGood: 'Good',
activeDatasets: 'Active Data Sets',
estimatedData: 'Estimated Data',
- docsCountTotal: 'Docs count (total)',
+ docsCountTotal: 'Total count',
size: 'Size',
services: 'Services',
hosts: 'Hosts',
@@ -86,20 +91,16 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
datasetQualityTable: 'datasetQualityTable',
datasetQualityFiltersContainer: 'datasetQualityFiltersContainer',
datasetQualityExpandButton: 'datasetQualityExpandButton',
- datasetQualityFlyout: 'datasetQualityFlyout',
- datasetQualityFlyoutBody: 'datasetQualityFlyoutBody',
- datasetQualityFlyoutTitle: 'datasetQualityFlyoutTitle',
- datasetQualityFlyoutDegradedFieldTable: 'datasetQualityFlyoutDegradedFieldTable',
- datasetQualityFlyoutDegradedTableNoData: 'datasetQualityFlyoutDegradedTableNoData',
+ datasetDetailsContainer: 'datasetDetailsContainer',
+ datasetQualityDetailsTitle: 'datasetQualityDetailsTitle',
+ datasetQualityDetailsDegradedFieldTable: 'datasetQualityDetailsDegradedFieldTable',
+ datasetQualityDetailsDegradedTableNoData: 'datasetQualityDetailsDegradedTableNoData',
datasetQualitySparkPlot: 'datasetQualitySparkPlot',
- datasetQualityHeaderButton: 'datasetQualityHeaderButton',
- datasetQualityFlyoutFieldValue: 'datasetQualityFlyoutFieldValue',
- datasetQualityFlyoutFieldsListIntegrationDetails:
- 'datasetQualityFlyoutFieldsList-integration_details',
- datasetQualityFlyoutIntegrationLoading: 'datasetQualityFlyoutIntegrationLoading',
- datasetQualityFlyoutIntegrationActionsButton: 'datasetQualityFlyoutIntegrationActionsButton',
- datasetQualityFlyoutIntegrationAction: (action: string) =>
- `datasetQualityFlyoutIntegrationAction${action}`,
+ datasetQualityDetailsHeaderButton: 'datasetQualityDetailsHeaderButton',
+ datasetQualityDetailsIntegrationLoading: 'datasetQualityDetailsIntegrationLoading',
+ datasetQualityDetailsIntegrationActionsButton: 'datasetQualityDetailsIntegrationActionsButton',
+ datasetQualityDetailsIntegrationAction: (action: string) =>
+ `datasetQualityDetailsIntegrationAction${action}`,
datasetQualityFilterBarFieldSearch: 'datasetQualityFilterBarFieldSearch',
datasetQualityIntegrationsSelectable: 'datasetQualityIntegrationsSelectable',
datasetQualityIntegrationsSelectableButton: 'datasetQualityIntegrationsSelectableButton',
@@ -107,9 +108,13 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
datasetQualityNamespacesSelectableButton: 'datasetQualityNamespacesSelectableButton',
datasetQualityQualitiesSelectable: 'datasetQualityQualitiesSelectable',
datasetQualityQualitiesSelectableButton: 'datasetQualityQualitiesSelectableButton',
+ datasetQualityDetailsEmptyPrompt: 'datasetQualityDetailsEmptyPrompt',
+ datasetQualityDetailsEmptyPromptBody: 'datasetQualityDetailsEmptyPromptBody',
datasetQualityDatasetHealthKpi: 'datasetQualityDatasetHealthKpi',
- datasetQualityFlyoutKpiValue: 'datasetQualityFlyoutKpiValue',
- datasetQualityFlyoutKpiLink: 'datasetQualityFlyoutKpiLink',
+ datasetQualityDetailsSummaryKpiValue: 'datasetQualityDetailsSummaryKpiValue',
+ datasetQualityDetailsIntegrationRowIntegration: 'datasetQualityDetailsFieldsList-integration',
+ datasetQualityDetailsIntegrationRowVersion: 'datasetQualityDetailsFieldsList-version',
+ datasetQualityDetailsLinkToDiscover: 'datasetQualityDetailsLinkToDiscover',
datasetQualityInsufficientPrivileges: 'datasetQualityInsufficientPrivileges',
datasetQualityNoDataEmptyState: 'datasetQualityNoDataEmptyState',
datasetQualityNoPrivilegesEmptyState: 'datasetQualityNoPrivilegesEmptyState',
@@ -117,7 +122,6 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
superDatePickerToggleQuickMenuButton: 'superDatePickerToggleQuickMenuButton',
superDatePickerApplyTimeButton: 'superDatePickerApplyTimeButton',
superDatePickerQuickMenu: 'superDatePickerQuickMenu',
- euiFlyoutCloseButton: 'euiFlyoutCloseButton',
unifiedHistogramBreakdownSelectorButton: 'unifiedHistogramBreakdownSelectorButton',
unifiedHistogramBreakdownSelectorSelectorSearch:
'unifiedHistogramBreakdownSelectorSelectorSearch',
@@ -156,19 +160,30 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
);
},
- async waitUntilTableLoaded() {
- await find.waitForDeletedByCssSelector('.euiBasicTable-loading', 20 * 1000);
- },
+ async navigateToDetails(pageState: datasetQualityDetailsUrlSchemaV1.UrlSchema) {
+ const queryStringParams = querystring.stringify({
+ [DATA_QUALITY_URL_STATE_KEY]: rison.encode(
+ datasetQualityDetailsUrlSchemaV1.urlSchemaRT.encode({
+ ...defaultDetailsPageState,
+ ...pageState,
+ })
+ ),
+ });
- async waitUntilTableInFlyoutLoaded() {
- await find.waitForDeletedByCssSelector('.euiFlyoutBody .euiBasicTable-loading', 20 * 1000);
+ return PageObjects.common.navigateToUrlWithBrowserHistory(
+ 'management',
+ '/data/data_quality/details',
+ queryStringParams,
+ {
+ // the check sometimes is too slow for the page so it misses the point
+ // in time before the app rewrites the URL
+ ensureCurrentUrl: false,
+ }
+ );
},
- async waitUntilIntegrationsInFlyoutLoaded() {
- await find.waitForDeletedByCssSelector(
- '.euiSkeletonTitle .datasetQualityFlyoutIntegrationLoading',
- 10 * 1000
- );
+ async waitUntilTableLoaded() {
+ await find.waitForDeletedByCssSelector('.euiBasicTable-loading', 20 * 1000);
},
async waitUntilSummaryPanelLoaded(isStateful: boolean = true) {
@@ -213,14 +228,14 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
return testSubjects.find(testSubjectSelectors.datasetQualityTable);
},
- getDatasetQualityFlyoutDegradedFieldTable(): Promise {
- return testSubjects.find(testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable);
+ getDatasetQualityDetailsDegradedFieldTable(): Promise {
+ return testSubjects.find(testSubjectSelectors.datasetQualityDetailsDegradedFieldTable);
},
- async getDatasetQualityFlyoutDegradedFieldTableRows(): Promise {
- await this.waitUntilTableInFlyoutLoaded();
+ async getDatasetQualityDetailsDegradedFieldTableRows(): Promise {
+ await this.waitUntilTableLoaded();
const table = await testSubjects.find(
- testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable
+ testSubjectSelectors.datasetQualityDetailsDegradedFieldTable
);
const tBody = await table.findByTagName('tbody');
return tBody.findAllByTagName('tr');
@@ -265,8 +280,8 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
},
async parseDegradedFieldTable() {
- await this.waitUntilTableInFlyoutLoaded();
- const table = await this.getDatasetQualityFlyoutDegradedFieldTable();
+ await this.waitUntilTableLoaded();
+ const table = await this.getDatasetQualityDetailsDegradedFieldTable();
return this.parseTable(table, ['Field', 'Docs count', 'Last Occurrence']);
},
@@ -302,46 +317,11 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
return find.clickByCssSelector(selectors.showFullDatasetNamesSwitch);
},
- async openDatasetFlyout(datasetName: string) {
- await this.waitUntilTableLoaded();
- const cols = await this.parseDatasetTable();
- const datasetNameCol = cols['Data Set Name'];
- const datasetNameColCellTexts = await datasetNameCol.getCellTexts();
- const testDatasetRowIndex = datasetNameColCellTexts.findIndex(
- (dName) => dName === datasetName
+ async refreshDetailsPageData() {
+ const datasetDetailsContainer: WebElementWrapper = await testSubjects.find(
+ testSubjectSelectors.datasetDetailsContainer
);
-
- expect(testDatasetRowIndex).to.be.greaterThan(-1);
-
- const expandColumn = cols['0'];
- const expandButtons = await expandColumn.getCellChildren(
- `[data-test-subj=${testSubjectSelectors.datasetQualityExpandButton}]`
- );
-
- expect(expandButtons.length).to.be.greaterThan(0);
-
- const datasetExpandButton = expandButtons[testDatasetRowIndex];
-
- // Check if 'title' attribute is "Expand" or "Collapse"
- const isCollapsed = (await datasetExpandButton.getAttribute('title')) === 'Expand';
-
- // Open if collapsed
- if (isCollapsed) {
- await datasetExpandButton.click();
- }
-
- await this.waitUntilIntegrationsInFlyoutLoaded();
- },
-
- async closeFlyout() {
- return testSubjects.click(testSubjectSelectors.euiFlyoutCloseButton);
- },
-
- async refreshFlyout() {
- const flyoutContainer: WebElementWrapper = await testSubjects.find(
- testSubjectSelectors.datasetQualityFlyoutBody
- );
- const refreshButton = await flyoutContainer.findByTestSubject(
+ const refreshButton = await datasetDetailsContainer.findByTestSubject(
testSubjectSelectors.superDatePickerApplyTimeButton
);
return refreshButton.click();
@@ -357,27 +337,27 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
return false;
},
- getFlyoutLogsExplorerButton() {
- return testSubjects.find(testSubjectSelectors.datasetQualityHeaderButton);
+ getDatasetQualityDetailsHeaderButton() {
+ return testSubjects.find(testSubjectSelectors.datasetQualityDetailsHeaderButton);
},
openIntegrationActionsMenu() {
- return testSubjects.click(testSubjectSelectors.datasetQualityFlyoutIntegrationActionsButton);
+ return testSubjects.click(testSubjectSelectors.datasetQualityDetailsIntegrationActionsButton);
},
getIntegrationActionButtonByAction(action: string) {
- return testSubjects.find(testSubjectSelectors.datasetQualityFlyoutIntegrationAction(action));
+ return testSubjects.find(testSubjectSelectors.datasetQualityDetailsIntegrationAction(action));
},
getIntegrationDashboardButtons() {
return testSubjects.findAll(
- testSubjectSelectors.datasetQualityFlyoutIntegrationAction('Dashboard')
+ testSubjectSelectors.datasetQualityDetailsIntegrationAction('Dashboard')
);
},
// `excludeKeys` needed to circumvent `_stats` not available in Serverless https://github.com/elastic/kibana/issues/178954
// TODO: Remove `excludeKeys` when `_stats` is available in Serverless
- async parseFlyoutKpis(excludeKeys: string[] = []): Promise {
+ async parseOverviewSummaryPanelKpis(excludeKeys: string[] = []): Promise {
const kpiTitleAndKeys = [
{ title: texts.docsCountTotal, key: 'docsCountTotal' },
{ title: texts.size, key: 'size' },
@@ -390,7 +370,7 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
kpiTitleAndKeys.map(async ({ title, key }) => ({
key,
value: await testSubjects.getVisibleText(
- `${testSubjectSelectors.datasetQualityFlyoutKpiValue}-${title}`
+ `${testSubjectSelectors.datasetQualityDetailsSummaryKpiValue}-${title}`
),
}))
);
@@ -400,52 +380,10 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv
...acc,
[key]: value,
}),
- {} as FlyoutKpi
+ {} as SummaryPanelKPI
);
},
- async setDatePickerLastXUnits(
- container: WebElementWrapper,
- timeValue: number,
- unit: TimeUnitId
- ) {
- // Only click the menu button found under the provided container
- const datePickerToggleQuickMenuButton = await container.findByTestSubject(
- testSubjectSelectors.superDatePickerToggleQuickMenuButton
- );
- await datePickerToggleQuickMenuButton.click();
-
- const datePickerQuickMenu = await testSubjects.find(
- testSubjectSelectors.superDatePickerQuickMenu
- );
-
- const timeTenseSelect = await datePickerQuickMenu.findByCssSelector(
- `select[aria-label="Time tense"]`
- );
- const timeValueInput = await datePickerQuickMenu.findByCssSelector(
- `input[aria-label="Time value"]`
- );
- const timeUnitSelect = await datePickerQuickMenu.findByCssSelector(
- `select[aria-label="Time unit"]`
- );
-
- await timeTenseSelect.focus();
- await timeTenseSelect.type('Last');
-
- await timeValueInput.focus();
- await timeValueInput.clearValue();
- await timeValueInput.type(timeValue.toString());
-
- await timeUnitSelect.focus();
- await timeUnitSelect.type(unit);
-
- await (
- await datePickerQuickMenu.findByCssSelector(selectors.superDatePickerApplyButton)
- ).click();
-
- return testSubjects.missingOrFail(testSubjectSelectors.superDatePickerQuickMenu);
- },
-
/**
* Selects a breakdown field from the unified histogram breakdown selector
* @param fieldText The text of the field to select. Use 'No breakdown' to clear the selection
diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts
similarity index 69%
rename from x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts
rename to x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts
index fda145ebfea7..bca31c506a77 100644
--- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_flyout.ts
+++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts
@@ -6,6 +6,7 @@
*/
import expect from '@kbn/expect';
+import { defaultNamespace } from '@kbn/test-suites-xpack/functional/apps/dataset_quality/data';
import { FtrProviderContext } from '../../../ftr_provider_context';
import {
datasetNames,
@@ -38,7 +39,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const excludeKeysFromServerless = ['size']; // https://github.com/elastic/kibana/issues/178954
const apacheAccessDatasetName = 'apache.access';
- const apacheAccessDatasetHumanName = 'Apache access logs';
+ const apacheAccessDataStreamName = `logs-${apacheAccessDatasetName}-${productionNamespace}`;
const apacheIntegrationId = 'apache';
const apachePkg = {
name: 'apache',
@@ -46,13 +47,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
};
const bitbucketDatasetName = 'atlassian_bitbucket.audit';
- const bitbucketDatasetHumanName = 'Bitbucket Audit Logs';
+ const bitbucketAuditDataStreamName = `logs-${bitbucketDatasetName}-${defaultNamespace}`;
const bitbucketPkg = {
name: 'atlassian_bitbucket',
version: '1.14.0',
};
+ const regularDatasetName = datasetNames[0];
+ const regularDataStreamName = `logs-${datasetNames[0]}-${defaultNamespace}`;
const degradedDatasetName = datasetNames[2];
+ const degradedDataStreamName = `logs-${degradedDatasetName}-${defaultNamespace}`;
describe('Flyout', function () {
before(async () => {
@@ -91,8 +95,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
]);
await PageObjects.svlCommonPage.loginWithPrivilegedRole();
-
- await PageObjects.datasetQuality.navigateTo();
});
after(async () => {
@@ -101,21 +103,49 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await synthtrace.clean();
});
- describe('open flyout', () => {
- it('should open the flyout for the right dataset', async () => {
- const testDatasetName = datasetNames[1];
+ describe('navigate to dataset details', () => {
+ it('should navigate to right dataset', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({ dataStream: regularDataStreamName });
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle
+ );
+ });
+
+ it('should navigate to details page from a main page', async () => {
+ await PageObjects.datasetQuality.navigateTo();
+
+ const synthDataset = await testSubjects.find(
+ 'datasetQualityTableDetailsLink-logs-synth.1-default',
+ 20 * 1000
+ );
+
+ await synthDataset.click();
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsTitle
+ );
+ });
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ it('should show an empty prompt with error message when the dataset is not found', async () => {
+ const nonExistentDataStreamName = 'logs-non.existent-production';
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: nonExistentDataStreamName,
+ });
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutTitle
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPrompt
+ );
+
+ const emptyPromptBody = await testSubjects.getVisibleText(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsEmptyPromptBody
);
- await PageObjects.datasetQuality.closeFlyout();
+ expect(emptyPromptBody).to.contain(nonExistentDataStreamName);
});
it('reflects the breakdown field state in url', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName });
const breakdownField = 'service.name';
await PageObjects.datasetQuality.selectBreakdownField(breakdownField);
@@ -134,46 +164,71 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const currentUrl = await browser.getCurrentUrl();
expect(currentUrl).to.not.contain('breakdownField');
});
- await PageObjects.datasetQuality.closeFlyout();
});
});
- describe('integrations', () => {
- it('should hide the integration section for non integrations', async () => {
- const testDatasetName = datasetNames[1];
+ describe('overview summary panel', () => {
+ it('should show summary KPIs', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ const { docsCountTotal, degradedDocs, services, hosts } =
+ await PageObjects.datasetQuality.parseOverviewSummaryPanelKpis(excludeKeysFromServerless);
+ expect(parseInt(docsCountTotal, 10)).to.be(226);
+ expect(parseInt(degradedDocs, 10)).to.be(1);
+ expect(parseInt(services, 10)).to.be(3);
+ expect(parseInt(hosts, 10)).to.be(52);
+ });
+ });
+ describe('overview integrations', () => {
+ it('should hide the integration section for non integrations', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
+
+ // The Integration row should not be present
await testSubjects.missingOrFail(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails
+ .datasetQualityDetailsIntegrationRowIntegration
);
- await PageObjects.datasetQuality.closeFlyout();
+ // The Version row should not be present
+ await testSubjects.missingOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion
+ );
});
it('should shows the integration section for integrations', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await testSubjects.existOrFail(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails
+ .datasetQualityDetailsIntegrationRowIntegration
+ );
+
+ await testSubjects.existOrFail(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationRowVersion
);
await retry.tryForTime(5000, async () => {
const integrationNameExists = await PageObjects.datasetQuality.doesTextExist(
PageObjects.datasetQuality.testSubjectSelectors
- .datasetQualityFlyoutFieldsListIntegrationDetails,
+ .datasetQualityDetailsIntegrationRowIntegration,
apacheIntegrationId
);
expect(integrationNameExists).to.be(true);
});
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should show the integration actions menu with correct actions', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
+
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const actions = await Promise.all(
@@ -183,23 +238,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
);
expect(actions.length).to.eql(3);
- await PageObjects.datasetQuality.closeFlyout();
});
it('should hide integration dashboard for integrations without dashboards', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: bitbucketAuditDataStreamName,
+ });
+
await PageObjects.datasetQuality.openIntegrationActionsMenu();
await testSubjects.missingOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutIntegrationAction(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsIntegrationAction(
integrationActions.viewDashboards
)
);
- await PageObjects.datasetQuality.closeFlyout();
});
it('Should navigate to integration overview page on clicking integration overview action', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(bitbucketDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: bitbucketAuditDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -214,12 +272,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
expect(parsedUrl.pathname).to.contain('/app/integrations/detail/atlassian_bitbucket');
});
-
- await PageObjects.datasetQuality.navigateTo();
});
it('should navigate to index template page in clicking Integration template', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -235,11 +293,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
`/app/management/data/index_management/templates/logs-${apacheAccessDatasetName}`
);
});
- await PageObjects.datasetQuality.navigateTo();
});
it('should navigate to the selected dashboard on clicking integration dashboard action ', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
await PageObjects.datasetQuality.openIntegrationActionsMenu();
const action = await PageObjects.datasetQuality.getIntegrationActionButtonByAction(
@@ -257,118 +316,87 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const breadcrumbText = await testSubjects.getVisibleText('breadcrumb last');
expect(breadcrumbText).to.eql(dashboardText);
-
- await PageObjects.datasetQuality.navigateTo();
- });
- });
-
- describe('summary panel', () => {
- it('should show summary KPIs', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
-
- const { docsCountTotal, degradedDocs, services, hosts } =
- await PageObjects.datasetQuality.parseFlyoutKpis(excludeKeysFromServerless);
- expect(parseInt(docsCountTotal, 10)).to.be(226);
- expect(parseInt(degradedDocs, 10)).to.be(1);
- expect(parseInt(services, 10)).to.be(3);
- expect(parseInt(hosts, 10)).to.be(52);
-
- await PageObjects.datasetQuality.closeFlyout();
});
});
describe('navigation', () => {
- afterEach(async () => {
- // Navigate back to dataset quality page after each test
- await PageObjects.datasetQuality.navigateTo();
- });
-
it('should go to log explorer page when the open in log explorer button is clicked', async () => {
- const testDatasetName = datasetNames[2];
- await PageObjects.datasetQuality.openDatasetFlyout(testDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
- const logExplorerButton = await PageObjects.datasetQuality.getFlyoutLogsExplorerButton();
+ const logExplorerButton =
+ await PageObjects.datasetQuality.getDatasetQualityDetailsHeaderButton();
await logExplorerButton.click();
// Confirm dataset selector text in observability logs explorer
const datasetSelectorText =
await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText();
- expect(datasetSelectorText).to.eql(testDatasetName);
+ expect(datasetSelectorText).to.eql(regularDatasetName);
});
- it('should go log explorer for degraded docs when the show all button is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
+ it('should go log explorer for degraded docs when the button next to breakdown selector is clicked', async () => {
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: apacheAccessDataStreamName,
+ });
- const degradedDocsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.degradedDocs}`;
- await testSubjects.click(degradedDocsShowAllSelector);
+ await testSubjects.click(
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsLinkToDiscover
+ );
// Confirm dataset selector text in observability logs explorer
const datasetSelectorText =
await PageObjects.observabilityLogsExplorer.getDataSourceSelectorButtonText();
expect(datasetSelectorText).to.contain(apacheAccessDatasetName);
});
-
- // Blocked by https://github.com/elastic/kibana/issues/181705
- // Its a test written ahead of its time.
- it.skip('goes to infra hosts for hosts when show all is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(apacheAccessDatasetHumanName);
-
- const hostsShowAllSelector = `${PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutKpiLink}-${PageObjects.datasetQuality.texts.hosts}`;
- await testSubjects.click(hostsShowAllSelector);
-
- // Confirm url contains metrics/hosts
- await retry.tryForTime(5000, async () => {
- const currentUrl = await browser.getCurrentUrl();
- const parsedUrl = new URL(currentUrl);
- expect(parsedUrl.pathname).to.contain('/app/metrics/hosts');
- });
- });
});
describe('degraded fields table', () => {
it(' should show empty degraded fields table when no degraded fields are present', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(datasetNames[0]);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: regularDataStreamName,
+ });
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedTableNoData
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedTableNoData
);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should show the degraded fields table with data when present', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
await testSubjects.existOrFail(
- PageObjects.datasetQuality.testSubjectSelectors.datasetQualityFlyoutDegradedFieldTable
+ PageObjects.datasetQuality.testSubjectSelectors.datasetQualityDetailsDegradedFieldTable
);
const rows =
- await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows();
+ await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows();
expect(rows.length).to.eql(2);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should display Spark Plot for every row of degraded fields', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const rows =
- await PageObjects.datasetQuality.getDatasetQualityFlyoutDegradedFieldTableRows();
+ await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows();
const sparkPlots = await testSubjects.findAll(
PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot
);
expect(rows.length).to.be(sparkPlots.length);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should sort the table when the count table header is clicked', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
@@ -379,12 +407,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const sortedCellTexts = await countColumn.getCellTexts();
expect(cellTexts.reverse()).to.eql(sortedCellTexts);
-
- await PageObjects.datasetQuality.closeFlyout();
});
it('should update the URL when the table is sorted', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
const countColumn = table['Docs count'];
@@ -410,8 +438,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
'sort:(direction:asc,field:count)'
);
});
-
- await PageObjects.datasetQuality.closeFlyout();
});
// This is the only test which ingest data during the test.
@@ -419,7 +445,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// Even though this test ingest data, it can also be freely moved inside
// this describe block, and it won't affect any of the existing tests
it('should update the table when new data is ingested and the flyout is refreshed using the time selector', async () => {
- await PageObjects.datasetQuality.openDatasetFlyout(degradedDatasetName);
+ await PageObjects.datasetQuality.navigateToDetails({
+ dataStream: degradedDataStreamName,
+ });
const table = await PageObjects.datasetQuality.parseDegradedFieldTable();
@@ -434,7 +462,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
}),
]);
- await PageObjects.datasetQuality.refreshFlyout();
+ await PageObjects.datasetQuality.refreshDetailsPageData();
const updatedTable = await PageObjects.datasetQuality.parseDegradedFieldTable();
const updatedCountColumn = updatedTable['Docs count'];
@@ -445,8 +473,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const singleValueNow = parseInt(updatedCellTexts[0], 10);
expect(singleValueNow).to.be.greaterThan(singleValuePreviously);
-
- await PageObjects.datasetQuality.closeFlyout();
});
});
});
diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts
index 30547ceb941b..683c879ae4e3 100644
--- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts
+++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/index.ts
@@ -13,7 +13,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./dataset_quality_summary'));
loadTestFile(require.resolve('./dataset_quality_table'));
loadTestFile(require.resolve('./dataset_quality_table_filters'));
- loadTestFile(require.resolve('./dataset_quality_flyout'));
loadTestFile(require.resolve('./dataset_quality_privileges'));
+ loadTestFile(require.resolve('./dataset_quality_details'));
});
}