[Metrics UI] Add process list header, tooltip, and empty prompt (#85202)
* [Metrics UI] Add process list header, tooltip, and empty prompt * CPU Time -> Time
This commit is contained in:
parent
6be8f63b52
commit
a0d69ca209
|
@ -4,10 +4,18 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { debounce } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiSearchBar, EuiSpacer, EuiEmptyPrompt, EuiButton } from '@elastic/eui';
|
||||
import {
|
||||
EuiSearchBar,
|
||||
EuiSpacer,
|
||||
EuiEmptyPrompt,
|
||||
EuiButton,
|
||||
EuiText,
|
||||
EuiIconTip,
|
||||
Query,
|
||||
} from '@elastic/eui';
|
||||
import {
|
||||
useProcessList,
|
||||
SortBy,
|
||||
|
@ -20,6 +28,7 @@ import { ProcessesTable } from './processes_table';
|
|||
import { parseSearchString } from './parse_search_string';
|
||||
|
||||
const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {
|
||||
const [searchBarState, setSearchBarState] = useState<Query>(Query.MATCH_ALL);
|
||||
const [searchFilter, setSearchFilter] = useState<string>('');
|
||||
const [sortBy, setSortBy] = useState<SortBy>({
|
||||
name: 'cpu',
|
||||
|
@ -45,14 +54,23 @@ const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {
|
|||
);
|
||||
|
||||
const debouncedSearchOnChange = useMemo(
|
||||
() =>
|
||||
debounce<(props: { queryText: string }) => void>(
|
||||
({ queryText }) => setSearchFilter(queryText),
|
||||
500
|
||||
),
|
||||
() => debounce<(queryText: string) => void>((queryText) => setSearchFilter(queryText), 500),
|
||||
[setSearchFilter]
|
||||
);
|
||||
|
||||
const searchBarOnChange = useCallback(
|
||||
({ query, queryText }) => {
|
||||
setSearchBarState(query);
|
||||
debouncedSearchOnChange(queryText);
|
||||
},
|
||||
[setSearchBarState, debouncedSearchOnChange]
|
||||
);
|
||||
|
||||
const clearSearchBar = useCallback(() => {
|
||||
setSearchBarState(Query.MATCH_ALL);
|
||||
setSearchFilter('');
|
||||
}, [setSearchBarState, setSearchFilter]);
|
||||
|
||||
return (
|
||||
<TabContent>
|
||||
<ProcessListContextProvider hostTerm={hostTerm} to={currentTime} timefield={timefield}>
|
||||
|
@ -61,8 +79,34 @@ const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {
|
|||
processSummary={(!error ? response?.summary : null) ?? { total: 0 }}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiText>
|
||||
<h4>
|
||||
{i18n.translate('xpack.infra.metrics.nodeDetails.processesHeader', {
|
||||
defaultMessage: 'Top processes',
|
||||
})}{' '}
|
||||
<EuiIconTip
|
||||
aria-label={i18n.translate(
|
||||
'xpack.infra.metrics.nodeDetails.processesHeader.tooltipLabel',
|
||||
{
|
||||
defaultMessage: 'More info',
|
||||
}
|
||||
)}
|
||||
size="m"
|
||||
type="iInCircle"
|
||||
content={i18n.translate(
|
||||
'xpack.infra.metrics.nodeDetails.processesHeader.tooltipBody',
|
||||
{
|
||||
defaultMessage:
|
||||
'The table below aggregates the top CPU and top memory consuming processes. It does not display all processes.',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</h4>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiSearchBar
|
||||
onChange={debouncedSearchOnChange}
|
||||
query={searchBarState}
|
||||
onChange={searchBarOnChange}
|
||||
box={{
|
||||
incremental: true,
|
||||
placeholder: i18n.translate('xpack.infra.metrics.nodeDetails.searchForProcesses', {
|
||||
|
@ -91,14 +135,15 @@ const TabComponent = ({ currentTime, node, nodeType, options }: TabProps) => {
|
|||
processList={response?.processList ?? []}
|
||||
sortBy={sortBy}
|
||||
setSortBy={setSortBy}
|
||||
clearSearchBar={clearSearchBar}
|
||||
/>
|
||||
) : (
|
||||
<EuiEmptyPrompt
|
||||
iconType="tableDensityNormal"
|
||||
iconType="alert"
|
||||
title={
|
||||
<h4>
|
||||
{i18n.translate('xpack.infra.metrics.nodeDetails.processListError', {
|
||||
defaultMessage: 'Unable to show process data',
|
||||
defaultMessage: 'Unable to load process data',
|
||||
})}
|
||||
</h4>
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import React, { useMemo, useState, useCallback } from 'react';
|
||||
import { omit } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import {
|
||||
EuiTable,
|
||||
EuiTableHeader,
|
||||
|
@ -15,6 +16,9 @@ import {
|
|||
EuiTableRowCell,
|
||||
EuiLoadingChart,
|
||||
EuiEmptyPrompt,
|
||||
EuiText,
|
||||
EuiLink,
|
||||
EuiButton,
|
||||
SortableProperties,
|
||||
LEFT_ALIGNMENT,
|
||||
RIGHT_ALIGNMENT,
|
||||
|
@ -34,6 +38,7 @@ interface TableProps {
|
|||
isLoading: boolean;
|
||||
sortBy: SortBy;
|
||||
setSortBy: (s: SortBy) => void;
|
||||
clearSearchBar: () => void;
|
||||
}
|
||||
|
||||
function useSortableProperties<T>(
|
||||
|
@ -66,6 +71,7 @@ export const ProcessesTable = ({
|
|||
isLoading,
|
||||
sortBy,
|
||||
setSortBy,
|
||||
clearSearchBar,
|
||||
}: TableProps) => {
|
||||
const { updateSortableProperties } = useSortableProperties<Process>(
|
||||
[
|
||||
|
@ -102,13 +108,42 @@ export const ProcessesTable = ({
|
|||
if (currentItems.length === 0)
|
||||
return (
|
||||
<EuiEmptyPrompt
|
||||
iconType="tableDensityNormal"
|
||||
iconType="search"
|
||||
titleSize="s"
|
||||
title={
|
||||
<h4>
|
||||
<strong>
|
||||
{i18n.translate('xpack.infra.metrics.nodeDetails.noProcesses', {
|
||||
defaultMessage: 'No processes matched these search terms',
|
||||
defaultMessage: 'No processes found',
|
||||
})}
|
||||
</h4>
|
||||
</strong>
|
||||
}
|
||||
body={
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.infra.metrics.nodeDetails.noProcessesBody"
|
||||
defaultMessage="Try modifying your filter. Only processes that are within the configured {metricbeatDocsLink} will display here."
|
||||
values={{
|
||||
metricbeatDocsLink: (
|
||||
<EuiLink
|
||||
href="https://www.elastic.co/guide/en/beats/metricbeat/current/metricbeat-module-system.html"
|
||||
target="_blank"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.infra.metrics.nodeDetails.noProcessesBody.metricbeatDocsLinkText"
|
||||
defaultMessage="top N by CPU or Memory"
|
||||
/>
|
||||
</EuiLink>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
}
|
||||
actions={
|
||||
<EuiButton onClick={clearSearchBar}>
|
||||
{i18n.translate('xpack.infra.metrics.nodeDetails.noProcessesClearFilters', {
|
||||
defaultMessage: 'Clear filters',
|
||||
})}
|
||||
</EuiButton>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue