[Uptime] Update TLS settings (#64111)
* Refactor settings form event handling and modify certs fields. * Fix/improve broken types/unit/integration/api tests. * Modify default expiration threshold. * Rename test vars. * Implement PR feedback. * Refresh snapshots, fix broken tests/types. * Remove unnecessary state spreading. * Add type for settings field errors. * Refresh test snapshots. * Improve punctuation.
This commit is contained in:
parent
a012ddf9df
commit
e918c43535
25 changed files with 382 additions and 336 deletions
|
@ -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';
|
||||
|
|
|
@ -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*',
|
||||
certThresholds: {
|
||||
expiration: 30,
|
||||
age: 365,
|
||||
},
|
||||
};
|
|
@ -6,19 +6,15 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
export const CertificatesStatesThresholdType = t.interface({
|
||||
warningState: t.number,
|
||||
errorState: t.number,
|
||||
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,12 +27,4 @@ export const DynamicSettingsSaveType = t.intersection([
|
|||
|
||||
export type DynamicSettings = t.TypeOf<typeof DynamicSettingsType>;
|
||||
export type DynamicSettingsSaveResponse = t.TypeOf<typeof DynamicSettingsSaveType>;
|
||||
export type CertificatesStatesThreshold = t.TypeOf<typeof CertificatesStatesThresholdType>;
|
||||
|
||||
export const defaultDynamicSettings: DynamicSettings = {
|
||||
heartbeatIndices: 'heartbeat-8*',
|
||||
certificatesThresholds: {
|
||||
errorState: 7,
|
||||
warningState: 30,
|
||||
},
|
||||
};
|
||||
export type CertStateThresholds = t.TypeOf<typeof CertStateThresholdsType>;
|
||||
|
|
|
@ -52,17 +52,18 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] =
|
|||
}
|
||||
>
|
||||
<CertificateExpirationForm
|
||||
fieldErrors={Object {}}
|
||||
fieldErrors={null}
|
||||
formFields={
|
||||
Object {
|
||||
"certificatesThresholds": Object {
|
||||
"errorState": 7,
|
||||
"warningState": 36,
|
||||
"certThresholds": Object {
|
||||
"age": 36,
|
||||
"expiration": 7,
|
||||
},
|
||||
"heartbeatIndices": "heartbeat-8*",
|
||||
}
|
||||
}
|
||||
isDisabled={false}
|
||||
loading={false}
|
||||
onChange={[MockFunction]}
|
||||
/>
|
||||
</ContextProvider>
|
||||
|
|
|
@ -52,17 +52,18 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] =
|
|||
}
|
||||
>
|
||||
<IndicesForm
|
||||
fieldErrors={Object {}}
|
||||
fieldErrors={null}
|
||||
formFields={
|
||||
Object {
|
||||
"certificatesThresholds": Object {
|
||||
"errorState": 7,
|
||||
"warningState": 36,
|
||||
"certThresholds": Object {
|
||||
"age": 36,
|
||||
"expiration": 7,
|
||||
},
|
||||
"heartbeatIndices": "heartbeat-8*",
|
||||
}
|
||||
}
|
||||
isDisabled={false}
|
||||
loading={false}
|
||||
onChange={[MockFunction]}
|
||||
/>
|
||||
</ContextProvider>
|
||||
|
|
|
@ -13,12 +13,13 @@ describe('CertificateForm', () => {
|
|||
expect(
|
||||
shallowWithRouter(
|
||||
<CertificateExpirationForm
|
||||
loading={false}
|
||||
onChange={jest.fn()}
|
||||
formFields={{
|
||||
heartbeatIndices: 'heartbeat-8*',
|
||||
certificatesThresholds: { errorState: 7, warningState: 36 },
|
||||
certThresholds: { expiration: 7, age: 36 },
|
||||
}}
|
||||
fieldErrors={{}}
|
||||
fieldErrors={null}
|
||||
isDisabled={false}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -13,12 +13,13 @@ describe('CertificateForm', () => {
|
|||
expect(
|
||||
shallowWithRouter(
|
||||
<IndicesForm
|
||||
loading={false}
|
||||
onChange={jest.fn()}
|
||||
formFields={{
|
||||
heartbeatIndices: 'heartbeat-8*',
|
||||
certificatesThresholds: { errorState: 7, warningState: 36 },
|
||||
certThresholds: { expiration: 7, age: 36 },
|
||||
}}
|
||||
fieldErrors={{}}
|
||||
fieldErrors={null}
|
||||
isDisabled={false}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -6,155 +6,157 @@
|
|||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
EuiDescribedFormGroup,
|
||||
EuiFormRow,
|
||||
EuiCode,
|
||||
EuiFieldNumber,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
EuiSpacer,
|
||||
EuiSelect,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import { defaultDynamicSettings, DynamicSettings } from '../../../common/runtime_types';
|
||||
import { selectDynamicSettings } from '../../state/selectors';
|
||||
import { CertStateThresholds } from '../../../common/runtime_types';
|
||||
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants';
|
||||
import { SettingsFormProps } from '../../pages/settings';
|
||||
|
||||
type NumStr = string | number;
|
||||
|
||||
export type OnFieldChangeType = (field: string, value?: NumStr) => void;
|
||||
|
||||
export interface SettingsFormProps {
|
||||
onChange: OnFieldChangeType;
|
||||
formFields: DynamicSettings | null;
|
||||
fieldErrors: any;
|
||||
isDisabled: boolean;
|
||||
interface ChangedValues {
|
||||
heartbeatIndices?: string;
|
||||
certThresholds?: Partial<CertStateThresholds>;
|
||||
}
|
||||
|
||||
export type OnFieldChangeType = (changedValues: ChangedValues) => void;
|
||||
|
||||
export const CertificateExpirationForm: React.FC<SettingsFormProps> = ({
|
||||
loading,
|
||||
onChange,
|
||||
formFields,
|
||||
fieldErrors,
|
||||
isDisabled,
|
||||
}) => {
|
||||
const dss = useSelector(selectDynamicSettings);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
}) => (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.certificationSectionTitle"
|
||||
defaultMessage="Certificate Expiration"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.certificationSectionTitle"
|
||||
defaultMessage="Certificate Expiration"
|
||||
id="xpack.uptime.sourceConfiguration.expirationThreshold"
|
||||
defaultMessage="Expiration/Age Thresholds"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.stateThresholds"
|
||||
defaultMessage="Expiration State Thresholds"
|
||||
/>
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.certificateThresholdDescription"
|
||||
defaultMessage="Change the threshold for displaying and alerting on certificate errors. Note: this will affect any configured alerts."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFormRow
|
||||
describedByIds={['errorState']}
|
||||
error={fieldErrors?.certificatesThresholds?.expirationThresholdError}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.stateThresholdsDescription"
|
||||
defaultMessage="Set certificate expiration warning/error thresholds"
|
||||
id="xpack.uptime.sourceConfiguration.expirationThresholdDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: (
|
||||
<EuiCode>{DYNAMIC_SETTINGS_DEFAULTS.certThresholds.expiration}</EuiCode>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.certificatesThresholds?.expirationThresholdError}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.errorStateLabel"
|
||||
defaultMessage="Expiration threshold"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFormRow
|
||||
describedByIds={['errorState']}
|
||||
error={fieldErrors?.certificatesThresholds?.errorState}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.errorStateDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: (
|
||||
<EuiCode>{defaultDynamicSettings?.certificatesThresholds?.errorState}</EuiCode>
|
||||
),
|
||||
}}
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiFieldNumber
|
||||
data-test-subj={`expiration-threshold-input-${loading ? 'loading' : 'loaded'}`}
|
||||
fullWidth
|
||||
disabled={isDisabled}
|
||||
isLoading={loading}
|
||||
value={formFields?.certThresholds?.expiration || ''}
|
||||
onChange={e =>
|
||||
onChange({
|
||||
certThresholds: {
|
||||
expiration: Number(e.target.value),
|
||||
},
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.certificatesThresholds?.errorState}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.errorStateLabel"
|
||||
defaultMessage="Error state"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiFieldNumber
|
||||
data-test-subj={`error-state-threshold-input-${dss.loading ? 'loading' : 'loaded'}`}
|
||||
fullWidth
|
||||
disabled={isDisabled}
|
||||
isLoading={dss.loading}
|
||||
value={formFields?.certificatesThresholds?.errorState || ''}
|
||||
onChange={({ currentTarget: { value } }: any) =>
|
||||
onChange(
|
||||
'certificatesThresholds.errorState',
|
||||
value === '' ? undefined : Number(value)
|
||||
)
|
||||
}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.ageLimit.units.days"
|
||||
defaultMessage="Days"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiSelect options={[{ value: 'day', text: 'Days' }]} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={['warningState']}
|
||||
error={fieldErrors?.certificatesThresholds?.warningState}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.warningStateDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: (
|
||||
<EuiCode>{defaultDynamicSettings?.certificatesThresholds?.warningState}</EuiCode>
|
||||
),
|
||||
}}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
<EuiFormRow
|
||||
describedByIds={['warningState']}
|
||||
error={fieldErrors?.certificatesThresholds?.ageThresholdError}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.ageThresholdDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>{DYNAMIC_SETTINGS_DEFAULTS.certThresholds.age}</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.certificatesThresholds?.ageThresholdError}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.warningStateLabel"
|
||||
defaultMessage="Age limit"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiFieldNumber
|
||||
data-test-subj={`age-threshold-input-${loading ? 'loading' : 'loaded'}`}
|
||||
fullWidth
|
||||
disabled={isDisabled}
|
||||
isLoading={loading}
|
||||
value={formFields?.certThresholds?.age || ''}
|
||||
onChange={e =>
|
||||
onChange({
|
||||
certThresholds: { age: Number(e.currentTarget.value) },
|
||||
})
|
||||
}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.certificatesThresholds?.warningState}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.warningStateLabel"
|
||||
defaultMessage="Warning state"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={2}>
|
||||
<EuiFieldNumber
|
||||
data-test-subj={`warning-state-threshold-input-${
|
||||
dss.loading ? 'loading' : 'loaded'
|
||||
}`}
|
||||
fullWidth
|
||||
disabled={isDisabled}
|
||||
isLoading={dss.loading}
|
||||
value={formFields?.certificatesThresholds?.warningState || ''}
|
||||
onChange={(event: any) =>
|
||||
onChange('certificatesThresholds.warningState', Number(event.currentTarget.value))
|
||||
}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.ageLimit.units.days"
|
||||
defaultMessage="Days"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<EuiSelect options={[{ value: 'day', text: 'Days' }]} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
EuiDescribedFormGroup,
|
||||
EuiFormRow,
|
||||
|
@ -15,76 +14,72 @@ import {
|
|||
EuiTitle,
|
||||
EuiSpacer,
|
||||
} from '@elastic/eui';
|
||||
import { defaultDynamicSettings } from '../../../common/runtime_types';
|
||||
import { selectDynamicSettings } from '../../state/selectors';
|
||||
import { SettingsFormProps } from './certificate_form';
|
||||
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants';
|
||||
import { SettingsFormProps } from '../../pages/settings';
|
||||
|
||||
export const IndicesForm: React.FC<SettingsFormProps> = ({
|
||||
onChange,
|
||||
loading,
|
||||
formFields,
|
||||
fieldErrors,
|
||||
isDisabled,
|
||||
}) => {
|
||||
const dss = useSelector(selectDynamicSettings);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
}) => (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.indicesSectionTitle"
|
||||
defaultMessage="Indices"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.indicesSectionTitle"
|
||||
defaultMessage="Indices"
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesTitle"
|
||||
defaultMessage="Uptime indices"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesTitle"
|
||||
defaultMessage="Uptime indices"
|
||||
/>
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
</h4>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesDescription"
|
||||
defaultMessage="Index pattern for matching indices that contain Heartbeat data"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFormRow
|
||||
describedByIds={['heartbeatIndices']}
|
||||
error={fieldErrors?.heartbeatIndices}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesDescription"
|
||||
defaultMessage="Index pattern for matching indices that contain Heartbeat data"
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>{DYNAMIC_SETTINGS_DEFAULTS.heartbeatIndices}</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.heartbeatIndices}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesLabel"
|
||||
defaultMessage="Heartbeat indices"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFormRow
|
||||
describedByIds={['heartbeatIndices']}
|
||||
error={fieldErrors?.heartbeatIndices}
|
||||
<EuiFieldText
|
||||
data-test-subj={`heartbeat-indices-input-${loading ? 'loading' : 'loaded'}`}
|
||||
fullWidth
|
||||
helpText={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesDefaultValue"
|
||||
defaultMessage="The default value is {defaultValue}"
|
||||
values={{
|
||||
defaultValue: <EuiCode>{defaultDynamicSettings.heartbeatIndices}</EuiCode>,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
isInvalid={!!fieldErrors?.heartbeatIndices}
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.sourceConfiguration.heartbeatIndicesLabel"
|
||||
defaultMessage="Heartbeat indices"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
data-test-subj={`heartbeat-indices-input-${dss.loading ? 'loading' : 'loaded'}`}
|
||||
fullWidth
|
||||
disabled={isDisabled}
|
||||
isLoading={dss.loading}
|
||||
value={formFields?.heartbeatIndices || ''}
|
||||
onChange={(event: any) => onChange('heartbeatIndices', event.currentTarget.value)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
disabled={isDisabled}
|
||||
isLoading={loading}
|
||||
value={formFields?.heartbeatIndices || ''}
|
||||
onChange={(event: any) => onChange({ heartbeatIndices: event.currentTarget.value })}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -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 } from 'lodash';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { selectDynamicSettings } from '../state/selectors';
|
||||
import { getDynamicSettings, setDynamicSettings } from '../state/actions/dynamic_settings';
|
||||
|
@ -32,21 +31,38 @@ import {
|
|||
CertificateExpirationForm,
|
||||
OnFieldChangeType,
|
||||
} 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 { certificatesThresholds, heartbeatIndices } = formFields;
|
||||
const { certThresholds: certificatesThresholds, heartbeatIndices } = formFields;
|
||||
const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr;
|
||||
const errorStateErr = certificatesThresholds?.errorState ? null : blankStr;
|
||||
const warningStateErr = certificatesThresholds?.warningState ? 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,
|
||||
};
|
||||
|
@ -57,10 +73,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,21 +83,28 @@ export const SettingsPage = () => {
|
|||
dispatch(getDynamicSettings());
|
||||
}, [dispatch]);
|
||||
|
||||
const [formFields, setFormFields] = useState<DynamicSettings | null>(dss.settings || null);
|
||||
const [formFields, setFormFields] = useState<DynamicSettings | null>(
|
||||
dss.settings ? { ...dss.settings } : null
|
||||
);
|
||||
|
||||
if (!dss.loadError && formFields == null && dss.settings) {
|
||||
setFormFields({ ...dss.settings });
|
||||
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 = (field, value) => {
|
||||
const onChangeFormField: OnFieldChangeType = changedField => {
|
||||
if (formFields) {
|
||||
const newFormFields = cloneDeep(formFields);
|
||||
set(newFormFields, field, value);
|
||||
setFormFields(cloneDeep(newFormFields));
|
||||
setFormFields({
|
||||
heartbeatIndices: changedField.heartbeatIndices ?? formFields.heartbeatIndices,
|
||||
certThresholds: Object.assign(
|
||||
{},
|
||||
formFields.certThresholds,
|
||||
changedField?.certThresholds ?? null
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -95,27 +115,18 @@ export const SettingsPage = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
if (formFields && dss.settings) {
|
||||
setFormFields({ ...dss.settings });
|
||||
}
|
||||
};
|
||||
const resetForm = () => setFormFields(dss.settings ? { ...dss.settings } : null);
|
||||
|
||||
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 : (
|
||||
<>
|
||||
<EuiCallOut title={editNoticeTitle}>{editNoticeText}</EuiCallOut>
|
||||
<EuiCallOut title={Translations.settings.editNoticeTitle}>
|
||||
{Translations.settings.editNoticeText}
|
||||
</EuiCallOut>
|
||||
<EuiSpacer size="s" />
|
||||
</>
|
||||
);
|
||||
|
@ -124,9 +135,7 @@ export const SettingsPage = () => {
|
|||
<>
|
||||
<Link to={OVERVIEW_ROUTE} data-test-subj="uptimeSettingsToOverviewLink">
|
||||
<EuiButtonEmpty size="s" color="primary" iconType="arrowLeft">
|
||||
{i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', {
|
||||
defaultMessage: 'Return to overview',
|
||||
})}
|
||||
{Translations.settings.returnToOverviewLinkLabel}
|
||||
</EuiButtonEmpty>
|
||||
</Link>
|
||||
<EuiSpacer size="s" />
|
||||
|
@ -139,12 +148,14 @@ export const SettingsPage = () => {
|
|||
<form onSubmit={onApply}>
|
||||
<EuiForm>
|
||||
<IndicesForm
|
||||
loading={dss.loading}
|
||||
onChange={onChangeFormField}
|
||||
formFields={formFields}
|
||||
fieldErrors={fieldErrors}
|
||||
isDisabled={isFormDisabled}
|
||||
/>
|
||||
<CertificateExpirationForm
|
||||
loading={dss.loading}
|
||||
onChange={onChangeFormField}
|
||||
formFields={formFields}
|
||||
fieldErrors={fieldErrors}
|
||||
|
|
23
x-pack/legacy/plugins/uptime/public/pages/translations.ts
Normal file
23
x-pack/legacy/plugins/uptime/public/pages/translations.ts
Normal file
|
@ -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',
|
||||
}),
|
||||
};
|
|
@ -31,23 +31,19 @@ export const dynamicSettingsReducer = handleActions<DynamicSettingsState, any>(
|
|||
...state,
|
||||
loading: true,
|
||||
}),
|
||||
[String(getDynamicSettingsSuccess)]: (state, action: Action<DynamicSettings>) => {
|
||||
return {
|
||||
loading: false,
|
||||
settings: action.payload,
|
||||
};
|
||||
},
|
||||
[String(getDynamicSettingsFail)]: (state, action: Action<Error>) => {
|
||||
return {
|
||||
loading: false,
|
||||
loadError: action.payload,
|
||||
};
|
||||
},
|
||||
[String(getDynamicSettingsSuccess)]: (_state, action: Action<DynamicSettings>) => ({
|
||||
loading: false,
|
||||
settings: action.payload,
|
||||
}),
|
||||
[String(getDynamicSettingsFail)]: (_state, action: Action<Error>) => ({
|
||||
loading: false,
|
||||
loadError: action.payload,
|
||||
}),
|
||||
[String(setDynamicSettings)]: state => ({
|
||||
...state,
|
||||
loading: true,
|
||||
}),
|
||||
[String(setDynamicSettingsSuccess)]: (state, action: Action<DynamicSettings>) => ({
|
||||
[String(setDynamicSettingsSuccess)]: (_state, action: Action<DynamicSettings>) => ({
|
||||
settings: action.payload,
|
||||
saveSucceded: true,
|
||||
loading: false,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import { getBasePath, isIntegrationsPopupOpen } from '../index';
|
||||
import { AppState } from '../../../state';
|
||||
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants';
|
||||
|
||||
describe('state selectors', () => {
|
||||
const state: AppState = {
|
||||
|
@ -20,6 +21,7 @@ describe('state selectors', () => {
|
|||
loading: false,
|
||||
},
|
||||
dynamicSettings: {
|
||||
settings: DYNAMIC_SETTINGS_DEFAULTS,
|
||||
loading: false,
|
||||
},
|
||||
monitor: {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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,
|
||||
|
@ -88,9 +88,9 @@ describe('status check alert', () => {
|
|||
Object {
|
||||
"callES": [MockFunction],
|
||||
"dynamicSettings": Object {
|
||||
"certificatesThresholds": Object {
|
||||
"errorState": 7,
|
||||
"warningState": 30,
|
||||
"certThresholds": Object {
|
||||
"age": 365,
|
||||
"expiration": 30,
|
||||
},
|
||||
"heartbeatIndices": "heartbeat-8*",
|
||||
},
|
||||
|
@ -135,9 +135,9 @@ describe('status check alert', () => {
|
|||
Object {
|
||||
"callES": [MockFunction],
|
||||
"dynamicSettings": Object {
|
||||
"certificatesThresholds": Object {
|
||||
"errorState": 7,
|
||||
"warningState": 30,
|
||||
"certThresholds": Object {
|
||||
"age": 365,
|
||||
"expiration": 30,
|
||||
},
|
||||
"heartbeatIndices": "heartbeat-8*",
|
||||
},
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
import { elasticsearchServiceMock } from '../../../../../../../src/core/server/mocks';
|
||||
import { getMonitorStatus } from '../get_monitor_status';
|
||||
import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../../legacy/plugins/uptime/common/constants';
|
||||
import { ScopedClusterClient } from 'src/core/server';
|
||||
import { defaultDynamicSettings } from '../../../../../../legacy/plugins/uptime/common/runtime_types';
|
||||
|
||||
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: {
|
||||
|
|
|
@ -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: '',
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
@ -28,12 +26,12 @@ export const umDynamicSettings: SavedObjectsType = {
|
|||
heartbeatIndices: {
|
||||
type: 'keyword',
|
||||
},
|
||||
certificatesThresholds: {
|
||||
certThresholds: {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
certThresholds: {
|
||||
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();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 () => {
|
||||
|
@ -62,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();
|
||||
|
||||
|
@ -91,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.errorState).to.eql(newErrorThreshold);
|
||||
expect(fields.certThresholds?.expiration).to.eql(newErrorThreshold);
|
||||
});
|
||||
|
||||
it('changing certificate expiration warning threshold is reflected in settings page', async () => {
|
||||
|
@ -108,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.warningState).to.eql(newWarningThreshold);
|
||||
expect(fields.certThresholds?.age).to.eql(newWarningThreshold);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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<DynamicSettings> => {
|
||||
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 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 errorThreshold = await errorInput.getAttribute('value');
|
||||
const warningThreshold = await warningInput.getAttribute('value');
|
||||
const expiration = await expirationInput.getAttribute('value');
|
||||
const age = await ageInput.getAttribute('value');
|
||||
|
||||
return {
|
||||
heartbeatIndices,
|
||||
certificatesThresholds: {
|
||||
errorState: errorThreshold,
|
||||
warningState: warningThreshold,
|
||||
certThresholds: {
|
||||
age: parseInt(age, 10),
|
||||
expiration: parseInt(expiration, 10),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue