From 674857e14b51d237663108d4e8882a12fc85aad5 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 21 Apr 2020 14:23:07 -0400 Subject: [PATCH 01/10] Refactor settings form event handling and modify certs fields. --- .../plugins/uptime/common/constants/index.ts | 1 + .../common/constants/settings_defaults.ts | 15 +++++ .../common/runtime_types/dynamic_settings.ts | 14 +---- .../__tests__/certificate_form.test.tsx | 2 +- .../settings/__tests__/indices_form.test.tsx | 2 +- .../components/settings/certificate_form.tsx | 59 +++++++++++-------- .../components/settings/indices_form.tsx | 5 +- .../plugins/uptime/public/pages/settings.tsx | 55 +++++------------ .../uptime/public/pages/translations.ts | 23 ++++++++ .../public/state/reducers/dynamic_settings.ts | 27 +++++---- .../uptime/server/lib/saved_objects.ts | 12 ++-- 11 files changed, 113 insertions(+), 102 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts create mode 100644 x-pack/legacy/plugins/uptime/public/pages/translations.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/index.ts b/x-pack/legacy/plugins/uptime/common/constants/index.ts index 74783cf46550fa..72d498056d6b3c 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/index.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/index.ts @@ -9,6 +9,7 @@ export { CHART_FORMAT_LIMITS } from './chart_format_limits'; export { CLIENT_DEFAULTS } from './client_defaults'; export { CONTEXT_DEFAULTS } from './context_defaults'; export * from './capabilities'; +export * from './settings_defaults'; export { PLUGIN } from './plugin'; export { QUERY, STATES } from './query'; export * from './ui'; diff --git a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts new file mode 100644 index 00000000000000..b77e5da983144c --- /dev/null +++ b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { DynamicSettings } from '../runtime_types'; + +export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = { + heartbeatIndices: 'heartbeat-8*', + certificatesThresholds: { + expiration: 7, + age: 365, + }, +}; diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts index 985b51891da99f..1cd8682510d736 100644 --- a/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts +++ b/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts @@ -6,9 +6,9 @@ import * as t from 'io-ts'; -export const CertificatesStatesThresholdType = t.interface({ - warningState: t.number, - errorState: t.number, +export const CertificatesStatesThresholdType = t.partial({ + age: t.number, + expiration: t.number, }); export const DynamicSettingsType = t.intersection([ @@ -32,11 +32,3 @@ export const DynamicSettingsSaveType = t.intersection([ export type DynamicSettings = t.TypeOf; export type DynamicSettingsSaveResponse = t.TypeOf; export type CertificatesStatesThreshold = t.TypeOf; - -export const defaultDynamicSettings: DynamicSettings = { - heartbeatIndices: 'heartbeat-8*', - certificatesThresholds: { - errorState: 7, - warningState: 30, - }, -}; diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx index a3158f3d724456..9e8c722b72cc58 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx @@ -16,7 +16,7 @@ describe('CertificateForm', () => { onChange={jest.fn()} formFields={{ heartbeatIndices: 'heartbeat-8*', - certificatesThresholds: { errorState: 7, warningState: 36 }, + certificatesThresholds: { expiration: 7, age: 36 }, }} fieldErrors={{}} isDisabled={false} diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx index 654d51019d4e57..352e30413ac6ed 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx @@ -16,7 +16,7 @@ describe('CertificateForm', () => { onChange={jest.fn()} formFields={{ heartbeatIndices: 'heartbeat-8*', - certificatesThresholds: { errorState: 7, warningState: 36 }, + certificatesThresholds: { expiration: 7, age: 36 }, }} fieldErrors={{}} isDisabled={false} diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx index 5103caee1e1c05..2b56dd906f3baa 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx @@ -12,18 +12,16 @@ import { EuiFormRow, EuiCode, EuiFieldNumber, + EuiText, EuiTitle, EuiSpacer, - EuiSelect, EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import { defaultDynamicSettings, DynamicSettings } from '../../../common/runtime_types'; +import { DynamicSettings } from '../../../common/runtime_types'; import { selectDynamicSettings } from '../../state/selectors'; -type NumStr = string | number; - -export type OnFieldChangeType = (field: string, value?: NumStr) => void; +export type OnFieldChangeType = (changedValues: Partial) => void; export interface SettingsFormProps { onChange: OnFieldChangeType; @@ -55,15 +53,15 @@ export const CertificateExpirationForm: React.FC = ({ title={

} description={ } > @@ -76,9 +74,7 @@ export const CertificateExpirationForm: React.FC = ({ id="xpack.uptime.sourceConfiguration.errorStateDefaultValue" defaultMessage="The default value is {defaultValue}" values={{ - defaultValue: ( - {defaultDynamicSettings?.certificatesThresholds?.errorState} - ), + defaultValue: {dss.settings.certificatesThresholds?.expiration}, }} /> } @@ -86,7 +82,7 @@ export const CertificateExpirationForm: React.FC = ({ label={ } > @@ -97,17 +93,23 @@ export const CertificateExpirationForm: React.FC = ({ fullWidth disabled={isDisabled} isLoading={dss.loading} - value={formFields?.certificatesThresholds?.errorState || ''} + value={formFields?.certificatesThresholds?.expiration || ''} onChange={({ currentTarget: { value } }: any) => - onChange( - 'certificatesThresholds.errorState', - value === '' ? undefined : Number(value) - ) + onChange({ + certificatesThresholds: { + expiration: value === '' ? undefined : Number(value), + }, + }) } /> - + + + @@ -120,9 +122,7 @@ export const CertificateExpirationForm: React.FC = ({ id="xpack.uptime.sourceConfiguration.warningStateDefaultValue" defaultMessage="The default value is {defaultValue}" values={{ - defaultValue: ( - {defaultDynamicSettings?.certificatesThresholds?.warningState} - ), + defaultValue: {dss.settings.certificatesThresholds?.age}, }} /> } @@ -130,7 +130,7 @@ export const CertificateExpirationForm: React.FC = ({ label={ } > @@ -143,14 +143,21 @@ export const CertificateExpirationForm: React.FC = ({ fullWidth disabled={isDisabled} isLoading={dss.loading} - value={formFields?.certificatesThresholds?.warningState || ''} + value={formFields?.certificatesThresholds?.age || ''} onChange={(event: any) => - onChange('certificatesThresholds.warningState', Number(event.currentTarget.value)) + onChange({ + certificatesThresholds: { age: Number(event.currentTarget.value) }, + }) } /> - + + + diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx index c28eca2ea229e5..c3f0342ef3ea5b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx @@ -15,7 +15,6 @@ import { EuiTitle, EuiSpacer, } from '@elastic/eui'; -import { defaultDynamicSettings } from '../../../common/runtime_types'; import { selectDynamicSettings } from '../../state/selectors'; import { SettingsFormProps } from './certificate_form'; @@ -63,7 +62,7 @@ export const IndicesForm: React.FC = ({ id="xpack.uptime.sourceConfiguration.heartbeatIndicesDefaultValue" defaultMessage="The default value is {defaultValue}" values={{ - defaultValue: {defaultDynamicSettings.heartbeatIndices}, + defaultValue: {dss.settings.heartbeatIndices}, }} /> } @@ -81,7 +80,7 @@ export const IndicesForm: React.FC = ({ disabled={isDisabled} isLoading={dss.loading} value={formFields?.heartbeatIndices || ''} - onChange={(event: any) => onChange('heartbeatIndices', event.currentTarget.value)} + onChange={(event: any) => onChange({ heartbeatIndices: event.currentTarget.value })} /> diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx index 6defb96e0da3d7..31f3433d3ccdac 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx @@ -17,8 +17,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch, useSelector } from 'react-redux'; -import { cloneDeep, isEqual, set } from 'lodash'; -import { i18n } from '@kbn/i18n'; +import { isEqual, merge } from 'lodash'; import { Link } from 'react-router-dom'; import { selectDynamicSettings } from '../state/selectors'; import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic_settings'; @@ -32,14 +31,15 @@ import { CertificateExpirationForm, OnFieldChangeType, } from '../components/settings/certificate_form'; +import * as Translations from './translations'; const getFieldErrors = (formFields: DynamicSettings | null) => { if (formFields) { const blankStr = 'May not be blank'; const { certificatesThresholds, heartbeatIndices } = formFields; const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr; - const errorStateErr = certificatesThresholds?.errorState ? null : blankStr; - const warningStateErr = certificatesThresholds?.warningState ? null : blankStr; + const errorStateErr = certificatesThresholds?.expiration ? null : blankStr; + const warningStateErr = certificatesThresholds?.age ? null : blankStr; return { heartbeatIndices: heartbeatIndErr, certificatesThresholds: @@ -57,10 +57,7 @@ const getFieldErrors = (formFields: DynamicSettings | null) => { export const SettingsPage = () => { const dss = useSelector(selectDynamicSettings); - const settingsBreadcrumbText = i18n.translate('xpack.uptime.settingsBreadcrumbText', { - defaultMessage: 'Settings', - }); - useBreadcrumbs([{ text: settingsBreadcrumbText }]); + useBreadcrumbs([{ text: Translations.settings.breadcrumbText }]); useUptimeTelemetry(UptimePage.Settings); @@ -70,52 +67,32 @@ export const SettingsPage = () => { dispatch(getDynamicSettings()); }, [dispatch]); - const [formFields, setFormFields] = useState(dss.settings || null); - - if (!dss.loadError && formFields == null && dss.settings) { - setFormFields({ ...dss.settings }); - } + const [formFields, setFormFields] = useState({ ...dss.settings }); const fieldErrors = getFieldErrors(formFields); const isFormValid = !(fieldErrors && Object.values(fieldErrors).find(v => !!v)); - const onChangeFormField: OnFieldChangeType = (field, value) => { - if (formFields) { - const newFormFields = cloneDeep(formFields); - set(newFormFields, field, value); - setFormFields(cloneDeep(newFormFields)); - } - }; + const onChangeFormField: OnFieldChangeType = changedField => + setFormFields(Object.assign({ ...merge(formFields, changedField) })); const onApply = (event: React.FormEvent) => { event.preventDefault(); - if (formFields) { - dispatch(setDynamicSettings(formFields)); - } + dispatch(setDynamicSettings(formFields)); }; - const resetForm = () => { - if (formFields && dss.settings) { - setFormFields({ ...dss.settings }); - } - }; + const resetForm = () => setFormFields({ ...dss.settings }); - const isFormDirty = dss.settings ? !isEqual(dss.settings, formFields) : true; + const isFormDirty = !isEqual(dss.settings, formFields); const canEdit: boolean = !!useKibana().services?.application?.capabilities.uptime.configureSettings || false; const isFormDisabled = dss.loading || !canEdit; - const editNoticeTitle = i18n.translate('xpack.uptime.settings.cannotEditTitle', { - defaultMessage: 'You do not have permission to edit settings.', - }); - const editNoticeText = i18n.translate('xpack.uptime.settings.cannotEditText', { - defaultMessage: - "Your user currently has 'Read' permissions for the Uptime app. Enable a permissions-level of 'All' to edit these settings.", - }); const cannotEditNotice = canEdit ? null : ( <> - {editNoticeText} + + {Translations.settings.editNoticeText} + ); @@ -124,9 +101,7 @@ export const SettingsPage = () => { <> - {i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', { - defaultMessage: 'Return to overview', - })} + {Translations.settings.returnToOverviewLinkLabel} diff --git a/x-pack/legacy/plugins/uptime/public/pages/translations.ts b/x-pack/legacy/plugins/uptime/public/pages/translations.ts new file mode 100644 index 00000000000000..85e4e3f931c46f --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/pages/translations.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const settings = { + breadcrumbText: i18n.translate('xpack.uptime.settingsBreadcrumbText', { + defaultMessage: 'Settings', + }), + editNoticeTitle: i18n.translate('xpack.uptime.settings.cannotEditTitle', { + defaultMessage: 'You do not have permission to edit settings.', + }), + editNoticeText: i18n.translate('xpack.uptime.settings.cannotEditText', { + defaultMessage: + "Your user currently has 'Read' permissions for the Uptime app. Enable a permissions-level of 'All' to edit these settings.", + }), + returnToOverviewLinkLabel: i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', { + defaultMessage: 'Return to overview', + }), +}; diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts index f003565e9873e4..9d44b3b5bd1c2c 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts @@ -13,15 +13,17 @@ import { setDynamicSettingsFail, } from '../actions/dynamic_settings'; import { DynamicSettings } from '../../../common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants'; export interface DynamicSettingsState { - settings?: DynamicSettings; + settings: DynamicSettings; loadError?: Error; saveError?: Error; loading: boolean; } const initialState: DynamicSettingsState = { + settings: DYNAMIC_SETTINGS_DEFAULTS, loading: true, }; @@ -31,23 +33,22 @@ export const dynamicSettingsReducer = handleActions( ...state, loading: true, }), - [String(getDynamicSettingsSuccess)]: (state, action: Action) => { - return { - loading: false, - settings: action.payload, - }; - }, - [String(getDynamicSettingsFail)]: (state, action: Action) => { - return { - loading: false, - loadError: action.payload, - }; - }, + [String(getDynamicSettingsSuccess)]: (state, action: Action) => ({ + ...state, + loading: false, + settings: action.payload, + }), + [String(getDynamicSettingsFail)]: (state, action: Action) => ({ + ...state, + loading: false, + loadError: action.payload, + }), [String(setDynamicSettings)]: state => ({ ...state, loading: true, }), [String(setDynamicSettingsSuccess)]: (state, action: Action) => ({ + ...state, settings: action.payload, saveSucceded: true, loading: false, diff --git a/x-pack/plugins/uptime/server/lib/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects.ts index 3ccfd498c44bfc..0e52207e234081 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - DynamicSettings, - defaultDynamicSettings, -} from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../legacy/plugins/uptime/common/constants'; import { SavedObjectsType, SavedObjectsErrorHelpers } from '../../../../../src/core/server'; import { UMSavedObjectsQueryFn } from './adapters'; @@ -30,10 +28,10 @@ export const umDynamicSettings: SavedObjectsType = { }, certificatesThresholds: { properties: { - errorState: { + expiration: { type: 'long', }, - warningState: { + age: { type: 'long', }, }, @@ -49,7 +47,7 @@ export const savedObjectsAdapter: UMSavedObjectsAdapter = { return obj.attributes; } catch (getErr) { if (SavedObjectsErrorHelpers.isNotFoundError(getErr)) { - return defaultDynamicSettings; + return DYNAMIC_SETTINGS_DEFAULTS; } throw getErr; } From 7d2bf4c5585ca396ab8f2363071df40c211cff40 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 21 Apr 2020 16:10:13 -0400 Subject: [PATCH 02/10] Fix/improve broken types/unit/integration/api tests. --- .../certificate_form.test.tsx.snap | 4 ++-- .../__snapshots__/indices_form.test.tsx.snap | 4 ++-- .../components/settings/certificate_form.tsx | 8 +++----- .../state/selectors/__tests__/index.test.ts | 2 ++ .../lib/alerts/__tests__/status_check.test.ts | 12 ++++++------ .../__tests__/get_latest_monitor.test.ts | 6 +++--- .../__tests__/get_monitor_charts.test.ts | 6 +++--- .../__tests__/get_monitor_status.test.ts | 10 +++++----- .../__tests__/get_ping_histogram.test.ts | 14 +++++++------- .../lib/requests/__tests__/get_pings.test.ts | 16 ++++++++-------- .../apis/uptime/rest/dynamic_settings.ts | 12 ++++++++---- .../test/functional/apps/uptime/settings.ts | 12 +++++------- .../functional/services/uptime/settings.ts | 19 ++++++++++--------- 13 files changed, 64 insertions(+), 61 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap index 36bc9bb8602111..4e1d477c9ec5a6 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap @@ -56,8 +56,8 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = formFields={ Object { "certificatesThresholds": Object { - "errorState": 7, - "warningState": 36, + "age": 36, + "expiration": 7, }, "heartbeatIndices": "heartbeat-8*", } diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap index 93151198c0f494..108dcf71b692fe 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap @@ -56,8 +56,8 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = formFields={ Object { "certificatesThresholds": Object { - "errorState": 7, - "warningState": 36, + "age": 36, + "expiration": 7, }, "heartbeatIndices": "heartbeat-8*", } diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx index 2b56dd906f3baa..76df1b7ec0a7d3 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx @@ -89,7 +89,7 @@ export const CertificateExpirationForm: React.FC = ({ = ({ onChange={({ currentTarget: { value } }: any) => onChange({ certificatesThresholds: { - expiration: value === '' ? undefined : Number(value), + expiration: Number(value), }, }) } @@ -137,9 +137,7 @@ export const CertificateExpirationForm: React.FC = ({ { const state: AppState = { @@ -20,6 +21,7 @@ describe('state selectors', () => { loading: false, }, dynamicSettings: { + settings: DYNAMIC_SETTINGS_DEFAULTS, loading: false, }, monitor: { diff --git a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts index 2cc6f23ebaae50..fe14986e0d2c6b 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts @@ -16,7 +16,7 @@ import { AlertType } from '../../../../../alerting/server'; import { IRouter } from 'kibana/server'; import { UMServerLibs } from '../../lib'; import { UptimeCoreSetup } from '../../adapters'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; /** @@ -52,7 +52,7 @@ const mockOptions = ( id: '', type: '', references: [], - attributes: defaultDynamicSettings, + attributes: DYNAMIC_SETTINGS_DEFAULTS, }); return { params, @@ -89,8 +89,8 @@ describe('status check alert', () => { "callES": [MockFunction], "dynamicSettings": Object { "certificatesThresholds": Object { - "errorState": 7, - "warningState": 30, + "age": 365, + "expiration": 7, }, "heartbeatIndices": "heartbeat-8*", }, @@ -136,8 +136,8 @@ describe('status check alert', () => { "callES": [MockFunction], "dynamicSettings": Object { "certificatesThresholds": Object { - "errorState": 7, - "warningState": 30, + "age": 365, + "expiration": 7, }, "heartbeatIndices": "heartbeat-8*", }, diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts index cf8414a3b0a68c..03e2bc7a44bd04 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_latest_monitor.test.ts @@ -5,14 +5,14 @@ */ import { getLatestMonitor } from '../get_latest_monitor'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; describe('getLatestMonitor', () => { let expectedGetLatestSearchParams: any; let mockEsSearchResult: any; beforeEach(() => { expectedGetLatestSearchParams = { - index: defaultDynamicSettings.heartbeatIndices, + index: DYNAMIC_SETTINGS_DEFAULTS.heartbeatIndices, body: { query: { bool: { @@ -64,7 +64,7 @@ describe('getLatestMonitor', () => { const mockEsClient = jest.fn(async (_request: any, _params: any) => mockEsSearchResult); const result = await getLatestMonitor({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateStart: 'now-1h', dateEnd: 'now', monitorId: 'testMonitor', diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts index c740581734fdd0..5d3f9ce8d4ad9d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_charts.test.ts @@ -7,7 +7,7 @@ import { set } from 'lodash'; import mockChartsData from './monitor_charts_mock.json'; import { getMonitorDurationChart } from '../get_monitor_duration'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; describe('ElasticsearchMonitorsAdapter', () => { it('getMonitorChartsData will provide expected filters', async () => { @@ -16,7 +16,7 @@ describe('ElasticsearchMonitorsAdapter', () => { const search = searchMock.bind({}); await getMonitorDurationChart({ callES: search, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, monitorId: 'fooID', dateStart: 'now-15m', dateEnd: 'now', @@ -39,7 +39,7 @@ describe('ElasticsearchMonitorsAdapter', () => { expect( await getMonitorDurationChart({ callES: search, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, monitorId: 'id', dateStart: 'now-15m', dateEnd: 'now', diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts index e429de9ae0d68c..1c26cab4b60ff5 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts @@ -7,7 +7,7 @@ import { elasticsearchServiceMock } from '../../../../../../../src/core/server/mocks'; import { getMonitorStatus } from '../get_monitor_status'; import { ScopedClusterClient } from 'src/core/server/elasticsearch'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; interface BucketItemCriteria { monitor_id: string; @@ -103,7 +103,7 @@ describe('getMonitorStatus', () => { }`; await getMonitorStatus({ callES, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, filters: exampleFilter, locations: [], numTimes: 5, @@ -206,7 +206,7 @@ describe('getMonitorStatus', () => { const [callES, esMock] = setupMock([]); await getMonitorStatus({ callES, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, locations: ['fairbanks', 'harrisburg'], numTimes: 1, timerange: { @@ -329,7 +329,7 @@ describe('getMonitorStatus', () => { }; const result = await getMonitorStatus({ callES, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, ...clientParameters, }); expect(esMock.callAsCurrentUser).toHaveBeenCalledTimes(1); @@ -494,7 +494,7 @@ describe('getMonitorStatus', () => { const [callES] = setupMock(criteria); const result = await getMonitorStatus({ callES, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, locations: [], numTimes: 5, timerange: { diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts index faeb291bb533b2..4de7d3ffd2a7d5 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_ping_histogram.test.ts @@ -5,7 +5,7 @@ */ import { getPingHistogram } from '../get_ping_histogram'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; describe('getPingHistogram', () => { const standardMockResponse: any = { @@ -59,7 +59,7 @@ describe('getPingHistogram', () => { const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: 'now-15m', to: 'now', filters: null, @@ -78,7 +78,7 @@ describe('getPingHistogram', () => { const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: 'now-15m', to: 'now', filters: null, @@ -140,7 +140,7 @@ describe('getPingHistogram', () => { const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: '1234', to: '5678', filters: JSON.stringify(searchFilter), @@ -196,7 +196,7 @@ describe('getPingHistogram', () => { const filters = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: 'now-15m', to: 'now', filters, @@ -213,7 +213,7 @@ describe('getPingHistogram', () => { mockEsClient.mockReturnValue(standardMockResponse); const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: '1234', to: '5678', filters: '', @@ -234,7 +234,7 @@ describe('getPingHistogram', () => { const result = await getPingHistogram({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, from: '1234', to: '5678', filters: '', diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts index fcf773db23de67..abd3655cc64028 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_pings.test.ts @@ -6,7 +6,7 @@ import { getPings } from '../get_pings'; import { set } from 'lodash'; -import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; describe('getAll', () => { let mockEsSearchResult: any; @@ -62,7 +62,7 @@ describe('getAll', () => { }, }; expectedGetAllParams = { - index: defaultDynamicSettings.heartbeatIndices, + index: DYNAMIC_SETTINGS_DEFAULTS.heartbeatIndices, body: { query: { bool: { @@ -88,7 +88,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); const result = await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, sort: 'asc', size: 12, @@ -110,7 +110,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, sort: 'asc', size: 12, @@ -166,7 +166,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, size: 12, }); @@ -220,7 +220,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, sort: 'desc', }); @@ -274,7 +274,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, monitorId: 'testmonitorid', }); @@ -333,7 +333,7 @@ describe('getAll', () => { mockEsClient.mockReturnValue(mockEsSearchResult); await getPings({ callES: mockEsClient, - dynamicSettings: defaultDynamicSettings, + dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, dateRange: { from: 'now-1h', to: 'now' }, status: 'down', }); diff --git a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts index a1b731169f0a0d..e7bbe5baa2ad0c 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts @@ -5,8 +5,10 @@ */ import expect from '@kbn/expect'; +import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { defaultDynamicSettings } from '../../../../../legacy/plugins/uptime/common/runtime_types/dynamic_settings'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { DynamicSettingsType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -14,15 +16,16 @@ export default function({ getService }: FtrProviderContext) { describe('dynamic settings', () => { it('returns the defaults when no user settings have been saved', async () => { const apiResponse = await supertest.get(`/api/uptime/dynamic_settings`); - expect(apiResponse.body).to.eql(defaultDynamicSettings as any); + expect(apiResponse.body).to.eql(DYNAMIC_SETTINGS_DEFAULTS); + expect(isRight(DynamicSettingsType.decode(apiResponse.body))).to.be.ok(); }); it('can change the settings', async () => { const newSettings = { heartbeatIndices: 'myIndex1*', certificatesThresholds: { - errorState: 5, - warningState: 15, + expiration: 5, + age: 15, }, }; const postResponse = await supertest @@ -35,6 +38,7 @@ export default function({ getService }: FtrProviderContext) { const getResponse = await supertest.get(`/api/uptime/dynamic_settings`); expect(getResponse.body).to.eql(newSettings); + expect(isRight(DynamicSettingsType.decode(getResponse.body))).to.be.ok(); }); }); } diff --git a/x-pack/test/functional/apps/uptime/settings.ts b/x-pack/test/functional/apps/uptime/settings.ts index e81bbc5ae42f92..8f7aab7aa6e295 100644 --- a/x-pack/test/functional/apps/uptime/settings.ts +++ b/x-pack/test/functional/apps/uptime/settings.ts @@ -6,10 +6,8 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { - defaultDynamicSettings, - DynamicSettings, -} from '../../../../legacy/plugins/uptime/common/runtime_types'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../legacy/plugins/uptime/common/constants'; +import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; import { makeChecks } from '../../../api_integration/apis/uptime/rest/helper/make_checks'; export default ({ getPageObjects, getService }: FtrProviderContext) => { @@ -32,7 +30,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await settings.go(); const fields = await settings.loadFields(); - expect(fields).to.eql(defaultDynamicSettings); + expect(fields).to.eql(DYNAMIC_SETTINGS_DEFAULTS); }); it('should disable the apply button when invalid or unchanged', async () => { @@ -91,7 +89,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certificatesThresholds.errorState).to.eql(newErrorThreshold); + expect(fields.certificatesThresholds?.expiration).to.eql(newErrorThreshold); }); it('changing certificate expiration warning threshold is reflected in settings page', async () => { @@ -108,7 +106,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certificatesThresholds.warningState).to.eql(newWarningThreshold); + expect(fields.certificatesThresholds?.age).to.eql(newWarningThreshold); }); }); }; diff --git a/x-pack/test/functional/services/uptime/settings.ts b/x-pack/test/functional/services/uptime/settings.ts index 14cab368b766a2..4700a3585c8a6f 100644 --- a/x-pack/test/functional/services/uptime/settings.ts +++ b/x-pack/test/functional/services/uptime/settings.ts @@ -5,6 +5,7 @@ */ import { FtrProviderContext } from '../../ftr_provider_context'; +import { DynamicSettings } from '../../../../legacy/plugins/uptime/common/runtime_types'; export function UptimeSettingsProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); @@ -25,24 +26,24 @@ export function UptimeSettingsProvider({ getService }: FtrProviderContext) { await changeInputField(text, 'heartbeat-indices-input-loaded'); }, changeErrorThresholdInput: async (text: string) => { - await changeInputField(text, 'error-state-threshold-input-loaded'); + await changeInputField(text, 'expiration-threshold-input-loaded'); }, changeWarningThresholdInput: async (text: string) => { - await changeInputField(text, 'warning-state-threshold-input-loaded'); + await changeInputField(text, 'age-threshold-input-loaded'); }, - loadFields: async () => { + loadFields: async (): Promise => { const indInput = await testSubjects.find('heartbeat-indices-input-loaded', 5000); - const errorInput = await testSubjects.find('error-state-threshold-input-loaded', 5000); - const warningInput = await testSubjects.find('warning-state-threshold-input-loaded', 5000); + const errorInput = await testSubjects.find('expiration-threshold-input-loaded', 5000); + const warningInput = await testSubjects.find('age-threshold-input-loaded', 5000); const heartbeatIndices = await indInput.getAttribute('value'); - const errorThreshold = await errorInput.getAttribute('value'); - const warningThreshold = await warningInput.getAttribute('value'); + const expiration = await errorInput.getAttribute('value'); + const age = await warningInput.getAttribute('value'); return { heartbeatIndices, certificatesThresholds: { - errorState: errorThreshold, - warningState: warningThreshold, + age: parseInt(age, 10), + expiration: parseInt(expiration, 10), }, }; }, From d0246a72202ca58952fefdec026b7d5e2106b5f3 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 10:28:28 -0400 Subject: [PATCH 03/10] Modify default expiration threshold. --- .../legacy/plugins/uptime/common/constants/settings_defaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts index b77e5da983144c..f7eee27ba438dc 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts @@ -9,7 +9,7 @@ import { DynamicSettings } from '../runtime_types'; export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = { heartbeatIndices: 'heartbeat-8*', certificatesThresholds: { - expiration: 7, + expiration: 30, age: 365, }, }; From f7678b685567f28ccb34c78f6010710b17c1b4b7 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 10:39:15 -0400 Subject: [PATCH 04/10] Rename test vars. --- x-pack/test/functional/services/uptime/settings.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional/services/uptime/settings.ts b/x-pack/test/functional/services/uptime/settings.ts index 4700a3585c8a6f..1eb19d2993e283 100644 --- a/x-pack/test/functional/services/uptime/settings.ts +++ b/x-pack/test/functional/services/uptime/settings.ts @@ -33,11 +33,11 @@ export function UptimeSettingsProvider({ getService }: FtrProviderContext) { }, loadFields: async (): Promise => { const indInput = await testSubjects.find('heartbeat-indices-input-loaded', 5000); - const errorInput = await testSubjects.find('expiration-threshold-input-loaded', 5000); - const warningInput = await testSubjects.find('age-threshold-input-loaded', 5000); + const expirationInput = await testSubjects.find('expiration-threshold-input-loaded', 5000); + const ageInput = await testSubjects.find('age-threshold-input-loaded', 5000); const heartbeatIndices = await indInput.getAttribute('value'); - const expiration = await errorInput.getAttribute('value'); - const age = await warningInput.getAttribute('value'); + const expiration = await expirationInput.getAttribute('value'); + const age = await ageInput.getAttribute('value'); return { heartbeatIndices, From 0ddd97b6031717ab5176f3fa5c9d8cfa4e435529 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 12:15:49 -0400 Subject: [PATCH 05/10] Implement PR feedback. --- .../common/constants/settings_defaults.ts | 2 +- .../common/runtime_types/dynamic_settings.ts | 16 +- .../__tests__/certificate_form.test.tsx | 3 +- .../settings/__tests__/indices_form.test.tsx | 3 +- .../components/settings/certificate_form.tsx | 246 +++++++++--------- .../components/settings/indices_form.tsx | 112 ++++---- .../plugins/uptime/public/pages/settings.tsx | 34 ++- .../public/state/reducers/dynamic_settings.ts | 5 +- .../uptime/public/state/selectors/index.ts | 4 +- .../uptime/server/lib/saved_objects.ts | 2 +- .../test/functional/apps/uptime/settings.ts | 12 +- .../functional/services/uptime/settings.ts | 2 +- 12 files changed, 230 insertions(+), 211 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts index f7eee27ba438dc..b7986679a09cad 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/settings_defaults.ts @@ -8,7 +8,7 @@ import { DynamicSettings } from '../runtime_types'; export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = { heartbeatIndices: 'heartbeat-8*', - certificatesThresholds: { + certThresholds: { expiration: 30, age: 365, }, diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts index 1cd8682510d736..da887cc5055c10 100644 --- a/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts +++ b/x-pack/legacy/plugins/uptime/common/runtime_types/dynamic_settings.ts @@ -6,19 +6,15 @@ import * as t from 'io-ts'; -export const CertificatesStatesThresholdType = t.partial({ +export const CertStateThresholdsType = t.type({ age: t.number, expiration: t.number, }); -export const DynamicSettingsType = t.intersection([ - t.type({ - heartbeatIndices: t.string, - }), - t.partial({ - certificatesThresholds: CertificatesStatesThresholdType, - }), -]); +export const DynamicSettingsType = t.type({ + heartbeatIndices: t.string, + certThresholds: CertStateThresholdsType, +}); export const DynamicSettingsSaveType = t.intersection([ t.type({ @@ -31,4 +27,4 @@ export const DynamicSettingsSaveType = t.intersection([ export type DynamicSettings = t.TypeOf; export type DynamicSettingsSaveResponse = t.TypeOf; -export type CertificatesStatesThreshold = t.TypeOf; +export type CertStateThresholds = t.TypeOf; diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx index 9e8c722b72cc58..b396a92828d22b 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx @@ -13,10 +13,11 @@ describe('CertificateForm', () => { expect( shallowWithRouter( { expect( shallowWithRouter( ) => void; +interface ChangedValues { + heartbeatIndices?: string; + certThresholds?: Partial; +} + +export type OnFieldChangeType = (changedValues: ChangedValues) => void; export interface SettingsFormProps { + loading: boolean; onChange: OnFieldChangeType; formFields: DynamicSettings | null; fieldErrors: any; @@ -31,135 +36,134 @@ export interface SettingsFormProps { } export const CertificateExpirationForm: React.FC = ({ + loading, onChange, formFields, fieldErrors, isDisabled, -}) => { - const dss = useSelector(selectDynamicSettings); - - return ( - <> - -

+}) => ( + <> + +

+ +

+
+ + +

+ } + description={ + + } + > + {DYNAMIC_SETTINGS_DEFAULTS.certThresholds.expiration} + ), + }} /> - -
- - - - } - description={ + isInvalid={!!fieldErrors?.certificatesThresholds?.errorState} + label={ } > - {dss.settings.certificatesThresholds?.expiration}, - }} + + + + onChange({ + certThresholds: { + expiration: Number(e.target.value), + }, + }) + } /> - } - isInvalid={!!fieldErrors?.certificatesThresholds?.errorState} - label={ - - } - > - - - - onChange({ - certificatesThresholds: { - expiration: Number(value), - }, - }) - } + + + + - - - - - - - - - {dss.settings.certificatesThresholds?.age}, - }} - /> - } - isInvalid={!!fieldErrors?.certificatesThresholds?.warningState} - label={ - +
+
+ + {DYNAMIC_SETTINGS_DEFAULTS.certThresholds.age}, + }} + /> + } + isInvalid={!!fieldErrors?.certificatesThresholds?.warningState} + label={ + + } + > + + + + onChange({ + certThresholds: { age: Number(e.currentTarget.value) }, + }) + } /> - } - > - - - - onChange({ - certificatesThresholds: { age: Number(event.currentTarget.value) }, - }) - } + + + + - - - - - - - - - - - ); -}; + +
+
+ + + +); diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx index c3f0342ef3ea5b..23c93da8896e26 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx @@ -6,7 +6,6 @@ import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { useSelector } from 'react-redux'; import { EuiDescribedFormGroup, EuiFormRow, @@ -15,75 +14,72 @@ import { EuiTitle, EuiSpacer, } from '@elastic/eui'; -import { selectDynamicSettings } from '../../state/selectors'; import { SettingsFormProps } from './certificate_form'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants'; export const IndicesForm: React.FC = ({ onChange, + loading, formFields, fieldErrors, isDisabled, -}) => { - const dss = useSelector(selectDynamicSettings); - - return ( - <> - -

+}) => ( + <> + +

+ +

+
+ + + +

+ } + description={ + + } + > + {DYNAMIC_SETTINGS_DEFAULTS.heartbeatIndices}, + }} /> - -
- - - - } - description={ + isInvalid={!!fieldErrors?.heartbeatIndices} + label={ } > - {dss.settings.heartbeatIndices}, - }} - /> - } - isInvalid={!!fieldErrors?.heartbeatIndices} - label={ - - } - > - onChange({ heartbeatIndices: event.currentTarget.value })} - /> - - - - ); -}; + disabled={isDisabled} + isLoading={loading} + value={formFields?.heartbeatIndices || ''} + onChange={(event: any) => onChange({ heartbeatIndices: event.currentTarget.value })} + /> + + + +); diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx index 31f3433d3ccdac..58e6b83d334fd5 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { useDispatch, useSelector } from 'react-redux'; -import { isEqual, merge } from 'lodash'; +import { isEqual } from 'lodash'; import { Link } from 'react-router-dom'; import { selectDynamicSettings } from '../state/selectors'; import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic_settings'; @@ -36,7 +36,7 @@ import * as Translations from './translations'; const getFieldErrors = (formFields: DynamicSettings | null) => { if (formFields) { const blankStr = 'May not be blank'; - const { certificatesThresholds, heartbeatIndices } = formFields; + const { certThresholds: certificatesThresholds, heartbeatIndices } = formFields; const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr; const errorStateErr = certificatesThresholds?.expiration ? null : blankStr; const warningStateErr = certificatesThresholds?.age ? null : blankStr; @@ -67,21 +67,39 @@ export const SettingsPage = () => { dispatch(getDynamicSettings()); }, [dispatch]); - const [formFields, setFormFields] = useState({ ...dss.settings }); + const [formFields, setFormFields] = useState( + dss.settings ? { ...dss.settings } : null + ); + + if (!dss.loadError && formFields === null && dss.settings) { + setFormFields(Object.assign({}, { ...dss.settings })); + } const fieldErrors = getFieldErrors(formFields); const isFormValid = !(fieldErrors && Object.values(fieldErrors).find(v => !!v)); - const onChangeFormField: OnFieldChangeType = changedField => - setFormFields(Object.assign({ ...merge(formFields, changedField) })); + const onChangeFormField: OnFieldChangeType = changedField => { + if (formFields) { + setFormFields({ + heartbeatIndices: changedField.heartbeatIndices ?? formFields.heartbeatIndices, + certThresholds: Object.assign( + {}, + formFields.certThresholds, + changedField?.certThresholds ?? null + ), + }); + } + }; const onApply = (event: React.FormEvent) => { event.preventDefault(); - dispatch(setDynamicSettings(formFields)); + if (formFields) { + dispatch(setDynamicSettings(formFields)); + } }; - const resetForm = () => setFormFields({ ...dss.settings }); + const resetForm = () => setFormFields(dss.settings ? { ...dss.settings } : null); const isFormDirty = !isEqual(dss.settings, formFields); const canEdit: boolean = @@ -114,12 +132,14 @@ export const SettingsPage = () => {
( loading: true, }), [String(setDynamicSettingsSuccess)]: (state, action: Action) => ({ - ...state, settings: action.payload, saveSucceded: true, loading: false, diff --git a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts index 7260c61f441473..15fc8b8a7b1735 100644 --- a/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/legacy/plugins/uptime/public/state/selectors/index.ts @@ -24,9 +24,7 @@ export const monitorLocationsSelector = (state: AppState, monitorId: string) => export const monitorStatusSelector = (state: AppState) => state.monitorStatus.status; -export const selectDynamicSettings = (state: AppState) => { - return state.dynamicSettings; -}; +export const selectDynamicSettings = (state: AppState) => state.dynamicSettings; export const selectIndexPattern = ({ indexPattern }: AppState) => { return { indexPattern: indexPattern.index_pattern, loading: indexPattern.loading }; diff --git a/x-pack/plugins/uptime/server/lib/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects.ts index 0e52207e234081..d849fbd8ce0a8f 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects.ts @@ -26,7 +26,7 @@ export const umDynamicSettings: SavedObjectsType = { heartbeatIndices: { type: 'keyword', }, - certificatesThresholds: { + certThresholds: { properties: { expiration: { type: 'long', diff --git a/x-pack/test/functional/apps/uptime/settings.ts b/x-pack/test/functional/apps/uptime/settings.ts index 8f7aab7aa6e295..64b6300e0df631 100644 --- a/x-pack/test/functional/apps/uptime/settings.ts +++ b/x-pack/test/functional/apps/uptime/settings.ts @@ -60,7 +60,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await settings.go(); - const newFieldValues: DynamicSettings = { heartbeatIndices: 'new*' }; + const newFieldValues: DynamicSettings = { + heartbeatIndices: 'new*', + certThresholds: { + age: 365, + expiration: 30, + }, + }; await settings.changeHeartbeatIndicesInput(newFieldValues.heartbeatIndices); await settings.apply(); @@ -89,7 +95,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certificatesThresholds?.expiration).to.eql(newErrorThreshold); + expect(fields.certThresholds?.expiration).to.eql(newErrorThreshold); }); it('changing certificate expiration warning threshold is reflected in settings page', async () => { @@ -106,7 +112,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certificatesThresholds?.age).to.eql(newWarningThreshold); + expect(fields.certThresholds?.age).to.eql(newWarningThreshold); }); }); }; diff --git a/x-pack/test/functional/services/uptime/settings.ts b/x-pack/test/functional/services/uptime/settings.ts index 1eb19d2993e283..9719152b62d354 100644 --- a/x-pack/test/functional/services/uptime/settings.ts +++ b/x-pack/test/functional/services/uptime/settings.ts @@ -41,7 +41,7 @@ export function UptimeSettingsProvider({ getService }: FtrProviderContext) { return { heartbeatIndices, - certificatesThresholds: { + certThresholds: { age: parseInt(age, 10), expiration: parseInt(expiration, 10), }, From ef2128680c1aef190873433730c37d808fbf74f4 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 12:59:34 -0400 Subject: [PATCH 06/10] Refresh snapshots, fix broken tests/types. --- .../__snapshots__/certificate_form.test.tsx.snap | 3 ++- .../__tests__/__snapshots__/indices_form.test.tsx.snap | 3 ++- .../server/lib/alerts/__tests__/status_check.test.ts | 8 ++++---- .../server/lib/requests/__tests__/get_certs.test.ts | 6 +++++- .../api_integration/apis/uptime/rest/dynamic_settings.ts | 2 +- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap index 4e1d477c9ec5a6..a0fab80ace84ee 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap @@ -55,7 +55,7 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = fieldErrors={Object {}} formFields={ Object { - "certificatesThresholds": Object { + "certThresholds": Object { "age": 36, "expiration": 7, }, @@ -63,6 +63,7 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = } } isDisabled={false} + loading={false} onChange={[MockFunction]} /> diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap index 108dcf71b692fe..6b9ce5a4b69479 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap @@ -55,7 +55,7 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = fieldErrors={Object {}} formFields={ Object { - "certificatesThresholds": Object { + "certThresholds": Object { "age": 36, "expiration": 7, }, @@ -63,6 +63,7 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = } } isDisabled={false} + loading={false} onChange={[MockFunction]} /> diff --git a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts index fe14986e0d2c6b..4f4c6e3011ad14 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts @@ -88,9 +88,9 @@ describe('status check alert', () => { Object { "callES": [MockFunction], "dynamicSettings": Object { - "certificatesThresholds": Object { + "certThresholds": Object { "age": 365, - "expiration": 7, + "expiration": 30, }, "heartbeatIndices": "heartbeat-8*", }, @@ -135,9 +135,9 @@ describe('status check alert', () => { Object { "callES": [MockFunction], "dynamicSettings": Object { - "certificatesThresholds": Object { + "certThresholds": Object { "age": 365, - "expiration": 7, + "expiration": 30, }, "heartbeatIndices": "heartbeat-8*", }, diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts index 539344dfca791f..b49a6b22ff9768 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -5,6 +5,7 @@ */ import { getCerts } from '../get_certs'; +import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants'; describe('getCerts', () => { let mockHits: any; @@ -86,7 +87,10 @@ describe('getCerts', () => { it('parses query result and returns expected values', async () => { const result = await getCerts({ callES: mockCallES, - dynamicSettings: { heartbeatIndices: 'heartbeat*' }, + dynamicSettings: { + heartbeatIndices: 'heartbeat*', + certThresholds: DYNAMIC_SETTINGS_DEFAULTS.certThresholds, + }, index: 1, from: 'now-2d', to: 'now+1h', diff --git a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts index e7bbe5baa2ad0c..ea980721b831bb 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts @@ -23,7 +23,7 @@ export default function({ getService }: FtrProviderContext) { it('can change the settings', async () => { const newSettings = { heartbeatIndices: 'myIndex1*', - certificatesThresholds: { + certThresholds: { expiration: 5, age: 15, }, From 84129513f7463ec7dddf2b78be245291f3bb8517 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 13:08:46 -0400 Subject: [PATCH 07/10] Remove unnecessary state spreading. --- .../uptime/public/state/reducers/dynamic_settings.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts index 624bb8a51c4810..a9ad58e64e5529 100644 --- a/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts +++ b/x-pack/legacy/plugins/uptime/public/state/reducers/dynamic_settings.ts @@ -31,13 +31,11 @@ export const dynamicSettingsReducer = handleActions( ...state, loading: true, }), - [String(getDynamicSettingsSuccess)]: (state, action: Action) => ({ - ...state, + [String(getDynamicSettingsSuccess)]: (_state, action: Action) => ({ loading: false, settings: action.payload, }), - [String(getDynamicSettingsFail)]: (state, action: Action) => ({ - ...state, + [String(getDynamicSettingsFail)]: (_state, action: Action) => ({ loading: false, loadError: action.payload, }), @@ -45,7 +43,7 @@ export const dynamicSettingsReducer = handleActions( ...state, loading: true, }), - [String(setDynamicSettingsSuccess)]: (state, action: Action) => ({ + [String(setDynamicSettingsSuccess)]: (_state, action: Action) => ({ settings: action.payload, saveSucceded: true, loading: false, From 59e60e8b5b830f0fc21fd793cd75137f9675124e Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 13:26:58 -0400 Subject: [PATCH 08/10] Add type for settings field errors. --- .../__tests__/certificate_form.test.tsx | 2 +- .../settings/__tests__/indices_form.test.tsx | 2 +- .../components/settings/certificate_form.tsx | 19 ++++--------- .../components/settings/indices_form.tsx | 2 +- .../plugins/uptime/public/pages/settings.tsx | 28 +++++++++++++++---- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx index b396a92828d22b..3d4bd58aabe0f6 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx @@ -19,7 +19,7 @@ describe('CertificateForm', () => { heartbeatIndices: 'heartbeat-8*', certThresholds: { expiration: 7, age: 36 }, }} - fieldErrors={{}} + fieldErrors={null} isDisabled={false} /> ) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx index 5c635250d19e60..07a3bf81e39d83 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx @@ -19,7 +19,7 @@ describe('CertificateForm', () => { heartbeatIndices: 'heartbeat-8*', certThresholds: { expiration: 7, age: 36 }, }} - fieldErrors={{}} + fieldErrors={null} isDisabled={false} /> ) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx index db74b91faa255c..1927e4389e6922 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx @@ -17,8 +17,9 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import { DynamicSettings, CertStateThresholds } from '../../../common/runtime_types'; +import { CertStateThresholds } from '../../../common/runtime_types'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants'; +import { SettingsFormProps } from '../../pages/settings'; interface ChangedValues { heartbeatIndices?: string; @@ -27,14 +28,6 @@ interface ChangedValues { export type OnFieldChangeType = (changedValues: ChangedValues) => void; -export interface SettingsFormProps { - loading: boolean; - onChange: OnFieldChangeType; - formFields: DynamicSettings | null; - fieldErrors: any; - isDisabled: boolean; -} - export const CertificateExpirationForm: React.FC = ({ loading, onChange, @@ -70,7 +63,7 @@ export const CertificateExpirationForm: React.FC = ({ > = ({ }} /> } - isInvalid={!!fieldErrors?.certificatesThresholds?.errorState} + isInvalid={!!fieldErrors?.certificatesThresholds?.expirationThresholdError} label={ = ({ = ({ }} /> } - isInvalid={!!fieldErrors?.certificatesThresholds?.warningState} + isInvalid={!!fieldErrors?.certificatesThresholds?.ageThresholdError} label={ = ({ onChange, diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx index 58e6b83d334fd5..d8c2a780928541 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx @@ -33,20 +33,36 @@ import { } from '../components/settings/certificate_form'; import * as Translations from './translations'; -const getFieldErrors = (formFields: DynamicSettings | null) => { +interface SettingsPageFieldErrors { + heartbeatIndices: 'May not be blank' | ''; + certificatesThresholds: { + expirationThresholdError: string | null; + ageThresholdError: string | null; + } | null; +} + +export interface SettingsFormProps { + loading: boolean; + onChange: OnFieldChangeType; + formFields: DynamicSettings | null; + fieldErrors: SettingsPageFieldErrors | null; + isDisabled: boolean; +} + +const getFieldErrors = (formFields: DynamicSettings | null): SettingsPageFieldErrors | null => { if (formFields) { const blankStr = 'May not be blank'; const { certThresholds: certificatesThresholds, heartbeatIndices } = formFields; const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr; - const errorStateErr = certificatesThresholds?.expiration ? null : blankStr; - const warningStateErr = certificatesThresholds?.age ? null : blankStr; + const expirationThresholdError = certificatesThresholds?.expiration ? null : blankStr; + const ageThresholdError = certificatesThresholds?.age ? null : blankStr; return { heartbeatIndices: heartbeatIndErr, certificatesThresholds: - errorStateErr || warningStateErr + expirationThresholdError || ageThresholdError ? { - errorState: errorStateErr, - warningState: warningStateErr, + expirationThresholdError, + ageThresholdError, } : null, }; From d47d4295de5f67008a6c7106460b74bc84b71b75 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 23 Apr 2020 13:30:08 -0400 Subject: [PATCH 09/10] Refresh test snapshots. --- .../__tests__/__snapshots__/certificate_form.test.tsx.snap | 2 +- .../settings/__tests__/__snapshots__/indices_form.test.tsx.snap | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap index a0fab80ace84ee..96d472c91680dc 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap +++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap @@ -52,7 +52,7 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = } > Date: Thu, 23 Apr 2020 13:34:02 -0400 Subject: [PATCH 10/10] Improve punctuation. --- .../uptime/public/components/settings/certificate_form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx index 1927e4389e6922..209e38785e1651 100644 --- a/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx @@ -57,7 +57,7 @@ export const CertificateExpirationForm: React.FC = ({ description={ } >