mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Unified Observability] Add feature flag for the new overview page (#119193)
* Add feature flag to display a blank overview page when enabled * Add tests for overview page feature flag * Fix types * Fix more types * Remove duplicated BucketSize type * fix linter Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d9ee4d7ee3
commit
2c4196270a
12 changed files with 335 additions and 130 deletions
|
@ -46,7 +46,13 @@ describe('renderApp', () => {
|
||||||
uiSettings: { get: () => false },
|
uiSettings: { get: () => false },
|
||||||
http: { basePath: { prepend: (path: string) => path } },
|
http: { basePath: { prepend: (path: string) => path } },
|
||||||
} as unknown as CoreStart;
|
} as unknown as CoreStart;
|
||||||
const config = { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } };
|
const config = {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
};
|
||||||
const params = {
|
const params = {
|
||||||
element: window.document.createElement('div'),
|
element: window.document.createElement('div'),
|
||||||
history: createMemoryHistory(),
|
history: createMemoryHistory(),
|
||||||
|
|
|
@ -42,7 +42,13 @@ describe('APMSection', () => {
|
||||||
http: { basePath: { prepend: jest.fn() } },
|
http: { basePath: { prepend: jest.fn() } },
|
||||||
} as unknown as CoreStart,
|
} as unknown as CoreStart,
|
||||||
appMountParameters: {} as AppMountParameters,
|
appMountParameters: {} as AppMountParameters,
|
||||||
config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } },
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(),
|
observabilityRuleTypeRegistry: createObservabilityRuleTypeRegistryMock(),
|
||||||
plugins: {
|
plugins: {
|
||||||
data: {
|
data: {
|
||||||
|
|
|
@ -42,7 +42,13 @@ describe('UXSection', () => {
|
||||||
http: { basePath: { prepend: jest.fn() } },
|
http: { basePath: { prepend: jest.fn() } },
|
||||||
} as unknown as CoreStart,
|
} as unknown as CoreStart,
|
||||||
appMountParameters: {} as AppMountParameters,
|
appMountParameters: {} as AppMountParameters,
|
||||||
config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } },
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
data: {
|
data: {
|
||||||
query: {
|
query: {
|
||||||
|
|
|
@ -24,7 +24,13 @@ describe('useTimeRange', () => {
|
||||||
jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
|
jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
|
||||||
core: {} as CoreStart,
|
core: {} as CoreStart,
|
||||||
appMountParameters: {} as AppMountParameters,
|
appMountParameters: {} as AppMountParameters,
|
||||||
config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } },
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
data: {
|
data: {
|
||||||
query: {
|
query: {
|
||||||
|
@ -67,7 +73,13 @@ describe('useTimeRange', () => {
|
||||||
jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
|
jest.spyOn(pluginContext, 'usePluginContext').mockImplementation(() => ({
|
||||||
core: {} as CoreStart,
|
core: {} as CoreStart,
|
||||||
appMountParameters: {} as AppMountParameters,
|
appMountParameters: {} as AppMountParameters,
|
||||||
config: { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } },
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
data: {
|
data: {
|
||||||
query: {
|
query: {
|
||||||
|
|
|
@ -26,7 +26,11 @@ export type {
|
||||||
export { enableInspectEsQueries } from '../common/ui_settings_keys';
|
export { enableInspectEsQueries } from '../common/ui_settings_keys';
|
||||||
|
|
||||||
export interface ConfigSchema {
|
export interface ConfigSchema {
|
||||||
unsafe: { alertingExperience: { enabled: boolean }; cases: { enabled: boolean } };
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: boolean };
|
||||||
|
cases: { enabled: boolean };
|
||||||
|
overviewNext: { enabled: boolean };
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const plugin: PluginInitializer<
|
export const plugin: PluginInitializer<
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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 { shallow } from 'enzyme';
|
||||||
|
import * as PluginContext from '../../hooks/use_plugin_context';
|
||||||
|
import { PluginContextValue } from '../../context/plugin_context';
|
||||||
|
import { OverviewPage } from './';
|
||||||
|
import { OverviewPage as OldOverviewPage } from './old_overview_page';
|
||||||
|
import { OverviewPage as NewOverviewPage } from './overview_page';
|
||||||
|
|
||||||
|
describe('Overview page', () => {
|
||||||
|
it('should render the old overview page when feature flag is disabled', () => {
|
||||||
|
const pluginContext = {
|
||||||
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(PluginContext, 'usePluginContext')
|
||||||
|
.mockReturnValue(pluginContext as PluginContextValue);
|
||||||
|
|
||||||
|
const component = shallow(<OverviewPage routeParams={{ query: {} }} />);
|
||||||
|
expect(component.find(OldOverviewPage)).toHaveLength(1);
|
||||||
|
expect(component.find(NewOverviewPage)).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the new overview page when feature flag is enabled', () => {
|
||||||
|
const pluginContext = {
|
||||||
|
config: {
|
||||||
|
unsafe: {
|
||||||
|
overviewNext: { enabled: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(PluginContext, 'usePluginContext')
|
||||||
|
.mockReturnValue(pluginContext as PluginContextValue);
|
||||||
|
|
||||||
|
const component = shallow(<OverviewPage routeParams={{ query: {} }} />);
|
||||||
|
expect(component.find(OldOverviewPage)).toHaveLength(0);
|
||||||
|
expect(component.find(NewOverviewPage)).toHaveLength(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,133 +4,24 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel } from '@elastic/eui';
|
|
||||||
import { i18n } from '@kbn/i18n';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTrackPageview } from '../..';
|
|
||||||
import { EmptySections } from '../../components/app/empty_sections';
|
|
||||||
import { ObservabilityHeaderMenu } from '../../components/app/header';
|
|
||||||
import { NewsFeed } from '../../components/app/news_feed';
|
|
||||||
import { Resources } from '../../components/app/resources';
|
|
||||||
import { AlertsSection } from '../../components/app/section/alerts';
|
|
||||||
import { DatePicker } from '../../components/shared/date_picker';
|
|
||||||
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
|
||||||
import { useFetcher } from '../../hooks/use_fetcher';
|
|
||||||
import { useHasData } from '../../hooks/use_has_data';
|
|
||||||
import { usePluginContext } from '../../hooks/use_plugin_context';
|
|
||||||
import { useTimeRange } from '../../hooks/use_time_range';
|
|
||||||
import { RouteParams } from '../../routes';
|
import { RouteParams } from '../../routes';
|
||||||
import { getNewsFeed } from '../../services/get_news_feed';
|
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||||
import { getBucketSize } from '../../utils/get_bucket_size';
|
import { OverviewPage as OldOverviewPage } from './old_overview_page';
|
||||||
import { getNoDataConfig } from '../../utils/no_data_config';
|
import { OverviewPage as NewOverviewPage } from './overview_page';
|
||||||
import { DataSections } from './data_sections';
|
|
||||||
import { LoadingObservability } from './loading_observability';
|
export type { BucketSize } from './old_overview_page';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
routeParams: RouteParams<'/overview'>;
|
routeParams: RouteParams<'/overview'>;
|
||||||
}
|
}
|
||||||
export type BucketSize = ReturnType<typeof calculateBucketSize>;
|
|
||||||
function calculateBucketSize({ start, end }: { start?: number; end?: number }) {
|
export function OverviewPage(props: Props) {
|
||||||
if (start && end) {
|
const { config } = usePluginContext();
|
||||||
return getBucketSize({ start, end, minInterval: '60s' });
|
|
||||||
|
if (config.unsafe.overviewNext.enabled) {
|
||||||
|
return <NewOverviewPage {...props} />;
|
||||||
|
} else {
|
||||||
|
return <OldOverviewPage {...props} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OverviewPage({ routeParams }: Props) {
|
|
||||||
useTrackPageview({ app: 'observability-overview', path: 'overview' });
|
|
||||||
useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 });
|
|
||||||
useBreadcrumbs([
|
|
||||||
{
|
|
||||||
text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', {
|
|
||||||
defaultMessage: 'Overview',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const { core, ObservabilityPageTemplate } = usePluginContext();
|
|
||||||
|
|
||||||
const { relativeStart, relativeEnd, absoluteStart, absoluteEnd } = useTimeRange();
|
|
||||||
|
|
||||||
const relativeTime = { start: relativeStart, end: relativeEnd };
|
|
||||||
const absoluteTime = { start: absoluteStart, end: absoluteEnd };
|
|
||||||
|
|
||||||
const { data: newsFeed } = useFetcher(() => getNewsFeed({ core }), [core]);
|
|
||||||
|
|
||||||
const { hasDataMap, hasAnyData, isAllRequestsComplete } = useHasData();
|
|
||||||
|
|
||||||
if (hasAnyData === undefined) {
|
|
||||||
return <LoadingObservability />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasData = hasAnyData === true || (isAllRequestsComplete === false ? undefined : false);
|
|
||||||
|
|
||||||
const noDataConfig = getNoDataConfig({
|
|
||||||
hasData,
|
|
||||||
basePath: core.http.basePath,
|
|
||||||
docsLink: core.docLinks.links.observability.guide,
|
|
||||||
});
|
|
||||||
|
|
||||||
const { refreshInterval = 10000, refreshPaused = true } = routeParams.query;
|
|
||||||
|
|
||||||
const bucketSize = calculateBucketSize({
|
|
||||||
start: absoluteTime.start,
|
|
||||||
end: absoluteTime.end,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ObservabilityPageTemplate
|
|
||||||
noDataConfig={noDataConfig}
|
|
||||||
pageHeader={
|
|
||||||
hasData
|
|
||||||
? {
|
|
||||||
pageTitle: overviewPageTitle,
|
|
||||||
rightSideItems: [
|
|
||||||
<DatePicker
|
|
||||||
rangeFrom={relativeTime.start}
|
|
||||||
rangeTo={relativeTime.end}
|
|
||||||
refreshInterval={refreshInterval}
|
|
||||||
refreshPaused={refreshPaused}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{hasData && (
|
|
||||||
<>
|
|
||||||
<ObservabilityHeaderMenu />
|
|
||||||
<EuiFlexGroup>
|
|
||||||
<EuiFlexItem grow={6}>
|
|
||||||
{/* Data sections */}
|
|
||||||
{hasAnyData && <DataSections bucketSize={bucketSize} />}
|
|
||||||
<EmptySections />
|
|
||||||
<EuiSpacer size="l" />
|
|
||||||
<EuiFlexGroup>
|
|
||||||
<EuiFlexItem>
|
|
||||||
{/* Resources / What's New sections */}
|
|
||||||
<EuiPanel hasBorder={true}>
|
|
||||||
<Resources />
|
|
||||||
<EuiSpacer size="l" />
|
|
||||||
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 5)} />}
|
|
||||||
</EuiPanel>
|
|
||||||
</EuiFlexItem>
|
|
||||||
{hasDataMap?.alert?.hasData && (
|
|
||||||
<EuiFlexItem>
|
|
||||||
<EuiPanel hasBorder={true}>
|
|
||||||
<AlertsSection />
|
|
||||||
</EuiPanel>
|
|
||||||
</EuiFlexItem>
|
|
||||||
)}
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</EuiFlexItem>
|
|
||||||
</EuiFlexGroup>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</ObservabilityPageTemplate>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const overviewPageTitle = i18n.translate('xpack.observability.overview.pageTitle', {
|
|
||||||
defaultMessage: 'Overview',
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* 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 { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel } from '@elastic/eui';
|
||||||
|
import { i18n } from '@kbn/i18n';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTrackPageview } from '../..';
|
||||||
|
import { EmptySections } from '../../components/app/empty_sections';
|
||||||
|
import { ObservabilityHeaderMenu } from '../../components/app/header';
|
||||||
|
import { NewsFeed } from '../../components/app/news_feed';
|
||||||
|
import { Resources } from '../../components/app/resources';
|
||||||
|
import { AlertsSection } from '../../components/app/section/alerts';
|
||||||
|
import { DatePicker } from '../../components/shared/date_picker';
|
||||||
|
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
||||||
|
import { useFetcher } from '../../hooks/use_fetcher';
|
||||||
|
import { useHasData } from '../../hooks/use_has_data';
|
||||||
|
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||||
|
import { useTimeRange } from '../../hooks/use_time_range';
|
||||||
|
import { RouteParams } from '../../routes';
|
||||||
|
import { getNewsFeed } from '../../services/get_news_feed';
|
||||||
|
import { getBucketSize } from '../../utils/get_bucket_size';
|
||||||
|
import { getNoDataConfig } from '../../utils/no_data_config';
|
||||||
|
import { DataSections } from './data_sections';
|
||||||
|
import { LoadingObservability } from './loading_observability';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
routeParams: RouteParams<'/overview'>;
|
||||||
|
}
|
||||||
|
export type BucketSize = ReturnType<typeof calculateBucketSize>;
|
||||||
|
function calculateBucketSize({ start, end }: { start?: number; end?: number }) {
|
||||||
|
if (start && end) {
|
||||||
|
return getBucketSize({ start, end, minInterval: '60s' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OverviewPage({ routeParams }: Props) {
|
||||||
|
useTrackPageview({ app: 'observability-overview', path: 'overview' });
|
||||||
|
useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 });
|
||||||
|
useBreadcrumbs([
|
||||||
|
{
|
||||||
|
text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', {
|
||||||
|
defaultMessage: 'Overview',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const { core, ObservabilityPageTemplate } = usePluginContext();
|
||||||
|
|
||||||
|
const { relativeStart, relativeEnd, absoluteStart, absoluteEnd } = useTimeRange();
|
||||||
|
|
||||||
|
const relativeTime = { start: relativeStart, end: relativeEnd };
|
||||||
|
const absoluteTime = { start: absoluteStart, end: absoluteEnd };
|
||||||
|
|
||||||
|
const { data: newsFeed } = useFetcher(() => getNewsFeed({ core }), [core]);
|
||||||
|
|
||||||
|
const { hasDataMap, hasAnyData, isAllRequestsComplete } = useHasData();
|
||||||
|
|
||||||
|
if (hasAnyData === undefined) {
|
||||||
|
return <LoadingObservability />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasData = hasAnyData === true || (isAllRequestsComplete === false ? undefined : false);
|
||||||
|
|
||||||
|
const noDataConfig = getNoDataConfig({
|
||||||
|
hasData,
|
||||||
|
basePath: core.http.basePath,
|
||||||
|
docsLink: core.docLinks.links.observability.guide,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { refreshInterval = 10000, refreshPaused = true } = routeParams.query;
|
||||||
|
|
||||||
|
const bucketSize = calculateBucketSize({
|
||||||
|
start: absoluteTime.start,
|
||||||
|
end: absoluteTime.end,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObservabilityPageTemplate
|
||||||
|
noDataConfig={noDataConfig}
|
||||||
|
pageHeader={
|
||||||
|
hasData
|
||||||
|
? {
|
||||||
|
pageTitle: overviewPageTitle,
|
||||||
|
rightSideItems: [
|
||||||
|
<DatePicker
|
||||||
|
rangeFrom={relativeTime.start}
|
||||||
|
rangeTo={relativeTime.end}
|
||||||
|
refreshInterval={refreshInterval}
|
||||||
|
refreshPaused={refreshPaused}
|
||||||
|
/>,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{hasData && (
|
||||||
|
<>
|
||||||
|
<ObservabilityHeaderMenu />
|
||||||
|
<EuiFlexGroup>
|
||||||
|
<EuiFlexItem grow={6}>
|
||||||
|
{/* Data sections */}
|
||||||
|
{hasAnyData && <DataSections bucketSize={bucketSize} />}
|
||||||
|
<EmptySections />
|
||||||
|
<EuiSpacer size="l" />
|
||||||
|
<EuiFlexGroup>
|
||||||
|
<EuiFlexItem>
|
||||||
|
{/* Resources / What's New sections */}
|
||||||
|
<EuiPanel hasBorder={true}>
|
||||||
|
<Resources />
|
||||||
|
<EuiSpacer size="l" />
|
||||||
|
{!!newsFeed?.items?.length && <NewsFeed items={newsFeed.items.slice(0, 5)} />}
|
||||||
|
</EuiPanel>
|
||||||
|
</EuiFlexItem>
|
||||||
|
{hasDataMap?.alert?.hasData && (
|
||||||
|
<EuiFlexItem>
|
||||||
|
<EuiPanel hasBorder={true}>
|
||||||
|
<AlertsSection />
|
||||||
|
</EuiPanel>
|
||||||
|
</EuiFlexItem>
|
||||||
|
)}
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</EuiFlexItem>
|
||||||
|
</EuiFlexGroup>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ObservabilityPageTemplate>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const overviewPageTitle = i18n.translate('xpack.observability.overview.pageTitle', {
|
||||||
|
defaultMessage: 'Overview',
|
||||||
|
});
|
|
@ -66,7 +66,11 @@ const withCore = makeDecorator({
|
||||||
setHeaderActionMenu: () => {},
|
setHeaderActionMenu: () => {},
|
||||||
} as unknown as AppMountParameters,
|
} as unknown as AppMountParameters,
|
||||||
config: {
|
config: {
|
||||||
unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } },
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
core: options as CoreStart,
|
core: options as CoreStart,
|
||||||
plugins: {
|
plugins: {
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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 { i18n } from '@kbn/i18n';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTrackPageview } from '../..';
|
||||||
|
import { DatePicker } from '../../components/shared/date_picker';
|
||||||
|
import { useBreadcrumbs } from '../../hooks/use_breadcrumbs';
|
||||||
|
import { useHasData } from '../../hooks/use_has_data';
|
||||||
|
import { usePluginContext } from '../../hooks/use_plugin_context';
|
||||||
|
import { useTimeRange } from '../../hooks/use_time_range';
|
||||||
|
import { RouteParams } from '../../routes';
|
||||||
|
import { getNoDataConfig } from '../../utils/no_data_config';
|
||||||
|
import { LoadingObservability } from './loading_observability';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
routeParams: RouteParams<'/overview'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OverviewPage({ routeParams }: Props) {
|
||||||
|
useTrackPageview({ app: 'observability-overview', path: 'overview' });
|
||||||
|
useTrackPageview({ app: 'observability-overview', path: 'overview', delay: 15000 });
|
||||||
|
useBreadcrumbs([
|
||||||
|
{
|
||||||
|
text: i18n.translate('xpack.observability.breadcrumbs.overviewLinkText', {
|
||||||
|
defaultMessage: 'Overview',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const { core, ObservabilityPageTemplate } = usePluginContext();
|
||||||
|
|
||||||
|
const { relativeStart, relativeEnd } = useTimeRange();
|
||||||
|
|
||||||
|
const relativeTime = { start: relativeStart, end: relativeEnd };
|
||||||
|
|
||||||
|
const { hasAnyData, isAllRequestsComplete } = useHasData();
|
||||||
|
|
||||||
|
if (hasAnyData === undefined) {
|
||||||
|
return <LoadingObservability />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasData = hasAnyData === true || (isAllRequestsComplete === false ? undefined : false);
|
||||||
|
|
||||||
|
const noDataConfig = getNoDataConfig({
|
||||||
|
hasData,
|
||||||
|
basePath: core.http.basePath,
|
||||||
|
docsLink: core.docLinks.links.observability.guide,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { refreshInterval = 10000, refreshPaused = true } = routeParams.query;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObservabilityPageTemplate
|
||||||
|
noDataConfig={noDataConfig}
|
||||||
|
pageHeader={
|
||||||
|
hasData
|
||||||
|
? {
|
||||||
|
pageTitle: overviewPageTitle,
|
||||||
|
rightSideItems: [
|
||||||
|
<DatePicker
|
||||||
|
rangeFrom={relativeTime.start}
|
||||||
|
rangeTo={relativeTime.end}
|
||||||
|
refreshInterval={refreshInterval}
|
||||||
|
refreshPaused={refreshPaused}
|
||||||
|
/>,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{hasData && <div>New observability content goes here</div>}
|
||||||
|
</ObservabilityPageTemplate>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const overviewPageTitle = i18n.translate('xpack.observability.overview.pageTitle', {
|
||||||
|
defaultMessage: 'Overview',
|
||||||
|
});
|
|
@ -34,7 +34,13 @@ export const core = {
|
||||||
},
|
},
|
||||||
} as unknown as CoreStart;
|
} as unknown as CoreStart;
|
||||||
|
|
||||||
const config = { unsafe: { alertingExperience: { enabled: true }, cases: { enabled: true } } };
|
const config = {
|
||||||
|
unsafe: {
|
||||||
|
alertingExperience: { enabled: true },
|
||||||
|
cases: { enabled: true },
|
||||||
|
overviewNext: { enabled: false },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const plugins = {
|
const plugins = {
|
||||||
data: { query: { timefilter: { timefilter: { setTime: jest.fn() } } } },
|
data: { query: { timefilter: { timefilter: { setTime: jest.fn() } } } },
|
||||||
|
|
|
@ -34,6 +34,7 @@ export const config: PluginConfigDescriptor = {
|
||||||
unsafe: schema.object({
|
unsafe: schema.object({
|
||||||
alertingExperience: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
alertingExperience: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
||||||
cases: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
cases: schema.object({ enabled: schema.boolean({ defaultValue: true }) }),
|
||||||
|
overviewNext: schema.object({ enabled: schema.boolean({ defaultValue: false }) }),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue