mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Stack Monitoring] Convert cluster listing view to React (#113585)
* [Stack Monitoring] Covnert cluster listing view to React * Fixing localStorage
This commit is contained in:
parent
b8cdc6fd1b
commit
141a88bf62
7 changed files with 244 additions and 65 deletions
|
@ -23,6 +23,7 @@ import {
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Legacy } from '../legacy_shims';
|
||||
import { useAlertsModal } from '../application/hooks/use_alerts_modal';
|
||||
|
||||
interface Props {
|
||||
alerts: {};
|
||||
|
@ -30,8 +31,7 @@ interface Props {
|
|||
|
||||
export const EnableAlertsModal: React.FC<Props> = ({ alerts }: Props) => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const $injector = Legacy.shims.getAngularInjector();
|
||||
const alertsEnableModalProvider: any = $injector.get('enableAlertsModal');
|
||||
const alertsEnableModalProvider = useAlertsModal();
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalVisible(false);
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 '../../../../../../src/plugins/kibana_react/public';
|
||||
import { showAlertsToast } from '../../alerts/lib/alerts_toast';
|
||||
import { ajaxErrorHandlersProvider } from '../../lib/ajax_error_handler';
|
||||
|
||||
export const useAlertsModal = () => {
|
||||
const { services } = useKibana();
|
||||
|
||||
function shouldShowAlertsModal(alerts: {}) {
|
||||
const modalHasBeenShown =
|
||||
window.sessionStorage.getItem('ALERTS_MODAL_HAS_BEEN_SHOWN') === 'true';
|
||||
const decisionMade = window.localStorage.getItem('ALERTS_MODAL_DECISION_MADE') === 'true';
|
||||
|
||||
if (Object.keys(alerts).length > 0) {
|
||||
window.localStorage.setItem('ALERTS_MODAL_DECISION_MADE', 'true');
|
||||
return false;
|
||||
} else if (!modalHasBeenShown && !decisionMade) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function enableAlerts() {
|
||||
try {
|
||||
const { data } = await services.http?.post('../api/monitoring/v1/alerts/enable', {});
|
||||
window.localStorage.setItem('ALERTS_MODAL_DECISION_MADE', 'true');
|
||||
showAlertsToast(data);
|
||||
} catch (err) {
|
||||
const ajaxErrorHandlers = ajaxErrorHandlersProvider();
|
||||
return ajaxErrorHandlers(err);
|
||||
}
|
||||
}
|
||||
|
||||
function notAskAgain() {
|
||||
window.localStorage.setItem('ALERTS_MODAL_DECISION_MADE', 'true');
|
||||
}
|
||||
|
||||
function hideModalForSession() {
|
||||
window.sessionStorage.setItem('ALERTS_MODAL_HAS_BEEN_SHOWN', 'true');
|
||||
}
|
||||
|
||||
return {
|
||||
shouldShowAlertsModal,
|
||||
enableAlerts,
|
||||
notAskAgain,
|
||||
hideModalForSession,
|
||||
};
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
|
||||
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants';
|
||||
import { fetchClusters } from '../../lib/fetch_clusters';
|
||||
|
||||
export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?: string[]) {
|
||||
const { services } = useKibana<{ data: any }>();
|
||||
|
@ -18,47 +18,29 @@ export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?:
|
|||
const [clusters, setClusters] = useState([] as any);
|
||||
const [loaded, setLoaded] = useState<boolean | null>(false);
|
||||
|
||||
let url = '../api/monitoring/v1/clusters';
|
||||
if (clusterUuid) {
|
||||
url += `/${clusterUuid}`;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const fetchClusters = async () => {
|
||||
async function makeRequest() {
|
||||
try {
|
||||
const response = await services.http?.fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
ccs,
|
||||
if (services.http?.fetch) {
|
||||
const response = await fetchClusters({
|
||||
timeRange: {
|
||||
min,
|
||||
max,
|
||||
},
|
||||
fetch: services.http.fetch,
|
||||
clusterUuid,
|
||||
codePaths,
|
||||
}),
|
||||
});
|
||||
|
||||
setClusters(formatClusters(response));
|
||||
} catch (err) {
|
||||
// TODO: handle errors
|
||||
});
|
||||
setClusters(response);
|
||||
}
|
||||
} catch (e) {
|
||||
// TODO: Handle errors
|
||||
} finally {
|
||||
setLoaded(true);
|
||||
}
|
||||
};
|
||||
|
||||
fetchClusters();
|
||||
}, [ccs, services.http, codePaths, url, min, max]);
|
||||
}
|
||||
makeRequest();
|
||||
}, [clusterUuid, ccs, services.http, codePaths, min, max]);
|
||||
|
||||
return { clusters, loaded };
|
||||
}
|
||||
|
||||
function formatClusters(clusters: any) {
|
||||
return clusters.map(formatCluster);
|
||||
}
|
||||
|
||||
function formatCluster(cluster: any) {
|
||||
if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) {
|
||||
cluster.cluster_name = 'Standalone Cluster';
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/p
|
|||
import { LoadingPage } from './pages/loading_page';
|
||||
import { LicensePage } from './pages/license_page';
|
||||
import { ClusterOverview } from './pages/cluster/overview_page';
|
||||
import { ClusterListing } from './pages/home/cluster_listing';
|
||||
import { MonitoringStartPluginDependencies } from '../types';
|
||||
import { GlobalStateProvider } from './global_state_context';
|
||||
import { ExternalConfigContext, ExternalConfig } from './external_config_context';
|
||||
|
@ -82,9 +83,10 @@ const MonitoringApp: React.FC<{
|
|||
/>
|
||||
<RouteInit
|
||||
path="/home"
|
||||
component={Home}
|
||||
component={ClusterListing}
|
||||
codePaths={['all']}
|
||||
fetchAllClusters={false}
|
||||
fetchAllClusters={true}
|
||||
unsetGlobalState={true}
|
||||
/>
|
||||
<RouteInit
|
||||
path="/overview"
|
||||
|
@ -217,7 +219,3 @@ const MonitoringApp: React.FC<{
|
|||
</KibanaContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
const Home: React.FC<{}> = () => {
|
||||
return <div>Home page (Cluster listing)</div>;
|
||||
};
|
||||
|
|
|
@ -16,8 +16,8 @@ import { Overview } from '../../../components/cluster/overview';
|
|||
import { ExternalConfigContext } from '../../external_config_context';
|
||||
import { SetupModeRenderer, SetupModeProps } from '../../setup_mode/setup_mode_renderer';
|
||||
import { SetupModeContext } from '../../../components/setup_mode/setup_mode_context';
|
||||
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../../common/constants';
|
||||
import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs';
|
||||
import { fetchClusters } from '../../../lib/fetch_clusters';
|
||||
|
||||
const CODE_PATHS = [CODE_PATH_ALL];
|
||||
|
||||
|
@ -54,25 +54,20 @@ export const ClusterOverview: React.FC<{}> = () => {
|
|||
|
||||
const getPageData = useCallback(async () => {
|
||||
const bounds = services.data?.query.timefilter.timefilter.getBounds();
|
||||
let url = '../api/monitoring/v1/clusters';
|
||||
if (clusterUuid) {
|
||||
url += `/${clusterUuid}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await services.http?.fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
ccs,
|
||||
if (services.http?.fetch) {
|
||||
const response = await fetchClusters({
|
||||
fetch: services.http.fetch,
|
||||
timeRange: {
|
||||
min: bounds.min.toISOString(),
|
||||
max: bounds.max.toISOString(),
|
||||
},
|
||||
ccs,
|
||||
clusterUuid,
|
||||
codePaths: CODE_PATHS,
|
||||
}),
|
||||
});
|
||||
|
||||
setClusters(formatClusters(response));
|
||||
});
|
||||
setClusters(response);
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: handle errors
|
||||
} finally {
|
||||
|
@ -106,14 +101,3 @@ export const ClusterOverview: React.FC<{}> = () => {
|
|||
</PageTemplate>
|
||||
);
|
||||
};
|
||||
|
||||
function formatClusters(clusters: any) {
|
||||
return clusters.map(formatCluster);
|
||||
}
|
||||
|
||||
function formatCluster(cluster: any) {
|
||||
if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) {
|
||||
cluster.cluster_name = 'Standalone Cluster';
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { useKibana } from '../../../../../../../src/plugins/kibana_react/public';
|
||||
// @ts-ignore
|
||||
import { Listing } from '../../../components/cluster/listing';
|
||||
import { EnableAlertsModal } from '../../../alerts/enable_alerts_modal';
|
||||
import { GlobalStateContext } from '../../global_state_context';
|
||||
import { ExternalConfigContext } from '../../external_config_context';
|
||||
import { ComponentProps } from '../../route_init';
|
||||
import { useTable } from '../../hooks/use_table';
|
||||
import { PageTemplate, TabMenuItem } from '../page_template';
|
||||
import { BreadcrumbContainer } from '../../hooks/use_breadcrumbs';
|
||||
import { fetchClusters } from '../../../lib/fetch_clusters';
|
||||
|
||||
const pageTitle = i18n.translate('xpack.monitoring.cluster.listing.pageTitle', {
|
||||
defaultMessage: 'Cluster listing',
|
||||
});
|
||||
|
||||
const tabTitle = i18n.translate('xpack.monitoring.cluster.listing.tabTitle', {
|
||||
defaultMessage: 'Clusters',
|
||||
});
|
||||
|
||||
const getAlerts = (clusters: any[]) => {
|
||||
return clusters.reduce(
|
||||
(alerts, cluster) => ({ ...alerts, ...((cluster.alerts && cluster.alerts.list) || {}) }),
|
||||
{}
|
||||
);
|
||||
};
|
||||
|
||||
export const ClusterListing: React.FC<ComponentProps> = () => {
|
||||
const globalState = useContext(GlobalStateContext);
|
||||
const externalConfig = useContext(ExternalConfigContext);
|
||||
const { services } = useKibana<{ data: any }>();
|
||||
const [clusters, setClusters] = useState([] as any);
|
||||
const { update: updateBreadcrumbs } = useContext(BreadcrumbContainer.Context);
|
||||
|
||||
const fakeScope = {
|
||||
$evalAsync: (fn: () => void) => fn(),
|
||||
filterQuery: '', // replace with something
|
||||
};
|
||||
const { getPaginationTableProps } = useTable('clusters');
|
||||
const { sorting, pagination, onTableChange } = getPaginationTableProps();
|
||||
|
||||
useEffect(() => {
|
||||
updateBreadcrumbs([
|
||||
{
|
||||
'data-test-subj': 'clusterListingBreadcrumb',
|
||||
text: tabTitle,
|
||||
},
|
||||
]);
|
||||
}, [updateBreadcrumbs]);
|
||||
|
||||
const tabs: TabMenuItem[] = [
|
||||
{
|
||||
id: 'clusters',
|
||||
label: tabTitle,
|
||||
testSubj: 'clusterListingTab',
|
||||
route: '/home',
|
||||
},
|
||||
];
|
||||
|
||||
const getPageData = useCallback(async () => {
|
||||
const bounds = services.data?.query.timefilter.timefilter.getBounds();
|
||||
try {
|
||||
if (services.http?.fetch) {
|
||||
const response = await fetchClusters({
|
||||
fetch: services.http.fetch,
|
||||
timeRange: {
|
||||
min: bounds.min.toISOString(),
|
||||
max: bounds.max.toISOString(),
|
||||
},
|
||||
ccs: globalState.ccs,
|
||||
codePaths: ['all'],
|
||||
});
|
||||
setClusters(response);
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: handle errors
|
||||
}
|
||||
}, [globalState, services.data?.query.timefilter.timefilter, services.http]);
|
||||
|
||||
if (globalState.save && clusters.length === 1) {
|
||||
globalState.cluster_uuid = clusters[0].cluster_uuid;
|
||||
globalState.save();
|
||||
}
|
||||
|
||||
return (
|
||||
<PageTemplate tabs={tabs} title={pageTitle} pageTitle={pageTitle} getPageData={getPageData}>
|
||||
{clusters.length === 1 && <Redirect to={{ pathname: '/overview' }} />}
|
||||
<Listing
|
||||
clusters={clusters}
|
||||
angular={{
|
||||
scope: fakeScope,
|
||||
globalState,
|
||||
storage: {
|
||||
get: (key: string) => window.localStorage.getItem(key),
|
||||
set: (key: string, value: string) => window.localStorage.setItem(key, value),
|
||||
},
|
||||
showLicenseExpiration: externalConfig.showLicenseExpiration,
|
||||
}}
|
||||
sorting={sorting}
|
||||
pagination={pagination}
|
||||
onTableChange={onTableChange}
|
||||
/>
|
||||
<EnableAlertsModal alerts={getAlerts(clusters)} />
|
||||
</PageTemplate>
|
||||
);
|
||||
};
|
45
x-pack/plugins/monitoring/public/lib/fetch_clusters.ts
Normal file
45
x-pack/plugins/monitoring/public/lib/fetch_clusters.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 { HttpHandler } from 'kibana/public';
|
||||
import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../common/constants';
|
||||
|
||||
interface Params {
|
||||
timeRange: { min: string; max: string };
|
||||
fetch: HttpHandler;
|
||||
clusterUuid?: string | null;
|
||||
ccs?: boolean;
|
||||
codePaths?: string[];
|
||||
}
|
||||
|
||||
export function formatClusters(clusters: any) {
|
||||
return clusters.map(formatCluster);
|
||||
}
|
||||
|
||||
export function formatCluster(cluster: any) {
|
||||
if (cluster.cluster_uuid === STANDALONE_CLUSTER_CLUSTER_UUID) {
|
||||
cluster.cluster_name = 'Standalone Cluster';
|
||||
}
|
||||
return cluster;
|
||||
}
|
||||
|
||||
export const fetchClusters = async ({ clusterUuid, timeRange, fetch, ccs, codePaths }: Params) => {
|
||||
let url = '../api/monitoring/v1/clusters';
|
||||
if (clusterUuid) {
|
||||
url += `/${clusterUuid}`;
|
||||
}
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
ccs,
|
||||
timeRange,
|
||||
codePaths,
|
||||
}),
|
||||
});
|
||||
|
||||
return formatClusters(response);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue