[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:
Zacqary Adam Xeper 2020-12-09 11:39:06 -06:00 committed by GitHub
parent 6be8f63b52
commit a0d69ca209
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 94 additions and 14 deletions

View file

@ -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>
}

View file

@ -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>
}
/>
);