Skip to content

Commit

Permalink
[Stack Monitoring] Convert cluster listing view to React (#113585) (#…
Browse files Browse the repository at this point in the history
…113953)

* [Stack Monitoring] Covnert cluster listing view to React

* Fixing localStorage

Co-authored-by: Chris Cowan <chris@chriscowan.us>
  • Loading branch information
kibanamachine and simianhacker authored Oct 5, 2021
1 parent 6d68541 commit 2997a69
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ 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: {};
}

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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
};
};
46 changes: 14 additions & 32 deletions x-pack/plugins/monitoring/public/application/hooks/use_clusters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>();
Expand All @@ -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;
}
10 changes: 4 additions & 6 deletions x-pack/plugins/monitoring/public/application/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -75,9 +76,10 @@ const MonitoringApp: React.FC<{
/>
<RouteInit
path="/home"
component={Home}
component={ClusterListing}
codePaths={['all']}
fetchAllClusters={false}
fetchAllClusters={true}
unsetGlobalState={true}
/>
<RouteInit
path="/overview"
Expand Down Expand Up @@ -182,7 +184,3 @@ const MonitoringApp: React.FC<{
</KibanaContextProvider>
);
};

const Home: React.FC<{}> = () => {
return <div>Home page (Cluster listing)</div>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { Overview } from '../../../components/cluster/overview';
import { ExternalConfigContext } from '../../external_config_context';
import { SetupModeRenderer } 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];
interface SetupModeProps {
Expand Down Expand Up @@ -59,25 +59,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 {
Expand Down Expand Up @@ -111,14 +106,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;
}
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions x-pack/plugins/monitoring/public/lib/fetch_clusters.ts
Original file line number Diff line number Diff line change
@@ -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);
};

0 comments on commit 2997a69

Please sign in to comment.