From 14bb0d1e58b0312643cbc2e822a163c046acd081 Mon Sep 17 00:00:00 2001
From: Shahzad
Date: Thu, 16 Apr 2020 21:13:35 +0200
Subject: [PATCH 1/5] [Uptime] Certificate expiration threshold settings
(#63682)
* update settings
* added cert form
* update settings
* update types
* update test
* updated tests
* updated snapshots
---
.../common/runtime_types/dynamic_settings.ts | 19 +-
.../certificate_form.test.tsx.snap | 69 ++++++++
.../__snapshots__/indices_form.test.tsx.snap | 69 ++++++++
.../__tests__/certificate_form.test.tsx | 27 +++
.../settings/__tests__/indices_form.test.tsx | 27 +++
.../components/settings/certificate_form.tsx | 160 +++++++++++++++++
.../components/settings/indices_form.tsx | 90 ++++++++++
.../plugins/uptime/public/pages/settings.tsx | 163 ++++++------------
.../lib/alerts/__tests__/status_check.test.ts | 8 +
.../uptime/server/lib/saved_objects.ts | 16 +-
.../apis/uptime/rest/dynamic_settings.ts | 8 +-
.../test/functional/apps/uptime/settings.ts | 36 +++-
.../functional/services/uptime/settings.ts | 33 +++-
13 files changed, 601 insertions(+), 124 deletions(-)
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx
create mode 100644 x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx
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 6f844447d5b4a4..dc9670bb23d851 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,10 +6,20 @@
import * as t from 'io-ts';
-export const DynamicSettingsType = t.type({
- heartbeatIndices: t.string,
+export const CertificatesStatesThresholdType = t.interface({
+ warningState: t.number,
+ errorState: t.number,
});
+export const DynamicSettingsType = t.intersection([
+ t.type({
+ heartbeatIndices: t.string,
+ }),
+ t.partial({
+ certificatesThresholds: CertificatesStatesThresholdType,
+ }),
+]);
+
export const DynamicSettingsSaveType = t.intersection([
t.type({
success: t.boolean,
@@ -21,7 +31,12 @@ 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-7*',
+ certificatesThresholds: {
+ errorState: 7,
+ warningState: 30,
+ },
};
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
new file mode 100644
index 00000000000000..36bc9bb8602111
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CertificateForm shallow renders expected elements for valid props 1`] = `
+
+
+
+`;
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
new file mode 100644
index 00000000000000..93151198c0f494
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CertificateForm shallow renders expected elements for valid props 1`] = `
+
+
+
+`;
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
new file mode 100644
index 00000000000000..a3158f3d724456
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx
@@ -0,0 +1,27 @@
+/*
+ * 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 React from 'react';
+import { CertificateExpirationForm } from '../certificate_form';
+import { shallowWithRouter } from '../../../lib';
+
+describe('CertificateForm', () => {
+ it('shallow renders expected elements for valid props', () => {
+ expect(
+ shallowWithRouter(
+
+ )
+ ).toMatchSnapshot();
+ });
+});
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
new file mode 100644
index 00000000000000..654d51019d4e57
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx
@@ -0,0 +1,27 @@
+/*
+ * 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 React from 'react';
+import { IndicesForm } from '../indices_form';
+import { shallowWithRouter } from '../../../lib';
+
+describe('CertificateForm', () => {
+ it('shallow renders expected elements for valid props', () => {
+ expect(
+ shallowWithRouter(
+
+ )
+ ).toMatchSnapshot();
+ });
+});
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
new file mode 100644
index 00000000000000..5103caee1e1c05
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/certificate_form.tsx
@@ -0,0 +1,160 @@
+/*
+ * 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 React from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { useSelector } from 'react-redux';
+import {
+ EuiDescribedFormGroup,
+ EuiFormRow,
+ EuiCode,
+ EuiFieldNumber,
+ EuiTitle,
+ EuiSpacer,
+ EuiSelect,
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '@elastic/eui';
+import { defaultDynamicSettings, DynamicSettings } from '../../../common/runtime_types';
+import { selectDynamicSettings } from '../../state/selectors';
+
+type NumStr = string | number;
+
+export type OnFieldChangeType = (field: string, value?: NumStr) => void;
+
+export interface SettingsFormProps {
+ onChange: OnFieldChangeType;
+ formFields: DynamicSettings | null;
+ fieldErrors: any;
+ isDisabled: boolean;
+}
+
+export const CertificateExpirationForm: React.FC = ({
+ onChange,
+ formFields,
+ fieldErrors,
+ isDisabled,
+}) => {
+ const dss = useSelector(selectDynamicSettings);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ }
+ description={
+
+ }
+ >
+ {defaultDynamicSettings?.certificatesThresholds?.errorState}
+ ),
+ }}
+ />
+ }
+ isInvalid={!!fieldErrors?.certificatesThresholds?.errorState}
+ label={
+
+ }
+ >
+
+
+
+ onChange(
+ 'certificatesThresholds.errorState',
+ value === '' ? undefined : Number(value)
+ )
+ }
+ />
+
+
+
+
+
+
+ {defaultDynamicSettings?.certificatesThresholds?.warningState}
+ ),
+ }}
+ />
+ }
+ isInvalid={!!fieldErrors?.certificatesThresholds?.warningState}
+ label={
+
+ }
+ >
+
+
+
+ onChange('certificatesThresholds.warningState', 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
new file mode 100644
index 00000000000000..c28eca2ea229e5
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/settings/indices_form.tsx
@@ -0,0 +1,90 @@
+/*
+ * 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 React from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { useSelector } from 'react-redux';
+import {
+ EuiDescribedFormGroup,
+ EuiFormRow,
+ EuiCode,
+ EuiFieldText,
+ EuiTitle,
+ EuiSpacer,
+} from '@elastic/eui';
+import { defaultDynamicSettings } from '../../../common/runtime_types';
+import { selectDynamicSettings } from '../../state/selectors';
+import { SettingsFormProps } from './certificate_form';
+
+export const IndicesForm: React.FC = ({
+ onChange,
+ formFields,
+ fieldErrors,
+ isDisabled,
+}) => {
+ const dss = useSelector(selectDynamicSettings);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ }
+ description={
+
+ }
+ >
+ {defaultDynamicSettings.heartbeatIndices},
+ }}
+ />
+ }
+ isInvalid={!!fieldErrors?.heartbeatIndices}
+ label={
+
+ }
+ >
+ 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 765b0e3c664bc0..049dffecd3f2ef 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
@@ -9,46 +9,54 @@ import {
EuiButton,
EuiButtonEmpty,
EuiCallOut,
- EuiCode,
- EuiDescribedFormGroup,
- EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
EuiForm,
- EuiFormRow,
EuiPanel,
EuiSpacer,
- EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { connect } from 'react-redux';
-import { isEqual } from 'lodash';
+import { useDispatch, useSelector } from 'react-redux';
+import { cloneDeep, isEqual, set } from 'lodash';
import { i18n } from '@kbn/i18n';
import { Link } from 'react-router-dom';
-import { AppState } from '../state';
import { selectDynamicSettings } from '../state/selectors';
-import { DynamicSettingsState } from '../state/reducers/dynamic_settings';
import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic_settings';
-import { defaultDynamicSettings, DynamicSettings } from '../../common/runtime_types';
+import { DynamicSettings } from '../../common/runtime_types';
import { useBreadcrumbs } from '../hooks/use_breadcrumbs';
import { OVERVIEW_ROUTE } from '../../common/constants';
import { useKibana } from '../../../../../../src/plugins/kibana_react/public';
import { UptimePage, useUptimeTelemetry } from '../hooks';
+import { IndicesForm } from '../components/settings/indices_form';
+import {
+ CertificateExpirationForm,
+ OnFieldChangeType,
+} from '../components/settings/certificate_form';
+
+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;
+ return {
+ heartbeatIndices: heartbeatIndErr,
+ certificatesThresholds:
+ errorStateErr || warningStateErr
+ ? {
+ errorState: errorStateErr,
+ warningState: warningStateErr,
+ }
+ : null,
+ };
+ }
+ return null;
+};
-interface Props {
- dynamicSettingsState: DynamicSettingsState;
-}
-
-interface DispatchProps {
- dispatchGetDynamicSettings: typeof getDynamicSettings;
- dispatchSetDynamicSettings: typeof setDynamicSettings;
-}
+export const SettingsPage = () => {
+ const dss = useSelector(selectDynamicSettings);
-export const SettingsPageComponent = ({
- dynamicSettingsState: dss,
- dispatchGetDynamicSettings,
- dispatchSetDynamicSettings,
-}: Props & DispatchProps) => {
const settingsBreadcrumbText = i18n.translate('xpack.uptime.settingsBreadcrumbText', {
defaultMessage: 'Settings',
});
@@ -56,9 +64,11 @@ export const SettingsPageComponent = ({
useUptimeTelemetry(UptimePage.Settings);
+ const dispatch = useDispatch();
+
useEffect(() => {
- dispatchGetDynamicSettings({});
- }, [dispatchGetDynamicSettings]);
+ dispatch(getDynamicSettings({}));
+ }, [dispatch]);
const [formFields, setFormFields] = useState(dss.settings || null);
@@ -66,22 +76,22 @@ export const SettingsPageComponent = ({
setFormFields({ ...dss.settings });
}
- const fieldErrors = formFields && {
- heartbeatIndices: formFields.heartbeatIndices.match(/^\S+$/) ? null : 'May not be blank',
- };
+ const fieldErrors = getFieldErrors(formFields);
+
const isFormValid = !(fieldErrors && Object.values(fieldErrors).find(v => !!v));
- const onChangeFormField = (field: keyof DynamicSettings, value: any) => {
+ const onChangeFormField: OnFieldChangeType = (field, value) => {
if (formFields) {
- formFields[field] = value;
- setFormFields({ ...formFields });
+ const newFormFields = cloneDeep(formFields);
+ set(newFormFields, field, value);
+ setFormFields(cloneDeep(newFormFields));
}
};
const onApply = (event: React.FormEvent) => {
event.preventDefault();
if (formFields) {
- dispatchSetDynamicSettings(formFields);
+ dispatch(setDynamicSettings(formFields));
}
};
@@ -128,68 +138,18 @@ export const SettingsPageComponent = ({
- }
- iconType="uptimeApp"
- title={
-
-
- bar
-
-
- }
- />
-
-
-
-`;
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap
new file mode 100644
index 00000000000000..25ac5a1f0974e9
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap
@@ -0,0 +1,92 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DataOrIndexMissing component renders headingMessage 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+
+ }
+ iconType="logoUptime"
+ title={
+
+
+
+ heartbeat-*
+ ,
+ }
+ }
+ />
+
+
+ }
+ />
+
+
+
+`;
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap
deleted file mode 100644
index 66100f717244d5..00000000000000
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap
+++ /dev/null
@@ -1,1141 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`EmptyState component does not render empty state with appropriate base path and no docs 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- }
- }
- />
-
- }
- iconType="uptimeApp"
- title={
-
-
- No uptime data found
-
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
- No uptime data found
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`EmptyState component doesn't render child components when count is falsy 1`] = `
-
-
-
-
-
-
-
- Loading…
-
-
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
- Loading…
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`EmptyState component notifies when index does not exist 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- }
- }
- />
-
- }
- iconType="uptimeApp"
- title={
-
-
- Uptime index not found
-
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Uptime index not found
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`EmptyState component renders child components when count is truthy 1`] = `
-
-
- Foo
-
-
- Bar
-
-
- Baz
-
-
-`;
-
-exports[`EmptyState component renders error message when an error occurs 1`] = `
-
-
-
-
-
-
-
-
-
-
- There was an error fetching your data.
-
-
- }
- iconColor="subdued"
- iconType="securityApp"
- title={
-
-
- Error
-
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
- Error
-
-
-
-
-
-
-
-
-
- There was an error fetching your data.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`EmptyState component renders loading state if no errors or doc count 1`] = `
-
-
-
-
-
-
-
- Loading…
-
-
-
- }
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
- Loading…
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_missing.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_missing.test.tsx
deleted file mode 100644
index 8605d2966aaaec..00000000000000
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_missing.test.tsx
+++ /dev/null
@@ -1,16 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { shallowWithIntl } from 'test_utils/enzyme_helpers';
-import React from 'react';
-import { DataMissing } from '../data_missing';
-
-describe('DataMissing component', () => {
- it('renders basePath and headingMessage', () => {
- const component = shallowWithIntl( );
- expect(component).toMatchSnapshot();
- });
-});
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_or_index_missing.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_or_index_missing.test.tsx
new file mode 100644
index 00000000000000..333802962fd3e1
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/data_or_index_missing.test.tsx
@@ -0,0 +1,24 @@
+/*
+ * 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 React from 'react';
+import { shallowWithIntl } from 'test_utils/enzyme_helpers';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { DataOrIndexMissing } from '../data_or_index_missing';
+
+describe('DataOrIndexMissing component', () => {
+ it('renders headingMessage', () => {
+ const headingMessage = (
+ heartbeat-* }}
+ />
+ );
+ const component = shallowWithIntl( );
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx
index a74ad543c3318f..acfe2ada5b68d1 100644
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx
@@ -5,11 +5,11 @@
*/
import React from 'react';
-import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { EmptyStateComponent } from '../empty_state';
import { StatesIndexStatus } from '../../../../../common/runtime_types';
import { IHttpFetchError } from '../../../../../../../../../target/types/core/public/http';
import { HttpFetchError } from '../../../../../../../../../src/core/public/http/http_fetch_error';
+import { mountWithRouter, shallowWithRouter } from '../../../../lib';
describe('EmptyState component', () => {
let statesIndexStatus: StatesIndexStatus;
@@ -22,7 +22,7 @@ describe('EmptyState component', () => {
});
it('renders child components when count is truthy', () => {
- const component = shallowWithIntl(
+ const component = shallowWithRouter(
Foo
Bar
@@ -33,7 +33,7 @@ describe('EmptyState component', () => {
});
it(`doesn't render child components when count is falsy`, () => {
- const component = mountWithIntl(
+ const component = mountWithRouter(
Shouldn't be rendered
@@ -45,7 +45,7 @@ describe('EmptyState component', () => {
const errors: IHttpFetchError[] = [
new HttpFetchError('There was an error fetching your data.', 'error', {} as any),
];
- const component = mountWithIntl(
+ const component = mountWithRouter(
Shouldn't appear...
@@ -54,7 +54,7 @@ describe('EmptyState component', () => {
});
it('renders loading state if no errors or doc count', () => {
- const component = mountWithIntl(
+ const component = mountWithRouter(
Should appear even while loading...
@@ -67,7 +67,7 @@ describe('EmptyState component', () => {
docCount: 0,
indexExists: true,
};
- const component = mountWithIntl(
+ const component = mountWithRouter(
If this is in the snapshot the test should fail
@@ -77,7 +77,7 @@ describe('EmptyState component', () => {
it('notifies when index does not exist', () => {
statesIndexStatus.indexExists = false;
- const component = mountWithIntl(
+ const component = mountWithRouter(
This text should not render
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_missing.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_missing.tsx
deleted file mode 100644
index e931ba5cce3f0a..00000000000000
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_missing.tsx
+++ /dev/null
@@ -1,64 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import {
- EuiFlexGroup,
- EuiEmptyPrompt,
- EuiFlexItem,
- EuiSpacer,
- EuiPanel,
- EuiTitle,
- EuiLink,
-} from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n/react';
-import React, { useContext } from 'react';
-import { UptimeSettingsContext } from '../../../contexts';
-
-interface DataMissingProps {
- headingMessage: string;
-}
-
-export const DataMissing = ({ headingMessage }: DataMissingProps) => {
- const { basePath } = useContext(UptimeSettingsContext);
- return (
-
-
-
-
-
- {headingMessage}
-
- }
- body={
-
-
-
-
- ),
- }}
- />
-
- }
- />
-
-
-
- );
-};
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_or_index_missing.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_or_index_missing.tsx
new file mode 100644
index 00000000000000..88c0920138f682
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/data_or_index_missing.tsx
@@ -0,0 +1,86 @@
+/*
+ * 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 {
+ EuiFlexGroup,
+ EuiEmptyPrompt,
+ EuiFlexItem,
+ EuiSpacer,
+ EuiPanel,
+ EuiTitle,
+ EuiButton,
+} from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import React, { useContext } from 'react';
+import { UptimeSettingsContext } from '../../../contexts';
+import { DynamicSettings } from '../../../../common/runtime_types';
+
+interface DataMissingProps {
+ headingMessage: JSX.Element;
+ settings?: DynamicSettings;
+}
+
+export const DataOrIndexMissing = ({ headingMessage, settings }: DataMissingProps) => {
+ const { basePath } = useContext(UptimeSettingsContext);
+ return (
+
+
+
+
+
+ {headingMessage}
+
+ }
+ body={
+ <>
+
+
+
+
+
+
+ >
+ }
+ actions={
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+
+
+
+ );
+};
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_index.tsx
deleted file mode 100644
index 13c1206fe5aed2..00000000000000
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_index.tsx
+++ /dev/null
@@ -1,67 +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;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import {
- EuiEmptyPrompt,
- EuiFlexGroup,
- EuiFlexItem,
- EuiLink,
- EuiPanel,
- EuiSpacer,
- EuiTitle,
-} from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n/react';
-import React, { Fragment } from 'react';
-
-interface EmptyIndexProps {
- basePath: string;
-}
-
-export const EmptyIndex = ({ basePath }: EmptyIndexProps) => (
-
-
-
-
-
-
-
-
-
- }
- body={
-
-
-
-
-
- ),
- }}
- />
-
-
- }
- />
-
-
-
-);
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_state.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_state.tsx
index ae6a1b892bc991..651103a34bf212 100644
--- a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_state.tsx
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/empty_state.tsx
@@ -5,11 +5,11 @@
*/
import React, { Fragment } from 'react';
-import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
import { EmptyStateError } from './empty_state_error';
import { EmptyStateLoading } from './empty_state_loading';
-import { DataMissing } from './data_missing';
-import { StatesIndexStatus } from '../../../../common/runtime_types';
+import { DataOrIndexMissing } from './data_or_index_missing';
+import { DynamicSettings, StatesIndexStatus } from '../../../../common/runtime_types';
import { IHttpFetchError } from '../../../../../../../../target/types/core/public/http';
interface EmptyStateProps {
@@ -17,6 +17,7 @@ interface EmptyStateProps {
statesIndexStatus: StatesIndexStatus | null;
loading: boolean;
errors?: IHttpFetchError[];
+ settings?: DynamicSettings;
}
export const EmptyStateComponent = ({
@@ -24,6 +25,7 @@ export const EmptyStateComponent = ({
statesIndexStatus,
loading,
errors,
+ settings,
}: EmptyStateProps) => {
if (errors?.length) {
return ;
@@ -32,18 +34,28 @@ export const EmptyStateComponent = ({
const { indexExists, docCount } = statesIndexStatus;
if (!indexExists) {
return (
- {settings?.heartbeatIndices} }}
+ />
+ }
/>
);
} else if (indexExists && docCount === 0) {
return (
- {settings?.heartbeatIndices} }}
+ />
+ }
/>
);
}
diff --git a/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx b/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx
index 821a70c85dc7c5..49e6ddb56602ca 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/page_header.tsx
@@ -17,7 +17,9 @@ interface PageHeaderProps {
extraLinks?: boolean;
datePicker?: boolean;
}
-
+const SETTINGS_LINK_TEXT = i18n.translate('xpack.uptime.page_header.settingsLink', {
+ defaultMessage: 'Settings',
+});
export const PageHeader = React.memo(
({ headingText, extraLinks = false, datePicker = true }: PageHeaderProps) => {
const datePickerComponent = datePicker ? (
@@ -26,9 +28,6 @@ export const PageHeader = React.memo(
) : null;
- const settingsLinkText = i18n.translate('xpack.uptime.page_header.settingsLink', {
- defaultMessage: 'Settings',
- });
const extraLinkComponents = !extraLinks ? null : (
@@ -37,7 +36,7 @@ export const PageHeader = React.memo(
- {settingsLinkText}
+ {SETTINGS_LINK_TEXT}
diff --git a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
index 765b0e3c664bc0..15b65bdea332bb 100644
--- a/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
+++ b/x-pack/legacy/plugins/uptime/public/pages/settings.tsx
@@ -57,8 +57,8 @@ export const SettingsPageComponent = ({
useUptimeTelemetry(UptimePage.Settings);
useEffect(() => {
- dispatchGetDynamicSettings({});
- }, [dispatchGetDynamicSettings]);
+ dispatch(getDynamicSettings());
+ }, [dispatch]);
const [formFields, setFormFields] = useState(dss.settings || null);
diff --git a/x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts
index d78c725c4b599d..3dbb1aa2346216 100644
--- a/x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/actions/dynamic_settings.ts
@@ -6,7 +6,7 @@
import { createAction } from 'redux-actions';
import { DynamicSettings } from '../../../common/runtime_types';
-export const getDynamicSettings = createAction<{}>('GET_DYNAMIC_SETTINGS');
+export const getDynamicSettings = createAction('GET_DYNAMIC_SETTINGS');
export const getDynamicSettingsSuccess = createAction(
'GET_DYNAMIC_SETTINGS_SUCCESS'
);
@@ -17,4 +17,3 @@ export const setDynamicSettingsSuccess = createAction(
'SET_DYNAMIC_SETTINGS_SUCCESS'
);
export const setDynamicSettingsFail = createAction('SET_DYNAMIC_SETTINGS_FAIL');
-export const acknowledgeSetDynamicSettings = createAction<{}>('ACKNOWLEDGE_SET_DYNAMIC_SETTINGS');
diff --git a/x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts
index 8ade2aa4595dcd..e52e40c53513cb 100644
--- a/x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/api/dynamic_settings.ts
@@ -14,22 +14,15 @@ import { apiService } from './utils';
const apiPath = '/api/uptime/dynamic_settings';
-interface BaseApiRequest {
- basePath: string;
-}
-
-type SaveApiRequest = BaseApiRequest & {
+interface SaveApiRequest {
settings: DynamicSettings;
-};
+}
-export const getDynamicSettings = async ({
- basePath,
-}: BaseApiRequest): Promise => {
+export const getDynamicSettings = async (): Promise => {
return await apiService.get(apiPath, undefined, DynamicSettingsType);
};
export const setDynamicSettings = async ({
- basePath,
settings,
}: SaveApiRequest): Promise => {
return await apiService.post(apiPath, settings, DynamicSettingsSaveType);
diff --git a/x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts b/x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts
index 9bc8bd95be68c6..bee92813aa1f0a 100644
--- a/x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts
+++ b/x-pack/legacy/plugins/uptime/public/state/effects/dynamic_settings.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { takeLatest, put, call, select } from 'redux-saga/effects';
+import { takeLatest, put, call } from 'redux-saga/effects';
import { Action } from 'redux-actions';
import { i18n } from '@kbn/i18n';
import { fetchEffectFactory } from './fetch_effect';
@@ -21,7 +21,6 @@ import {
setDynamicSettings as setDynamicSettingsAPI,
} from '../api';
import { DynamicSettings } from '../../../common/runtime_types';
-import { getBasePath } from '../selectors';
import { kibanaService } from '../kibana_service';
export function* fetchDynamicSettingsEffect() {
@@ -46,8 +45,7 @@ export function* setDynamicSettingsEffect() {
});
return;
}
- const basePath = yield select(getBasePath);
- yield call(setDynamicSettingsAPI, { settings: action.payload, basePath });
+ yield call(setDynamicSettingsAPI, { settings: action.payload });
yield put(setDynamicSettingsSuccess(action.payload));
kibanaService.core.notifications.toasts.addSuccess('Settings saved!');
} catch (err) {
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 7f5bd0eda809b3..41820305ee308f 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -16253,12 +16253,7 @@
"xpack.uptime.dataMissing.configureHeartbeatToGetStartedMessage": "アップタイムデータのロギングを開始するには{configureHeartbeatLink}。",
"xpack.uptime.durationChart.emptyPrompt.description": "このモニターは選択された時間範囲で一度も {emphasizedText} していません。",
"xpack.uptime.durationChart.emptyPrompt.title": "利用可能な期間データがありません",
- "xpack.uptime.emptyState.configureHeartbeatLinkText": "Heartbeat を構成",
- "xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage": "アップタイムデータの収集を開始するには {configureHeartbeatLink}。",
"xpack.uptime.emptyState.loadingMessage": "読み込み中…",
- "xpack.uptime.emptyState.noDataMessage": "アップタイムデータが見つかりませんでした",
- "xpack.uptime.emptyState.noDataTitle": "利用可能なアップタイムデータがありません",
- "xpack.uptime.emptyState.noIndexTitle": "アップタイムインデックスが見つかりません",
"xpack.uptime.emptyStateError.notAuthorized": "アップタイムデータの表示が承認されていません。システム管理者にお問い合わせください。",
"xpack.uptime.emptyStateError.notFoundPage": "ページが見つかりません",
"xpack.uptime.emptyStateError.title": "エラー",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 6fc2e1f146086a..68e4f62f1f2ce4 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -16258,12 +16258,7 @@
"xpack.uptime.dataMissing.configureHeartbeatToGetStartedMessage": "{configureHeartbeatLink}以开始记录运行时间数据。",
"xpack.uptime.durationChart.emptyPrompt.description": "在选定时间范围内此监测从未{emphasizedText}。",
"xpack.uptime.durationChart.emptyPrompt.title": "没有持续时间数据",
- "xpack.uptime.emptyState.configureHeartbeatLinkText": "配置 Heartbeat",
- "xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage": "{configureHeartbeatLink}以开始收集运行时间数据。",
"xpack.uptime.emptyState.loadingMessage": "正在加载……",
- "xpack.uptime.emptyState.noDataMessage": "未找到任何运行时间数据",
- "xpack.uptime.emptyState.noDataTitle": "没有可用的运行时间数据",
- "xpack.uptime.emptyState.noIndexTitle": "找不到运行时间索引",
"xpack.uptime.emptyStateError.notAuthorized": "您无权查看 Uptime 数据,请联系系统管理员。",
"xpack.uptime.emptyStateError.notFoundPage": "未找到页面",
"xpack.uptime.emptyStateError.title": "错误",
From a95789d0d3c2436df795ed4993525f4bbcd9cc63 Mon Sep 17 00:00:00 2001
From: shahzad
Date: Wed, 22 Apr 2020 13:41:02 +0200
Subject: [PATCH 3/5] updated snapshots
---
.../__snapshots__/empty_state.test.tsx.snap | 1627 +++++++++++++++++
1 file changed, 1627 insertions(+)
create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap
diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap
new file mode 100644
index 00000000000000..d0e7af24e1c1b9
--- /dev/null
+++ b/x-pack/legacy/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap
@@ -0,0 +1,1627 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EmptyState component does not render empty state with appropriate base path and no docs 1`] = `
+
+
+ ,
+ }
+ }
+ />
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+
+ }
+ iconType="logoUptime"
+ title={
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ >
+ No uptime data found in index
+
+
+
+
+
+
+
+
+
+
+
+
+ If you have not setup heartbeat yet, you can setup heartbeat to start monitoring your services.
+
+
+
+
+ If you have setup heartbeat and confirmed data is being sent to Elasticsearch, update your index pattern settings and insure they are aligned with your Heartbeat config.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EmptyState component doesn't render child components when count is falsy 1`] = `
+
+
+
+
+
+
+
+
+ Loading…
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading…
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EmptyState component notifies when index does not exist 1`] = `
+
+
+ ,
+ }
+ }
+ />
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+ body={
+
+
+
+
+
+
+
+
+ }
+ iconType="logoUptime"
+ title={
+
+
+ ,
+ }
+ }
+ />
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ }
+ }
+ >
+ No indices found matching pattern
+
+
+
+
+
+
+
+
+
+
+
+
+ If you have not setup heartbeat yet, you can setup heartbeat to start monitoring your services.
+
+
+
+
+ If you have setup heartbeat and confirmed data is being sent to Elasticsearch, update your index pattern settings and insure they are aligned with your Heartbeat config.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EmptyState component renders child components when count is truthy 1`] = `
+
+
+
+ Foo
+
+
+ Bar
+
+
+ Baz
+
+
+
+`;
+
+exports[`EmptyState component renders error message when an error occurs 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+ There was an error fetching your data.
+
+
+ }
+ iconColor="subdued"
+ iconType="securityApp"
+ title={
+
+
+ Error
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ Error
+
+
+
+
+
+
+
+
+
+ There was an error fetching your data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`EmptyState component renders loading state if no errors or doc count 1`] = `
+
+
+
+
+
+
+
+
+ Loading…
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading…
+
+
+
+
+
+
+
+
+
+
+
+`;
From dc2839f7c547b3edf2fd678b014189b2d82433d7 Mon Sep 17 00:00:00 2001
From: shahzad
Date: Wed, 22 Apr 2020 18:10:34 +0200
Subject: [PATCH 4/5] up snapshots
---
.../uptime/server/lib/alerts/__tests__/status_check.test.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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 f94b3f7545fb30..55c8a69df6c4c2 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,11 +88,11 @@ describe('status check alert', () => {
Object {
"callES": [MockFunction],
"dynamicSettings": Object {
- "heartbeatIndices": "heartbeat-7*",
"certificatesThresholds": Object {
"errorState": 7,
"warningState": 30,
},
+ "heartbeatIndices": "heartbeat-7*",
},
"locations": Array [],
"numTimes": 5,
@@ -135,11 +135,11 @@ describe('status check alert', () => {
Object {
"callES": [MockFunction],
"dynamicSettings": Object {
- "heartbeatIndices": "heartbeat-7*",
"certificatesThresholds": Object {
"errorState": 7,
"warningState": 30,
},
+ "heartbeatIndices": "heartbeat-7*",
},
"locations": Array [],
"numTimes": 5,
From 23e1ac3c4e235e5369b6129b743685c070aa9ef1 Mon Sep 17 00:00:00 2001
From: shahzad
Date: Thu, 23 Apr 2020 19:12:46 +0200
Subject: [PATCH 5/5] update trans
---
x-pack/plugins/translations/translations/ja-JP.json | 1 -
x-pack/plugins/translations/translations/zh-CN.json | 1 -
2 files changed, 2 deletions(-)
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 29dba3667c5d68..b86025780b1377 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -16234,7 +16234,6 @@
"xpack.uptime.charts.mlAnnotation.header": "スコア: {score}",
"xpack.uptime.charts.mlAnnotation.severity": "深刻度: {severity}",
"xpack.uptime.components.embeddables.embeddedMap.embeddablePanelTitle": "オブザーバー位置情報マップを監視",
- "xpack.uptime.dataMissing.configureHeartbeatToGetStartedMessage": "アップタイムデータのロギングを開始するには{configureHeartbeatLink}。",
"xpack.uptime.durationChart.emptyPrompt.description": "このモニターは選択された時間範囲で一度も {emphasizedText} していません。",
"xpack.uptime.durationChart.emptyPrompt.title": "利用可能な期間データがありません",
"xpack.uptime.emptyState.loadingMessage": "読み込み中…",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index e1eb9ef4c5f97b..7164bbc10689bf 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -16239,7 +16239,6 @@
"xpack.uptime.charts.mlAnnotation.header": "分数:{score}",
"xpack.uptime.charts.mlAnnotation.severity": "严重性:{severity}",
"xpack.uptime.components.embeddables.embeddedMap.embeddablePanelTitle": "监测观察者位置地图",
- "xpack.uptime.dataMissing.configureHeartbeatToGetStartedMessage": "{configureHeartbeatLink}以开始记录运行时间数据。",
"xpack.uptime.durationChart.emptyPrompt.description": "在选定时间范围内此监测从未{emphasizedText}。",
"xpack.uptime.durationChart.emptyPrompt.title": "没有持续时间数据",
"xpack.uptime.emptyState.loadingMessage": "正在加载……",