diff --git a/x-pack/plugins/infra/public/components/asset_details/context_providers.tsx b/x-pack/plugins/infra/public/components/asset_details/context_providers.tsx index 179a1bfaf80b3..6af455dff2b02 100644 --- a/x-pack/plugins/infra/public/components/asset_details/context_providers.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/context_providers.tsx @@ -19,7 +19,7 @@ export const ContextProviders = ({ }) => { const { asset, dateRange, overrides, onTabsStateChange, assetType = 'host', renderMode } = props; return ( - + { + const { dateRange, setDateRange } = useDateRangeProviderContext(); + const onTimeChange = useCallback( + ({ start, end, isInvalid }: OnTimeChangeProps) => { + if (!isInvalid) { + setDateRange({ from: start, to: end }); + } + }, + [setDateRange] + ); + + return ( + + ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_state.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_state.ts index c8bd88f126859..53bb74beef943 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_state.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_asset_details_state.ts @@ -7,7 +7,6 @@ import createContainer from 'constate'; import type { AssetDetailsProps } from '../types'; -import { useDateRangeProviderContext } from './use_date_range'; import { useMetadataStateProviderContext } from './use_metadata_state'; export interface UseAssetDetailsStateProps { @@ -19,7 +18,6 @@ export interface UseAssetDetailsStateProps { export function useAssetDetailsState({ state }: UseAssetDetailsStateProps) { const { metadata } = useMetadataStateProviderContext(); - const { dateRange, dateRangeTs } = useDateRangeProviderContext(); const { asset, assetType, onTabsStateChange, overrides, renderMode } = state; // When the asset asset.name is known we can load the page faster @@ -32,8 +30,6 @@ export function useAssetDetailsState({ state }: UseAssetDetailsStateProps) { name: asset.name || metadata?.name || 'asset-name', }, assetType, - dateRange, - dateRangeTs, onTabsStateChange, overrides, renderMode, diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts index bb20ddab56957..8253b7e8b5685 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_date_range.ts @@ -5,33 +5,38 @@ * 2.0. */ +import type { TimeRange } from '@kbn/es-query'; import createContainer from 'constate'; -import { useMemo } from 'react'; +import { useCallback, useMemo, useState } from 'react'; import { parseDateRange } from '../../../utils/datemath'; -import type { AssetDetailsProps } from '../types'; + import { toTimestampRange } from '../utils'; -const DEFAULT_DATE_RANGE = { +const DEFAULT_DATE_RANGE: TimeRange = { from: 'now-15m', to: 'now', }; -export type UseAssetDetailsStateProps = Pick; +export interface UseAssetDetailsStateProps { + initialDateRange: TimeRange; +} + +export function useDateRangeProvider({ initialDateRange }: UseAssetDetailsStateProps) { + const [dateRange, setDateRange] = useState(initialDateRange); -export function useDateRangeProvider({ dateRange: rawDateRange }: UseAssetDetailsStateProps) { - const dateRange = useMemo(() => { + const parsedDateRange = useMemo(() => { const { from = DEFAULT_DATE_RANGE.from, to = DEFAULT_DATE_RANGE.to } = - parseDateRange(rawDateRange); + parseDateRange(dateRange); return { from, to }; - }, [rawDateRange]); + }, [dateRange]); - const dateRangeTs = toTimestampRange(dateRange); + const getDateRangeInTimestamp = useCallback( + () => toTimestampRange(parsedDateRange), + [parsedDateRange] + ); - return { - dateRange, - dateRangeTs, - }; + return { dateRange, setDateRange, getDateRangeInTimestamp }; } export const [DateRangeProvider, useDateRangeProviderContext] = diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_metadata_state.ts b/x-pack/plugins/infra/public/components/asset_details/hooks/use_metadata_state.ts index e9a162b2a4c7e..6fc1991fcb1dc 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_metadata_state.ts +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_metadata_state.ts @@ -15,7 +15,7 @@ import { useDateRangeProviderContext } from './use_date_range'; export type UseMetadataProviderProps = Pick; export function useMetadataProvider({ asset, assetType }: UseMetadataProviderProps) { - const { dateRangeTs } = useDateRangeProviderContext(); + const { getDateRangeInTimestamp } = useDateRangeProviderContext(); const inventoryModel = findInventoryModel(assetType); const { sourceId } = useSourceContext(); @@ -24,7 +24,7 @@ export function useMetadataProvider({ asset, assetType }: UseMetadataProviderPro assetType, inventoryModel.requiredMetrics, sourceId, - dateRangeTs + getDateRangeInTimestamp() ); return { diff --git a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx index c7db9b6c4893c..fe72eea16e802 100644 --- a/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/hooks/use_page_header.tsx @@ -15,7 +15,6 @@ import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { APM_HOST_FILTER_FIELD } from '../constants'; import { LinkToAlertsRule, LinkToApmServices, LinkToNodeDetails, LinkToUptime } from '../links'; import { FlyoutTabIds, type LinkOptions, type Tab, type TabIds } from '../types'; -import { toTimestampRange } from '../utils'; import { useAssetDetailsStateContext } from './use_asset_details_state'; import { useDateRangeProviderContext } from './use_date_range'; import { useTabSwitcherContext } from './use_tab_switcher'; @@ -31,7 +30,7 @@ export const usePageHeader = (tabs: Tab[], links?: LinkOptions[]) => { }; const useRightSideItems = (links?: LinkOptions[]) => { - const { dateRange } = useDateRangeProviderContext(); + const { getDateRangeInTimestamp } = useDateRangeProviderContext(); const { asset, assetType, overrides } = useAssetDetailsStateContext(); const { metadata } = useMetadataStateProviderContext(); @@ -41,7 +40,7 @@ const useRightSideItems = (links?: LinkOptions[]) => { ), alertRule: , @@ -58,7 +57,13 @@ const useRightSideItems = (links?: LinkOptions[]) => { /> ), }), - [asset, assetType, dateRange, metadata?.info?.host?.ip, overrides?.alertRule?.onCreateRuleClick] + [ + asset, + assetType, + getDateRangeInTimestamp, + metadata?.info?.host?.ip, + overrides?.alertRule?.onCreateRuleClick, + ] ); const rightSideItems = useMemo( diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.tsx index 6ccf95e240f62..76774ed16c5ef 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/anomalies/anomalies.tsx @@ -5,13 +5,30 @@ * 2.0. */ -import React from 'react'; +import type { TimeRange } from '@kbn/es-query'; +import React, { useCallback } from 'react'; import { AnomaliesTable } from '../../../../pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table'; import { useAssetDetailsStateContext } from '../../hooks/use_asset_details_state'; +import { useDateRangeProviderContext } from '../../hooks/use_date_range'; export const Anomalies = () => { + const { dateRange, setDateRange } = useDateRangeProviderContext(); const { asset, overrides } = useAssetDetailsStateContext(); const { onClose = () => {} } = overrides?.anomalies ?? {}; - return ; + const handleDateRangeChange = useCallback( + (newDateRange: TimeRange) => { + setDateRange(newDateRange); + }, + [setDateRange] + ); + + return ( + + ); }; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx index 10478af29d86e..c27fb0fd36fca 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx @@ -13,18 +13,19 @@ import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elas import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { LogStream } from '@kbn/logs-shared-plugin/public'; import { DEFAULT_LOG_VIEW, LogViewReference } from '@kbn/logs-shared-plugin/common'; - import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; import { findInventoryFields } from '../../../../../common/inventory_models'; import { InfraLoadingPanel } from '../../../loading'; import { useAssetDetailsStateContext } from '../../hooks/use_asset_details_state'; import { useDataViewsProviderContext } from '../../hooks/use_data_views'; +import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { DatePicker } from '../../date_picker/date_picker'; const TEXT_QUERY_THROTTLE_INTERVAL_MS = 500; export const Logs = () => { - const { asset, assetType, overrides, onTabsStateChange, dateRangeTs } = - useAssetDetailsStateContext(); + const { getDateRangeInTimestamp } = useDateRangeProviderContext(); + const { asset, assetType, overrides, onTabsStateChange } = useAssetDetailsStateContext(); const { logs } = useDataViewsProviderContext(); const { query: overrideQuery } = overrides?.logs ?? {}; @@ -35,7 +36,7 @@ export const Logs = () => { const [textQuery, setTextQuery] = useState(overrideQuery ?? ''); const [textQueryDebounced, setTextQueryDebounced] = useState(overrideQuery ?? ''); - const currentTimestamp = dateRangeTs.to; + const currentTimestamp = getDateRangeInTimestamp().to; const startTimestamp = currentTimestamp - 60 * 60 * 1000; // 60 minutes useDebounce( @@ -89,6 +90,9 @@ export const Logs = () => { return ( + + + diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx index f3b27b9a8caca..8987918246781 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx @@ -9,10 +9,13 @@ import React, { useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiCallOut, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiFlexGroup } from '@elastic/eui'; +import { EuiFlexItem } from '@elastic/eui'; import { Table } from './table'; import { getAllFields } from './utils'; import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; import { useAssetDetailsStateContext } from '../../hooks/use_asset_details_state'; +import { DatePicker } from '../../date_picker/date_picker'; export interface MetadataSearchUrlState { metadataSearchUrlState: string; @@ -70,13 +73,20 @@ export const Metadata = () => { } return ( - + + + + + +
+ + ); }; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx index 609feca5222e2..28e611f3ae21e 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx @@ -10,6 +10,7 @@ import { EuiFlexGrid, EuiFlexItem, EuiTitle, EuiSpacer, EuiFlexGroup } from '@el import type { DataView } from '@kbn/data-views-plugin/public'; import type { TimeRange } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; +import { LensEmbeddableInput } from '@kbn/lens-plugin/public'; import { assetDetailsDashboards, XY_MISSING_VALUE_DOTTED_LINE_CONFIG, @@ -18,6 +19,7 @@ import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; import { LensChart, HostMetricsExplanationContent } from '../../../../lens'; import { METRIC_CHART_HEIGHT } from '../../../constants'; import { Popover } from '../../common/popover'; +import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; type DataViewOrigin = 'logs' | 'metrics'; @@ -30,6 +32,7 @@ interface Props { export const MetricsGrid = React.memo( ({ nodeName, metricsDataView, logsDataView, timeRange }: Props) => { + const { setDateRange } = useDateRangeProviderContext(); const getDataView = useCallback( (dataViewOrigin: DataViewOrigin) => { return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; @@ -50,6 +53,21 @@ export const MetricsGrid = React.memo( [getDataView, nodeName] ); + const handleBrushEnd = useCallback( + ({ + range, + preventDefault, + }: Parameters>[0]) => { + setDateRange({ + from: new Date(range[0]).toISOString(), + to: new Date(range[1]).toISOString(), + }); + + preventDefault(); + }, + [setDateRange] + ); + return ( @@ -77,7 +95,7 @@ export const MetricsGrid = React.memo( title={title} overrides={overrides} visualizationType="lnsXY" - disableTriggers + onBrushEnd={handleBrushEnd} /> ) diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx index c8e0e08bba85f..9f8b7f5005653 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -17,9 +17,12 @@ import { MetricsGrid } from './metrics/metrics_grid'; import { useAssetDetailsStateContext } from '../../hooks/use_asset_details_state'; import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; import { useDataViewsProviderContext } from '../../hooks/use_data_views'; +import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { DatePicker } from '../../date_picker/date_picker'; export const Overview = () => { - const { asset, assetType, dateRange, renderMode } = useAssetDetailsStateContext(); + const { dateRange } = useDateRangeProviderContext(); + const { asset, assetType, renderMode } = useAssetDetailsStateContext(); const { metadata, loading: metadataLoading, @@ -29,6 +32,9 @@ export const Overview = () => { return ( + + + diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx index 7bb8e96276fd8..7db0185a54b10 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx @@ -10,13 +10,15 @@ import { debounce } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiSearchBar, - EuiSpacer, EuiEmptyPrompt, EuiButton, - EuiText, EuiIconTip, + EuiTitle, Query, + EuiFlexGroup, + EuiFlexItem, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; import { parseSearchString } from './parse_search_string'; import { ProcessesTable } from './processes_table'; import { STATE_NAMES } from './states'; @@ -28,6 +30,8 @@ import { } from '../../../../pages/metrics/inventory_view/hooks/use_process_list'; import { getFieldByType } from '../../../../../common/inventory_models'; import { useAssetDetailsStateContext } from '../../hooks/use_asset_details_state'; +import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { DatePicker } from '../../date_picker/date_picker'; const options = Object.entries(STATE_NAMES).map(([value, view]: [string, string]) => ({ value, @@ -35,8 +39,8 @@ const options = Object.entries(STATE_NAMES).map(([value, view]: [string, string] })); export const Processes = () => { - const { asset, assetType, overrides, dateRangeTs, onTabsStateChange } = - useAssetDetailsStateContext(); + const { getDateRangeInTimestamp } = useDateRangeProviderContext(); + const { asset, assetType, overrides, onTabsStateChange } = useAssetDetailsStateContext(); const { query: overrideQuery } = overrides?.processes ?? {}; @@ -44,7 +48,8 @@ export const Processes = () => { const [searchBarState, setSearchBarState] = useState(() => searchText ? Query.parse(searchText) : Query.MATCH_ALL ); - const currentTimestamp = dateRangeTs.to; + + const currentTimestamp = getDateRangeInTimestamp().to; const [sortBy, setSortBy] = useState({ name: 'cpu', @@ -90,87 +95,109 @@ export const Processes = () => { return ( - - - -

- {i18n.translate('xpack.infra.metrics.nodeDetails.processesHeader', { - defaultMessage: 'Top processes', - })}{' '} - + + + + + + + + + + + + + + + + + + + + + + -

-
- - - - {!error ? ( - - ) : ( - - {i18n.translate('xpack.infra.metrics.nodeDetails.processListError', { - defaultMessage: 'Unable to load process data', - })} - - } - actions={ - - {i18n.translate('xpack.infra.metrics.nodeDetails.processListRetry', { - defaultMessage: 'Try again', - })} - - } - /> - )} + + + {!error ? ( + + ) : ( + + + + } + actions={ + + + + } + /> + )} + +
); }; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx index 2a199549943f4..f5505da3a634b 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes_table.tsx @@ -17,14 +17,16 @@ import { EuiTableRowCell, EuiLoadingChart, EuiEmptyPrompt, + useEuiTheme, EuiText, EuiLink, EuiButton, SortableProperties, LEFT_ALIGNMENT, RIGHT_ALIGNMENT, + EuiCode, } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { css } from '@emotion/react'; import { FORMATTERS } from '../../../../../common/formatters'; import type { SortBy } from '../../../../pages/metrics/inventory_view/hooks/use_process_list'; import type { Process } from './types'; @@ -113,9 +115,10 @@ export const ProcessesTable = ({ titleSize="s" title={ - {i18n.translate('xpack.infra.metrics.nodeDetails.noProcesses', { - defaultMessage: 'No processes found', - })} + } body={ @@ -145,37 +148,43 @@ export const ProcessesTable = ({ data-test-subj="infraProcessesTableClearFiltersButton" onClick={clearSearchBar} > - {i18n.translate('xpack.infra.metrics.nodeDetails.noProcessesClearFilters', { - defaultMessage: 'Clear filters', - })} + } /> ); return ( - <> - - - - {columns.map((column) => ( - updateSortableProperties(column.field) : undefined} - isSorted={sortBy.name === column.field} - isSortAscending={sortBy.name === column.field && sortBy.isAscending} - > - {column.name} - - ))} - - - - - - + + + + {columns.map((column) => ( + updateSortableProperties(column.field) : undefined} + isSorted={sortBy.name === column.field} + isSortAscending={sortBy.name === column.field && sortBy.isAscending} + > + {column.name} + + ))} + + + + + ); }; @@ -200,6 +209,7 @@ interface TableBodyProps { items: Process[]; currentTime: number; } + const ProcessesTableBody = ({ items, currentTime }: TableBodyProps) => ( <> {items.map((item, i) => { @@ -218,14 +228,6 @@ const ProcessesTableBody = ({ items, currentTime }: TableBodyProps) => ( ); -const StyledTableBody = euiStyled(EuiTableBody)` - & .euiTableCellContent { - padding-top: 0; - padding-bottom: 0; - - } -`; - const ONE_MINUTE = 60 * 1000; const ONE_HOUR = ONE_MINUTE * 60; const RuntimeCell = ({ startTime, currentTime }: { startTime: number; currentTime: number }) => { @@ -271,7 +273,7 @@ const columns: Array<{ }), sortable: false, width: '40%', - render: (command: string) => {command}, + render: (command: string) => , }, { field: 'startTime', @@ -302,10 +304,25 @@ const columns: Array<{ }, ]; -const CodeLine = euiStyled.div` - font-family: ${(props) => props.theme.eui.euiCodeFontFamily}; - font-size: ${(props) => props.theme.eui.euiFontSizeS}; - white-space: pre; - overflow: hidden; - text-overflow: ellipsis; -`; +const CodeLine = ({ command }: { command: string }) => { + const euiTheme = useEuiTheme(); + return ( +
+ + {command} + +
+ ); +}; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx index 928f48307eee7..6b097275d9f62 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/summary_table.tsx @@ -17,7 +17,7 @@ import { EuiDescriptionListDescription, EuiHorizontalRule, } from '@elastic/eui'; -import { euiStyled } from '@kbn/kibana-react-plugin/common'; +import { css } from '@emotion/react'; import type { ProcessListAPIResponse } from '../../../../../common/http_api'; import { STATE_NAMES } from './states'; import { NOT_AVAILABLE_LABEL } from '../../translations'; @@ -63,9 +63,25 @@ export const SummaryTable = ({ processSummary, isLoading }: Props) => { data-test-subj="infraAssetDetailsProcessesSummaryTableItem" compressed > - {columnTitles[field as keyof SummaryRecord]} + + {columnTitles[field as keyof SummaryRecord]} + - {value === -1 ? : value} + {value === -1 ? ( + + ) : ( + value + )} @@ -82,12 +98,3 @@ const columnTitles = { }), ...STATE_NAMES, }; - -const LoadingSpinner = euiStyled(EuiLoadingSpinner).attrs({ size: 'm' })` - margin-top: 2px; - margin-bottom: 3px; -`; - -const ColumnTitle = euiStyled(EuiDescriptionListTitle)` - white-space: nowrap; -`; diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx index 6daf6b36e5609..b45250cb5a921 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/host_details_flyout/flyout_wrapper.tsx @@ -21,14 +21,14 @@ export interface Props { export const FlyoutWrapper = ({ node: { name }, closeFlyout }: Props) => { const { source } = useSourceContext(); - const { searchCriteria } = useUnifiedSearchContext(); + const { parsedDateRange } = useUnifiedSearchContext(); const [hostFlyoutState, setHostFlyoutState] = useHostFlyoutUrlState(); return source ? ( { const { services: { telemetry }, } = useKibanaContextForPlugin(); - const { buildQuery, getParsedDateRange } = useUnifiedSearchContext(); + const { buildQuery, parsedDateRange } = useUnifiedSearchContext(); const { search: fetchHostCount, requests$ } = useDataSearch({ getRequest: useCallback(() => { const query = buildQuery(); - const dateRange = getParsedDateRange(); + const dateRange = parsedDateRange; const filters: QueryDslQueryContainer = { bool: { @@ -74,7 +74,7 @@ export const useHostCount = () => { }, options: { strategy: ES_SEARCH_STRATEGY }, }; - }, [buildQuery, dataView, getParsedDateRange, metricAlias]), + }, [buildQuery, dataView, parsedDateRange, metricAlias]), parseResponses: normalizeDataSearchResponse, }); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts index fdf57978ccd02..6cf0a0f09de54 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts @@ -43,18 +43,18 @@ export const useHostsView = () => { const { services: { http }, } = useKibanaContextForPlugin(); - const { buildQuery, getParsedDateRange, searchCriteria } = useUnifiedSearchContext(); + const { buildQuery, parsedDateRange, searchCriteria } = useUnifiedSearchContext(); const abortCtrlRef = useRef(new AbortController()); const baseRequest = useMemo( () => createInfraMetricsRequest({ - dateRange: getParsedDateRange(), + dateRange: parsedDateRange, esQuery: buildQuery(), sourceId, limit: searchCriteria.limit, }), - [buildQuery, getParsedDateRange, sourceId, searchCriteria.limit] + [buildQuery, parsedDateRange, sourceId, searchCriteria.limit] ); const [state, refetch] = useAsyncFn( diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts index db0b01a70f3ee..3f6741b33f65c 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_unified_search.ts @@ -5,7 +5,7 @@ * 2.0. */ import createContainer from 'constate'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { buildEsQuery, fromKueryExpression, type Query } from '@kbn/es-query'; import { map, skip, startWith } from 'rxjs/operators'; import { combineLatest } from 'rxjs'; @@ -99,7 +99,7 @@ export const useUnifiedSearch = () => { [queryStringService, setSearch, validateQuery] ); - const getParsedDateRange = useCallback(() => { + const parsedDateRange = useMemo(() => { const defaults = getDefaultTimestamps(); const { from = defaults.from, to = defaults.to } = parseDateRange(searchCriteria.dateRange); @@ -108,13 +108,11 @@ export const useUnifiedSearch = () => { }, [searchCriteria.dateRange]); const getDateRangeAsTimestamp = useCallback(() => { - const parsedDate = getParsedDateRange(); - - const from = new Date(parsedDate.from).getTime(); - const to = new Date(parsedDate.to).getTime(); + const from = new Date(parsedDateRange.from).getTime(); + const to = new Date(parsedDateRange.to).getTime(); return { from, to }; - }, [getParsedDateRange]); + }, [parsedDateRange]); const buildQuery = useCallback(() => { return buildEsQuery( @@ -176,9 +174,9 @@ export const useUnifiedSearch = () => { // Track telemetry event on query/filter/date changes useEffect(() => { - const parsedDateRange = getDateRangeAsTimestamp(); + const dateRangeInTimestamp = getDateRangeAsTimestamp(); telemetry.reportHostsViewQuerySubmitted( - buildQuerySubmittedPayload({ ...searchCriteria, parsedDateRange }) + buildQuerySubmittedPayload({ ...searchCriteria, parsedDateRange: dateRangeInTimestamp }) ); }, [getDateRangeAsTimestamp, searchCriteria, telemetry]); @@ -186,7 +184,7 @@ export const useUnifiedSearch = () => { error, buildQuery, onSubmit, - getParsedDateRange, + parsedDateRange, getDateRangeAsTimestamp, searchCriteria, }; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx index 4cb2920f8dcc8..9a7af0611564f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx @@ -7,10 +7,10 @@ import { i18n } from '@kbn/i18n'; import React, { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'; -import { EuiSuperDatePicker } from '@elastic/eui'; import { + EuiSuperDatePicker, + useEuiTheme, EuiFlexItem, - EuiSpacer, EuiFieldSearch, EuiBasicTable, EuiFlexGroup, @@ -22,19 +22,19 @@ import { EuiButtonIcon, EuiPopover, EuiContextMenuPanel, - EuiIcon, - EuiText, - OnTimeChangeProps, + type OnTimeChangeProps, + EuiEmptyPrompt, } from '@elastic/eui'; import { FormattedMessage, FormattedDate } from '@kbn/i18n-react'; -import { withTheme } from '@kbn/kibana-react-plugin/common'; import { useLinkProps, useUiTracker } from '@kbn/observability-shared-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; +import { css } from '@emotion/react'; import { datemathToEpochMillis } from '../../../../../../../utils/datemath'; -import { SnapshotMetricType } from '../../../../../../../../common/inventory_models/types'; +import type { SnapshotMetricType } from '../../../../../../../../common/inventory_models/types'; import { useSorting } from '../../../../../../../hooks/use_sorting'; import { useMetricsK8sAnomaliesResults } from '../../../../hooks/use_metrics_k8s_anomalies'; import { useMetricsHostsAnomaliesResults } from '../../../../hooks/use_metrics_hosts_anomalies'; -import { +import type { Metric, MetricsHostsAnomaly, Sort, @@ -45,8 +45,10 @@ import { AnomalySeverityIndicator } from '../../../../../../../components/loggin import { useSourceContext } from '../../../../../../../containers/metrics_source'; import { createResultsUrl } from '../flyout_home'; import { useWaffleViewState, WaffleViewState } from '../../../../hooks/use_waffle_view_state'; + type JobType = 'k8s' | 'hosts'; type SortField = 'anomalyScore' | 'startTime'; + interface JobOption { id: JobType; label: string; @@ -159,40 +161,55 @@ const AnomalyActionMenu = ({ ); }; -export const NoAnomaliesFound = withTheme(({ theme }) => ( - - -

- -

-

- -

- - - { + const euiTheme = useEuiTheme(); + return ( +
+ + + + } + body={ + + } /> - - -)); +
+ ); +}; interface Props { closeFlyout(): void; hostName?: string; + dateRange?: TimeRange; + onDateRangeChange?: (dateRange: TimeRange) => void; } + +const DEFAULT_DATE_RANGE: TimeRange = { + from: 'now-30d', + to: 'now', +}; + export const AnomaliesTable = (props: Props) => { - const { closeFlyout, hostName } = props; + const { closeFlyout, hostName, onDateRangeChange } = props; const [search, setSearch] = useState(''); - const [start, setStart] = useState('now-30d'); - const [end, setEnd] = useState('now'); + const [dateRange, setDateRange] = useState(props.dateRange ?? DEFAULT_DATE_RANGE); const trackMetric = useUiTracker({ app: 'infra_metrics' }); const [timeRange, setTimeRange] = useState<{ start: number; end: number }>({ - start: datemathToEpochMillis(start) || 0, - end: datemathToEpochMillis(end, 'up') || 0, + start: datemathToEpochMillis(dateRange.from) || 0, + end: datemathToEpochMillis(dateRange.to, 'up') || 0, }); const { sorting, setSorting } = useSorting({ field: 'startTime', @@ -224,15 +241,17 @@ export const AnomaliesTable = (props: Props) => { const onTimeChange = useCallback( ({ isInvalid, start: startChange, end: endChange }: OnTimeChangeProps) => { if (!isInvalid) { - setStart(startChange); - setEnd(endChange); + setDateRange({ from: startChange, to: endChange }); setTimeRange({ start: datemathToEpochMillis(startChange)!, end: datemathToEpochMillis(endChange, 'up')!, }); + if (onDateRangeChange) { + onDateRangeChange({ from: startChange, to: endChange }); + } } }, - [] + [onDateRangeChange] ); const anomalyParams = useMemo( @@ -436,73 +455,75 @@ export const AnomaliesTable = (props: Props) => { return ( - + - - {!hostName && ( - - - - - - - - - )} - - - - - columns={columns} - items={results} - sorting={{ sort: sorting }} - onChange={onTableChange} - hasActions={true} - loading={isLoading} - noItemsMessage={ - isLoading ? ( - - ) : ( - - ) - } - /> - - + + {!hostName && ( + + + + + + + + + )} + + + + columns={columns} + items={results} + sorting={{ sort: sorting }} + onChange={onTableChange} + hasActions={true} + loading={isLoading} + noItemsMessage={ + isLoading ? ( + + ) : ( + + ) + } + /> + + + + ); };