diff --git a/x-pack/plugins/monitoring/public/application/index.tsx b/x-pack/plugins/monitoring/public/application/index.tsx index acdf3b0986a64..a958e6061215d 100644 --- a/x-pack/plugins/monitoring/public/application/index.tsx +++ b/x-pack/plugins/monitoring/public/application/index.tsx @@ -27,6 +27,8 @@ import { KibanaOverviewPage } from './pages/kibana/overview'; import { CODE_PATH_ELASTICSEARCH, CODE_PATH_BEATS, CODE_PATH_KIBANA } from '../../common/constants'; import { ElasticsearchNodesPage } from './pages/elasticsearch/nodes_page'; import { ElasticsearchIndicesPage } from './pages/elasticsearch/indices_page'; +import { ElasticsearchIndexPage } from './pages/elasticsearch/index_page'; +import { ElasticsearchIndexAdvancedPage } from './pages/elasticsearch/index_advanced_page'; import { ElasticsearchNodePage } from './pages/elasticsearch/node_page'; import { MonitoringTimeContainer } from './hooks/use_monitoring_time'; import { BreadcrumbContainer } from './hooks/use_breadcrumbs'; @@ -84,6 +86,21 @@ const MonitoringApp: React.FC<{ /> {/* ElasticSearch Views */} + + + + + = ({ clusters }) => { + const globalState = useContext(GlobalStateContext); + const { services } = useKibana<{ data: any }>(); + const { index }: { index: string } = useParams(); + const { zoomInfo, onBrush } = useCharts(); + const clusterUuid = globalState.cluster_uuid; + const [data, setData] = useState({} as any); + + const title = i18n.translate('xpack.monitoring.elasticsearch.index.advanced.title', { + defaultMessage: 'Elasticsearch - Indices - {indexName} - Advanced', + values: { + indexName: index, + }, + }); + + const getPageData = useCallback(async () => { + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices/${index}`; + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: true, + }), + }); + setData(response); + }, [clusterUuid, services.data?.query.timefilter.timefilter, services.http, index]); + + return ( + + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> + + ); +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx new file mode 100644 index 0000000000000..b23f9c71a98bf --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/index_page.tsx @@ -0,0 +1,106 @@ +/* + * 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 } from 'react'; +import { i18n } from '@kbn/i18n'; +import { useParams } from 'react-router-dom'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +import { GlobalStateContext } from '../../global_state_context'; +// @ts-ignore +import { IndexReact } from '../../../components/elasticsearch/index/index_react'; +import { ComponentProps } from '../../route_init'; +import { SetupModeRenderer } from '../../setup_mode/setup_mode_renderer'; +import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context'; +import { useCharts } from '../../hooks/use_charts'; +import { ItemTemplate } from './item_template'; +// @ts-ignore +import { indicesByNodes } from '../../../components/elasticsearch/shard_allocation/transformers/indices_by_nodes'; +// @ts-ignore +import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; + +interface SetupModeProps { + setupMode: any; + flyoutComponent: any; + bottomBarComponent: any; +} + +export const ElasticsearchIndexPage: React.FC = ({ clusters }) => { + const globalState = useContext(GlobalStateContext); + const { services } = useKibana<{ data: any }>(); + const { index }: { index: string } = useParams(); + const { zoomInfo, onBrush } = useCharts(); + const clusterUuid = globalState.cluster_uuid; + const [data, setData] = useState({} as any); + const [indexLabel, setIndexLabel] = useState(labels.index as any); + const [nodesByIndicesData, setNodesByIndicesData] = useState([]); + + const title = i18n.translate('xpack.monitoring.elasticsearch.index.overview.title', { + defaultMessage: 'Elasticsearch - Indices - {indexName} - Overview', + values: { + indexName: index, + }, + }); + + const pageTitle = i18n.translate('xpack.monitoring.elasticsearch.index.overview.pageTitle', { + defaultMessage: 'Index: {indexName}', + values: { + indexName: index, + }, + }); + + const getPageData = useCallback(async () => { + const bounds = services.data?.query.timefilter.timefilter.getBounds(); + const url = `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices/${index}`; + const response = await services.http?.fetch(url, { + method: 'POST', + body: JSON.stringify({ + timeRange: { + min: bounds.min.toISOString(), + max: bounds.max.toISOString(), + }, + is_advanced: false, + }), + }); + setData(response); + const transformer = indicesByNodes(); + setNodesByIndicesData(transformer(response.shards, response.nodes)); + + const shards = response.shards; + if (shards.some((shard: any) => shard.state === 'UNASSIGNED')) { + setIndexLabel(labels.indexWithUnassigned); + } + }, [clusterUuid, services.data?.query.timefilter.timefilter, services.http, index]); + + return ( + + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> + + ); +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx new file mode 100644 index 0000000000000..1f06ba18bf102 --- /dev/null +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/item_template.tsx @@ -0,0 +1,36 @@ +/* + * 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 from 'react'; +import { i18n } from '@kbn/i18n'; +import { PageTemplate } from '../page_template'; +import { TabMenuItem, PageTemplateProps } from '../page_template'; + +interface ItemTemplateProps extends PageTemplateProps { + id: string; + pageType: string; +} +export const ItemTemplate: React.FC = (props) => { + const { pageType, id, ...rest } = props; + const tabs: TabMenuItem[] = [ + { + id: 'overview', + label: i18n.translate('xpack.monitoring.esItemNavigation.overviewLinkText', { + defaultMessage: 'Overview', + }), + route: `/elasticsearch/${pageType}/${id}`, + }, + { + id: 'advanced', + label: i18n.translate('xpack.monitoring.esItemNavigation.advancedLinkText', { + defaultMessage: 'Advanced', + }), + route: `/elasticsearch/${pageType}/${id}/advanced`, + }, + ]; + + return ; +}; diff --git a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx index ffbde2efcac6b..9b3a67f612e5c 100644 --- a/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx +++ b/x-pack/plugins/monitoring/public/application/pages/elasticsearch/node_page.tsx @@ -7,8 +7,7 @@ import React, { useContext, useState, useCallback } from 'react'; import { useParams } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { find } from 'lodash'; -import { ElasticsearchTemplate } from './elasticsearch_template'; +import { ItemTemplate } from './item_template'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; import { GlobalStateContext } from '../../global_state_context'; import { NodeReact } from '../../../components/elasticsearch'; @@ -18,6 +17,8 @@ import { SetupModeContext } from '../../../components/setup_mode/setup_mode_cont import { useLocalStorage } from '../../hooks/use_local_storage'; import { useCharts } from '../../hooks/use_charts'; import { nodesByIndices } from '../../../components/elasticsearch/shard_allocation/transformers/nodes_by_indices'; +// @ts-ignore +import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; interface SetupModeProps { setupMode: any; @@ -38,9 +39,6 @@ export const ElasticsearchNodePage: React.FC = ({ clusters }) => const clusterUuid = globalState.cluster_uuid; const ccs = globalState.ccs; - const cluster = find(clusters, { - cluster_uuid: clusterUuid, - }); const [data, setData] = useState({} as any); const [nodesByIndicesData, setNodesByIndicesData] = useState([]); @@ -92,33 +90,33 @@ export const ElasticsearchNodePage: React.FC = ({ clusters }) => }, [showSystemIndices, setShowSystemIndices]); return ( - - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> + ); }; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/index/index_react.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index/index_react.js new file mode 100644 index 0000000000000..70bac52a0926c --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/index/index_react.js @@ -0,0 +1,70 @@ +/* + * 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 from 'react'; +import { + EuiPage, + EuiPageContent, + EuiPageBody, + EuiPanel, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, +} from '@elastic/eui'; +import { IndexDetailStatus } from '../index_detail_status'; +import { MonitoringTimeseriesContainer } from '../../chart'; +import { ShardAllocationReact } from '../shard_allocation/shard_allocation_react'; +import { Logs } from '../../logs'; +import { AlertsCallout } from '../../../alerts/callout'; + +export const IndexReact = ({ + indexSummary, + metrics, + clusterUuid, + indexUuid, + logs, + alerts, + ...props +}) => { + const metricsToShow = [ + metrics.index_mem, + metrics.index_size, + metrics.index_search_request_rate, + metrics.index_request_rate, + metrics.index_segment_count, + metrics.index_document_count, + ]; + + return ( + + + + + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view_react.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view_react.js index 987ca467931f4..2d0c4b59df4b8 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view_react.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view_react.js @@ -8,13 +8,12 @@ import React from 'react'; import { TableHeadReact } from './table_head_react'; import { TableBody } from './table_body'; -import { labels } from '../lib/labels'; export const ClusterViewReact = (props) => { return ( @@ -22,7 +21,7 @@ export const ClusterViewReact = (props) => { filter={props.filter} totalCount={props.totalCount} rows={props.nodesByIndices} - cols={labels.node.length} + cols={props.labels.length} shardStats={props.shardStats} />