mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Infrastructure UI] inital hosts page (#138173)
* inital empty hosts page and navigation item * lens table and unified search * add data view id * cleanup * clear searchs session when unmounting * cleanup * add some basic error handling for Data View * change back loading text for now because of breaking test
This commit is contained in:
parent
a16fd1e033
commit
7e1b60fa22
10 changed files with 572 additions and 1 deletions
|
@ -15,7 +15,8 @@
|
|||
"triggersActionsUi",
|
||||
"observability",
|
||||
"ruleRegistry",
|
||||
"unifiedSearch"
|
||||
"unifiedSearch",
|
||||
"lens"
|
||||
],
|
||||
"optionalPlugins": ["ml", "home", "embeddable", "osquery"],
|
||||
"server": true,
|
||||
|
|
|
@ -46,6 +46,7 @@ export const renderApp = (
|
|||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(element);
|
||||
plugins.data.search.session.clear();
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* 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 { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { TypedLensByValueInput } from '@kbn/lens-plugin/public';
|
||||
import type { Query, TimeRange } from '@kbn/es-query';
|
||||
import React from 'react';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { InfraClientStartDeps } from '../../../../types';
|
||||
|
||||
const getLensHostsTable = (
|
||||
metricsDataView: DataView,
|
||||
query: Query
|
||||
): TypedLensByValueInput['attributes'] =>
|
||||
({
|
||||
visualizationType: 'lnsDatatable',
|
||||
title: 'Lens visualization',
|
||||
references: [
|
||||
{
|
||||
id: metricsDataView.id,
|
||||
name: 'indexpattern-datasource-current-indexpattern',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
{
|
||||
id: metricsDataView.id,
|
||||
name: 'indexpattern-datasource-layer-cbe5d8a0-381d-49bf-b8ac-f8f312ec7129',
|
||||
type: 'index-pattern',
|
||||
},
|
||||
],
|
||||
state: {
|
||||
datasourceStates: {
|
||||
indexpattern: {
|
||||
layers: {
|
||||
'cbe5d8a0-381d-49bf-b8ac-f8f312ec7129': {
|
||||
columns: {
|
||||
'8d17458d-31af-41d1-a23c-5180fd960bee': {
|
||||
label: 'Name',
|
||||
dataType: 'string',
|
||||
operationType: 'terms',
|
||||
scale: 'ordinal',
|
||||
sourceField: 'host.name',
|
||||
isBucketed: true,
|
||||
params: {
|
||||
size: 10000,
|
||||
orderBy: {
|
||||
type: 'column',
|
||||
columnId: '467de550-9186-4e18-8cfa-bce07087801a',
|
||||
},
|
||||
orderDirection: 'desc',
|
||||
otherBucket: true,
|
||||
missingBucket: false,
|
||||
parentFormat: {
|
||||
id: 'terms',
|
||||
},
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'155fc728-d010-498e-8126-0bc46cad2be2': {
|
||||
label: 'Operating system',
|
||||
dataType: 'string',
|
||||
operationType: 'terms',
|
||||
scale: 'ordinal',
|
||||
sourceField: 'host.os.name',
|
||||
isBucketed: true,
|
||||
params: {
|
||||
size: 10000,
|
||||
orderBy: {
|
||||
type: 'column',
|
||||
columnId: '467de550-9186-4e18-8cfa-bce07087801a',
|
||||
},
|
||||
orderDirection: 'desc',
|
||||
otherBucket: false,
|
||||
missingBucket: false,
|
||||
parentFormat: {
|
||||
id: 'terms',
|
||||
},
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'467de550-9186-4e18-8cfa-bce07087801a': {
|
||||
label: '# of CPUs',
|
||||
dataType: 'number',
|
||||
operationType: 'max',
|
||||
sourceField: 'system.cpu.cores',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
emptyAsNull: true,
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'0a9bd0fa-9966-489b-8c95-70997a7aad4cX0': {
|
||||
label: 'Part of Memory Total (avg)',
|
||||
dataType: 'number',
|
||||
operationType: 'average',
|
||||
sourceField: 'system.memory.total',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
emptyAsNull: false,
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'0a9bd0fa-9966-489b-8c95-70997a7aad4c': {
|
||||
label: 'Memory total (avg.)',
|
||||
dataType: 'number',
|
||||
operationType: 'formula',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
formula: 'average(system.memory.total)',
|
||||
isFormulaBroken: false,
|
||||
format: {
|
||||
id: 'bytes',
|
||||
params: {
|
||||
decimals: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
references: ['0a9bd0fa-9966-489b-8c95-70997a7aad4cX0'],
|
||||
customLabel: true,
|
||||
},
|
||||
'fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0': {
|
||||
label: 'Part of Memory Usage (avg)',
|
||||
dataType: 'number',
|
||||
operationType: 'average',
|
||||
sourceField: 'system.memory.used.pct',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
emptyAsNull: false,
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'fe5a4d7d-6f48-45ab-974c-96bc864ac36f': {
|
||||
label: 'Memory usage (avg.)',
|
||||
dataType: 'number',
|
||||
operationType: 'formula',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
formula: 'average(system.memory.used.pct)',
|
||||
isFormulaBroken: false,
|
||||
format: {
|
||||
id: 'percent',
|
||||
params: {
|
||||
decimals: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
references: ['fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0'],
|
||||
customLabel: true,
|
||||
},
|
||||
'3eca2307-228e-4842-a023-57e15c8c364dX0': {
|
||||
label: 'Part of Disk Latency (avg ms)',
|
||||
dataType: 'number',
|
||||
operationType: 'average',
|
||||
sourceField: 'system.diskio.io.time',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
emptyAsNull: false,
|
||||
},
|
||||
customLabel: true,
|
||||
},
|
||||
'3eca2307-228e-4842-a023-57e15c8c364dX1': {
|
||||
label: 'Part of Disk Latency (avg ms)',
|
||||
dataType: 'number',
|
||||
operationType: 'math',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
tinymathAst: {
|
||||
type: 'function',
|
||||
name: 'divide',
|
||||
args: ['3eca2307-228e-4842-a023-57e15c8c364dX0', 1000],
|
||||
location: {
|
||||
min: 0,
|
||||
max: 37,
|
||||
},
|
||||
text: 'average(system.diskio.io.time) / 1000',
|
||||
},
|
||||
},
|
||||
references: ['3eca2307-228e-4842-a023-57e15c8c364dX0'],
|
||||
customLabel: true,
|
||||
},
|
||||
'3eca2307-228e-4842-a023-57e15c8c364d': {
|
||||
label: 'Disk latency (avg.)',
|
||||
dataType: 'number',
|
||||
operationType: 'formula',
|
||||
isBucketed: false,
|
||||
scale: 'ratio',
|
||||
params: {
|
||||
formula: 'average(system.diskio.io.time) / 1000',
|
||||
isFormulaBroken: false,
|
||||
format: {
|
||||
id: 'number',
|
||||
params: {
|
||||
decimals: 0,
|
||||
suffix: 'ms',
|
||||
},
|
||||
},
|
||||
},
|
||||
references: ['3eca2307-228e-4842-a023-57e15c8c364dX1'],
|
||||
customLabel: true,
|
||||
},
|
||||
},
|
||||
columnOrder: [
|
||||
'8d17458d-31af-41d1-a23c-5180fd960bee',
|
||||
'155fc728-d010-498e-8126-0bc46cad2be2',
|
||||
'467de550-9186-4e18-8cfa-bce07087801a',
|
||||
'3eca2307-228e-4842-a023-57e15c8c364d',
|
||||
'0a9bd0fa-9966-489b-8c95-70997a7aad4c',
|
||||
'fe5a4d7d-6f48-45ab-974c-96bc864ac36f',
|
||||
'0a9bd0fa-9966-489b-8c95-70997a7aad4cX0',
|
||||
'fe5a4d7d-6f48-45ab-974c-96bc864ac36fX0',
|
||||
'3eca2307-228e-4842-a023-57e15c8c364dX0',
|
||||
'3eca2307-228e-4842-a023-57e15c8c364dX1',
|
||||
],
|
||||
incompleteColumns: {},
|
||||
indexPatternId: '305688db-9e02-4046-acc1-5d0d8dd73ef6',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
visualization: {
|
||||
layerId: 'cbe5d8a0-381d-49bf-b8ac-f8f312ec7129',
|
||||
layerType: 'data',
|
||||
columns: [
|
||||
{
|
||||
columnId: '8d17458d-31af-41d1-a23c-5180fd960bee',
|
||||
width: 296.16666666666663,
|
||||
},
|
||||
{
|
||||
columnId: '155fc728-d010-498e-8126-0bc46cad2be2',
|
||||
isTransposed: false,
|
||||
width: 152.36666666666667,
|
||||
},
|
||||
{
|
||||
columnId: '467de550-9186-4e18-8cfa-bce07087801a',
|
||||
isTransposed: false,
|
||||
width: 121.11666666666667,
|
||||
},
|
||||
{
|
||||
columnId: '0a9bd0fa-9966-489b-8c95-70997a7aad4c',
|
||||
isTransposed: false,
|
||||
},
|
||||
{
|
||||
columnId: 'fe5a4d7d-6f48-45ab-974c-96bc864ac36f',
|
||||
isTransposed: false,
|
||||
},
|
||||
{
|
||||
columnId: '3eca2307-228e-4842-a023-57e15c8c364d',
|
||||
isTransposed: false,
|
||||
},
|
||||
],
|
||||
paging: {
|
||||
size: 10,
|
||||
enabled: true,
|
||||
},
|
||||
headerRowHeight: 'custom',
|
||||
headerRowHeightLines: 2,
|
||||
rowHeight: 'single',
|
||||
rowHeightLines: 1,
|
||||
},
|
||||
filters: [],
|
||||
query,
|
||||
},
|
||||
} as TypedLensByValueInput['attributes']);
|
||||
|
||||
interface Props {
|
||||
dataView: DataView;
|
||||
timeRange: TimeRange;
|
||||
query: Query;
|
||||
searchSessionId: string;
|
||||
}
|
||||
export const HostsTable: React.FunctionComponent<Props> = ({
|
||||
dataView,
|
||||
timeRange,
|
||||
query,
|
||||
searchSessionId,
|
||||
}) => {
|
||||
const {
|
||||
services: { lens },
|
||||
} = useKibana<InfraClientStartDeps>();
|
||||
const LensComponent = lens?.EmbeddableComponent;
|
||||
|
||||
return (
|
||||
<LensComponent
|
||||
id="hostsView"
|
||||
timeRange={timeRange}
|
||||
attributes={getLensHostsTable(dataView, query)}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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 { useCallback, useState, useEffect } from 'react';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import createContainer from 'constate';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { InfraClientStartDeps } from '../../../../types';
|
||||
import { useTrackedPromise } from '../../../../utils/use_tracked_promise';
|
||||
|
||||
export const useDataView = ({ metricAlias }: { metricAlias: string }) => {
|
||||
const [metricsDataView, setMetricsDataView] = useState<DataView>();
|
||||
const {
|
||||
services: { dataViews },
|
||||
} = useKibana<InfraClientStartDeps>();
|
||||
|
||||
const [createDataViewRequest, createDataView] = useTrackedPromise(
|
||||
{
|
||||
createPromise: (config): Promise<DataView> => {
|
||||
return dataViews.createAndSave(config);
|
||||
},
|
||||
onResolve: (response: DataView) => {
|
||||
setMetricsDataView(response);
|
||||
},
|
||||
cancelPreviousOn: 'creation',
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const [getDataViewRequest, getDataView] = useTrackedPromise(
|
||||
{
|
||||
createPromise: (indexPattern: string): Promise<DataView[]> => {
|
||||
return dataViews.find(metricAlias, 1);
|
||||
},
|
||||
onResolve: (response: DataView[]) => {
|
||||
setMetricsDataView(response[0]);
|
||||
},
|
||||
cancelPreviousOn: 'creation',
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const loadDataView = useCallback(async () => {
|
||||
try {
|
||||
let view = (await getDataView(metricAlias))[0];
|
||||
if (!view) {
|
||||
view = await createDataView({
|
||||
title: metricAlias,
|
||||
timeFieldName: '@timestamp',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
setMetricsDataView(undefined);
|
||||
}
|
||||
}, [metricAlias, createDataView, getDataView]);
|
||||
|
||||
const hasFailedFetchingDataView = getDataViewRequest.state === 'rejected';
|
||||
const hasFailedCreatingDataView = createDataViewRequest.state === 'rejected';
|
||||
|
||||
useEffect(() => {
|
||||
loadDataView();
|
||||
}, [metricAlias, loadDataView]);
|
||||
|
||||
return {
|
||||
metricsDataView,
|
||||
hasFailedCreatingDataView,
|
||||
hasFailedFetchingDataView,
|
||||
};
|
||||
};
|
||||
|
||||
export const MetricsDataView = createContainer(useDataView);
|
||||
export const [MetricsDataViewProvider, useMetricsDataViewContext] = MetricsDataView;
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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 type { Query, TimeRange } from '@kbn/es-query';
|
||||
import { useKibana } from '@kbn/kibana-react-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import { SearchBar } from '@kbn/unified-search-plugin/public';
|
||||
import { InfraLoadingPanel } from '../../../components/loading';
|
||||
import { useMetricsDataViewContext } from './hooks/use_data_view';
|
||||
import { HostsTable } from './components/hosts_table';
|
||||
import { InfraClientStartDeps } from '../../../types';
|
||||
import { useSourceContext } from '../../../containers/metrics_source';
|
||||
|
||||
export const HostsContent: React.FunctionComponent = () => {
|
||||
const {
|
||||
services: { data },
|
||||
} = useKibana<InfraClientStartDeps>();
|
||||
const { source } = useSourceContext();
|
||||
const [dateRange, setDateRange] = useState<TimeRange>({ from: 'now-15m', to: 'now' });
|
||||
const [query, setQuery] = useState<Query>({ query: '', language: 'kuery' });
|
||||
const { metricsDataView, hasFailedCreatingDataView, hasFailedFetchingDataView } =
|
||||
useMetricsDataViewContext();
|
||||
// needed to refresh the lens table when filters havent changed
|
||||
const [searchSessionId, setSearchSessionId] = useState(data.search.session.start());
|
||||
|
||||
const onQuerySubmit = useCallback(
|
||||
(payload: { dateRange: TimeRange; query?: Query }) => {
|
||||
setDateRange(payload.dateRange);
|
||||
if (payload.query) {
|
||||
setQuery(payload.query);
|
||||
}
|
||||
setSearchSessionId(data.search.session.start());
|
||||
},
|
||||
[setDateRange, setQuery, data.search.session]
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{metricsDataView ? (
|
||||
<>
|
||||
<SearchBar
|
||||
showQueryBar={true}
|
||||
showFilterBar={false}
|
||||
showDatePicker={true}
|
||||
showAutoRefreshOnly={false}
|
||||
showSaveQuery={true}
|
||||
showQueryInput={true}
|
||||
query={query}
|
||||
dateRangeFrom={dateRange.from}
|
||||
dateRangeTo={dateRange.to}
|
||||
indexPatterns={[metricsDataView]}
|
||||
onQuerySubmit={onQuerySubmit}
|
||||
/>
|
||||
<HostsTable
|
||||
dataView={metricsDataView}
|
||||
timeRange={dateRange}
|
||||
query={query}
|
||||
searchSessionId={searchSessionId}
|
||||
/>
|
||||
</>
|
||||
) : hasFailedCreatingDataView || hasFailedFetchingDataView ? (
|
||||
<div>
|
||||
<div>There was an error trying to load or create the Data View:</div>
|
||||
{source?.configuration.metricAlias}
|
||||
</div>
|
||||
) : (
|
||||
<InfraLoadingPanel
|
||||
height="100vh"
|
||||
width="auto"
|
||||
text={i18n.translate('xpack.infra.waffle.loadingDataText', {
|
||||
defaultMessage: 'Loading data',
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
95
x-pack/plugins/infra/public/pages/metrics/hosts/index.tsx
Normal file
95
x-pack/plugins/infra/public/pages/metrics/hosts/index.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 { EuiErrorBoundary } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { euiStyled } from '@kbn/kibana-react-plugin/common';
|
||||
import React from 'react';
|
||||
import { useTrackPageview } from '@kbn/observability-plugin/public';
|
||||
import { APP_WRAPPER_CLASS } from '@kbn/core/public';
|
||||
|
||||
import { DocumentTitle } from '../../../components/document_title';
|
||||
|
||||
import { SourceErrorPage } from '../../../components/source_error_page';
|
||||
import { SourceLoadingPage } from '../../../components/source_loading_page';
|
||||
import { useSourceContext } from '../../../containers/metrics_source';
|
||||
import { useMetricsBreadcrumbs } from '../../../hooks/use_metrics_breadcrumbs';
|
||||
import { MetricsPageTemplate } from '../page_template';
|
||||
import { hostsTitle } from '../../../translations';
|
||||
import { HostsContent } from './hosts_content';
|
||||
import { MetricsDataViewProvider } from './hooks/use_data_view';
|
||||
|
||||
export const HostsPage = () => {
|
||||
const {
|
||||
hasFailedLoadingSource,
|
||||
isLoading,
|
||||
loadSourceFailureMessage,
|
||||
loadSource,
|
||||
source,
|
||||
metricIndicesExist,
|
||||
} = useSourceContext();
|
||||
useTrackPageview({ app: 'infra_metrics', path: 'hosts' });
|
||||
useTrackPageview({ app: 'infra_metrics', path: 'hosts', delay: 15000 });
|
||||
|
||||
useMetricsBreadcrumbs([
|
||||
{
|
||||
text: hostsTitle,
|
||||
},
|
||||
]);
|
||||
return (
|
||||
<EuiErrorBoundary>
|
||||
<DocumentTitle
|
||||
title={(previousTitle: string) =>
|
||||
i18n.translate('xpack.infra.infrastructureHostsPage.documentTitle', {
|
||||
defaultMessage: '{previousTitle} | Hosts',
|
||||
values: {
|
||||
previousTitle,
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
{isLoading && !source ? (
|
||||
<SourceLoadingPage />
|
||||
) : metricIndicesExist && source ? (
|
||||
<>
|
||||
<HostsPageWrapper className={APP_WRAPPER_CLASS}>
|
||||
<MetricsPageTemplate
|
||||
hasData={metricIndicesExist}
|
||||
pageHeader={{
|
||||
pageTitle: hostsTitle,
|
||||
}}
|
||||
pageBodyProps={{
|
||||
paddingSize: 'none',
|
||||
}}
|
||||
>
|
||||
<MetricsDataViewProvider metricAlias={source.configuration.metricAlias}>
|
||||
<HostsContent />
|
||||
</MetricsDataViewProvider>
|
||||
</MetricsPageTemplate>
|
||||
</HostsPageWrapper>
|
||||
</>
|
||||
) : hasFailedLoadingSource ? (
|
||||
<SourceErrorPage errorMessage={loadSourceFailureMessage || ''} retry={loadSource} />
|
||||
) : (
|
||||
<MetricsPageTemplate hasData={metricIndicesExist} data-test-subj="noMetricsIndicesPrompt" />
|
||||
)}
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
// This is added to facilitate a full height layout whereby the
|
||||
// inner container will set it's own height and be scrollable.
|
||||
// The "fullHeight" prop won't help us as it only applies to certain breakpoints.
|
||||
const HostsPageWrapper = euiStyled.div`
|
||||
.euiPage .euiPageContentBody {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 0 auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
`;
|
|
@ -30,6 +30,7 @@ import { MetricsExplorerPage } from './metrics_explorer';
|
|||
import { SnapshotPage } from './inventory_view';
|
||||
import { MetricDetail } from './metric_detail';
|
||||
import { MetricsSettingsPage } from './settings';
|
||||
import { HostsPage } from './hosts';
|
||||
import { SourceLoadingPage } from '../../components/source_loading_page';
|
||||
import { WaffleOptionsProvider } from './inventory_view/hooks/use_waffle_options';
|
||||
import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time';
|
||||
|
@ -126,6 +127,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => {
|
|||
)}
|
||||
/>
|
||||
<Route path="/detail/:type/:node" component={MetricDetail} />
|
||||
<Route path={'/hosts'} component={HostsPage} />
|
||||
<Route path={'/settings'} component={MetricsSettingsPage} />
|
||||
</Switch>
|
||||
</InfraMLCapabilitiesProvider>
|
||||
|
|
|
@ -101,6 +101,7 @@ export class Plugin implements InfraClientPluginClass {
|
|||
label: 'Infrastructure',
|
||||
sortKey: 300,
|
||||
entries: [
|
||||
{ label: 'Hosts', app: 'metrics', path: '/hosts' },
|
||||
{ label: 'Inventory', app: 'metrics', path: '/inventory' },
|
||||
{ label: 'Metrics Explorer', app: 'metrics', path: '/explorer' },
|
||||
],
|
||||
|
@ -191,6 +192,13 @@ export class Plugin implements InfraClientPluginClass {
|
|||
}),
|
||||
path: '/explorer',
|
||||
},
|
||||
{
|
||||
id: 'metrics-hosts',
|
||||
title: i18n.translate('xpack.infra.homePage.metricsHostsTabTitle', {
|
||||
defaultMessage: 'Hosts',
|
||||
}),
|
||||
path: '/hosts',
|
||||
},
|
||||
{
|
||||
id: 'settings',
|
||||
title: i18n.translate('xpack.infra.homePage.settingsTabTitle', {
|
||||
|
|
|
@ -45,3 +45,7 @@ export const inventoryTitle = i18n.translate('xpack.infra.metrics.inventoryPageT
|
|||
export const metricsExplorerTitle = i18n.translate('xpack.infra.metrics.metricsExplorerTitle', {
|
||||
defaultMessage: 'Metrics Explorer',
|
||||
});
|
||||
|
||||
export const hostsTitle = i18n.translate('xpack.infra.metrics.hostsTitle', {
|
||||
defaultMessage: 'Hosts',
|
||||
});
|
||||
|
|
|
@ -28,6 +28,7 @@ import type {
|
|||
} from '@kbn/observability-plugin/public';
|
||||
// import type { OsqueryPluginStart } from '../../osquery/public';
|
||||
import type { SpacesPluginStart } from '@kbn/spaces-plugin/public';
|
||||
import type { LensPublicStart } from '@kbn/lens-plugin/public';
|
||||
import { UnwrapPromise } from '../common/utility_types';
|
||||
import type {
|
||||
SourceProviderProps,
|
||||
|
@ -73,6 +74,7 @@ export interface InfraClientStartDeps {
|
|||
embeddable?: EmbeddableStart;
|
||||
osquery?: unknown; // OsqueryPluginStart;
|
||||
share: SharePluginStart;
|
||||
lens: LensPublicStart;
|
||||
}
|
||||
|
||||
export type InfraClientCoreSetup = CoreSetup<InfraClientStartDeps, InfraClientStartExports>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue