[Uptime] hide UI Monitor Management features behind feature flag (#119559) (#119752)

* hide ui monitor management features behind feature flag

* adjust tests

* adjust content

* adjust rtl_helpers

Co-authored-by: Dominique Clarke <doclarke71@gmail.com>
This commit is contained in:
Shahzad 2021-11-25 19:37:40 +01:00 committed by GitHub
parent b9888d24d3
commit a086bd8fc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 295 additions and 109 deletions

View file

@ -9,9 +9,25 @@ import { PluginConfigDescriptor } from 'kibana/server';
import { schema, TypeOf } from '@kbn/config-schema';
export const config: PluginConfigDescriptor = {
exposeToBrowser: {
ui: true,
},
schema: schema.maybe(
schema.object({
index: schema.maybe(schema.string()),
ui: schema.maybe(
schema.object({
unsafe: schema.maybe(
schema.object({
monitorManagement: schema.maybe(
schema.object({
enabled: schema.boolean(),
})
),
})
),
})
),
unsafe: schema.maybe(
schema.object({
service: schema.maybe(
@ -30,3 +46,6 @@ export const config: PluginConfigDescriptor = {
};
export type UptimeConfig = TypeOf<typeof config.schema>;
export interface UptimeUiConfig {
ui?: TypeOf<typeof config.schema>['ui'];
}

View file

@ -7,6 +7,10 @@
export const MONITOR_ROUTE = '/monitor/:monitorId?';
export const MONITOR_ADD_ROUTE = '/add-monitor';
export const MONITOR_EDIT_ROUTE = '/edit-monitor/:monitorId';
export const OVERVIEW_ROUTE = '/';
export const SETTINGS_ROUTE = '/settings';

View file

@ -15,6 +15,7 @@ import { from } from 'rxjs';
import { map } from 'rxjs/operators';
import { i18n } from '@kbn/i18n';
import { DEFAULT_APP_CATEGORIES } from '../../../../../src/core/public';
import {
FeatureCatalogueCategory,
HomePublicPluginSetup,
@ -43,6 +44,7 @@ import {
} from '../components/fleet_package';
import { LazySyntheticsCustomAssetsExtension } from '../components/fleet_package/lazy_synthetics_custom_assets_extension';
import { Start as InspectorPluginStart } from '../../../../../src/plugins/inspector/public';
import { UptimeUiConfig } from '../../common/config';
export interface ClientPluginsSetup {
data: DataPublicPluginSetup;
@ -73,9 +75,10 @@ export type ClientStart = void;
export class UptimePlugin
implements Plugin<ClientSetup, ClientStart, ClientPluginsSetup, ClientPluginsStart>
{
constructor(_context: PluginInitializerContext) {}
constructor(private readonly initContext: PluginInitializerContext) {}
public setup(core: CoreSetup<ClientPluginsStart, unknown>, plugins: ClientPluginsSetup): void {
const config = this.initContext.config.get<UptimeUiConfig>();
if (plugins.home) {
plugins.home.featureCatalogue.register({
id: PLUGIN.ID,
@ -203,7 +206,7 @@ export class UptimePlugin
const [coreStart, corePlugins] = await core.getStartServices();
const { renderApp } = await import('./render_app');
return renderApp(coreStart, plugins, corePlugins, params);
return renderApp(coreStart, plugins, corePlugins, params, config);
},
});
}

View file

@ -17,12 +17,14 @@ import {
} from '../../common/constants';
import { UptimeApp, UptimeAppProps } from './uptime_app';
import { ClientPluginsSetup, ClientPluginsStart } from './plugin';
import { UptimeUiConfig } from '../../common/config';
export function renderApp(
core: CoreStart,
plugins: ClientPluginsSetup,
startPlugins: ClientPluginsStart,
appMountParameters: AppMountParameters
appMountParameters: AppMountParameters,
config: UptimeUiConfig
) {
const {
application: { capabilities },
@ -70,6 +72,7 @@ export function renderApp(
setBadge,
appMountParameters,
setBreadcrumbs: core.chrome.setBreadcrumbs,
config,
};
ReactDOM.render(<UptimeApp {...props} />, appMountParameters.element);

View file

@ -34,6 +34,7 @@ import { EuiThemeProvider } from '../../../../../src/plugins/kibana_react/common
import { Storage } from '../../../../../src/plugins/kibana_utils/public';
import { UptimeIndexPatternContextProvider } from '../contexts/uptime_index_pattern_context';
import { InspectorContextProvider } from '../../../observability/public';
import { UptimeUiConfig } from '../../common/config';
export interface UptimeAppColors {
danger: string;
@ -62,6 +63,7 @@ export interface UptimeAppProps {
commonlyUsedRanges: CommonlyUsedRange[];
setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;
appMountParameters: AppMountParameters;
config: UptimeUiConfig;
}
const Application = (props: UptimeAppProps) => {
@ -76,6 +78,7 @@ const Application = (props: UptimeAppProps) => {
setBadge,
startPlugins,
appMountParameters,
config,
} = props;
useEffect(() => {
@ -130,7 +133,7 @@ const Application = (props: UptimeAppProps) => {
>
<InspectorContextProvider>
<UptimeAlertsFlyoutWrapper />
<PageRouter />
<PageRouter config={config} />
<ActionMenu appMountParameters={appMountParameters} />
</InspectorContextProvider>
</RedirectAppLinks>

View file

@ -40,6 +40,7 @@ describe('ML Flyout component', () => {
isApmAvailable: true,
isInfraAvailable: true,
isLogsAvailable: true,
config: {},
};
const { findByText, findAllByText } = render(
<UptimeSettingsContext.Provider value={value}>
@ -66,6 +67,7 @@ describe('ML Flyout component', () => {
isApmAvailable: true,
isInfraAvailable: true,
isLogsAvailable: true,
config: {},
};
const { queryByText } = render(
<UptimeSettingsContext.Provider value={value}>

View file

@ -10,6 +10,7 @@ import { UptimeAppProps } from '../apps/uptime_app';
import { CLIENT_DEFAULTS, CONTEXT_DEFAULTS } from '../../common/constants';
import { CommonlyUsedRange } from '../components/common/uptime_date_picker';
import { useGetUrlParams } from '../hooks';
import { UptimeUiConfig } from '../../common/config';
export interface UptimeSettingsContextValues {
basePath: string;
@ -18,6 +19,7 @@ export interface UptimeSettingsContextValues {
isApmAvailable: boolean;
isInfraAvailable: boolean;
isLogsAvailable: boolean;
config: UptimeUiConfig;
commonlyUsedRanges?: CommonlyUsedRange[];
}
@ -36,11 +38,19 @@ const defaultContext: UptimeSettingsContextValues = {
isApmAvailable: true,
isInfraAvailable: true,
isLogsAvailable: true,
config: {},
};
export const UptimeSettingsContext = createContext(defaultContext);
export const UptimeSettingsContextProvider: React.FC<UptimeAppProps> = ({ children, ...props }) => {
const { basePath, isApmAvailable, isInfraAvailable, isLogsAvailable, commonlyUsedRanges } = props;
const {
basePath,
isApmAvailable,
isInfraAvailable,
isLogsAvailable,
commonlyUsedRanges,
config,
} = props;
const { dateRangeStart, dateRangeEnd } = useGetUrlParams();
@ -51,6 +61,7 @@ export const UptimeSettingsContextProvider: React.FC<UptimeAppProps> = ({ childr
isInfraAvailable,
isLogsAvailable,
commonlyUsedRanges,
config,
dateRangeStart: dateRangeStart ?? DATE_RANGE_START,
dateRangeEnd: dateRangeEnd ?? DATE_RANGE_END,
};
@ -62,6 +73,7 @@ export const UptimeSettingsContextProvider: React.FC<UptimeAppProps> = ({ childr
dateRangeStart,
dateRangeEnd,
commonlyUsedRanges,
config,
]);
return <UptimeSettingsContext.Provider value={value} children={children} />;

View file

@ -14,6 +14,8 @@ export enum UptimePage {
Overview = 'Overview',
MappingError = 'MappingError',
Monitor = 'Monitor',
MonitorAdd = 'AddMonitor',
MonitorEdit = 'EditMonitor',
Settings = 'Settings',
Certificates = 'Certificates',
StepDetail = 'StepDetail',

View file

@ -13,6 +13,7 @@ import { Router } from 'react-router-dom';
import { createMemoryHistory, History } from 'history';
import { CoreStart } from 'kibana/public';
import { I18nProvider } from '@kbn/i18n-react';
import { EuiPageTemplate } from '@elastic/eui';
import { coreMock } from 'src/core/public/mocks';
// eslint-disable-next-line import/no-extraneous-dependencies
import { configure } from '@testing-library/dom';
@ -113,6 +114,12 @@ const mockCore: () => Partial<CoreStart> = () => {
triggersActionsUi: triggersActionsUiMock.createStart(),
storage: createMockStore(),
data: dataPluginMock.createStartContract(),
observability: {
navigation: {
// @ts-ignore
PageTemplate: EuiPageTemplate,
},
},
};
return core;

View file

@ -0,0 +1,12 @@
/*
* 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';
export const AddMonitorPage: React.FC = () => {
return null;
};

View file

@ -0,0 +1,12 @@
/*
* 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';
export const EditMonitorPage: React.FC = () => {
return null;
};

View file

@ -10,3 +10,5 @@ export { MonitorPage } from './monitor';
export { StepDetailPage } from './synthetics/step_detail_page';
export { SettingsPage } from './settings';
export { NotFoundPage } from './not_found';
export { AddMonitorPage } from './add_monitor';
export { EditMonitorPage } from './edit_monitor';

View file

@ -0,0 +1,47 @@
/*
* 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 { screen } from '@testing-library/react';
import { render } from './lib/helper/rtl_helpers';
import { createMemoryHistory } from 'history';
import React from 'react';
import * as telemetry from './hooks/use_telemetry';
import { MONITOR_ADD_ROUTE, MONITOR_EDIT_ROUTE } from '../common/constants';
import '@testing-library/jest-dom';
import { PageRouter } from './routes';
describe('PageRouter', () => {
beforeEach(() => {
jest.spyOn(telemetry, 'useUptimeTelemetry').mockImplementation(() => {});
});
it.each([MONITOR_ADD_ROUTE, MONITOR_EDIT_ROUTE])(
'hides ui monitor management pages when feature flag is not enabled',
(page) => {
const history = createMemoryHistory();
history.push(page);
render(<PageRouter config={{}} />, { history });
expect(screen.getByText(/Page not found/i)).toBeInTheDocument();
}
);
it.each([
[MONITOR_ADD_ROUTE, 'Add Monitor'],
[MONITOR_EDIT_ROUTE, 'Edit Monitor'],
])('hides ui monitor management pages when feature flag is not enabled', (page, heading) => {
const history = createMemoryHistory();
history.push(page);
render(<PageRouter config={{ ui: { unsafe: { monitorManagement: { enabled: true } } } }} />, {
history,
});
expect(screen.getByText(heading)).toBeInTheDocument();
});
});

View file

@ -13,12 +13,22 @@ import {
CERTIFICATES_ROUTE,
MAPPING_ERROR_ROUTE,
MONITOR_ROUTE,
MONITOR_ADD_ROUTE,
MONITOR_EDIT_ROUTE,
OVERVIEW_ROUTE,
SETTINGS_ROUTE,
STEP_DETAIL_ROUTE,
SYNTHETIC_CHECK_STEPS_ROUTE,
} from '../common/constants';
import { MappingErrorPage, MonitorPage, StepDetailPage, NotFoundPage, SettingsPage } from './pages';
import {
MappingErrorPage,
MonitorPage,
AddMonitorPage,
EditMonitorPage,
StepDetailPage,
NotFoundPage,
SettingsPage,
} from './pages';
import { CertificatesPage } from './pages/certificates';
import { UptimePage, useUptimeTelemetry } from './hooks';
import { OverviewPageComponent } from './pages/overview';
@ -41,6 +51,11 @@ import {
import { UptimePageTemplateComponent } from './apps/uptime_page_template';
import { apiService } from './state/api/utils';
import { useInspectorContext } from '../../observability/public';
import { UptimeConfig } from '../common/config';
interface PageRouterProps {
config: UptimeConfig;
}
interface RouteProps {
path: string;
@ -63,7 +78,8 @@ export const MONITORING_OVERVIEW_LABEL = i18n.translate('xpack.uptime.overview.h
defaultMessage: 'Monitors',
});
const Routes: RouteProps[] = [
const getRoutes = (config: UptimeConfig): RouteProps[] => {
return [
{
title: i18n.translate('xpack.uptime.monitorRoute.title', {
defaultMessage: 'Monitor | {baseTitle}',
@ -165,7 +181,48 @@ const Routes: RouteProps[] = [
rightSideItems: [],
},
},
...(config.ui?.unsafe?.monitorManagement?.enabled
? [
{
title: i18n.translate('xpack.uptime.addMonitorRoute.title', {
defaultMessage: 'Add Monitor | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_ADD_ROUTE,
component: AddMonitorPage,
dataTestSubj: 'uptimeMonitorAddPage',
telemetryId: UptimePage.MonitorAdd,
pageHeader: {
pageTitle: (
<FormattedMessage
id="xpack.uptime.addMonitor.pageHeader.title"
defaultMessage="Add Monitor"
/>
),
},
},
{
title: i18n.translate('xpack.uptime.editMonitorRoute.title', {
defaultMessage: 'Edit Monitor | {baseTitle}',
values: { baseTitle },
}),
path: MONITOR_EDIT_ROUTE,
component: EditMonitorPage,
dataTestSubj: 'uptimeMonitorEditPage',
telemetryId: UptimePage.MonitorEdit,
pageHeader: {
pageTitle: (
<FormattedMessage
id="xpack.uptime.editMonitor.pageHeader.title"
defaultMessage="Edit Monitor"
/>
),
},
},
]
: []),
];
};
const RouteInit: React.FC<Pick<RouteProps, 'path' | 'title' | 'telemetryId'>> = ({
path,
@ -179,14 +236,15 @@ const RouteInit: React.FC<Pick<RouteProps, 'path' | 'title' | 'telemetryId'>> =
return null;
};
export const PageRouter: FC = () => {
export const PageRouter: FC<PageRouterProps> = ({ config = {} }) => {
const routes = getRoutes(config);
const { addInspectorRequest } = useInspectorContext();
apiService.addInspectorRequest = addInspectorRequest;
return (
<Switch>
{Routes.map(
{routes.map(
({ title, path, component: RouteComponent, dataTestSubj, telemetryId, pageHeader }) => (
<Route path={path} key={telemetryId} exact={true}>
<div className={APP_WRAPPER_CLASS} data-test-subj={dataTestSubj}>

View file

@ -11,4 +11,4 @@ import { Plugin } from './plugin';
export const plugin = (initializerContext: PluginInitializerContext) =>
new Plugin(initializerContext);
export { config } from './config';
export { config } from '../common/config';

View file

@ -18,7 +18,7 @@ import { MlPluginSetup as MlSetup } from '../../../../../ml/server';
import { RuleRegistryPluginSetupContract } from '../../../../../rule_registry/server';
import { UptimeESClient } from '../../lib';
import type { UptimeRouter } from '../../../types';
import { UptimeConfig } from '../../../config';
import { UptimeConfig } from '../../../../common/config';
export type UMElasticsearchQueryFn<P, R = any> = (
params: {

View file

@ -12,7 +12,7 @@ import {
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants';
import { DynamicSettings } from '../../../common/runtime_types';
import { UMSavedObjectsQueryFn } from '../adapters';
import { UptimeConfig } from '../../config';
import { UptimeConfig } from '../../../common/config';
import { settingsObjectId, umDynamicSettings } from './uptime_settings';
import { syntheticsMonitor } from './synthetics_monitor';

View file

@ -19,7 +19,7 @@ import { KibanaTelemetryAdapter, UptimeCorePlugins } from './lib/adapters';
import { registerUptimeSavedObjects, savedObjectsAdapter } from './lib/saved_objects/saved_objects';
import { mappingFromFieldMap } from '../../rule_registry/common/mapping_from_field_map';
import { Dataset } from '../../rule_registry/server';
import { UptimeConfig } from './config';
import { UptimeConfig } from '../common/config';
export type UptimeRuleRegistry = ReturnType<Plugin['setup']>['ruleRegistry'];
@ -28,7 +28,7 @@ export class Plugin implements PluginType {
private initContext: PluginInitializerContext;
private logger?: Logger;
constructor(_initializerContext: PluginInitializerContext) {
constructor(_initializerContext: PluginInitializerContext<UptimeConfig>) {
this.initContext = _initializerContext;
}