) {
+ this.factory = factory;
+ }
+
+ start(
+ coreSetup: CoreSetup,
+ coreStart: CoreStart,
+ canvasSetupPlugins: CanvasSetupDeps,
+ canvasStartPlugins: CanvasStartDeps
+ ) {
+ this.service = this.factory(coreSetup, coreStart, canvasSetupPlugins, canvasStartPlugins);
+ }
+
+ getService(): Service {
+ if (!this.service) {
+ throw new Error('Service not ready');
+ }
+
+ return this.service;
+ }
+
+ stop() {
+ this.service = undefined;
+ }
+}
+
+export type ServiceFromProvider = P extends CanvasServiceProvider ? T : never;
+
+export const services = {
+ notify: new CanvasServiceProvider(notifyServiceFactory),
+};
+
+export interface CanvasServices {
+ notify: ServiceFromProvider;
+}
+
+export const startServices = (
+ coreSetup: CoreSetup,
+ coreStart: CoreStart,
+ canvasSetupPlugins: CanvasSetupDeps,
+ canvasStartPlugins: CanvasStartDeps
+) => {
+ Object.entries(services).forEach(([key, provider]) =>
+ provider.start(coreSetup, coreStart, canvasSetupPlugins, canvasStartPlugins)
+ );
+};
+
+export const stopServices = () => {
+ Object.entries(services).forEach(([key, provider]) => provider.stop());
+};
+
+export const { notify: notifyService } = services;
diff --git a/x-pack/legacy/plugins/canvas/public/services/notify.ts b/x-pack/legacy/plugins/canvas/public/services/notify.ts
new file mode 100644
index 0000000000000..3e18e2178a818
--- /dev/null
+++ b/x-pack/legacy/plugins/canvas/public/services/notify.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 { get } from 'lodash';
+import { CanvasServiceFactory } from '.';
+import { formatMsg } from '../../../../../../src/plugins/kibana_legacy/public';
+import { ToastInputFields } from '../../../../../../src/core/public';
+
+const getToast = (err: Error | string, opts: ToastInputFields = {}) => {
+ const errData = (get(err, 'response') || err) as Error | string;
+ const errMsg = formatMsg(errData);
+ const { title, ...rest } = opts;
+ let text;
+
+ if (title) {
+ text = errMsg;
+ }
+
+ return {
+ ...rest,
+ title: title || errMsg,
+ text,
+ };
+};
+
+interface NotifyService {
+ error: (err: string | Error, opts?: ToastInputFields) => void;
+ warning: (err: string | Error, opts?: ToastInputFields) => void;
+ info: (err: string | Error, opts?: ToastInputFields) => void;
+ success: (err: string | Error, opts?: ToastInputFields) => void;
+}
+
+export const notifyServiceFactory: CanvasServiceFactory = (setup, start) => {
+ const toasts = start.notifications.toasts;
+
+ return {
+ /*
+ * @param {(string | Object)} err: message or Error object
+ * @param {Object} opts: option to override toast title or icon, see https://github.com/elastic/kibana/blob/master/src/legacy/ui/public/notify/toasts/TOAST_NOTIFICATIONS.md
+ */
+ error(err, opts) {
+ toasts.addDanger(getToast(err, opts));
+ },
+ warning(err, opts) {
+ toasts.addWarning(getToast(err, opts));
+ },
+ info(err, opts) {
+ toasts.add(getToast(err, opts));
+ },
+ success(err, opts) {
+ toasts.addSuccess(getToast(err, opts));
+ },
+ };
+};
diff --git a/x-pack/legacy/plugins/canvas/public/state/actions/elements.js b/x-pack/legacy/plugins/canvas/public/state/actions/elements.js
index 1798aaab22f06..f4a3393b8962d 100644
--- a/x-pack/legacy/plugins/canvas/public/state/actions/elements.js
+++ b/x-pack/legacy/plugins/canvas/public/state/actions/elements.js
@@ -13,9 +13,9 @@ import { getPages, getNodeById, getNodes, getSelectedPageIndex } from '../select
import { getValue as getResolvedArgsValue } from '../selectors/resolved_args';
import { getDefaultElement } from '../defaults';
import { ErrorStrings } from '../../../i18n';
-import { notify } from '../../lib/notify';
import { runInterpreter, interpretAst } from '../../lib/run_interpreter';
import { subMultitree } from '../../lib/aeroelastic/functional';
+import { services } from '../../services';
import { selectToplevelNodes } from './transient';
import * as args from './resolved_args';
@@ -134,7 +134,7 @@ const fetchRenderableWithContextFn = ({ dispatch }, element, ast, context) => {
dispatch(getAction(renderable));
})
.catch(err => {
- notify.error(err);
+ services.notify.getService().error(err);
dispatch(getAction(err));
});
};
@@ -176,7 +176,7 @@ export const fetchAllRenderables = createThunk(
return runInterpreter(ast, null, { castToRender: true })
.then(renderable => ({ path: argumentPath, value: renderable }))
.catch(err => {
- notify.error(err);
+ services.notify.getService().error(err);
return { path: argumentPath, value: err };
});
});
@@ -293,7 +293,7 @@ const setAst = createThunk('setAst', ({ dispatch }, ast, element, pageId, doRend
const expression = toExpression(ast);
dispatch(setExpression(expression, element.id, pageId, doRender));
} catch (err) {
- notify.error(err);
+ services.notify.getService().error(err);
// TODO: remove this, may have been added just to cause a re-render, but why?
dispatch(setExpression(element.expression, element.id, pageId, doRender));
diff --git a/x-pack/legacy/plugins/canvas/public/state/middleware/es_persist.js b/x-pack/legacy/plugins/canvas/public/state/middleware/es_persist.js
index bcbfc3544981a..a197cdf893244 100644
--- a/x-pack/legacy/plugins/canvas/public/state/middleware/es_persist.js
+++ b/x-pack/legacy/plugins/canvas/public/state/middleware/es_persist.js
@@ -14,7 +14,7 @@ import { setAssets, resetAssets } from '../actions/assets';
import * as transientActions from '../actions/transient';
import * as resolvedArgsActions from '../actions/resolved_args';
import { update, updateAssets, updateWorkpad } from '../../lib/workpad_service';
-import { notify } from '../../lib/notify';
+import { services } from '../../services';
import { canUserWrite } from '../selectors/app';
const { esPersist: strings } = ErrorStrings;
@@ -62,15 +62,15 @@ export const esPersistMiddleware = ({ getState }) => {
const statusCode = err.response && err.response.status;
switch (statusCode) {
case 400:
- return notify.error(err.response, {
+ return services.notify.getService().error(err.response, {
title: strings.getSaveFailureTitle(),
});
case 413:
- return notify.error(strings.getTooLargeErrorMessage(), {
+ return services.notify.getService().error(strings.getTooLargeErrorMessage(), {
title: strings.getSaveFailureTitle(),
});
default:
- return notify.error(err, {
+ return services.notify.getService().error(err, {
title: strings.getUpdateFailureTitle(),
});
}
diff --git a/x-pack/legacy/plugins/graph/index.ts b/x-pack/legacy/plugins/graph/index.ts
deleted file mode 100644
index 5c7f8fa46c18b..0000000000000
--- a/x-pack/legacy/plugins/graph/index.ts
+++ /dev/null
@@ -1,32 +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.
- */
-
-// @ts-ignore
-import migrations from './migrations';
-import mappings from './mappings.json';
-import { LegacyPluginInitializer } from '../../../../src/legacy/plugin_discovery/types';
-
-export const graph: LegacyPluginInitializer = kibana => {
- return new kibana.Plugin({
- id: 'graph',
- configPrefix: 'xpack.graph',
- require: ['kibana', 'elasticsearch', 'xpack_main'],
- uiExports: {
- mappings,
- migrations,
- },
-
- config(Joi: any) {
- return Joi.object({
- enabled: Joi.boolean().default(true),
- canEditDrillDownUrls: Joi.boolean().default(true),
- savePolicy: Joi.string()
- .valid(['config', 'configAndDataWithConsent', 'configAndData', 'none'])
- .default('configAndData'),
- }).default();
- },
- });
-};
diff --git a/x-pack/legacy/plugins/graph/mappings.json b/x-pack/legacy/plugins/graph/mappings.json
deleted file mode 100644
index f1950c459eee5..0000000000000
--- a/x-pack/legacy/plugins/graph/mappings.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "graph-workspace": {
- "properties": {
- "description": {
- "type": "text"
- },
- "kibanaSavedObjectMeta": {
- "properties": {
- "searchSourceJSON": {
- "type": "text"
- }
- }
- },
- "numLinks": {
- "type": "integer"
- },
- "numVertices": {
- "type": "integer"
- },
- "title": {
- "type": "text"
- },
- "version": {
- "type": "integer"
- },
- "wsState": {
- "type": "text"
- }
- }
- }
-}
diff --git a/x-pack/legacy/plugins/graph/migrations.js b/x-pack/legacy/plugins/graph/migrations.js
deleted file mode 100644
index 0cefe6217b45d..0000000000000
--- a/x-pack/legacy/plugins/graph/migrations.js
+++ /dev/null
@@ -1,41 +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 { get } from 'lodash';
-
-export default {
- 'graph-workspace': {
- '7.0.0': doc => {
- // Set new "references" attribute
- doc.references = doc.references || [];
- // Migrate index pattern
- const wsState = get(doc, 'attributes.wsState');
- if (typeof wsState !== 'string') {
- return doc;
- }
- let state;
- try {
- state = JSON.parse(JSON.parse(wsState));
- } catch (e) {
- // Let it go, the data is invalid and we'll leave it as is
- return doc;
- }
- const { indexPattern } = state;
- if (!indexPattern) {
- return doc;
- }
- state.indexPatternRefName = 'indexPattern_0';
- delete state.indexPattern;
- doc.attributes.wsState = JSON.stringify(JSON.stringify(state));
- doc.references.push({
- name: 'indexPattern_0',
- type: 'index-pattern',
- id: indexPattern,
- });
- return doc;
- },
- },
-};
diff --git a/x-pack/legacy/plugins/graph/migrations.test.js b/x-pack/legacy/plugins/graph/migrations.test.js
deleted file mode 100644
index 93162d94857ce..0000000000000
--- a/x-pack/legacy/plugins/graph/migrations.test.js
+++ /dev/null
@@ -1,102 +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 migrations from './migrations';
-
-describe('graph-workspace', () => {
- describe('7.0.0', () => {
- const migration = migrations['graph-workspace']['7.0.0'];
-
- test('returns doc on empty object', () => {
- expect(migration({})).toMatchInlineSnapshot(`
-Object {
- "references": Array [],
-}
-`);
- });
-
- test('returns doc when wsState is not a string', () => {
- const doc = {
- id: '1',
- attributes: {
- wsState: true,
- },
- };
- expect(migration(doc)).toMatchInlineSnapshot(`
-Object {
- "attributes": Object {
- "wsState": true,
- },
- "id": "1",
- "references": Array [],
-}
-`);
- });
-
- test('returns doc when wsState is not valid JSON', () => {
- const doc = {
- id: '1',
- attributes: {
- wsState: '123abc',
- },
- };
- expect(migration(doc)).toMatchInlineSnapshot(`
-Object {
- "attributes": Object {
- "wsState": "123abc",
- },
- "id": "1",
- "references": Array [],
-}
-`);
- });
-
- test('returns doc when "indexPattern" is missing from wsState', () => {
- const doc = {
- id: '1',
- attributes: {
- wsState: JSON.stringify(JSON.stringify({ foo: true })),
- },
- };
- expect(migration(doc)).toMatchInlineSnapshot(`
-Object {
- "attributes": Object {
- "wsState": "\\"{\\\\\\"foo\\\\\\":true}\\"",
- },
- "id": "1",
- "references": Array [],
-}
-`);
- });
-
- test('extract "indexPattern" attribute from doc', () => {
- const doc = {
- id: '1',
- attributes: {
- wsState: JSON.stringify(JSON.stringify({ foo: true, indexPattern: 'pattern*' })),
- bar: true,
- },
- };
- const migratedDoc = migration(doc);
- expect(migratedDoc).toMatchInlineSnapshot(`
-Object {
- "attributes": Object {
- "bar": true,
- "wsState": "\\"{\\\\\\"foo\\\\\\":true,\\\\\\"indexPatternRefName\\\\\\":\\\\\\"indexPattern_0\\\\\\"}\\"",
- },
- "id": "1",
- "references": Array [
- Object {
- "id": "pattern*",
- "name": "indexPattern_0",
- "type": "index-pattern",
- },
- ],
-}
-`);
- });
- });
-});
diff --git a/x-pack/legacy/plugins/task_manager/server/index.ts b/x-pack/legacy/plugins/task_manager/server/index.ts
index ff25d8a1e0e5d..3ea687f7003f4 100644
--- a/x-pack/legacy/plugins/task_manager/server/index.ts
+++ b/x-pack/legacy/plugins/task_manager/server/index.ts
@@ -15,19 +15,26 @@ export { LegacyTaskManagerApi, getTaskManagerSetup, getTaskManagerStart } from '
// Once all plugins are migrated to NP, this can be removed
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { TaskManager } from '../../../../plugins/task_manager/server/task_manager';
+import {
+ LegacyPluginApi,
+ LegacyPluginSpec,
+ ArrayOrItem,
+} from '../../../../../src/legacy/plugin_discovery/types';
const savedObjectSchemas = {
task: {
hidden: true,
isNamespaceAgnostic: true,
convertToAliasScript: `ctx._id = ctx._source.type + ':' + ctx._id`,
+ // legacy config is marked as any in core, no choice here
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
indexPattern(config: any) {
return config.get('xpack.task_manager.index');
},
},
};
-export function taskManager(kibana: any) {
+export function taskManager(kibana: LegacyPluginApi): ArrayOrItem {
return new kibana.Plugin({
id: 'task_manager',
require: ['kibana', 'elasticsearch', 'xpack_main'],
@@ -58,7 +65,11 @@ export function taskManager(kibana: any) {
// instead we will start the internal Task Manager plugin when
// all legacy plugins have finished initializing
// Once all plugins are migrated to NP, this can be removed
- this.kbnServer.afterPluginsInit(() => {
+
+ // the typing for the lagcy server isn't quite correct, so
+ // we'll bypase it for now
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this as any).kbnServer.afterPluginsInit(() => {
taskManagerPlugin.start();
});
return taskManagerPlugin;
@@ -71,5 +82,5 @@ export function taskManager(kibana: any) {
migrations,
savedObjectSchemas,
},
- });
+ } as Legacy.PluginSpecOptions);
}
diff --git a/x-pack/legacy/plugins/task_manager/server/legacy.ts b/x-pack/legacy/plugins/task_manager/server/legacy.ts
index cd2047b757e61..0d50828004a94 100644
--- a/x-pack/legacy/plugins/task_manager/server/legacy.ts
+++ b/x-pack/legacy/plugins/task_manager/server/legacy.ts
@@ -49,10 +49,10 @@ export function createLegacyApi(legacyTaskManager: Promise): Legacy
fetch: (opts: SearchOpts) => legacyTaskManager.then((tm: TaskManager) => tm.fetch(opts)),
get: (id: string) => legacyTaskManager.then((tm: TaskManager) => tm.get(id)),
remove: (id: string) => legacyTaskManager.then((tm: TaskManager) => tm.remove(id)),
- schedule: (taskInstance: TaskInstanceWithDeprecatedFields, options?: any) =>
+ schedule: (taskInstance: TaskInstanceWithDeprecatedFields, options?: object) =>
legacyTaskManager.then((tm: TaskManager) => tm.schedule(taskInstance, options)),
runNow: (taskId: string) => legacyTaskManager.then((tm: TaskManager) => tm.runNow(taskId)),
- ensureScheduled: (taskInstance: TaskInstanceWithId, options?: any) =>
+ ensureScheduled: (taskInstance: TaskInstanceWithId, options?: object) =>
legacyTaskManager.then((tm: TaskManager) => tm.ensureScheduled(taskInstance, options)),
};
}
diff --git a/x-pack/legacy/plugins/task_manager/server/migrations.ts b/x-pack/legacy/plugins/task_manager/server/migrations.ts
index 97c4f97f59c58..1c2cf73d0fe13 100644
--- a/x-pack/legacy/plugins/task_manager/server/migrations.ts
+++ b/x-pack/legacy/plugins/task_manager/server/migrations.ts
@@ -7,7 +7,7 @@ import { SavedObject } from '../../../../../src/core/server';
export const migrations = {
task: {
- '7.4.0': (doc: SavedObject>) => ({
+ '7.4.0': (doc: SavedObject>) => ({
...doc,
updated_at: new Date().toISOString(),
}),
@@ -18,7 +18,7 @@ export const migrations = {
function moveIntervalIntoSchedule({
attributes: { interval, ...attributes },
...doc
-}: SavedObject>) {
+}: SavedObject>) {
return {
...doc,
attributes: {
diff --git a/x-pack/legacy/plugins/uptime/common/constants/index.ts b/x-pack/legacy/plugins/uptime/common/constants/index.ts
index 74783cf46550f..72d498056d6b3 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 0000000000000..b7986679a09ca
--- /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*',
+ 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 985b51891da99..da887cc5055c1 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.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;
export type DynamicSettingsSaveResponse = t.TypeOf;
-export type CertificatesStatesThreshold = t.TypeOf;
-
-export const defaultDynamicSettings: DynamicSettings = {
- heartbeatIndices: 'heartbeat-8*',
- certificatesThresholds: {
- errorState: 7,
- warningState: 30,
- },
-};
+export type CertStateThresholds = t.TypeOf;
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 36bc9bb860211..96d472c91680d 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,17 +52,18 @@ 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
index 93151198c0f49..3b0c6d99fd9f8 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
@@ -52,17 +52,18 @@ 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
index a3158f3d72445..3d4bd58aabe0f 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,12 +13,13 @@ describe('CertificateForm', () => {
expect(
shallowWithRouter(
)
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 654d51019d4e5..07a3bf81e39d8 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
@@ -13,12 +13,13 @@ describe('CertificateForm', () => {
expect(
shallowWithRouter(
)
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 5103caee1e1c0..209e38785e165 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
@@ -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;
}
+export type OnFieldChangeType = (changedValues: ChangedValues) => void;
+
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?.expirationThresholdError}
+ label={
}
>
- {defaultDynamicSettings?.certificatesThresholds?.errorState}
- ),
- }}
- />
- }
- isInvalid={!!fieldErrors?.certificatesThresholds?.errorState}
- label={
-
+
+
+ onChange({
+ certThresholds: {
+ expiration: Number(e.target.value),
+ },
+ })
+ }
/>
- }
- >
-
-
-
- onChange(
- 'certificatesThresholds.errorState',
- value === '' ? undefined : Number(value)
- )
- }
+
+
+
+
-
-
-
-
-
-
- {defaultDynamicSettings?.certificatesThresholds?.warningState}
- ),
- }}
- />
- }
- isInvalid={!!fieldErrors?.certificatesThresholds?.warningState}
- label={
-
+
+
+
+ {DYNAMIC_SETTINGS_DEFAULTS.certThresholds.age},
+ }}
+ />
+ }
+ isInvalid={!!fieldErrors?.certificatesThresholds?.ageThresholdError}
+ label={
+
+ }
+ >
+
+
+
+ onChange({
+ certThresholds: { age: Number(e.currentTarget.value) },
+ })
+ }
/>
- }
- >
-
-
-
- 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
index c28eca2ea229e..b9a5ca0e730de 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,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 = ({
onChange,
+ loading,
formFields,
fieldErrors,
isDisabled,
-}) => {
- const dss = useSelector(selectDynamicSettings);
-
- return (
- <>
-
-
+}) => (
+ <>
+
+
+
+
+
+
+
+
+
+ }
+ description={
+
+ }
+ >
+ {DYNAMIC_SETTINGS_DEFAULTS.heartbeatIndices},
+ }}
/>
-
-
-
-
-
-
}
- description={
+ isInvalid={!!fieldErrors?.heartbeatIndices}
+ label={
}
>
- {defaultDynamicSettings.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 6defb96e0da3d..d8c2a78092854 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 } 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';
-
-const getFieldErrors = (formFields: DynamicSettings | null) => {
+import * as Translations from './translations';
+
+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(dss.settings || null);
+ const [formFields, setFormFields] = useState(
+ 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 : (
<>
- {editNoticeText}
+
+ {Translations.settings.editNoticeText}
+
>
);
@@ -124,9 +135,7 @@ export const SettingsPage = () => {
<>
- {i18n.translate('xpack.uptime.settings.returnToOverviewLinkLabel', {
- defaultMessage: 'Return to overview',
- })}
+ {Translations.settings.returnToOverviewLinkLabel}
@@ -139,12 +148,14 @@ export const SettingsPage = () => {