[Stack Monitoring] Add overview page first version (#110486)

* Add header to page template

* add external config provider and overview content

* REmove unnecessary todos

* Remove non working section from header

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Ester Martí Vilaseca 2021-08-31 17:44:34 +02:00 committed by GitHub
parent 192556ef63
commit 50a95ff78a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 195 additions and 38 deletions

View file

@ -0,0 +1,17 @@
/*
* 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 { createContext } from 'react';
export interface ExternalConfig {
minIntervalSeconds: number;
showLicenseExpiration: boolean;
showCgroupMetricsElasticsearch: boolean;
showCgroupMetricsLogstash: boolean;
renderReactApp: boolean;
}
export const ExternalConfigContext = createContext({} as ExternalConfig);

View file

@ -16,6 +16,7 @@ interface GlobalStateProviderProps {
interface State {
cluster_uuid?: string;
ccs?: any;
}
export const GlobalStateContext = createContext({} as State);

View file

@ -15,7 +15,7 @@ export function useClusters(clusterUuid?: string | null, ccs?: any, codePaths?:
const [min] = useState(bounds.min.toISOString());
const [max] = useState(bounds.max.toISOString());
const [clusters, setClusters] = useState([]);
const [clusters, setClusters] = useState([] as any);
const [loaded, setLoaded] = useState<boolean | null>(false);
let url = '../api/monitoring/v1/clusters';

View file

@ -11,17 +11,23 @@ import ReactDOM from 'react-dom';
import { Route, Switch, Redirect, Router } from 'react-router-dom';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
import { LoadingPage } from './pages/loading_page';
import { ClusterOverview } from './pages/cluster/overview_page';
import { MonitoringStartPluginDependencies } from '../types';
import { GlobalStateProvider } from './global_state_context';
import { ExternalConfigContext, ExternalConfig } from './external_config_context';
import { createPreserveQueryHistory } from './preserve_query_history';
import { RouteInit } from './route_init';
export const renderApp = (
core: CoreStart,
plugins: MonitoringStartPluginDependencies,
{ element }: AppMountParameters
{ element }: AppMountParameters,
externalConfig: ExternalConfig
) => {
ReactDOM.render(<MonitoringApp core={core} plugins={plugins} />, element);
ReactDOM.render(
<MonitoringApp core={core} plugins={plugins} externalConfig={externalConfig} />,
element
);
return () => {
ReactDOM.unmountComponentAtNode(element);
@ -31,38 +37,46 @@ export const renderApp = (
const MonitoringApp: React.FC<{
core: CoreStart;
plugins: MonitoringStartPluginDependencies;
}> = ({ core, plugins }) => {
externalConfig: ExternalConfig;
}> = ({ core, plugins, externalConfig }) => {
const history = createPreserveQueryHistory();
return (
<KibanaContextProvider services={{ ...core, ...plugins }}>
<GlobalStateProvider query={plugins.data.query} toasts={core.notifications.toasts}>
<Router history={history}>
<Switch>
<Route path="/no-data" component={NoData} />
<Route path="/loading" component={LoadingPage} />
<RouteInit
path="/license"
component={License}
codePaths={['all']}
fetchAllClusters={false}
/>
<RouteInit path="/home" component={Home} codePaths={['all']} fetchAllClusters={false} />
<RouteInit
path="/overview"
component={ClusterOverview}
codePaths={['all']}
fetchAllClusters={false}
/>
<Redirect
to={{
pathname: '/loading',
search: history.location.search,
}}
/>
</Switch>
</Router>
</GlobalStateProvider>
<ExternalConfigContext.Provider value={externalConfig}>
<GlobalStateProvider query={plugins.data.query} toasts={core.notifications.toasts}>
<Router history={history}>
<Switch>
<Route path="/no-data" component={NoData} />
<Route path="/loading" component={LoadingPage} />
<RouteInit
path="/license"
component={License}
codePaths={['all']}
fetchAllClusters={false}
/>
<RouteInit
path="/home"
component={Home}
codePaths={['all']}
fetchAllClusters={false}
/>
<RouteInit
path="/overview"
component={ClusterOverview}
codePaths={['all']}
fetchAllClusters={false}
/>
<Redirect
to={{
pathname: '/loading',
search: history.location.search,
}}
/>
</Switch>
</Router>
</GlobalStateProvider>
</ExternalConfigContext.Provider>
</KibanaContextProvider>
);
};
@ -75,10 +89,6 @@ const Home: React.FC<{}> = () => {
return <div>Home page (Cluster listing)</div>;
};
const ClusterOverview: React.FC<{}> = () => {
return <div>Cluster overview page</div>;
};
const License: React.FC<{}> = () => {
return <div>License page</div>;
};

View file

@ -0,0 +1,63 @@
/*
* 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 } from 'react';
import { i18n } from '@kbn/i18n';
import { CODE_PATH_ALL } from '../../../../common/constants';
import { PageTemplate } from '../page_template';
import { useClusters } from '../../hooks/use_clusters';
import { GlobalStateContext } from '../../global_state_context';
import { TabMenuItem } from '../page_template';
import { PageLoading } from '../../../components';
import { Overview } from '../../../components/cluster/overview';
import { ExternalConfigContext } from '../../external_config_context';
const CODE_PATHS = [CODE_PATH_ALL];
export const ClusterOverview: React.FC<{}> = () => {
// TODO: check how many requests with useClusters
const state = useContext(GlobalStateContext);
const externalConfig = useContext(ExternalConfigContext);
const { clusters, loaded } = useClusters(state.cluster_uuid, state.ccs, CODE_PATHS);
let tabs: TabMenuItem[] = [];
const title = i18n.translate('xpack.monitoring.cluster.overviewTitle', {
defaultMessage: 'Overview',
});
const pageTitle = i18n.translate('xpack.monitoring.cluster.overview.pageTitle', {
defaultMessage: 'Cluster overview',
});
if (loaded) {
tabs = [
{
id: 'clusterName',
label: clusters[0].cluster_name,
disabled: false,
description: clusters[0].cluster_name,
onClick: () => {},
testSubj: 'clusterName',
},
];
}
return (
<PageTemplate title={title} pageTitle={pageTitle} tabs={tabs}>
{loaded ? (
<Overview
cluster={clusters[0]}
alerts={[]}
setupMode={{}}
showLicenseExpiration={externalConfig.showLicenseExpiration}
/>
) : (
<PageLoading />
)}
</PageTemplate>
);
};

View file

@ -5,16 +5,74 @@
* 2.0.
*/
import { EuiFlexGroup, EuiFlexItem, EuiTab, EuiTabs, EuiTitle } from '@elastic/eui';
import React from 'react';
import { useTitle } from '../hooks/use_title';
export interface TabMenuItem {
id: string;
label: string;
description: string;
disabled: boolean;
onClick: () => void;
testSubj: string;
}
interface PageTemplateProps {
title: string;
pageTitle?: string;
children: React.ReactNode;
tabs?: TabMenuItem[];
}
export const PageTemplate = ({ title, children }: PageTemplateProps) => {
export const PageTemplate = ({ title, pageTitle, tabs, children }: PageTemplateProps) => {
useTitle('', title);
return <div>{children}</div>;
return (
<div className="app-container">
<EuiFlexGroup gutterSize="l" justifyContent="spaceBetween" responsive>
<EuiFlexItem>
<EuiFlexGroup
gutterSize="none"
justifyContent="spaceEvenly"
direction="column"
responsive
>
<EuiFlexItem>
<div id="setupModeNav">{/* HERE GOES THE SETUP BUTTON */}</div>
</EuiFlexItem>
<EuiFlexItem className="monTopNavSecondItem">
{pageTitle && (
<div data-test-subj="monitoringPageTitle">
<EuiTitle size="xs">
<h1>{pageTitle}</h1>
</EuiTitle>
</div>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem>{/* HERE GOES THE TIMEPICKER */}</EuiFlexItem>
</EuiFlexGroup>
{tabs && (
<EuiTabs>
{tabs.map((item, idx) => {
return (
<EuiTab
key={idx}
disabled={item.disabled}
onClick={item.onClick}
title={item.label}
data-test-subj={item.testSubj}
>
{item.label}
</EuiTab>
);
})}
</EuiTabs>
)}
<div>{children}</div>
</div>
);
};

View file

@ -0,0 +1,8 @@
/*
* 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.
*/
export const Overview: FunctionComponent<Props>;

View file

@ -127,7 +127,7 @@ export class MonitoringPlugin
const config = Object.fromEntries(externalConfig);
if (config.renderReactApp) {
const { renderApp } = await import('./application');
return renderApp(coreStart, pluginsStart, params);
return renderApp(coreStart, pluginsStart, params, config);
} else {
const monitoringApp = new AngularApp(deps);
const removeHistoryListener = params.history.listen((location) => {