diff --git a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts index 88bbc945e32dc7..a92809022c7e8b 100644 --- a/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts +++ b/x-pack/plugins/infra/common/saved_objects/metrics_explorer_view.ts @@ -55,6 +55,9 @@ export const metricsExplorerViewSavedObjectType: SavedObjectsType = { aggregation: { type: 'keyword', }, + source: { + type: 'keyword', + }, }, }, chartOptions: { diff --git a/x-pack/plugins/infra/public/components/saved_views/toolbar_control.tsx b/x-pack/plugins/infra/public/components/saved_views/toolbar_control.tsx index 9ef8af1fd1b620..f5fb22a17d2008 100644 --- a/x-pack/plugins/infra/public/components/saved_views/toolbar_control.tsx +++ b/x-pack/plugins/infra/public/components/saved_views/toolbar_control.tsx @@ -166,8 +166,8 @@ export function SavedViewsToolbarControls(props: Props) { {currentView ? currentView.name - : i18n.translate('xpack.infra.savedView.defaultView', { - defaultMessage: 'Default view', + : i18n.translate('xpack.infra.savedView.unknownView', { + defaultMessage: 'Unknown', })} @@ -190,6 +190,7 @@ export function SavedViewsToolbarControls(props: Props) { { const finalState = {}; if (value) { if (value.options && isMetricExplorerOptions(value.options)) { + value.options.source = 'url'; set(finalState, 'options', value.options); } if (value.timerange && isMetricExplorerTimeOption(value.timerange)) { diff --git a/x-pack/plugins/infra/public/containers/saved_view/saved_view.tsx b/x-pack/plugins/infra/public/containers/saved_view/saved_view.tsx index e496972530aba9..d0d51f0d2c6593 100644 --- a/x-pack/plugins/infra/public/containers/saved_view/saved_view.tsx +++ b/x-pack/plugins/infra/public/containers/saved_view/saved_view.tsx @@ -198,7 +198,7 @@ export const useSavedView = (props: Props) => { const setDefault = useCallback(() => { setCurrentView({ name: i18n.translate('xpack.infra.savedView.defaultViewNameHosts', { - defaultMessage: 'Hosts', + defaultMessage: 'Default view', }), id: '0', isDefault: !defaultViewId || defaultViewId === '0', // If there is no default view then hosts is the default @@ -209,11 +209,11 @@ export const useSavedView = (props: Props) => { useEffect(() => { const shouldLoadDefault = props.shouldLoadDefault; - if (loadingDefaultView || currentView) { + if (loadingDefaultView || currentView || !shouldLoadDefault) { return; } - if (shouldLoadDefault && !currentView && defaultViewId !== '0') { + if (defaultViewId !== '0') { loadDefaultView(); } else { setDefault(); @@ -242,6 +242,7 @@ export const useSavedView = (props: Props) => { errorOnUpdate, errorOnFind, errorOnCreate: createError, + shouldLoadDefault: props.shouldLoadDefault, makeDefault, deleteView, loadingDefaultView, diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index af5297675daaf7..58b9505dabe4cc 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -6,10 +6,11 @@ import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { useContext } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { EuiErrorBoundary, EuiFlexItem, EuiFlexGroup, EuiButtonEmpty } from '@elastic/eui'; +import { IIndexPattern } from 'src/plugins/data/common'; import { DocumentTitle } from '../../components/document_title'; import { HelpCenterContent } from '../../components/help_center_content'; import { RoutedTabs } from '../../components/navigation/routed_tabs'; @@ -35,6 +36,7 @@ import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters import { InventoryAlertDropdown } from '../../alerting/inventory/components/alert_dropdown'; import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; import { SavedView } from '../../containers/saved_view/saved_view'; +import { SourceConfigurationFields } from '../../graphql/types'; const ADD_DATA_LABEL = i18n.translate('xpack.infra.metricsHeaderAddDataButtonLabel', { defaultMessage: 'Add data', @@ -137,19 +139,10 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { {configuration ? ( - - - + ) : ( )} @@ -168,3 +161,25 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { ); }; + +const PageContent = (props: { + configuration: SourceConfigurationFields.Fragment; + createDerivedIndexPattern: (type: 'logs' | 'metrics' | 'both') => IIndexPattern; +}) => { + const { createDerivedIndexPattern, configuration } = props; + const { options } = useContext(MetricsExplorerOptionsContainer.Context); + + return ( + + + + ); +}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx index 0cf6a54568df8e..3884ee5b7279ab 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx @@ -30,7 +30,7 @@ import { SavedViewsToolbarControls } from '../../../../components/saved_views/to export const Layout = () => { const { sourceId, source } = useSourceContext(); - const { currentView } = useSavedViewContext(); + const { currentView, shouldLoadDefault } = useSavedViewContext(); const { metric, groupBy, @@ -90,11 +90,11 @@ export const Layout = () => { }, [currentView, onViewChange]); useEffect(() => { - // load snapshot data after default view loaded - if (currentView != null) { + // load snapshot data after default view loaded, unless we're not loading a view + if (currentView != null || !shouldLoadDefault) { reload(); } - }, [reload, currentView]); + }, [reload, currentView, shouldLoadDefault]); return ( <> diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts index 975e33cf2415fe..2e8337d932625a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.ts @@ -38,6 +38,7 @@ export const DEFAULT_WAFFLE_OPTIONS_STATE: WaffleOptionsState = { steps: 10, reverseColors: false, }, + source: 'default', sort: { by: 'name', direction: 'desc' }, }; @@ -153,36 +154,44 @@ export const WaffleSortOptionRT = rt.type({ direction: rt.keyof({ asc: null, desc: null }), }); -export const WaffleOptionsStateRT = rt.type({ - metric: SnapshotMetricInputRT, - groupBy: SnapshotGroupByRT, - nodeType: ItemTypeRT, - view: rt.string, - customOptions: rt.array( - rt.type({ - text: rt.string, - field: rt.string, - }) - ), - boundsOverride: rt.type({ - min: rt.number, - max: rt.number, +export const WaffleOptionsStateRT = rt.intersection([ + rt.type({ + metric: SnapshotMetricInputRT, + groupBy: SnapshotGroupByRT, + nodeType: ItemTypeRT, + view: rt.string, + customOptions: rt.array( + rt.type({ + text: rt.string, + field: rt.string, + }) + ), + boundsOverride: rt.type({ + min: rt.number, + max: rt.number, + }), + autoBounds: rt.boolean, + accountId: rt.string, + region: rt.string, + customMetrics: rt.array(SnapshotCustomMetricInputRT), + legend: WaffleLegendOptionsRT, + sort: WaffleSortOptionRT, }), - autoBounds: rt.boolean, - accountId: rt.string, - region: rt.string, - customMetrics: rt.array(SnapshotCustomMetricInputRT), - legend: WaffleLegendOptionsRT, - sort: WaffleSortOptionRT, -}); + rt.partial({ source: rt.string }), +]); export type WaffleSortOption = rt.TypeOf; export type WaffleOptionsState = rt.TypeOf; const encodeUrlState = (state: WaffleOptionsState) => { return WaffleOptionsStateRT.encode(state); }; -const decodeUrlState = (value: unknown) => - pipe(WaffleOptionsStateRT.decode(value), fold(constant(undefined), identity)); +const decodeUrlState = (value: unknown) => { + const state = pipe(WaffleOptionsStateRT.decode(value), fold(constant(undefined), identity)); + if (state) { + state.source = 'url'; + } + return state; +}; export const WaffleOptions = createContainer(useWaffleOptions); export const [WaffleOptionsProvider, useWaffleOptionsContext] = WaffleOptions; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx index 0ddfe62c8a8dff..4f5ec8ecaf9362 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/index.tsx @@ -25,7 +25,7 @@ import { Layout } from './components/layout'; import { useLinkProps } from '../../../hooks/use_link_props'; import { SavedView } from '../../../containers/saved_view/saved_view'; import { DEFAULT_WAFFLE_VIEW_STATE } from './hooks/use_waffle_view_state'; -import { useHistory } from '../../../utils/history_context'; +import { useWaffleOptionsContext } from './hooks/use_waffle_options'; export const SnapshotPage = () => { const uiCapabilities = useKibana().services.application?.capabilities; @@ -39,10 +39,7 @@ export const SnapshotPage = () => { } = useContext(Source.Context); useTrackPageview({ app: 'infra_metrics', path: 'inventory' }); useTrackPageview({ app: 'infra_metrics', path: 'inventory', delay: 15000 }); - - const history = useHistory(); - const getQueryStringFromLocation = (location: Location) => location.search.substring(1); - const queryString = history?.location ? getQueryStringFromLocation(history.location) : ''; + const { source: optionsSource } = useWaffleOptionsContext(); const tutorialLinkProps = useLinkProps({ app: 'home', @@ -68,7 +65,7 @@ export const SnapshotPage = () => { <> diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts index 66cc77a576f994..4b46ed2efafc0f 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.ts @@ -27,7 +27,8 @@ export interface MetricExplorerViewState { export const useMetricsExplorerState = ( source: SourceQuery.Query['source']['configuration'], - derivedIndexPattern: IIndexPattern + derivedIndexPattern: IIndexPattern, + shouldLoadImmediately = true ) => { const [refreshSignal, setRefreshSignal] = useState(0); const [afterKey, setAfterKey] = useState>(null); @@ -40,13 +41,15 @@ export const useMetricsExplorerState = ( setTimeRange, setOptions, } = useContext(MetricsExplorerOptionsContainer.Context); - const { loading, error, data } = useMetricsExplorerData( + const { loading, error, data, loadData } = useMetricsExplorerData( options, source, derivedIndexPattern, currentTimerange, afterKey, - refreshSignal + refreshSignal, + undefined, + shouldLoadImmediately ); const handleRefresh = useCallback(() => { @@ -144,7 +147,7 @@ export const useMetricsExplorerState = ( handleLoadMore: setAfterKey, defaultViewState, onViewStateChange, - + loadData, refreshSignal, afterKey, }; diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts index 5ed710414718a2..db1e4ec8e4db81 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.ts @@ -6,7 +6,7 @@ import DateMath from '@elastic/datemath'; import { isEqual } from 'lodash'; -import { useEffect, useState } from 'react'; +import { useEffect, useState, useCallback } from 'react'; import { HttpHandler } from 'src/core/public'; import { IIndexPattern } from 'src/plugins/data/public'; import { SourceQuery } from '../../../../../common/graphql/types'; @@ -30,7 +30,8 @@ export function useMetricsExplorerData( timerange: MetricsExplorerTimeOptions, afterKey: string | null | Record, signal: any, - fetch?: HttpHandler + fetch?: HttpHandler, + shouldLoadImmediately = true ) { const kibana = useKibana(); const fetchFn = fetch ? fetch : kibana.services.http?.fetch; @@ -40,7 +41,7 @@ export function useMetricsExplorerData( const [lastOptions, setLastOptions] = useState(null); const [lastTimerange, setLastTimerange] = useState(null); - useEffect(() => { + const loadData = useCallback(() => { (async () => { setLoading(true); try { @@ -112,9 +113,15 @@ export function useMetricsExplorerData( } setLoading(false); })(); - - // TODO: fix this dependency list while preserving the semantics // eslint-disable-next-line react-hooks/exhaustive-deps }, [options, source, timerange, signal, afterKey]); - return { error, loading, data }; + + useEffect(() => { + if (!shouldLoadImmediately) { + return; + } + + loadData(); + }, [loadData, shouldLoadImmediately]); + return { error, loading, data, loadData }; } diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts index a257f1f80238b9..0ebc6f74c82742 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.ts @@ -42,6 +42,7 @@ export interface MetricsExplorerOptions { aggregation: MetricsExplorerAggregation; forceInterval?: boolean; dropLastBucket?: boolean; + source?: string; } export interface MetricsExplorerTimeOptions { @@ -83,6 +84,7 @@ export const DEFAULT_METRICS: MetricsExplorerOptionsMetric[] = [ export const DEFAULT_OPTIONS: MetricsExplorerOptions = { aggregation: 'avg', metrics: DEFAULT_METRICS, + source: 'default', }; export const DEFAULT_METRICS_EXPLORER_VIEW_STATE = { diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx index d0b30deb2a5193..cd875ae54071cb 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/index.tsx @@ -39,8 +39,9 @@ export const MetricsExplorerPage = ({ source, derivedIndexPattern }: MetricsExpl handleRefresh, handleLoadMore, onViewStateChange, - } = useMetricsExplorerState(source, derivedIndexPattern); - const { currentView } = useSavedViewContext(); + loadData, + } = useMetricsExplorerState(source, derivedIndexPattern, false); + const { currentView, shouldLoadDefault } = useSavedViewContext(); useTrackPageview({ app: 'infra_metrics', path: 'metrics_explorer' }); useTrackPageview({ app: 'infra_metrics', path: 'metrics_explorer', delay: 15000 }); @@ -51,6 +52,13 @@ export const MetricsExplorerPage = ({ source, derivedIndexPattern }: MetricsExpl } }, [currentView, onViewStateChange]); + useEffect(() => { + if (currentView != null || !shouldLoadDefault) { + // load metrics explorer data after default view loaded, unless we're not loading a view + loadData(); + } + }, [loadData, currentView, shouldLoadDefault]); + return (