diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx
index 690ea26319bd3..dea8d18bb65b1 100644
--- a/x-pack/plugins/monitoring/public/application/index.tsx
+++ b/x-pack/plugins/monitoring/public/application/index.tsx
@@ -22,6 +22,7 @@ import { NoDataPage } from './pages/no_data';
import { ElasticsearchOverviewPage } from './pages/elasticsearch/overview';
import { BeatsOverviewPage } from './pages/beats/overview';
import { BeatsInstancesPage } from './pages/beats/instances';
+import { BeatsInstancePage } from './pages/beats/instance';
import { CODE_PATH_ELASTICSEARCH, CODE_PATH_BEATS } from '../../common/constants';
import { ElasticsearchNodesPage } from './pages/elasticsearch/nodes_page';
import { ElasticsearchIndicesPage } from './pages/elasticsearch/indices_page';
@@ -111,6 +112,13 @@ const MonitoringApp: React.FC<{
/>
{/* Beats Views */}
+
+
= ({ cluster, ...props }) => {
- const tabs: TabMenuItem[] = [
- {
+export const BeatsTemplate: React.FC = ({ instance, ...props }) => {
+ const tabs: TabMenuItem[] = [];
+
+ if (!instance) {
+ tabs.push({
id: 'overview',
label: i18n.translate('xpack.monitoring.beatsNavigation.overviewLinkText', {
defaultMessage: 'Overview',
}),
route: '/beats',
- },
- {
+ });
+ tabs.push({
id: 'instances',
label: i18n.translate('xpack.monitoring.beatsNavigation.instancesLinkText', {
defaultMessage: 'Instances',
}),
route: '/beats/beats',
- },
- ];
+ });
+ } else {
+ tabs.push({
+ id: 'overview',
+ label: i18n.translate('xpack.monitoring.beatsNavigation.instance.overviewLinkText', {
+ defaultMessage: 'Overview',
+ }),
+ route: `/beats/beat/${instance}`,
+ });
+ }
return ;
};
diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx
new file mode 100644
index 0000000000000..f7ff03898fda6
--- /dev/null
+++ b/x-pack/plugins/monitoring/public/application/pages/beats/instance.tsx
@@ -0,0 +1,90 @@
+/*
+ * 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 React, { useContext, useState, useCallback, useEffect } from 'react';
+import { useParams } from 'react-router-dom';
+import { i18n } from '@kbn/i18n';
+import { find } from 'lodash';
+import { ComponentProps } from '../../route_init';
+import { GlobalStateContext } from '../../global_state_context';
+import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
+import { useCharts } from '../../hooks/use_charts';
+// @ts-ignore
+import { Beat } from '../../../components/beats/beat';
+import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs';
+import { BeatsTemplate } from './beats_template';
+
+export const BeatsInstancePage: React.FC = ({ clusters }) => {
+ const { instance }: { instance: string } = useParams();
+
+ const globalState = useContext(GlobalStateContext);
+ const { services } = useKibana<{ data: any }>();
+ const { generate: generateBreadcrumbs } = useContext(BreadcrumbContainer.Context);
+ const { zoomInfo, onBrush } = useCharts();
+ const clusterUuid = globalState.cluster_uuid;
+ const ccs = globalState.ccs;
+ const cluster = find(clusters, {
+ cluster_uuid: clusterUuid,
+ }) as any;
+ const [data, setData] = useState({} as any);
+ const [beatName, setBeatName] = useState('');
+
+ const title = i18n.translate('xpack.monitoring.beats.instance.routeTitle', {
+ defaultMessage: 'Beats - {instanceName} - Overview',
+ values: {
+ instanceName: beatName,
+ },
+ });
+
+ const pageTitle = i18n.translate('xpack.monitoring.beats.instance.pageTitle', {
+ defaultMessage: 'Beat instance: {beatName}',
+ values: {
+ beatName,
+ },
+ });
+
+ useEffect(() => {
+ if (cluster) {
+ generateBreadcrumbs(cluster.cluster_name, {
+ inBeats: true,
+ instance: beatName,
+ });
+ }
+ }, [cluster, beatName, generateBreadcrumbs]);
+
+ const getPageData = useCallback(async () => {
+ const bounds = services.data?.query.timefilter.timefilter.getBounds();
+ const url = `../api/monitoring/v1/clusters/${clusterUuid}/beats/beat/${instance}`;
+ const response = await services.http?.fetch(url, {
+ method: 'POST',
+ body: JSON.stringify({
+ ccs,
+ timeRange: {
+ min: bounds.min.toISOString(),
+ max: bounds.max.toISOString(),
+ },
+ }),
+ });
+
+ setData(response);
+ setBeatName(response.summary.name);
+ }, [ccs, clusterUuid, instance, services.data?.query.timefilter.timefilter, services.http]);
+
+ return (
+
+
+
+
+
+ );
+};
diff --git a/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx b/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx
index 3f32e1abf9a88..873cc7e939269 100644
--- a/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx
+++ b/x-pack/plugins/monitoring/public/application/pages/beats/instances.tsx
@@ -81,7 +81,6 @@ export const BeatsInstancesPage: React.FC = ({ clusters }) => {
pageTitle={pageTitle}
getPageData={getPageData}
data-test-subj="beatsListingPage"
- cluster={cluster}
>
= ({ clusters }) => {
pageTitle={pageTitle}
getPageData={getPageData}
data-test-subj="beatsOverviewPage"
- cluster={cluster}
>
{renderOverview(data)}