Skip to content

Commit

Permalink
[Dataset quality] Degraded docs insights in flyout (#176912)
Browse files Browse the repository at this point in the history
The PR adds the Degraded Docs insights panel which shows the percentage
of degraded docs over time using Lens Embeddable.

<img width="621" alt="Screenshot 2024-02-14 at 13 25 19"
src="https://github.com/elastic/kibana/assets/2748376/2ae421b1-bfae-44e2-8da5-a2063061d761">

<img width="981" alt="Screenshot 2024-02-14 at 13 15 33"
src="https://github.com/elastic/kibana/assets/2748376/7d70cb6b-0d5a-4c7c-84f6-509eb12886d3">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
awahab07 and kibanamachine committed Feb 22, 2024
1 parent ff15ecf commit e610f09
Show file tree
Hide file tree
Showing 16 changed files with 570 additions and 19 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-timerange/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const { startDate, endDate } = getDateRange({ from: 'now-24h', to: 'now' });
This function return an ISO string for `startDate` and `endDate` of a given date range.

```tsx
import { getDateRange } from '@kbn/timerange';
import { getDateISORange } from '@kbn/timerange';

const { startDate, endDate } = getDateISORange({ from: 'now-24h', to: 'now' });
```
1 change: 1 addition & 0 deletions x-pack/plugins/dataset_quality/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

export const DATASET_QUALITY_APP_ID = 'dataset_quality';
export const DEFAULT_DATASET_TYPE = 'logs';
export const DEFAULT_LOGS_DATA_VIEW = 'logs-*-*';

export const POOR_QUALITY_MINIMUM_PERCENTAGE = 3;
export const DEGRADED_QUALITY_MINIMUM_PERCENTAGE = 0;
Expand Down
26 changes: 26 additions & 0 deletions x-pack/plugins/dataset_quality/common/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export const tableSummaryOfText = i18n.translate('xpack.datasetQuality.tableSumm
defaultMessage: 'of',
});

/*
Flyout
*/

export const flyoutCancelText = i18n.translate('xpack.datasetQuality.flyoutCancelText', {
defaultMessage: 'Cancel',
});
Expand Down Expand Up @@ -84,6 +88,28 @@ export const flyoutIntegrationNameText = i18n.translate(
}
);

export const flyoutDegradedDocsText = i18n.translate(
'xpack.datasetQuality.flyout.degradedDocsTitle',
{
defaultMessage: 'Degraded docs',
}
);

export const flyoutDegradedDocsTrendText = i18n.translate(
'xpack.datasetQuality.flyoutDegradedDocsViz',
{
defaultMessage: 'Degraded documents trend',
}
);

export const flyoutDegradedDocsPercentageText = i18n.translate(
'xpack.datasetQuality.flyoutDegradedDocsPercentage',
{
defaultMessage: 'Degraded docs %',
description: 'Tooltip label for the percentage of degraded documents chart.',
}
);

/*
Summary Panel
*/
Expand Down
23 changes: 20 additions & 3 deletions x-pack/plugins/dataset_quality/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,27 @@
"id": "datasetQuality",
"server": true,
"browser": true,
"configPath": ["xpack", "datasetQuality"],
"requiredPlugins": ["data", "kibanaReact", "kibanaUtils", "controls", "embeddable", "share", "observabilityShared", "fleet", "fieldFormats"],
"configPath": [
"xpack",
"datasetQuality"
],
"requiredPlugins": [
"data",
"kibanaReact",
"kibanaUtils",
"controls",
"embeddable",
"share",
"observabilityShared",
"fleet",
"fieldFormats",
"dataViews",
"lens"
],
"optionalPlugins": [],
"requiredBundles": [],
"extraPublicDirs": ["common"]
"extraPublicDirs": [
"common"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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 { css } from '@emotion/react';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiFlexGroup,
EuiPanel,
EuiSpacer,
EuiTitle,
EuiText,
EuiSuperDatePicker,
OnRefreshProps,
EuiToolTip,
EuiIcon,
EuiCode,
} from '@elastic/eui';

import { DEFAULT_TIME_RANGE } from '../../../../common/constants';
import { flyoutDegradedDocsText } from '../../../../common/translations';
import { TimeRangeConfig } from '../../../state_machines/dataset_quality_controller';
import { useDatasetQualityContext } from '../../dataset_quality/context';
import { DegradedDocsChart } from './degraded_docs_chart';

const DEFAULT_REFRESH = { interval: 60000, isPaused: false };

export function DegradedDocs({
dataStream,
timeRange = { ...DEFAULT_TIME_RANGE, refresh: DEFAULT_REFRESH },
}: {
dataStream?: string;
timeRange?: TimeRangeConfig;
}) {
const { service } = useDatasetQualityContext();

const [lastReloadTime, setLastReloadTime] = useState<number>(Date.now());

const handleRefresh = useCallback((_refreshProps: OnRefreshProps) => {
setLastReloadTime(Date.now());
}, []);

const handleTimeChange = useCallback(
(durationRange) => {
service.send({
type: 'UPDATE_INSIGHTS_TIME_RANGE',
timeRange: {
from: durationRange.start,
to: durationRange.end,
refresh: timeRange.refresh ?? DEFAULT_REFRESH,
},
});
},
[service, timeRange.refresh]
);

return (
<EuiPanel hasBorder grow={false}>
<EuiFlexGroup alignItems="center" wrap={true}>
<EuiFlexGroup
css={css`
flex-grow: 1;
`}
justifyContent="flexStart"
alignItems="center"
gutterSize="xs"
>
<EuiTitle size="s">
<EuiText>{flyoutDegradedDocsText}</EuiText>
</EuiTitle>
<EuiToolTip content={degradedDocsTooltip}>
<EuiIcon size="m" color="subdued" type="questionInCircle" className="eui-alignTop" />
</EuiToolTip>
</EuiFlexGroup>

<EuiFlexGroup
css={css`
flex-grow: 0;
`}
>
<EuiSuperDatePicker
width="auto"
compressed={true}
isLoading={false}
start={timeRange.from}
end={timeRange.to}
onTimeChange={handleTimeChange}
onRefresh={handleRefresh}
isQuickSelectOnly={false}
showUpdateButton="iconOnly"
updateButtonProps={{ fill: false }}
/>
</EuiFlexGroup>
</EuiFlexGroup>
<EuiSpacer />
<DegradedDocsChart
dataStream={dataStream}
timeRange={timeRange}
lastReloadTime={lastReloadTime}
/>
</EuiPanel>
);
}

const degradedDocsTooltip = (
<FormattedMessage
id="xpack.datasetQuality.flyoutDegradedDocsTooltip"
defaultMessage="The percentage of degraded documents —documents with the {ignoredProperty} property— in your dataset."
values={{
ignoredProperty: (
<EuiCode language="json" transparentBackground>
_ignored
</EuiCode>
),
}}
/>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* 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 { useEuiTheme, EuiFlexGroup, EuiLoadingChart } from '@elastic/eui';
import { ViewMode } from '@kbn/embeddable-plugin/common';
import { KibanaErrorBoundary } from '@kbn/shared-ux-error-boundary';

import { indexNameToDataStreamParts } from '../../../../common/utils';
import { DEFAULT_LOGS_DATA_VIEW } from '../../../../common/constants';
import { flyoutDegradedDocsTrendText } from '../../../../common/translations';
import { TimeRangeConfig } from '../../../state_machines/dataset_quality_controller';
import { useKibanaContextForPlugin } from '../../../utils';
import { useCreateDataView } from '../../../hooks';
import { getLensAttributes } from './lens_attributes';

const CHART_HEIGHT = 180;
const DISABLED_ACTIONS = [
'ACTION_CUSTOMIZE_PANEL',
'ACTION_CONFIGURE_IN_LENS',
'create-ml-ad-job-action',
];

export function DegradedDocsChart({
dataStream,
timeRange,
lastReloadTime,
}: {
dataStream?: string;
timeRange: TimeRangeConfig;
lastReloadTime: number;
}) {
const {
services: { lens },
} = useKibanaContextForPlugin();

const { euiTheme } = useEuiTheme();

const [isChartLoading, setIsChartLoading] = useState<boolean | undefined>(undefined);
const [attributes, setAttributes] = useState<ReturnType<typeof getLensAttributes> | undefined>(
undefined
);

const datasetTypeIndexPattern = dataStream
? `${indexNameToDataStreamParts(dataStream).type}-*-*`
: undefined;
const { dataView } = useCreateDataView({
indexPatternString: datasetTypeIndexPattern ?? DEFAULT_LOGS_DATA_VIEW,
});

const handleChartLoading = (isLoading: boolean) => {
setIsChartLoading(isLoading);
};

const filterQuery = `_index: ${dataStream ?? 'match-none'}`;

useEffect(() => {
if (dataView) {
const lensAttributes = getLensAttributes(euiTheme.colors.danger, dataView);
setAttributes(lensAttributes);
}
}, [lens, euiTheme.colors.danger, dataView]);

return (
<>
<KibanaErrorBoundary>
<EuiFlexGroup
css={{ minHeight: CHART_HEIGHT }}
direction="column"
justifyContent="center"
alignItems={isChartLoading === undefined ? 'center' : undefined}
>
{!attributes ? (
<EuiLoadingChart title={flyoutDegradedDocsTrendText} size="l" mono={true} />
) : (
<lens.EmbeddableComponent
id="datasetQualityFlyoutDegradedDocsTrend"
style={{ height: CHART_HEIGHT }}
css={lensEmbeddableComponentStyles}
viewMode={ViewMode.VIEW}
hidePanelTitles={true}
disabledActions={DISABLED_ACTIONS}
timeRange={timeRange}
attributes={attributes!}
withDefaultActions={true}
disableTriggers={false}
lastReloadRequestTime={lastReloadTime}
query={{
language: 'kuery',
query: filterQuery || '',
}}
onLoad={handleChartLoading}
/>
)}
</EuiFlexGroup>
</KibanaErrorBoundary>
</>
);
}

const lensEmbeddableComponentStyles = css`
.lnsExpressionRenderer__component {
margin-left: -16px;
.expExpressionRenderer__expression {
padding: 0 !important;
}
}
`;
Loading

0 comments on commit e610f09

Please sign in to comment.