[Synthetics] Some ui code clean up (#149821)

This commit is contained in:
Shahzad 2023-01-30 20:30:20 +01:00 committed by GitHub
parent be498a5c58
commit a489d221dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 270 additions and 566 deletions

View file

@ -1,34 +0,0 @@
/*
* 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.
*/
// app.test.js
import React from 'react';
import 'jest-styled-components';
import { render } from '../../../utils/testing/rtl_helpers';
import { SyntheticsPageTemplateComponent } from './synthetics_page_template';
import { OVERVIEW_ROUTE } from '../../../../../../common/constants';
describe('SyntheticsPageTemplateComponent', () => {
describe('styling', () => {
// In this test we use snapshots because we're asserting on generated
// styles. Writing assertions manually here could make this test really
// convoluted, and it require us to manually update styling strings
// according to `styled-components` generator, which is counter-productive.
// In general, however, we avoid snaphshot tests.
it('does not apply header centering on bigger resolutions', () => {
const { container } = render(<SyntheticsPageTemplateComponent path={OVERVIEW_ROUTE} />);
expect(container.firstChild).toBeDefined();
});
it('applies the header centering on mobile', () => {
window.innerWidth = 600;
const { container } = render(<SyntheticsPageTemplateComponent path={OVERVIEW_ROUTE} />);
expect(container.firstChild).toBeDefined();
});
});
});

View file

@ -1,60 +0,0 @@
/*
* 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, { useEffect } from 'react';
import { EuiPageHeaderProps, EuiPageTemplateProps } from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useInspectorContext } from '@kbn/observability-plugin/public';
import { useSyntheticsDataView } from '../../../contexts';
import { ClientPluginsStart } from '../../../../../plugin';
import { EmptyStateLoading } from '../../monitors_page/overview/empty_state/empty_state_loading';
import { EmptyStateError } from '../../monitors_page/overview/empty_state/empty_state_error';
interface Props {
path: string;
pageHeader?: EuiPageHeaderProps;
}
export const SyntheticsPageTemplateComponent: React.FC<Props & EuiPageTemplateProps> = ({
path,
pageHeader,
children,
...pageTemplateProps
}) => {
const {
services: { observability },
} = useKibana<ClientPluginsStart>();
const PageTemplateComponent = observability.navigation.PageTemplate;
const { loading, error, hasData } = useSyntheticsDataView();
const { inspectorAdapters } = useInspectorContext();
useEffect(() => {
inspectorAdapters.requests.reset();
}, [inspectorAdapters.requests]);
if (error) {
return <EmptyStateError errors={[error]} />;
}
const showLoading = loading && !hasData;
return (
<>
<PageTemplateComponent
pageHeader={pageHeader}
data-test-subj={'synthetics-page-template'}
isPageDataLoaded={loading === false}
{...pageTemplateProps}
>
{showLoading && <EmptyStateLoading />}
<div style={{ visibility: showLoading ? 'hidden' : 'initial' }}>{children}</div>
</PageTemplateComponent>
</>
);
};

View file

@ -12,6 +12,7 @@ import moment from 'moment';
import { AllSeries, createExploratoryViewUrl } from '@kbn/observability-plugin/public';
import { euiStyled } from '@kbn/kibana-react-plugin/common';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants';
import { JourneyStep } from '../../../../../../common/runtime_types';
import { useSyntheticsStartPlugins } from '../../../contexts';
@ -78,7 +79,7 @@ export function StepFieldTrend({
axisTitlesVisibility={{ x: false, yLeft: false, yRight: false }}
legendIsVisible={false}
dataTypesIndexPatterns={{
synthetics: 'synthetics-*',
synthetics: SYNTHETICS_INDEX_PATTERN,
}}
withActions={false}
/>

View file

@ -0,0 +1,150 @@
/*
* 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 { useHistory, useRouteMatch } from 'react-router-dom';
import { EuiIcon, EuiPageHeaderProps } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { MonitorDetailsPageTitle } from './monitor_details_page_title';
import { EditMonitorLink } from '../common/links/edit_monitor';
import { RunTestManually } from './run_test_manually';
import { MonitorDetailsLastRun } from './monitor_details_last_run';
import { MonitorDetailsStatus } from './monitor_details_status';
import { MonitorDetailsLocation } from './monitor_details_location';
import { MonitorErrors } from './monitor_errors/monitor_errors';
import { MonitorHistory } from './monitor_history/monitor_history';
import { MonitorSummary } from './monitor_summary/monitor_summary';
import { MonitorDetailsPage } from './monitor_details_page';
import {
MONITOR_ERRORS_ROUTE,
MONITOR_HISTORY_ROUTE,
MONITOR_ROUTE,
OVERVIEW_ROUTE,
} from '../../../../../common/constants';
import { RouteProps } from '../../routes';
export const getMonitorDetailsRoute = (
history: ReturnType<typeof useHistory>,
syntheticsPath: string,
baseTitle: string
): RouteProps[] => {
return [
{
title: i18n.translate('xpack.synthetics.monitorDetails.title', {
defaultMessage: 'Synthetics Monitor Details | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorSummary />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorDetailsPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'overview'),
},
{
title: i18n.translate('xpack.synthetics.monitorHistory.title', {
defaultMessage: 'Synthetics Monitor History | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_HISTORY_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorHistory />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorHistoryPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'history'),
},
{
title: i18n.translate('xpack.synthetics.monitorErrors.title', {
defaultMessage: 'Synthetics Monitor Errors | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_ERRORS_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorErrors />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorHistoryPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'errors'),
},
];
};
const getMonitorSummaryHeader = (
history: ReturnType<typeof useHistory>,
syntheticsPath: string,
selectedTab: 'overview' | 'history' | 'errors'
): EuiPageHeaderProps => {
// Not a component, but it doesn't matter. Hooks are just functions
const match = useRouteMatch<{ monitorId: string }>(MONITOR_ROUTE); // eslint-disable-line react-hooks/rules-of-hooks
if (!match) {
return {};
}
const search = history.location.search;
const monitorId = match.params.monitorId;
return {
pageTitle: <MonitorDetailsPageTitle />,
breadcrumbs: [
{
text: (
<>
<EuiIcon size="s" type="arrowLeft" />{' '}
<FormattedMessage
id="xpack.synthetics.monitorSummaryRoute.monitorBreadcrumb"
defaultMessage="Monitors"
/>
</>
),
color: 'primary',
'aria-current': false,
href: `${syntheticsPath}${OVERVIEW_ROUTE}`,
},
],
rightSideItems: [
<EditMonitorLink />,
<RunTestManually />,
<MonitorDetailsLastRun />,
<MonitorDetailsStatus />,
<MonitorDetailsLocation />,
],
tabs: [
{
label: i18n.translate('xpack.synthetics.monitorOverviewTab.title', {
defaultMessage: 'Overview',
}),
isSelected: selectedTab === 'overview',
href: `${syntheticsPath}${MONITOR_ROUTE.replace(':monitorId?', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorOverviewTab',
},
{
label: i18n.translate('xpack.synthetics.monitorHistoryTab.title', {
defaultMessage: 'History',
}),
isSelected: selectedTab === 'history',
href: `${syntheticsPath}${MONITOR_HISTORY_ROUTE.replace(':monitorId', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorHistoryTab',
},
{
label: i18n.translate('xpack.synthetics.monitorErrorsTab.title', {
defaultMessage: 'Errors',
}),
prepend: <EuiIcon type="alert" color="danger" />,
isSelected: selectedTab === 'errors',
href: `${syntheticsPath}${MONITOR_ERRORS_ROUTE.replace(':monitorId', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorErrorsTab',
},
],
};
};

View file

@ -1,28 +0,0 @@
/*
* 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, { Fragment } from 'react';
import { EuiEmptyPrompt, EuiLoadingSpinner, EuiSpacer, EuiTitle } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
export const EmptyStateLoading = () => (
<EuiEmptyPrompt
body={
<Fragment>
<EuiLoadingSpinner size="xl" />
<EuiSpacer />
<EuiTitle size="l">
<h2>
{i18n.translate('xpack.synthetics.emptyState.loadingMessage', {
defaultMessage: 'Loading…',
})}
</h2>
</EuiTitle>
</Fragment>
}
/>
);

View file

@ -1,37 +0,0 @@
/*
* 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 { useContext, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getIndexStatus, selectIndexState } from '../../../../state';
import { SyntheticsRefreshContext } from '../../../../contexts';
// import { getDynamicSettings } from '../../../state/actions/dynamic_settings';
export const useHasData = () => {
const { loading, error, data } = useSelector(selectIndexState);
const { lastRefresh } = useContext(SyntheticsRefreshContext);
// const { settings } = useSelector(selectDynamicSettings); // TODO: Add state for dynamicSettings
const settings = { heartbeatIndices: 'synthetics-*' };
const dispatch = useDispatch();
useEffect(() => {
dispatch(getIndexStatus());
}, [dispatch, lastRefresh]);
/* useEffect(() => {
dispatch(getDynamicSettings());
}, [dispatch]);*/
return {
data,
error,
loading,
settings,
};
};

View file

@ -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 { useHistory } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n-react';
import { OverviewPage } from './overview/overview_page';
import { MonitorsPageHeader } from './management/page_header/monitors_page_header';
import { CreateMonitorButton } from './create_monitor_button';
import { MonitorsPageWithServiceAllowed } from './monitors_page';
import { RouteProps } from '../../routes';
import { MONITORS_ROUTE, OVERVIEW_ROUTE } from '../../../../../common/constants';
export const getMonitorsRoute = (
history: ReturnType<typeof useHistory>,
syntheticsPath: string,
baseTitle: string
): RouteProps[] => {
return [
{
title: i18n.translate('xpack.synthetics.overviewRoute.title', {
defaultMessage: 'Synthetics Overview | {baseTitle}',
values: { baseTitle },
}),
path: OVERVIEW_ROUTE,
component: OverviewPage,
dataTestSubj: 'syntheticsOverviewPage',
pageHeader: {
pageTitle: <MonitorsPageHeader />,
rightSideItems: [<CreateMonitorButton />],
tabs: getMonitorsTabs(syntheticsPath, 'overview'),
},
},
{
title: i18n.translate('xpack.synthetics.monitorManagementRoute.title', {
defaultMessage: 'Monitor Management | {baseTitle}',
values: { baseTitle },
}),
path: MONITORS_ROUTE,
component: MonitorsPageWithServiceAllowed,
dataTestSubj: 'syntheticsMonitorManagementPage',
pageHeader: {
pageTitle: <MonitorsPageHeader />,
rightSideItems: [<CreateMonitorButton />],
tabs: getMonitorsTabs(syntheticsPath, 'management'),
},
},
];
};
const getMonitorsTabs = (syntheticsPath: string, selected: 'overview' | 'management') => {
return [
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.overviewTab.title"
defaultMessage="Overview"
/>
),
href: `${syntheticsPath}${OVERVIEW_ROUTE}`,
isSelected: selected === 'overview',
'data-test-subj': 'syntheticsMonitorOverviewTab',
},
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.monitorsTab.title"
defaultMessage="Management"
/>
),
href: `${syntheticsPath}${MONITORS_ROUTE}`,
isSelected: selected === 'management',
'data-test-subj': 'syntheticsMonitorManagementTab',
},
];
};

View file

@ -12,16 +12,11 @@ import {
BROWSER_TRACE_TYPE,
useStepWaterfallMetrics,
} from './use_step_waterfall_metrics';
import * as reduxHooks from 'react-redux';
import * as searchHooks from '@kbn/observability-plugin/public/hooks/use_es_search';
import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants';
describe('useStepWaterfallMetrics', () => {
jest
.spyOn(reduxHooks, 'useSelector')
.mockReturnValue({ settings: { heartbeatIndices: 'heartbeat-*' } });
it('returns result as expected', () => {
// @ts-ignore
const searchHook = jest.spyOn(searchHooks, 'useEsSearch').mockReturnValue({
loading: false,
data: {
@ -85,7 +80,7 @@ describe('useStepWaterfallMetrics', () => {
},
size: 1000,
},
index: 'synthetics-*',
index: SYNTHETICS_INDEX_PATTERN,
},
['44D-444FFF-444-FFF-3333', true],
{ name: 'getWaterfallStepMetrics' }

View file

@ -6,6 +6,7 @@
*/
import { createEsParams, useEsSearch } from '@kbn/observability-plugin/public';
import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants';
import { MarkerItems } from './waterfall/context/waterfall_context';
export interface Props {
@ -22,7 +23,7 @@ export const useStepWaterfallMetrics = ({ checkGroup, hasNavigationRequest, step
const { data, loading } = useEsSearch(
hasNavigationRequest
? createEsParams({
index: 'synthetics-*',
index: SYNTHETICS_INDEX_PATTERN,
body: {
query: {
bool: {

View file

@ -9,4 +9,3 @@ export * from './synthetics_refresh_context';
export * from './synthetics_settings_context';
export * from './synthetics_theme_context';
export * from './synthetics_startup_plugins_context';
export * from './synthetics_data_view_context';

View file

@ -1,56 +0,0 @@
/*
* 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, { createContext, useContext, useEffect, useMemo } from 'react';
import { useFetcher } from '@kbn/observability-plugin/public';
import { DataViewsPublicPluginStart, DataView } from '@kbn/data-views-plugin/public';
import { useDispatch, useSelector } from 'react-redux';
import { IHttpSerializedFetchError } from '../state/utils/http_error';
import { getIndexStatus, selectIndexState } from '../state';
export const SyntheticsDataViewContext = createContext(
{} as {
dataView?: DataView;
loading?: boolean;
indices?: string;
error?: IHttpSerializedFetchError | null;
hasData?: boolean;
}
);
export const SyntheticsDataViewContextProvider: React.FC<{
dataViews: DataViewsPublicPluginStart;
}> = ({ children, dataViews }) => {
const { loading: hasDataLoading, error, data: indexStatus } = useSelector(selectIndexState);
const heartbeatIndices = indexStatus?.indices || '';
const dispatch = useDispatch();
const hasData = Boolean(indexStatus?.indexExists);
useEffect(() => {
dispatch(getIndexStatus());
}, [dispatch]);
const { data, loading } = useFetcher<Promise<DataView | undefined>>(async () => {
if (heartbeatIndices && indexStatus?.indexExists) {
// this only creates an dateView in memory, not as saved object
return dataViews.create({ title: heartbeatIndices });
}
}, [heartbeatIndices, indexStatus?.indexExists]);
const isLoading = loading || hasDataLoading;
const value = useMemo(() => {
return { dataView: data, indices: heartbeatIndices, isLoading, error, hasData };
}, [data, heartbeatIndices, isLoading, error, hasData]);
return <SyntheticsDataViewContext.Provider value={value} children={children} />;
};
export const useSyntheticsDataView = () => useContext(SyntheticsDataViewContext);

View file

@ -7,8 +7,8 @@
import { EuiThemeComputed } from '@elastic/eui/src/services/theme/types';
import React, { FC, useEffect } from 'react';
import { EuiIcon, EuiLink, EuiPageHeaderProps, useEuiTheme } from '@elastic/eui';
import { Route, Switch, useHistory, useRouteMatch } from 'react-router-dom';
import { EuiLink, useEuiTheme } from '@elastic/eui';
import { Route, Switch, useHistory } from 'react-router-dom';
import { OutPortal } from 'react-reverse-portal';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
@ -16,21 +16,16 @@ import { APP_WRAPPER_CLASS } from '@kbn/core/public';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useInspectorContext } from '@kbn/observability-plugin/public';
import type { LazyObservabilityPageTemplateProps } from '@kbn/observability-plugin/public';
import { EditMonitorLink } from './components/common/links/edit_monitor';
import { MonitorDetailsLocation } from './components/monitor_details/monitor_details_location';
import { ClientPluginsStart } from '../../plugin';
import { getMonitorsRoute } from './components/monitors_page/route_config';
import { getMonitorDetailsRoute } from './components/monitor_details/route_config';
import { getStepDetailsRoute } from './components/step_details_page/route_config';
import { getTestRunDetailsRoute } from './components/test_run_details/route_config';
import { getSettingsRouteConfig } from './components/settings/route_config';
import { TestRunDetails } from './components/test_run_details/test_run_details';
import { MonitorAddPageWithServiceAllowed } from './components/monitor_add_edit/monitor_add_page';
import { MonitorEditPageWithServiceAllowed } from './components/monitor_add_edit/monitor_edit_page';
import { MonitorDetailsPageTitle } from './components/monitor_details/monitor_details_page_title';
import { MonitorDetailsPage } from './components/monitor_details/monitor_details_page';
import { GettingStartedPage } from './components/getting_started/getting_started_page';
import { MonitorsPageHeader } from './components/monitors_page/management/page_header/monitors_page_header';
import { CreateMonitorButton } from './components/monitors_page/create_monitor_button';
import { OverviewPage } from './components/monitors_page/overview/overview_page';
import { SyntheticsPageTemplateComponent } from './components/common/pages/synthetics_page_template';
import { NotFoundPage } from './components/common/pages/not_found';
import {
MonitorTypePortalNode,
@ -38,24 +33,12 @@ import {
} from './components/monitor_add_edit/portals';
import {
GETTING_STARTED_ROUTE,
MONITORS_ROUTE,
MONITOR_ADD_ROUTE,
MONITOR_EDIT_ROUTE,
MONITOR_ERRORS_ROUTE,
MONITOR_HISTORY_ROUTE,
MONITOR_ROUTE,
OVERVIEW_ROUTE,
TEST_RUN_DETAILS_ROUTE,
} from '../../../common/constants';
import { PLUGIN } from '../../../common/constants/plugin';
import { MonitorsPageWithServiceAllowed } from './components/monitors_page/monitors_page';
import { apiService } from '../../utils/api_service';
import { RunTestManually } from './components/monitor_details/run_test_manually';
import { MonitorDetailsStatus } from './components/monitor_details/monitor_details_status';
import { MonitorDetailsLastRun } from './components/monitor_details/monitor_details_last_run';
import { MonitorSummary } from './components/monitor_details/monitor_summary/monitor_summary';
import { MonitorHistory } from './components/monitor_details/monitor_history/monitor_history';
import { MonitorErrors } from './components/monitor_details/monitor_errors/monitor_errors';
import { getErrorDetailsRouteConfig } from './components/error_details/route_config';
export type RouteProps = LazyObservabilityPageTemplateProps & {
@ -86,6 +69,8 @@ const getRoutes = (
getErrorDetailsRouteConfig(history, syntheticsPath, baseTitle),
getTestRunDetailsRoute(history, syntheticsPath, baseTitle),
getStepDetailsRoute(history, syntheticsPath, baseTitle),
...getMonitorDetailsRoute(history, syntheticsPath, baseTitle),
...getMonitorsRoute(history, syntheticsPath, baseTitle),
{
title: i18n.translate('xpack.synthetics.gettingStartedRoute.title', {
defaultMessage: 'Synthetics Getting Started | {baseTitle}',
@ -99,118 +84,6 @@ const getRoutes = (
paddingSize: 'none',
},
},
{
title: i18n.translate('xpack.synthetics.monitorDetails.title', {
defaultMessage: 'Synthetics Monitor Details | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorSummary />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorDetailsPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'overview'),
},
{
title: i18n.translate('xpack.synthetics.monitorHistory.title', {
defaultMessage: 'Synthetics Monitor History | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_HISTORY_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorHistory />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorHistoryPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'history'),
},
{
title: i18n.translate('xpack.synthetics.monitorErrors.title', {
defaultMessage: 'Synthetics Monitor Errors | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_ERRORS_ROUTE,
component: () => (
<MonitorDetailsPage>
<MonitorErrors />
</MonitorDetailsPage>
),
dataTestSubj: 'syntheticsMonitorHistoryPage',
pageHeader: getMonitorSummaryHeader(history, syntheticsPath, 'errors'),
},
{
title: i18n.translate('xpack.synthetics.overviewRoute.title', {
defaultMessage: 'Synthetics Overview | {baseTitle}',
values: { baseTitle },
}),
path: OVERVIEW_ROUTE,
component: OverviewPage,
dataTestSubj: 'syntheticsOverviewPage',
pageHeader: {
pageTitle: <MonitorsPageHeader />,
rightSideItems: [<CreateMonitorButton />],
tabs: [
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.overviewTab.title"
defaultMessage="Overview"
/>
),
isSelected: true,
'data-test-subj': 'syntheticsMonitorOverviewTab',
},
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.monitorsTab.title"
defaultMessage="Management"
/>
),
href: `${syntheticsPath}${MONITORS_ROUTE}`,
'data-test-subj': 'syntheticsMonitorManagementTab',
},
],
},
},
{
title: i18n.translate('xpack.synthetics.monitorManagementRoute.title', {
defaultMessage: 'Monitor Management | {baseTitle}',
values: { baseTitle },
}),
path: MONITORS_ROUTE,
component: MonitorsPageWithServiceAllowed,
dataTestSubj: 'syntheticsMonitorManagementPage',
pageHeader: {
pageTitle: <MonitorsPageHeader />,
rightSideItems: [<CreateMonitorButton />],
tabs: [
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.overviewTab.title"
defaultMessage="Overview"
/>
),
href: `${syntheticsPath}${OVERVIEW_ROUTE}`,
'data-test-subj': 'syntheticsMonitorOverviewTab',
},
{
label: (
<FormattedMessage
id="xpack.synthetics.monitorManagement.monitorsTab.title"
defaultMessage="Management"
/>
),
isSelected: true,
'data-test-subj': 'syntheticsMonitorManagementTab',
},
],
},
},
{
title: i18n.translate('xpack.synthetics.createMonitorRoute.title', {
defaultMessage: 'Create Monitor | {baseTitle}',
@ -289,76 +162,6 @@ const getRoutes = (
];
};
const getMonitorSummaryHeader = (
history: ReturnType<typeof useHistory>,
syntheticsPath: string,
selectedTab: 'overview' | 'history' | 'errors'
): EuiPageHeaderProps => {
// Not a component, but it doesn't matter. Hooks are just functions
const match = useRouteMatch<{ monitorId: string }>(MONITOR_ROUTE); // eslint-disable-line react-hooks/rules-of-hooks
if (!match) {
return {};
}
const search = history.location.search;
const monitorId = match.params.monitorId;
return {
pageTitle: <MonitorDetailsPageTitle />,
breadcrumbs: [
{
text: (
<>
<EuiIcon size="s" type="arrowLeft" />{' '}
<FormattedMessage
id="xpack.synthetics.monitorSummaryRoute.monitorBreadcrumb"
defaultMessage="Monitors"
/>
</>
),
color: 'primary',
'aria-current': false,
href: `${syntheticsPath}${OVERVIEW_ROUTE}`,
},
],
rightSideItems: [
<EditMonitorLink />,
<RunTestManually />,
<MonitorDetailsLastRun />,
<MonitorDetailsStatus />,
<MonitorDetailsLocation />,
],
tabs: [
{
label: i18n.translate('xpack.synthetics.monitorOverviewTab.title', {
defaultMessage: 'Overview',
}),
isSelected: selectedTab === 'overview',
href: `${syntheticsPath}${MONITOR_ROUTE.replace(':monitorId?', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorOverviewTab',
},
{
label: i18n.translate('xpack.synthetics.monitorHistoryTab.title', {
defaultMessage: 'History',
}),
isSelected: selectedTab === 'history',
href: `${syntheticsPath}${MONITOR_HISTORY_ROUTE.replace(':monitorId', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorHistoryTab',
},
{
label: i18n.translate('xpack.synthetics.monitorErrorsTab.title', {
defaultMessage: 'Errors',
}),
prepend: <EuiIcon type="alert" color="danger" />,
isSelected: selectedTab === 'errors',
href: `${syntheticsPath}${MONITOR_ERRORS_ROUTE.replace(':monitorId', monitorId)}${search}`,
'data-test-subj': 'syntheticsMonitorErrorsTab',
},
],
};
};
const RouteInit: React.FC<Pick<RouteProps, 'path' | 'title'>> = ({ path, title }) => {
useEffect(() => {
document.title = title;
@ -367,15 +170,17 @@ const RouteInit: React.FC<Pick<RouteProps, 'path' | 'title'>> = ({ path, title }
};
export const PageRouter: FC = () => {
const { services } = useKibana();
const { application, observability } = useKibana<ClientPluginsStart>().services;
const { addInspectorRequest } = useInspectorContext();
const { euiTheme } = useEuiTheme();
const history = useHistory();
const routes = getRoutes(
euiTheme,
history,
services.application!.getUrlForApp(PLUGIN.SYNTHETICS_PLUGIN_ID)
application.getUrlForApp(PLUGIN.SYNTHETICS_PLUGIN_ID)
);
const PageTemplateComponent = observability.navigation.PageTemplate;
apiService.addInspectorRequest = addInspectorRequest;
@ -393,13 +198,14 @@ export const PageRouter: FC = () => {
<Route path={path} key={dataTestSubj} exact={true}>
<div className={APP_WRAPPER_CLASS} data-test-subj={dataTestSubj}>
<RouteInit title={title} path={path} />
<SyntheticsPageTemplateComponent
path={path}
<PageTemplateComponent
pageHeader={pageHeader}
data-test-subj={'synthetics-page-template'}
isPageDataLoaded={true}
{...pageTemplateProps}
>
<RouteComponent />
</SyntheticsPageTemplateComponent>
</PageTemplateComponent>
</div>
</Route>
)

View file

@ -11,7 +11,6 @@ export type { SyntheticsAppState as AppState } from './root_reducer';
export type { IHttpSerializedFetchError } from './utils/http_error';
export * from './ui';
export * from './index_status';
export * from './synthetics_enablement';
export * from './service_locations';
export * from './monitor_list';

View file

@ -1,15 +0,0 @@
/*
* 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 { createAction } from '@reduxjs/toolkit';
import { StatesIndexStatus } from '../../../../../common/runtime_types';
import { IHttpSerializedFetchError } from '../utils/http_error';
export const getIndexStatus = createAction<void>('[INDEX STATUS] GET');
export const getIndexStatusSuccess = createAction<StatesIndexStatus>('[INDEX STATUS] GET SUCCESS');
export const getIndexStatusFail =
createAction<IHttpSerializedFetchError>('[INDEX STATUS] GET FAIL');

View file

@ -1,14 +0,0 @@
/*
* 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 { API_URLS } from '../../../../../common/constants';
import { StatesIndexStatus, StatesIndexStatusType } from '../../../../../common/runtime_types';
import { apiService } from '../../../../utils/api_service';
export const fetchIndexStatus = async (): Promise<StatesIndexStatus> => {
return await apiService.get(API_URLS.INDEX_STATUS, undefined, StatesIndexStatusType);
};

View file

@ -1,18 +0,0 @@
/*
* 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 { takeLeading } from 'redux-saga/effects';
import { getIndexStatus, getIndexStatusSuccess, getIndexStatusFail } from './actions';
import { fetchEffectFactory } from '../utils/fetch_effect';
import { fetchIndexStatus } from './api';
export function* fetchIndexStatusEffect() {
yield takeLeading(
getIndexStatus,
fetchEffectFactory(fetchIndexStatus, getIndexStatusSuccess, getIndexStatusFail)
);
}

View file

@ -1,43 +0,0 @@
/*
* 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 { createReducer } from '@reduxjs/toolkit';
import { IHttpSerializedFetchError } from '../utils/http_error';
import { StatesIndexStatus } from '../../../../../common/runtime_types';
import { getIndexStatus, getIndexStatusSuccess, getIndexStatusFail } from './actions';
export interface IndexStatusState {
data: StatesIndexStatus | null;
loading: boolean;
error: IHttpSerializedFetchError | null;
}
const initialState: IndexStatusState = {
data: null,
loading: false,
error: null,
};
export const indexStatusReducer = createReducer(initialState, (builder) => {
builder
.addCase(getIndexStatus, (state) => {
state.loading = true;
})
.addCase(getIndexStatusSuccess, (state, action) => {
state.data = action.payload;
state.loading = false;
})
.addCase(getIndexStatusFail, (state, action) => {
state.error = action.payload;
state.loading = false;
});
});
export * from './actions';
export * from './effects';
export * from './selectors';

View file

@ -1,12 +0,0 @@
/*
* 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 { createSelector } from 'reselect';
import type { SyntheticsAppState } from '../root_reducer';
const getState = (appState: SyntheticsAppState) => appState.indexStatus;
export const selectIndexState = createSelector(getState, (state) => state);

View file

@ -18,7 +18,6 @@ import { syncGlobalParamsEffect } from './settings';
import { fetchAgentPoliciesEffect } from './private_locations';
import { fetchNetworkEventsEffect } from './network_events/effects';
import { fetchSyntheticsMonitorEffect } from './monitor_details';
import { fetchIndexStatusEffect } from './index_status';
import { fetchSyntheticsEnablementEffect } from './synthetics_enablement';
import {
enableMonitorAlertEffect,
@ -32,7 +31,6 @@ import { fetchPingStatusesEffect } from './ping_status';
export const rootEffect = function* root(): Generator {
yield all([
fork(fetchIndexStatusEffect),
fork(fetchSyntheticsEnablementEffect),
fork(upsertMonitorEffect),
fork(fetchServiceLocationsEffect),

View file

@ -21,7 +21,6 @@ import { agentPoliciesReducer, AgentPoliciesState } from './private_locations';
import { networkEventsReducer, NetworkEventsState } from './network_events';
import { monitorDetailsReducer, MonitorDetailsState } from './monitor_details';
import { uiReducer, UiState } from './ui';
import { indexStatusReducer, IndexStatusState } from './index_status';
import { syntheticsEnablementReducer, SyntheticsEnablementState } from './synthetics_enablement';
import { monitorListReducer, MonitorListState } from './monitor_list';
import { serviceLocationsReducer, ServiceLocationsState } from './service_locations';
@ -35,7 +34,6 @@ export interface SyntheticsAppState {
pingStatus: PingStatusState;
elasticsearch: QueriesState;
monitorList: MonitorListState;
indexStatus: IndexStatusState;
overview: MonitorOverviewState;
networkEvents: NetworkEventsState;
agentPolicies: AgentPoliciesState;
@ -53,7 +51,6 @@ export const rootReducer = combineReducers<SyntheticsAppState>({
settings: settingsReducer,
pingStatus: pingStatusReducer,
monitorList: monitorListReducer,
indexStatus: indexStatusReducer,
overview: monitorOverviewReducer,
networkEvents: networkEventsReducer,
elasticsearch: elasticsearchReducer,

View file

@ -17,7 +17,7 @@ import {
} from '@kbn/kibana-react-plugin/public';
import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common';
import { InspectorContextProvider } from '@kbn/observability-plugin/public';
import { SyntheticsAppProps, SyntheticsDataViewContextProvider } from './contexts';
import { SyntheticsAppProps } from './contexts';
import {
SyntheticsRefreshContextProvider,
@ -100,24 +100,22 @@ const Application = (props: SyntheticsAppProps) => {
<EuiThemeProvider darkMode={darkMode}>
<SyntheticsRefreshContextProvider>
<SyntheticsSettingsContextProvider {...props}>
<SyntheticsDataViewContextProvider dataViews={startPlugins.dataViews}>
<SyntheticsThemeContextProvider darkMode={darkMode}>
<SyntheticsStartupPluginsContextProvider {...startPlugins}>
<div className={APP_WRAPPER_CLASS} data-test-subj="syntheticsApp">
<RedirectAppLinks
className={APP_WRAPPER_CLASS}
application={core.application}
>
<InspectorContextProvider>
<PageRouter />
<ActionMenu appMountParameters={appMountParameters} />
<TestNowModeFlyoutContainer />
</InspectorContextProvider>
</RedirectAppLinks>
</div>
</SyntheticsStartupPluginsContextProvider>
</SyntheticsThemeContextProvider>
</SyntheticsDataViewContextProvider>
<SyntheticsThemeContextProvider darkMode={darkMode}>
<SyntheticsStartupPluginsContextProvider {...startPlugins}>
<div className={APP_WRAPPER_CLASS} data-test-subj="syntheticsApp">
<RedirectAppLinks
className={APP_WRAPPER_CLASS}
application={core.application}
>
<InspectorContextProvider>
<PageRouter />
<ActionMenu appMountParameters={appMountParameters} />
<TestNowModeFlyoutContainer />
</InspectorContextProvider>
</RedirectAppLinks>
</div>
</SyntheticsStartupPluginsContextProvider>
</SyntheticsThemeContextProvider>
</SyntheticsSettingsContextProvider>
</SyntheticsRefreshContextProvider>
</EuiThemeProvider>

View file

@ -30,11 +30,6 @@ export const mockState: SyntheticsAppState = {
searchText: '',
monitorId: '',
},
indexStatus: {
data: null,
error: null,
loading: false,
},
serviceLocations: {
throttling: DEFAULT_THROTTLING,
locations: [