[8.x] [DataUsage][Serverless] Data usage charts enhancements (#196559) (#196996)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[DataUsage][Serverless] Data usage charts enhancements
(#196559)](https://github.com/elastic/kibana/pull/196559)

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

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

<!--BACKPORT
[{"author":{"name":"Ash","email":"1849116+ashokaditya@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-10-18T13:10:30Z","message":"[DataUsage][Serverless]
Data usage charts enhancements (#196559)\n\n## Summary\r\n\r\nfollow up
of:\r\n- elastic/kibana/pull/195556\r\n\r\nAdds a lot of enhancements to
the datastream dropdown including:\r\n\r\n- [x] shows storage sizes on
the data stream dropdown\r\n- [x] preselects all data streams on the
first page load\r\n- [x] updates selected data streams to URL
params\r\n- [x] selects data streams based on URL load\r\n- [x] doesn't
allow deselecting all data streams\r\n- [x] cancels older API
requests\r\n\r\n### screen\r\n![Screenshot 2024-10-16 at 16
57\r\n43](https://github.com/user-attachments/assets/38db2d93-f531-4269-88ea-51b4926b6a72)\r\n\r\n###
clip\r\n\r\n![metrics-ux-16-10](https://github.com/user-attachments/assets/7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\r\n\r\nrelated
PRs\r\n- elastic/kibana/pull/193966 \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
<42973632+kibanamachine@users.noreply.github.com>","sha":"13e19cb645e3e3b037ea40809dfbfdaf93529169","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","v8.16.0","backport:version","v8.17.0"],"number":196559,"url":"https://github.com/elastic/kibana/pull/196559","mergeCommit":{"message":"[DataUsage][Serverless]
Data usage charts enhancements (#196559)\n\n## Summary\r\n\r\nfollow up
of:\r\n- elastic/kibana/pull/195556\r\n\r\nAdds a lot of enhancements to
the datastream dropdown including:\r\n\r\n- [x] shows storage sizes on
the data stream dropdown\r\n- [x] preselects all data streams on the
first page load\r\n- [x] updates selected data streams to URL
params\r\n- [x] selects data streams based on URL load\r\n- [x] doesn't
allow deselecting all data streams\r\n- [x] cancels older API
requests\r\n\r\n### screen\r\n![Screenshot 2024-10-16 at 16
57\r\n43](https://github.com/user-attachments/assets/38db2d93-f531-4269-88ea-51b4926b6a72)\r\n\r\n###
clip\r\n\r\n![metrics-ux-16-10](https://github.com/user-attachments/assets/7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\r\n\r\nrelated
PRs\r\n- elastic/kibana/pull/193966 \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
<42973632+kibanamachine@users.noreply.github.com>","sha":"13e19cb645e3e3b037ea40809dfbfdaf93529169"}},"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/196559","number":196559,"mergeCommit":{"message":"[DataUsage][Serverless]
Data usage charts enhancements (#196559)\n\n## Summary\r\n\r\nfollow up
of:\r\n- elastic/kibana/pull/195556\r\n\r\nAdds a lot of enhancements to
the datastream dropdown including:\r\n\r\n- [x] shows storage sizes on
the data stream dropdown\r\n- [x] preselects all data streams on the
first page load\r\n- [x] updates selected data streams to URL
params\r\n- [x] selects data streams based on URL load\r\n- [x] doesn't
allow deselecting all data streams\r\n- [x] cancels older API
requests\r\n\r\n### screen\r\n![Screenshot 2024-10-16 at 16
57\r\n43](https://github.com/user-attachments/assets/38db2d93-f531-4269-88ea-51b4926b6a72)\r\n\r\n###
clip\r\n\r\n![metrics-ux-16-10](https://github.com/user-attachments/assets/7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\r\n\r\nrelated
PRs\r\n- elastic/kibana/pull/193966 \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
<42973632+kibanamachine@users.noreply.github.com>","sha":"13e19cb645e3e3b037ea40809dfbfdaf93529169"}},{"branch":"8.16","label":"v8.16.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/196876","number":196876,"state":"MERGED","mergeCommit":{"sha":"79e7c86a094093c8fb40d9152ab84d6f773a3eea","message":"[8.16]
[DataUsage][Serverless] Data usage charts enhancements (#196559)
(#196876)\n\n# Backport\n\nThis will backport the following commits from
`main` to `8.16`:\n- [[DataUsage][Serverless] Data usage charts
enhancements\n(#196559)](https://github.com/elastic/kibana/pull/196559)\n\n<!---
Backport version: 9.4.3 -->\n\n### Questions ?\nPlease refer to the
[Backport
tool\ndocumentation](https://github.com/sqren/backport)\n\n<!--BACKPORT\n[{\"author\":{\"name\":\"Ash\",\"email\":\"1849116+ashokaditya@users.noreply.github.com\"},\"sourceCommit\":{\"committedDate\":\"2024-10-18T13:10:30Z\",\"message\":\"[DataUsage][Serverless]\nData
usage charts enhancements (#196559)\\n\\n## Summary\\r\\n\\r\\nfollow
up\nof:\\r\\n- elastic/kibana/pull/195556\\r\\n\\r\\nAdds a lot of
enhancements to\nthe datastream dropdown including:\\r\\n\\r\\n- [x]
shows storage sizes on\nthe data stream dropdown\\r\\n- [x] preselects
all data streams on the\nfirst page load\\r\\n- [x] updates selected
data streams to URL\nparams\\r\\n- [x] selects data streams based on URL
load\\r\\n- [x] doesn't\nallow deselecting all data streams\\r\\n- [x]
cancels older API\nrequests\\r\\n\\r\\n### screen\\r\\n![Screenshot
2024-10-16 at
16\n57\\r\\n43](7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\\r\\n\\r\\nrelated\nPRs\\r\\n-
elastic/kibana/pull/193966 \\r\\n \\r\\n### Checklist\\r\\n- [x]
Any\ntext added follows
[EUI's\nwriting\\r\\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),\nuses\\r\\nsentence
case text and
includes\n[i18n\\r\\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\\r\\n-\n[
] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most common scenarios\\r\\n- [ ]
[Flaky\nTest\\r\\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)\nwas\\r\\nused
on any tests changed\\r\\n- [x] Any UI touched in this PR does\nnot
create any new axe failures\\r\\n(run axe
in\nbrowser:\\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-\n[x]
This renders correctly on smaller devices using
a\nresponsive\\r\\nlayout. (You can test this
[in\nyour\\r\\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\\r\\n-\n[x]
This was checked
for\n[cross-browser\\r\\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:\nkibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"13e19cb645e3e3b037ea40809dfbfdaf93529169\",\"branchLabelMapping\":{\"^v9.0.0$\":\"main\",\"^v8.17.0$\":\"8.x\",\"^v(\\\\d+).(\\\\d+).\\\\d+$\":\"$1.$2\"}},\"sourcePullRequest\":{\"labels\":[\"release_note:skip\",\"v9.0.0\",\"v8.16.0\",\"backport:version\"],\"title\":\"[DataUsage][Serverless]\nData
usage
charts\nenhancements\",\"number\":196559,\"url\":\"https://github.com/elastic/kibana/pull/196559\",\"mergeCommit\":{\"message\":\"[DataUsage][Serverless]\nData
usage charts enhancements (#196559)\\n\\n## Summary\\r\\n\\r\\nfollow
up\nof:\\r\\n- elastic/kibana/pull/195556\\r\\n\\r\\nAdds a lot of
enhancements to\nthe datastream dropdown including:\\r\\n\\r\\n- [x]
shows storage sizes on\nthe data stream dropdown\\r\\n- [x] preselects
all data streams on the\nfirst page load\\r\\n- [x] updates selected
data streams to URL\nparams\\r\\n- [x] selects data streams based on URL
load\\r\\n- [x] doesn't\nallow deselecting all data streams\\r\\n- [x]
cancels older API\nrequests\\r\\n\\r\\n### screen\\r\\n![Screenshot
2024-10-16 at
16\n57\\r\\n43](7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\\r\\n\\r\\nrelated\nPRs\\r\\n-
elastic/kibana/pull/193966 \\r\\n \\r\\n### Checklist\\r\\n- [x]
Any\ntext added follows
[EUI's\nwriting\\r\\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),\nuses\\r\\nsentence
case text and
includes\n[i18n\\r\\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\\r\\n-\n[
] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most common scenarios\\r\\n- [ ]
[Flaky\nTest\\r\\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)\nwas\\r\\nused
on any tests changed\\r\\n- [x] Any UI touched in this PR does\nnot
create any new axe failures\\r\\n(run axe
in\nbrowser:\\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-\n[x]
This renders correctly on smaller devices using
a\nresponsive\\r\\nlayout. (You can test this
[in\nyour\\r\\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\\r\\n-\n[x]
This was checked
for\n[cross-browser\\r\\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:\nkibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"13e19cb645e3e3b037ea40809dfbfdaf93529169\"}},\"sourceBranch\":\"main\",\"suggestedTargetBranches\":[\"8.16\"],\"targetPullRequestStates\":[{\"branch\":\"main\",\"label\":\"v9.0.0\",\"branchLabelMappingKey\":\"^v9.0.0$\",\"isSourceBranch\":true,\"state\":\"MERGED\",\"url\":\"https://github.com/elastic/kibana/pull/196559\",\"number\":196559,\"mergeCommit\":{\"message\":\"[DataUsage][Serverless]\nData
usage charts enhancements (#196559)\\n\\n## Summary\\r\\n\\r\\nfollow
up\nof:\\r\\n- elastic/kibana/pull/195556\\r\\n\\r\\nAdds a lot of
enhancements to\nthe datastream dropdown including:\\r\\n\\r\\n- [x]
shows storage sizes on\nthe data stream dropdown\\r\\n- [x] preselects
all data streams on the\nfirst page load\\r\\n- [x] updates selected
data streams to URL\nparams\\r\\n- [x] selects data streams based on URL
load\\r\\n- [x] doesn't\nallow deselecting all data streams\\r\\n- [x]
cancels older API\nrequests\\r\\n\\r\\n### screen\\r\\n![Screenshot
2024-10-16 at
16\n57\\r\\n43](7913d1b6-31df-48e6-a3a9-f4dad0dc1b1e)\\r\\n\\r\\nrelated\nPRs\\r\\n-
elastic/kibana/pull/193966 \\r\\n \\r\\n### Checklist\\r\\n- [x]
Any\ntext added follows
[EUI's\nwriting\\r\\nguidelines](https://elastic.github.io/eui/#/guidelines/writing),\nuses\\r\\nsentence
case text and
includes\n[i18n\\r\\nsupport](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)\\r\\n-\n[
] [Unit
or\nfunctional\\r\\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\\r\\nwere\nupdated
or added to match the most common scenarios\\r\\n- [ ]
[Flaky\nTest\\r\\nRunner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1)\nwas\\r\\nused
on any tests changed\\r\\n- [x] Any UI touched in this PR does\nnot
create any new axe failures\\r\\n(run axe
in\nbrowser:\\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-\n[x]
This renders correctly on smaller devices using
a\nresponsive\\r\\nlayout. (You can test this
[in\nyour\\r\\nbrowser](https://www.browserstack.com/guide/responsive-testing-on-local-server))\\r\\n-\n[x]
This was checked
for\n[cross-browser\\r\\ncompatibility](https://www.elastic.co/support/matrix#matrix_browsers)\\r\\n\\r\\n---------\\r\\n\\r\\nCo-authored-by:\nkibanamachine\n<42973632+kibanamachine@users.noreply.github.com>\",\"sha\":\"13e19cb645e3e3b037ea40809dfbfdaf93529169\"}},{\"branch\":\"8.16\",\"label\":\"v8.16.0\",\"branchLabelMappingKey\":\"^v(\\\\d+).(\\\\d+).\\\\d+$\",\"isSourceBranch\":false,\"state\":\"NOT_CREATED\"}]}]\nBACKPORT-->\n\nCo-authored-by:
Ash
<1849116+ashokaditya@users.noreply.github.com>"}},{"branch":"8.x","label":"v8.17.0","labelRegex":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Ash 2024-10-23 15:49:56 +02:00 committed by GitHub
parent ce8ef51a59
commit 0bd80e508a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 161 additions and 196 deletions

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import React, { useCallback, useMemo } from 'react';
import numeral from '@elastic/numeral';
import { EuiFlexItem, EuiPanel, EuiTitle, useEuiTheme } from '@elastic/eui';
import {
Chart,
@ -20,6 +20,7 @@ import {
import { i18n } from '@kbn/i18n';
import { LegendAction } from './legend_action';
import { MetricTypes, MetricSeries } from '../../../common/rest_types';
import { formatBytes } from '../../utils/format_bytes';
// TODO: Remove this when we have a title for each metric type
type ChartKey = Extract<MetricTypes, 'ingest_rate' | 'storage_retained'>;
@ -118,7 +119,3 @@ export const ChartPanel: React.FC<ChartPanelProps> = ({
</EuiFlexItem>
);
};
const formatBytes = (bytes: number) => {
return numeral(bytes).format('0.0 b');
};

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import React, { useCallback, useEffect, memo, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { css } from '@emotion/react';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic, EuiCallOut } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic } from '@elastic/eui';
import { Charts } from './charts';
import { useBreadcrumbs } from '../../utils/use_breadcrumbs';
import { useKibanaContextForPlugin } from '../../utils/use_kibana';
@ -16,21 +16,22 @@ 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';
import { ChartFilters, ChartFiltersProps } from './filters/charts_filters';
import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams';
const EuiItemCss = css`
width: 100%;
`;
const FlexItemWithCss = memo(({ children }: { children: React.ReactNode }) => (
const FlexItemWithCss = ({ children }: { children: React.ReactNode }) => (
<EuiFlexItem css={EuiItemCss}>{children}</EuiFlexItem>
));
);
export const DataUsageMetrics = () => {
const {
services: { chrome, appParams },
} = useKibanaContextForPlugin();
useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome);
const {
metricTypes: metricTypesFromUrl,
@ -38,9 +39,17 @@ export const DataUsageMetrics = () => {
startDate: startDateFromUrl,
endDate: endDateFromUrl,
setUrlMetricTypesFilter,
setUrlDataStreamsFilter,
setUrlDateRangeFilter,
} = useDataUsageMetricsUrlParams();
const { data: dataStreams, isFetching: isFetchingDataStreams } = useGetDataUsageDataStreams({
selectedDataStreams: dataStreamsFromUrl,
options: {
enabled: true,
},
});
const [metricsFilters, setMetricsFilters] = useState<UsageMetricsRequestBody>({
metricTypes: [...DEFAULT_METRIC_TYPES],
dataStreams: [],
@ -52,15 +61,22 @@ export const DataUsageMetrics = () => {
if (!metricTypesFromUrl) {
setUrlMetricTypesFilter(metricsFilters.metricTypes.join(','));
}
if (!dataStreamsFromUrl && dataStreams) {
setUrlDataStreamsFilter(dataStreams.map((ds) => ds.name).join(','));
}
if (!startDateFromUrl || !endDateFromUrl) {
setUrlDateRangeFilter({ startDate: metricsFilters.from, endDate: metricsFilters.to });
}
}, [
dataStreams,
dataStreamsFromUrl,
endDateFromUrl,
metricTypesFromUrl,
metricsFilters.dataStreams,
metricsFilters.from,
metricsFilters.metricTypes,
metricsFilters.to,
setUrlDataStreamsFilter,
setUrlDateRangeFilter,
setUrlMetricTypesFilter,
startDateFromUrl,
@ -77,7 +93,6 @@ export const DataUsageMetrics = () => {
const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker();
const {
error,
data,
isFetching,
isFetched,
@ -90,6 +105,7 @@ export const DataUsageMetrics = () => {
},
{
retry: false,
enabled: !!metricsFilters.dataStreams.length,
}
);
@ -111,33 +127,51 @@ export const DataUsageMetrics = () => {
[setMetricsFilters]
);
useBreadcrumbs([{ text: PLUGIN_NAME }], appParams, chrome);
const filterOptions: ChartFiltersProps['filterOptions'] = useMemo(() => {
const dataStreamsOptions = dataStreams?.reduce<Record<string, number>>((acc, ds) => {
acc[ds.name] = ds.storageSizeBytes;
return acc;
}, {});
return {
dataStreams: {
filterName: 'dataStreams',
options: dataStreamsOptions ? Object.keys(dataStreamsOptions) : metricsFilters.dataStreams,
appendOptions: dataStreamsOptions,
selectedOptions: metricsFilters.dataStreams,
onChangeFilterOptions: onChangeDataStreamsFilter,
isFilterLoading: isFetchingDataStreams,
},
metricTypes: {
filterName: 'metricTypes',
options: metricsFilters.metricTypes,
onChangeFilterOptions: onChangeMetricTypesFilter,
},
};
}, [
dataStreams,
isFetchingDataStreams,
metricsFilters.dataStreams,
metricsFilters.metricTypes,
onChangeDataStreamsFilter,
onChangeMetricTypesFilter,
]);
return (
<EuiFlexGroup alignItems="flexStart" direction="column">
<FlexItemWithCss>
<ChartFilters
dateRangePickerState={dateRangePickerState}
isDataLoading={isFetching}
isDataLoading={isFetchingDataStreams}
onClick={refetchDataUsageMetrics}
onRefresh={onRefresh}
onRefreshChange={onRefreshChange}
onTimeChange={onTimeChange}
onChangeDataStreamsFilter={onChangeDataStreamsFilter}
onChangeMetricTypesFilter={onChangeMetricTypesFilter}
filterOptions={filterOptions}
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} />

View file

@ -7,7 +7,7 @@
import { orderBy } from 'lodash/fp';
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiPopoverTitle, EuiSelectable } from '@elastic/eui';
import { EuiPopoverTitle, EuiSelectable } from '@elastic/eui';
import { useTestIdGenerator } from '../../../hooks/use_test_id_generator';
import {
@ -15,7 +15,6 @@ import {
type MetricTypes,
} from '../../../../common/rest_types';
import { ClearAllButton } from './clear_all_button';
import { UX_LABELS } from '../../translations';
import { ChartsFilterPopover } from './charts_filter_popover';
import { FilterItems, FilterName, useChartsFilter } from '../../hooks';
@ -27,20 +26,34 @@ const getSearchPlaceholder = (filterName: FilterName) => {
return UX_LABELS.filterSearchPlaceholder('metric types');
};
export const ChartsFilter = memo(
({
filterName,
onChangeFilterOptions,
'data-test-subj': dataTestSubj,
}: {
export interface ChartsFilterProps {
filterOptions: {
filterName: FilterName;
onChangeFilterOptions?: (selectedOptions: string[]) => void;
'data-test-subj'?: string;
options: string[];
appendOptions?: Record<string, number>;
selectedOptions?: string[];
onChangeFilterOptions: (selectedOptions: string[]) => void;
isFilterLoading?: boolean;
};
'data-test-subj'?: string;
}
export const ChartsFilter = memo<ChartsFilterProps>(
({
filterOptions: {
filterName,
options,
appendOptions,
selectedOptions,
onChangeFilterOptions,
isFilterLoading = false,
},
'data-test-subj': dataTestSubj,
}) => {
const getTestId = useTestIdGenerator(dataTestSubj);
const isMetricsFilter = filterName === 'metricTypes';
const isDataStreamsFilter = filterName === 'dataStreams';
// popover states and handlers
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
const onPopoverButtonClick = useCallback(() => {
@ -50,11 +63,8 @@ export const ChartsFilter = memo(
setIsPopoverOpen(false);
}, [setIsPopoverOpen]);
// search string state
const [searchString, setSearchString] = useState('');
const {
areDataStreamsSelectedOnMount,
isLoading,
items,
setItems,
hasActiveFilters,
@ -64,17 +74,18 @@ export const ChartsFilter = memo(
setUrlDataStreamsFilter,
setUrlMetricTypesFilter,
} = useChartsFilter({
filterName,
searchString,
filterOptions: {
filterName,
options,
appendOptions,
selectedOptions,
onChangeFilterOptions,
isFilterLoading,
},
});
// track popover state to pin selected options
const wasPopoverOpen = useRef(isPopoverOpen);
useEffect(() => {
return () => {
wasPopoverOpen.current = isPopoverOpen;
};
}, [isPopoverOpen, wasPopoverOpen]);
// compute if selected dataStreams should be pinned
const shouldPinSelectedDataStreams = useCallback(
@ -104,8 +115,16 @@ export const ChartsFilter = memo(
const onOptionsChange = useCallback(
(newOptions: FilterItems) => {
const optionItemsToSet = newOptions.map((option) => option);
const currChecks = optionItemsToSet.filter((option) => option.checked === 'on');
// don't update filter state if trying to uncheck all options
if (currChecks.length < 1) {
return;
}
// update filter UI options state
setItems(newOptions.map((option) => option));
setItems(optionItemsToSet);
// compute a selected list of options
const selectedItems = newOptions.reduce<string[]>((acc, curr) => {
@ -129,10 +148,7 @@ export const ChartsFilter = memo(
shouldPinSelectedDataStreams(false);
setAreDataStreamsSelectedOnMount(false);
// update overall query state
if (typeof onChangeFilterOptions !== 'undefined') {
onChangeFilterOptions(selectedItems);
}
onChangeFilterOptions(selectedItems);
},
[
setItems,
@ -146,35 +162,11 @@ export const ChartsFilter = memo(
]
);
// clear all selected options
const onClearAll = useCallback(() => {
// update filter UI options state
setItems(
items.map((option) => {
option.checked = undefined;
return option;
})
);
// update URL params based on filter on page
if (isMetricsFilter) {
setUrlMetricTypesFilter('');
} else if (isDataStreamsFilter) {
setUrlDataStreamsFilter('');
}
if (typeof onChangeFilterOptions !== 'undefined') {
onChangeFilterOptions([]);
}
}, [
setItems,
items,
isMetricsFilter,
isDataStreamsFilter,
onChangeFilterOptions,
setUrlMetricTypesFilter,
setUrlDataStreamsFilter,
]);
useEffect(() => {
return () => {
wasPopoverOpen.current = isPopoverOpen;
};
}, [isPopoverOpen, wasPopoverOpen]);
return (
<ChartsFilterPopover
@ -190,14 +182,13 @@ export const ChartsFilter = memo(
<EuiSelectable
aria-label={`${filterName}`}
emptyMessage={UX_LABELS.filterEmptyMessage(filterName)}
isLoading={isLoading}
isLoading={isFilterLoading}
onChange={onOptionsChange}
options={sortedHostsFilterOptions}
searchable={isSearchable ? true : undefined}
searchProps={{
placeholder: getSearchPlaceholder(filterName),
compressed: true,
onChange: (searchValue) => setSearchString(searchValue.trim()),
}}
>
{(list, search) => {
@ -215,17 +206,6 @@ export const ChartsFilter = memo(
</EuiPopoverTitle>
)}
{list}
{!isMetricsFilter && (
<EuiFlexGroup>
<EuiFlexItem>
<ClearAllButton
data-test-subj={getTestId(`${filterName}-filter-clearAllButton`)}
isDisabled={!hasActiveFilters}
onClick={onClearAll}
/>
</EuiFlexItem>
</EuiFlexGroup>
)}
</div>
);
}}

View file

@ -14,13 +14,13 @@ import type {
import { useTestIdGenerator } from '../../../hooks/use_test_id_generator';
import { useGetDataUsageMetrics } from '../../../hooks/use_get_usage_metrics';
import { DateRangePickerValues, UsageMetricsDateRangePicker } from './date_picker';
import { ChartsFilter } from './charts_filter';
import { ChartsFilter, ChartsFilterProps } from './charts_filter';
import { FilterName } from '../../hooks';
interface ChartFiltersProps {
export interface ChartFiltersProps {
dateRangePickerState: DateRangePickerValues;
isDataLoading: boolean;
onChangeDataStreamsFilter: (selectedDataStreams: string[]) => void;
onChangeMetricTypesFilter?: (selectedMetricTypes: string[]) => void;
filterOptions: Record<FilterName, ChartsFilterProps['filterOptions']>;
onRefresh: () => void;
onRefreshChange: (evt: OnRefreshChangeProps) => void;
onTimeChange: ({ start, end }: DurationRange) => void;
@ -33,9 +33,8 @@ export const ChartFilters = memo<ChartFiltersProps>(
({
dateRangePickerState,
isDataLoading,
filterOptions,
onClick,
onChangeMetricTypesFilter,
onChangeDataStreamsFilter,
onRefresh,
onRefreshChange,
onTimeChange,
@ -47,19 +46,13 @@ export const ChartFilters = memo<ChartFiltersProps>(
const filters = useMemo(() => {
return (
<>
{showMetricsTypesFilter && (
<ChartsFilter
filterName={'metricTypes'}
onChangeFilterOptions={onChangeMetricTypesFilter}
/>
{showMetricsTypesFilter && <ChartsFilter filterOptions={filterOptions.metricTypes} />}
{!filterOptions.dataStreams.isFilterLoading && (
<ChartsFilter filterOptions={filterOptions.dataStreams} />
)}
<ChartsFilter
filterName={'dataStreams'}
onChangeFilterOptions={onChangeDataStreamsFilter}
/>
</>
);
}, [onChangeDataStreamsFilter, onChangeMetricTypesFilter, showMetricsTypesFilter]);
}, [filterOptions, showMetricsTypesFilter]);
const onClickRefreshButton = useCallback(() => onClick(), [onClick]);

View file

@ -1,43 +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, { memo } from 'react';
import { css } from '@emotion/react';
import { euiThemeVars } from '@kbn/ui-theme';
import { EuiButtonEmpty } from '@elastic/eui';
import { UX_LABELS } from '../../translations';
const buttonCss = css`
border-top: ${euiThemeVars.euiBorderThin};
border-radius: 0;
`;
export const ClearAllButton = memo(
({
'data-test-subj': dataTestSubj,
isDisabled,
onClick,
}: {
'data-test-subj'?: string;
isDisabled: boolean;
onClick: () => void;
}) => {
return (
<EuiButtonEmpty
css={buttonCss}
data-test-subj={dataTestSubj}
isDisabled={isDisabled}
onClick={onClick}
iconType="cross"
color="danger"
>
{UX_LABELS.filterClearAll}
</EuiButtonEmpty>
);
}
);
ClearAllButton.displayName = 'ClearAllButton';

View file

@ -11,9 +11,10 @@ import {
METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP,
METRIC_TYPE_VALUES,
} from '../../../common/rest_types';
import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams';
import { FILTER_NAMES } from '../translations';
import { useDataUsageMetricsUrlParams } from './use_charts_url_params';
import { formatBytes } from '../../utils/format_bytes';
import { ChartsFilterProps } from '../components/filters/charts_filter';
export type FilterName = keyof typeof FILTER_NAMES;
@ -26,14 +27,11 @@ export type FilterItems = Array<{
}>;
export const useChartsFilter = ({
filterName,
searchString,
filterOptions,
}: {
filterName: FilterName;
searchString: string;
filterOptions: ChartsFilterProps['filterOptions'];
}): {
areDataStreamsSelectedOnMount: boolean;
isLoading: boolean;
items: FilterItems;
setItems: React.Dispatch<React.SetStateAction<FilterItems>>;
hasActiveFilters: boolean;
@ -52,12 +50,8 @@ export const useChartsFilter = ({
setUrlMetricTypesFilter,
setUrlDataStreamsFilter,
} = useDataUsageMetricsUrlParams();
const isMetricTypesFilter = filterName === 'metricTypes';
const isDataStreamsFilter = filterName === 'dataStreams';
const { data: dataStreams, isFetching } = useGetDataUsageDataStreams({
searchString,
selectedDataStreams: selectedDataStreamsFromUrl,
});
const isMetricTypesFilter = filterOptions.filterName === 'metricTypes';
const isDataStreamsFilter = filterOptions.filterName === 'dataStreams';
// track the state of selected data streams via URL
// when the page is loaded via selected data streams on URL
@ -80,24 +74,23 @@ export const useChartsFilter = ({
label: METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP[metricType],
checked: isDefaultMetricType(metricType) ? 'on' : undefined, // default metrics are selected by default
disabled: isDefaultMetricType(metricType),
'data-test-subj': `${filterName}-filter-option`,
'data-test-subj': `${filterOptions.filterName}-filter-option`,
}))
: isDataStreamsFilter && !!filterOptions.options.length
? filterOptions.options?.map((filterOption) => ({
key: filterOption,
label: filterOption,
append: formatBytes(filterOptions.appendOptions?.[filterOption] ?? 0),
checked: selectedDataStreamsFromUrl
? selectedDataStreamsFromUrl.includes(filterOption)
? 'on'
: undefined
: 'on',
'data-test-subj': `${filterOptions.filterName}-filter-option`,
}))
: []
);
useEffect(() => {
if (isDataStreamsFilter && dataStreams) {
setItems(
dataStreams?.map((dataStream) => ({
key: dataStream.name,
label: dataStream.name,
checked: dataStream.selected ? 'on' : undefined,
'data-test-subj': `${filterName}-filter-option`,
}))
);
}
}, [dataStreams, filterName, isDataStreamsFilter, setItems]);
const hasActiveFilters = useMemo(() => !!items.find((item) => item.checked === 'on'), [items]);
const numActiveFilters = useMemo(
() => items.filter((item) => item.checked === 'on').length,
@ -110,7 +103,6 @@ export const useChartsFilter = ({
return {
areDataStreamsSelectedOnMount,
isLoading: isDataStreamsFilter && isFetching,
items,
setItems,
hasActiveFilters,

View file

@ -53,9 +53,7 @@ export const getDataUsageMetricsFiltersFromUrlParams = (
}, [])
: [];
const urlDataStreams = urlParams.dataStreams
? String(urlParams.dataStreams).split(',').sort()
: [];
const urlDataStreams = urlParams.dataStreams ? String(urlParams.dataStreams).split(',') : [];
dataUsageMetricsFilters.metricTypes = urlMetricTypes.length ? urlMetricTypes : undefined;
dataUsageMetricsFilters.dataStreams = urlDataStreams.length ? urlDataStreams : undefined;

View file

@ -48,7 +48,4 @@ export const UX_LABELS = Object.freeze({
defaultMessage: 'No {filterName} available',
values: { filterName },
}),
noDataStreamsSelected: i18n.translate('xpack.dataUsage.metrics.noDataStreamsSelected', {
defaultMessage: 'Select one or more data streams to view data usage metrics.',
}),
});

View file

@ -14,6 +14,7 @@ import { useKibanaContextForPlugin } from '../utils/use_kibana';
type GetDataUsageDataStreamsResponse = Array<{
name: string;
storageSizeBytes: number;
selected: boolean;
}>;
@ -23,11 +24,11 @@ const PAGING_PARAMS = Object.freeze({
});
export const useGetDataUsageDataStreams = ({
searchString,
selectedDataStreams,
options = {},
options = {
enabled: false,
},
}: {
searchString: string;
selectedDataStreams?: string[];
options?: UseQueryOptions<GetDataUsageDataStreamsResponse, IHttpFetchError>;
}): UseQueryResult<GetDataUsageDataStreamsResponse, IHttpFetchError> => {
@ -45,7 +46,7 @@ export const useGetDataUsageDataStreams = ({
DATA_USAGE_DATA_STREAMS_API_ROUTE,
{
version: '1',
query: {},
// query: {},
}
);
@ -53,12 +54,14 @@ export const useGetDataUsageDataStreams = ({
selected: GetDataUsageDataStreamsResponse;
rest: GetDataUsageDataStreamsResponse;
}>(
(acc, list) => {
(acc, ds) => {
const item = {
name: list.name,
name: ds.name,
storageSizeBytes: ds.storageSizeBytes,
selected: ds.selected,
};
if (selectedDataStreams?.includes(list.name)) {
if (selectedDataStreams?.includes(ds.name)) {
acc.selected.push({ ...item, selected: true });
} else {
acc.rest.push({ ...item, selected: false });

View file

@ -31,8 +31,9 @@ export const useGetDataUsageMetrics = (
queryKey: ['get-data-usage-metrics', body],
...options,
keepPreviousData: true,
queryFn: async () => {
queryFn: async ({ signal }) => {
return http.post<UsageMetricsResponseSchemaBody>(DATA_USAGE_METRICS_API_ROUTE, {
signal,
version: '1',
body: JSON.stringify({
from: body.from,

View file

@ -0,0 +1,12 @@
/*
* 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 numeral from '@elastic/numeral';
export const formatBytes = (bytes: number) => {
return numeral(bytes).format('0.0 b');
};

View file

@ -45,7 +45,7 @@ export const getDataStreamsHandler = (
.sort((a, b) => b.size_in_bytes - a.size_in_bytes)
.map((stat) => ({
name: stat.name,
storageSizeBytes: stat.size_in_bytes,
storageSizeBytes: stat.size_in_bytes ?? 0,
}));
return response.ok({

View file

@ -35,6 +35,8 @@ export const getUsageMetricsHandler = (
logger.debug(`Retrieving usage metrics`);
const { from, to, metricTypes, dataStreams: requestDsNames } = request.body;
// redundant check as we don't allow making requests via UI without data streams,
// but it's here to make sure the request body is validated before requesting metrics from auto-ops
if (!requestDsNames?.length) {
return errorHandler(
logger,

View file

@ -28,7 +28,6 @@
"@kbn/core-chrome-browser",
"@kbn/features-plugin",
"@kbn/index-management-shared-types",
"@kbn/ui-theme",
"@kbn/repo-info",
"@kbn/cloud-plugin",
"@kbn/server-http-tools",