Skip to content

Commit

Permalink
[8.x] [DataUsage][Serverless] Data usage metrics page enhancements (e…
Browse files Browse the repository at this point in the history
…lastic#195556) (elastic#196202)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[DataUsage][Serverless] Data usage metrics page enhancements
(elastic#195556)](elastic#195556)

<!--- Backport version: 8.9.8 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT
[{"author":{"name":"Ash","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-14T09:54:22Z","message":"[DataUsage][Serverless]
Data usage metrics page enhancements (elastic#195556)\n\n## Summary\r\n\r\nThis
PR is a follow-up of elastic/pull/193966 and adds: \r\n\r\n1.
Datastreams filter to data usage metrics page.\r\n2. Metrics filter
(hidden for now) that lists out metric types to\r\nrequest.\r\n3.
Refactors to make code easier to maintain.\r\n4. Shows a callout if no
data stream is selected.\r\n\r\n### screen\r\n![Screenshot 2024-10-09 at
17
36\r\n32](https://github.com/user-attachments/assets/a0779c91-25ae-4a64-819e-bc8a626f1f96)\r\n\r\n###
clip\r\n\r\n![latest-metrics-ux](https://github.com/user-attachments/assets/0f4b1a9b-d160-435b-917b-f59c3a5cc9f8)\r\n\r\n###
Checklist\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR does
not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"a7332ad11611d224a16f2bb3c0d3f207cf746065","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","v8.16.0","backport:version"],"number":195556,"url":"https://github.com/elastic/kibana/pull/195556","mergeCommit":{"message":"[DataUsage][Serverless]
Data usage metrics page enhancements (elastic#195556)\n\n## Summary\r\n\r\nThis
PR is a follow-up of elastic/pull/193966 and adds: \r\n\r\n1.
Datastreams filter to data usage metrics page.\r\n2. Metrics filter
(hidden for now) that lists out metric types to\r\nrequest.\r\n3.
Refactors to make code easier to maintain.\r\n4. Shows a callout if no
data stream is selected.\r\n\r\n### screen\r\n![Screenshot 2024-10-09 at
17
36\r\n32](https://github.com/user-attachments/assets/a0779c91-25ae-4a64-819e-bc8a626f1f96)\r\n\r\n###
clip\r\n\r\n![latest-metrics-ux](https://github.com/user-attachments/assets/0f4b1a9b-d160-435b-917b-f59c3a5cc9f8)\r\n\r\n###
Checklist\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR does
not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"a7332ad11611d224a16f2bb3c0d3f207cf746065"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","labelRegex":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/195556","number":195556,"mergeCommit":{"message":"[DataUsage][Serverless]
Data usage metrics page enhancements (elastic#195556)\n\n## Summary\r\n\r\nThis
PR is a follow-up of elastic/pull/193966 and adds: \r\n\r\n1.
Datastreams filter to data usage metrics page.\r\n2. Metrics filter
(hidden for now) that lists out metric types to\r\nrequest.\r\n3.
Refactors to make code easier to maintain.\r\n4. Shows a callout if no
data stream is selected.\r\n\r\n### screen\r\n![Screenshot 2024-10-09 at
17
36\r\n32](https://github.com/user-attachments/assets/a0779c91-25ae-4a64-819e-bc8a626f1f96)\r\n\r\n###
clip\r\n\r\n![latest-metrics-ux](https://github.com/user-attachments/assets/0f4b1a9b-d160-435b-917b-f59c3a5cc9f8)\r\n\r\n###
Checklist\r\n- [x] Any text added follows [EUI's
writing\r\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),
uses\r\nsentence case text and includes
[i18n\r\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\r\n-
[ ] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n- [ ] [Flaky
Test\r\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)
was\r\nused on any tests changed\r\n- [x] Any UI touched in this PR does
not create any new axe failures\r\n(run axe in
browser:\r\n[FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/),\r\n[Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US))\r\n-
[x] This renders correctly on smaller devices using a
responsive\r\nlayout. (You can test this [in
your\r\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\r\n-
[x] This was checked for
[cross-browser\r\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<[email protected]>","sha":"a7332ad11611d224a16f2bb3c0d3f207cf746065"}},{"branch":"8.x","label":"v8.16.0","labelRegex":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
  • Loading branch information
ashokaditya authored Oct 14, 2024
1 parent 84faa5c commit 06a2faa
Show file tree
Hide file tree
Showing 24 changed files with 1,083 additions and 230 deletions.
4 changes: 3 additions & 1 deletion x-pack/plugins/data_usage/common/rest_types/data_streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { schema } from '@kbn/config-schema';
import { schema, TypeOf } from '@kbn/config-schema';

export const DataStreamsResponseSchema = {
body: () =>
Expand All @@ -16,3 +16,5 @@ export const DataStreamsResponseSchema = {
})
),
};

export type DataStreamsResponseBodySchemaBody = TypeOf<typeof DataStreamsResponseSchema.body>;
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ describe('usage_metrics schemas', () => {
).not.toThrow();
});

it('should error if `dataStream` list is empty', () => {
it('should not error if `dataStream` list is empty', () => {
expect(() =>
UsageMetricsRequestSchema.validate({
from: new Date().toISOString(),
to: new Date().toISOString(),
metricTypes: ['storage_retained'],
dataStreams: [],
})
).toThrowError('[dataStreams]: array size is [0], but cannot be smaller than [1]');
).not.toThrow();
});

it('should error if `dataStream` is given type not array', () => {
Expand All @@ -71,7 +71,7 @@ describe('usage_metrics schemas', () => {
metricTypes: ['storage_retained'],
dataStreams: ['ds_1', ' '],
})
).toThrow('[dataStreams]: [dataStreams] list cannot contain empty values');
).toThrow('[dataStreams]: list cannot contain empty values');
});

it('should error if `metricTypes` is empty string', () => {
Expand All @@ -82,7 +82,7 @@ describe('usage_metrics schemas', () => {
dataStreams: ['data_stream_1', 'data_stream_2', 'data_stream_3'],
metricTypes: ' ',
})
).toThrow();
).toThrow('[metricTypes]: could not parse array value from json input');
});

it('should error if `metricTypes` contains an empty item', () => {
Expand All @@ -93,7 +93,7 @@ describe('usage_metrics schemas', () => {
dataStreams: ['data_stream_1', 'data_stream_2', 'data_stream_3'],
metricTypes: [' ', 'storage_retained'], // First item is invalid
})
).toThrowError(/list cannot contain empty values/);
).toThrow('list cannot contain empty values');
});

it('should error if `metricTypes` is not a valid type', () => {
Expand All @@ -116,7 +116,7 @@ describe('usage_metrics schemas', () => {
metricTypes: ['storage_retained', 'foo'],
})
).toThrow(
'[metricTypes] must be one of storage_retained, ingest_rate, search_vcu, ingest_vcu, ml_vcu, index_latency, index_rate, search_latency, search_rate'
'[metricTypes]: must be one of ingest_rate, storage_retained, search_vcu, ingest_vcu, ml_vcu, index_latency, index_rate, search_latency, search_rate'
);
});

Expand Down
31 changes: 24 additions & 7 deletions x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

import { schema, type TypeOf } from '@kbn/config-schema';

const METRIC_TYPE_VALUES = [
'storage_retained',
'ingest_rate',
// note these should be sorted alphabetically as we sort the URL params on the browser side
// before making the request, else the cache key will be different and that would invoke a new request
export const DEFAULT_METRIC_TYPES = ['ingest_rate', 'storage_retained'] as const;
export const METRIC_TYPE_VALUES = [
...DEFAULT_METRIC_TYPES,
'search_vcu',
'ingest_vcu',
'ml_vcu',
Expand All @@ -21,6 +23,22 @@ const METRIC_TYPE_VALUES = [

export type MetricTypes = (typeof METRIC_TYPE_VALUES)[number];

export const isDefaultMetricType = (metricType: string) =>
// @ts-ignore
DEFAULT_METRIC_TYPES.includes(metricType);

export const METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP = Object.freeze<Record<MetricTypes, string>>({
storage_retained: 'Data Retained in Storage',
ingest_rate: 'Data Ingested',
search_vcu: 'Search VCU',
ingest_vcu: 'Ingest VCU',
ml_vcu: 'ML VCU',
index_latency: 'Index Latency',
index_rate: 'Index Rate',
search_latency: 'Search Latency',
search_rate: 'Search Rate',
});

// type guard for MetricTypes
export const isMetricType = (type: string): type is MetricTypes =>
METRIC_TYPE_VALUES.includes(type as MetricTypes);
Expand All @@ -47,21 +65,20 @@ export const UsageMetricsRequestSchema = schema.object({
if (trimmedValues.some((v) => !v.length)) {
return '[metricTypes] list cannot contain empty values';
} else if (trimmedValues.some((v) => !isValidMetricType(v))) {
return `[metricTypes] must be one of ${METRIC_TYPE_VALUES.join(', ')}`;
return `must be one of ${METRIC_TYPE_VALUES.join(', ')}`;
}
},
}),
dataStreams: schema.arrayOf(schema.string(), {
minSize: 1,
validate: (values) => {
if (values.map((v) => v.trim()).some((v) => !v.length)) {
return '[dataStreams] list cannot contain empty values';
return 'list cannot contain empty values';
}
},
}),
});

export type UsageMetricsRequestSchemaQueryParams = TypeOf<typeof UsageMetricsRequestSchema>;
export type UsageMetricsRequestBody = TypeOf<typeof UsageMetricsRequestSchema>;

export const UsageMetricsResponseSchema = {
body: () =>
Expand Down
150 changes: 150 additions & 0 deletions x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* 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, useEffect, memo, useState } from 'react';
import { css } from '@emotion/react';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic, EuiCallOut } from '@elastic/eui';
import { Charts } from './charts';
import { useBreadcrumbs } from '../../utils/use_breadcrumbs';
import { useKibanaContextForPlugin } from '../../utils/use_kibana';
import { PLUGIN_NAME } from '../../../common';
import { useGetDataUsageMetrics } from '../../hooks/use_get_usage_metrics';
import { useDataUsageMetricsUrlParams } from '../hooks/use_charts_url_params';
import { DEFAULT_DATE_RANGE_OPTIONS, useDateRangePicker } from '../hooks/use_date_picker';
import { DEFAULT_METRIC_TYPES, UsageMetricsRequestBody } from '../../../common/rest_types';
import { ChartFilters } from './filters/charts_filters';
import { UX_LABELS } from '../translations';

const EuiItemCss = css`
width: 100%;
`;

const FlexItemWithCss = memo(({ children }: { children: React.ReactNode }) => (
<EuiFlexItem css={EuiItemCss}>{children}</EuiFlexItem>
));

export const DataUsageMetrics = () => {
const {
services: { chrome, appParams },
} = useKibanaContextForPlugin();

const {
metricTypes: metricTypesFromUrl,
dataStreams: dataStreamsFromUrl,
startDate: startDateFromUrl,
endDate: endDateFromUrl,
setUrlMetricTypesFilter,
setUrlDateRangeFilter,
} = useDataUsageMetricsUrlParams();

const [metricsFilters, setMetricsFilters] = useState<UsageMetricsRequestBody>({
metricTypes: [...DEFAULT_METRIC_TYPES],
dataStreams: [],
from: DEFAULT_DATE_RANGE_OPTIONS.startDate,
to: DEFAULT_DATE_RANGE_OPTIONS.endDate,
});

useEffect(() => {
if (!metricTypesFromUrl) {
setUrlMetricTypesFilter(metricsFilters.metricTypes.join(','));
}
if (!startDateFromUrl || !endDateFromUrl) {
setUrlDateRangeFilter({ startDate: metricsFilters.from, endDate: metricsFilters.to });
}
}, [
endDateFromUrl,
metricTypesFromUrl,
metricsFilters.from,
metricsFilters.metricTypes,
metricsFilters.to,
setUrlDateRangeFilter,
setUrlMetricTypesFilter,
startDateFromUrl,
]);

useEffect(() => {
setMetricsFilters((prevState) => ({
...prevState,
metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes,
dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams,
}));
}, [metricTypesFromUrl, dataStreamsFromUrl]);

const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker();

const {
error,
data,
isFetching,
isFetched,
refetch: refetchDataUsageMetrics,
} = useGetDataUsageMetrics(
{
...metricsFilters,
from: dateRangePickerState.startDate,
to: dateRangePickerState.endDate,
},
{
retry: false,
}
);

const onRefresh = useCallback(() => {
refetchDataUsageMetrics();
}, [refetchDataUsageMetrics]);

const onChangeDataStreamsFilter = useCallback(
(selectedDataStreams: string[]) => {
setMetricsFilters((prevState) => ({ ...prevState, dataStreams: selectedDataStreams }));
},
[setMetricsFilters]
);

const onChangeMetricTypesFilter = useCallback(
(selectedMetricTypes: string[]) => {
setMetricsFilters((prevState) => ({ ...prevState, metricTypes: selectedMetricTypes }));
},
[setMetricsFilters]
);

useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome);

return (
<EuiFlexGroup alignItems="flexStart" direction="column">
<FlexItemWithCss>
<ChartFilters
dateRangePickerState={dateRangePickerState}
isDataLoading={isFetching}
onClick={refetchDataUsageMetrics}
onRefresh={onRefresh}
onRefreshChange={onRefreshChange}
onTimeChange={onTimeChange}
onChangeDataStreamsFilter={onChangeDataStreamsFilter}
onChangeMetricTypesFilter={onChangeMetricTypesFilter}
showMetricsTypesFilter={false}
/>
</FlexItemWithCss>
{!isFetching && error?.message && (
<FlexItemWithCss>
<EuiCallOut
size="s"
title={UX_LABELS.noDataStreamsSelected}
iconType="iInCircle"
color="warning"
/>
</FlexItemWithCss>
)}
<FlexItemWithCss>
{isFetched && data?.metrics ? (
<Charts data={data} />
) : isFetching ? (
<EuiLoadingElastic />
) : null}
</FlexItemWithCss>
</EuiFlexGroup>
);
};
Loading

0 comments on commit 06a2faa

Please sign in to comment.