From 69ccb8b196ed6ead8c0f8e3637bfdeae965257e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yulia=20=C4=8Cech?= <6585477+yuliacech@users.noreply.github.com> Date: Thu, 8 Apr 2021 14:18:18 +0200 Subject: [PATCH] [Remote clusters] Cloud deployment form when adding new cluster (#94450) * Implemented in-form Cloud deployment url input * Fixed i18n files and added mode switch back for non-Cloud * Added cloud docs link to the documentation service, fixed snapshot tests * Fixed docs build * Added jest test for the new cloud url input * Added unit test for cloud validation * Fixed eslint error * Fixed ts errors * Added ts-ignore * Fixed ts errors * Refactored connection mode component and component tests * Fixed import * Fixed copy * Fixed copy * Reverted docs changes * Reverted docs changes * Replaced the screenshot with a popover and refactored integration tests * Added todo for cloud deployments link * Changed cloud URL help text copy * Added cloud base url and deleted unnecessary base path * Fixed es error * Fixed es error * Changed wording * Reverted docs changes * Updated the help popover * Deleted unneeded fragment component * Deleted unneeded fragment component * Updated tests descriptions to be more detailed Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../add/remote_clusters_add.helpers.js | 43 - .../add/remote_clusters_add.helpers.tsx | 47 + .../add/remote_clusters_add.test.js | 230 -- .../add/remote_clusters_add.test.ts | 260 +++ ...al_characters.js => special_characters.ts} | 0 .../edit/remote_clusters_edit.helpers.js | 34 - .../edit/remote_clusters_edit.helpers.tsx | 58 + .../edit/remote_clusters_edit.test.js | 80 - .../edit/remote_clusters_edit.test.tsx | 141 ++ .../{http_requests.js => http_requests.ts} | 19 +- .../helpers/{index.js => index.ts} | 1 + .../helpers/remote_clusters_actions.ts | 199 ++ ...up_environment.js => setup_environment.ts} | 2 + .../public/application/app_context.tsx | 10 +- .../public/application/index.d.ts | 3 +- .../remote_cluster_form.test.js.snap | 2017 ----------------- .../components/cloud_url_help.tsx | 61 + .../components/connection_mode.tsx | 99 + .../remote_cluster_form/components/index.ts | 8 + .../components/proxy_connection.tsx | 162 ++ .../components/sniff_connection.tsx | 158 ++ .../{index.js => index.ts} | 0 .../remote_cluster_form.js | 962 -------- .../remote_cluster_form.test.js | 53 - .../remote_cluster_form.tsx | 629 +++++ .../remote_cluster_form/request_flyout.tsx | 4 +- .../remote_cluster_form/validators/index.ts | 7 + .../validators/validate_cloud_url.test.ts | 128 ++ .../validators/validate_cloud_url.tsx | 80 + .../validators/validate_cluster.tsx | 39 + .../validators/validate_seed.ts | 43 - .../validators/validate_seed.tsx | 40 + .../public/application/sections/index.d.ts | 11 + .../remote_cluster_add/remote_cluster_add.js | 2 +- .../remote_cluster_edit.js | 7 +- .../public/application/services/api.ts | 2 +- .../application/services/documentation.ts | 10 +- .../public/application/services/index.ts | 8 +- .../public/application/services/routing.ts | 2 +- .../public/application/store/index.d.ts | 11 + .../public/assets/cloud_screenshot.png | Bin 0 -> 197089 bytes .../plugins/remote_clusters/public/plugin.ts | 5 +- x-pack/plugins/remote_clusters/tsconfig.json | 2 + .../translations/translations/ja-JP.json | 5 - .../translations/translations/zh-CN.json | 5 - 45 files changed, 2184 insertions(+), 3503 deletions(-) delete mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.js create mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.tsx delete mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.js create mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.ts rename x-pack/plugins/remote_clusters/__jest__/client_integration/add/{special_characters.js => special_characters.ts} (100%) delete mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.js create mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.tsx delete mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.js create mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.tsx rename x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/{http_requests.js => http_requests.ts} (63%) rename x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/{index.js => index.ts} (80%) create mode 100644 x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_actions.ts rename x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/{setup_environment.js => setup_environment.ts} (95%) delete mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/cloud_url_help.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/connection_mode.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/index.ts create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/proxy_connection.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/sniff_connection.tsx rename x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/{index.js => index.ts} (100%) delete mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js delete mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.test.ts create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cluster.tsx delete mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.ts create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.tsx create mode 100644 x-pack/plugins/remote_clusters/public/application/sections/index.d.ts create mode 100644 x-pack/plugins/remote_clusters/public/application/store/index.d.ts create mode 100644 x-pack/plugins/remote_clusters/public/assets/cloud_screenshot.png diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.js deleted file mode 100644 index 38672b4d59a20..0000000000000 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.js +++ /dev/null @@ -1,43 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act } from 'react-dom/test-utils'; - -import { registerTestBed } from '@kbn/test/jest'; - -import { RemoteClusterAdd } from '../../../public/application/sections/remote_cluster_add'; -import { createRemoteClustersStore } from '../../../public/application/store'; -import { registerRouter } from '../../../public/application/services/routing'; - -const testBedConfig = { - store: createRemoteClustersStore, - memoryRouter: { - onRouter: (router) => registerRouter(router), - }, -}; - -const initTestBed = registerTestBed(RemoteClusterAdd, testBedConfig); - -export const setup = (props) => { - const testBed = initTestBed(props); - - // User actions - const clickSaveForm = async () => { - await act(async () => { - testBed.find('remoteClusterFormSaveButton').simulate('click'); - }); - - testBed.component.update(); - }; - - return { - ...testBed, - actions: { - clickSaveForm, - }, - }; -}; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.tsx b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.tsx new file mode 100644 index 0000000000000..a47e6c023a161 --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.helpers.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { registerTestBed } from '@kbn/test/jest'; + +import { RemoteClusterAdd } from '../../../public/application/sections'; +import { createRemoteClustersStore } from '../../../public/application/store'; +import { AppRouter, registerRouter } from '../../../public/application/services'; +import { createRemoteClustersActions } from '../helpers'; +import { AppContextProvider } from '../../../public/application/app_context'; + +const ComponentWithContext = ({ isCloudEnabled }: { isCloudEnabled: boolean }) => { + return ( + + + + ); +}; + +const testBedConfig = ({ isCloudEnabled }: { isCloudEnabled: boolean }) => { + return { + store: createRemoteClustersStore, + memoryRouter: { + onRouter: (router: AppRouter) => registerRouter(router), + }, + defaultProps: { isCloudEnabled }, + }; +}; + +const initTestBed = (isCloudEnabled: boolean) => + registerTestBed(ComponentWithContext, testBedConfig({ isCloudEnabled }))(); + +export const setup = async (isCloudEnabled = false) => { + const testBed = await initTestBed(isCloudEnabled); + + return { + ...testBed, + actions: { + ...createRemoteClustersActions(testBed), + }, + }; +}; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.js deleted file mode 100644 index 40abde35835f0..0000000000000 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.js +++ /dev/null @@ -1,230 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act } from 'react-dom/test-utils'; - -import { setupEnvironment } from '../helpers'; -import { NON_ALPHA_NUMERIC_CHARS, ACCENTED_CHARS } from './special_characters'; -import { setup } from './remote_clusters_add.helpers'; - -describe('Create Remote cluster', () => { - describe('on component mount', () => { - let find; - let exists; - let actions; - let form; - let server; - let component; - - beforeAll(() => { - ({ server } = setupEnvironment()); - }); - - afterAll(() => { - server.restore(); - }); - - beforeEach(async () => { - await act(async () => { - ({ form, exists, find, actions, component } = setup()); - }); - component.update(); - }); - - test('should have the title of the page set correctly', () => { - expect(exists('remoteClusterPageTitle')).toBe(true); - expect(find('remoteClusterPageTitle').text()).toEqual('Add remote cluster'); - }); - - test('should have a link to the documentation', () => { - expect(exists('remoteClusterDocsButton')).toBe(true); - }); - - test('should have a toggle to Skip unavailable remote cluster', () => { - expect(exists('remoteClusterFormSkipUnavailableFormToggle')).toBe(true); - - // By default it should be set to "false" - expect(find('remoteClusterFormSkipUnavailableFormToggle').props()['aria-checked']).toBe( - false - ); - - act(() => { - form.toggleEuiSwitch('remoteClusterFormSkipUnavailableFormToggle'); - }); - - component.update(); - - expect(find('remoteClusterFormSkipUnavailableFormToggle').props()['aria-checked']).toBe(true); - }); - - test('should have a toggle to enable "proxy" mode for a remote cluster', () => { - expect(exists('remoteClusterFormConnectionModeToggle')).toBe(true); - - // By default it should be set to "false" - expect(find('remoteClusterFormConnectionModeToggle').props()['aria-checked']).toBe(false); - - act(() => { - form.toggleEuiSwitch('remoteClusterFormConnectionModeToggle'); - }); - - component.update(); - - expect(find('remoteClusterFormConnectionModeToggle').props()['aria-checked']).toBe(true); - }); - - test('should display errors and disable the save button when clicking "save" without filling the form', async () => { - expect(exists('remoteClusterFormGlobalError')).toBe(false); - expect(find('remoteClusterFormSaveButton').props().disabled).toBe(false); - - await actions.clickSaveForm(); - - expect(exists('remoteClusterFormGlobalError')).toBe(true); - expect(form.getErrorsMessages()).toEqual([ - 'Name is required.', - 'At least one seed node is required.', - ]); - expect(find('remoteClusterFormSaveButton').props().disabled).toBe(true); - }); - }); - - describe('form validation', () => { - describe('remote cluster name', () => { - let component; - let actions; - let form; - - beforeEach(async () => { - await act(async () => { - ({ component, form, actions } = setup()); - }); - - component.update(); - }); - - test('should not allow spaces', async () => { - form.setInputValue('remoteClusterFormNameInput', 'with space'); - - await actions.clickSaveForm(); - - expect(form.getErrorsMessages()).toContain('Spaces are not allowed in the name.'); - }); - - test('should only allow alpha-numeric characters, "-" (dash) and "_" (underscore)', async () => { - const expectInvalidChar = (char) => { - if (char === '-' || char === '_') { - return; - } - - try { - form.setInputValue('remoteClusterFormNameInput', `with${char}`); - - expect(form.getErrorsMessages()).toContain( - `Remove the character ${char} from the name.` - ); - } catch { - throw Error(`Char "${char}" expected invalid but was allowed`); - } - }; - - await actions.clickSaveForm(); // display form errors - - [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS].forEach(expectInvalidChar); - }); - }); - - describe('seeds', () => { - let actions; - let form; - let component; - - beforeEach(async () => { - await act(async () => { - ({ form, actions, component } = setup()); - }); - - component.update(); - - form.setInputValue('remoteClusterFormNameInput', 'remote_cluster_test'); - }); - - test('should only allow alpha-numeric characters and "-" (dash) in the node "host" part', async () => { - await actions.clickSaveForm(); // display form errors - - const notInArray = (array) => (value) => array.indexOf(value) < 0; - - const expectInvalidChar = (char) => { - form.setComboBoxValue('remoteClusterFormSeedsInput', `192.16${char}:3000`); - expect(form.getErrorsMessages()).toContain( - `Seed node must use host:port format. Example: 127.0.0.1:9400, localhost:9400. Hosts can only consist of letters, numbers, and dashes.` - ); - }; - - [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS] - .filter(notInArray(['-', '_', ':'])) - .forEach(expectInvalidChar); - }); - - test('should require a numeric "port" to be set', async () => { - await actions.clickSaveForm(); - - form.setComboBoxValue('remoteClusterFormSeedsInput', '192.168.1.1'); - expect(form.getErrorsMessages()).toContain('A port is required.'); - - form.setComboBoxValue('remoteClusterFormSeedsInput', '192.168.1.1:abc'); - expect(form.getErrorsMessages()).toContain('A port is required.'); - }); - }); - - describe('proxy address', () => { - let actions; - let form; - let component; - - beforeEach(async () => { - await act(async () => { - ({ form, actions, component } = setup()); - }); - - component.update(); - - act(() => { - // Enable "proxy" mode - form.toggleEuiSwitch('remoteClusterFormConnectionModeToggle'); - }); - - component.update(); - }); - - test('should only allow alpha-numeric characters and "-" (dash) in the proxy address "host" part', async () => { - await actions.clickSaveForm(); // display form errors - - const notInArray = (array) => (value) => array.indexOf(value) < 0; - - const expectInvalidChar = (char) => { - form.setInputValue('remoteClusterFormProxyAddressInput', `192.16${char}:3000`); - expect(form.getErrorsMessages()).toContain( - 'Address must use host:port format. Example: 127.0.0.1:9400, localhost:9400. Hosts can only consist of letters, numbers, and dashes.' - ); - }; - - [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS] - .filter(notInArray(['-', '_', ':'])) - .forEach(expectInvalidChar); - }); - - test('should require a numeric "port" to be set', async () => { - await actions.clickSaveForm(); - - form.setInputValue('remoteClusterFormProxyAddressInput', '192.168.1.1'); - expect(form.getErrorsMessages()).toContain('A port is required.'); - - form.setInputValue('remoteClusterFormProxyAddressInput', '192.168.1.1:abc'); - expect(form.getErrorsMessages()).toContain('A port is required.'); - }); - }); - }); -}); diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.ts b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.ts new file mode 100644 index 0000000000000..0727bc0c9ba2d --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/remote_clusters_add.test.ts @@ -0,0 +1,260 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SinonFakeServer } from 'sinon'; +import { TestBed } from '@kbn/test/jest'; +import { act } from 'react-dom/test-utils'; + +import { setupEnvironment, RemoteClustersActions } from '../helpers'; +import { setup } from './remote_clusters_add.helpers'; +import { NON_ALPHA_NUMERIC_CHARS, ACCENTED_CHARS } from './special_characters'; + +const notInArray = (array: string[]) => (value: string) => array.indexOf(value) < 0; + +let component: TestBed['component']; +let actions: RemoteClustersActions; +let server: SinonFakeServer; + +describe('Create Remote cluster', () => { + beforeAll(() => { + ({ server } = setupEnvironment()); + }); + + afterAll(() => { + server.restore(); + }); + + beforeEach(async () => { + await act(async () => { + ({ actions, component } = await setup()); + }); + component.update(); + }); + + describe('on component mount', () => { + test('should have the title of the page set correctly', () => { + expect(actions.pageTitle.exists()).toBe(true); + expect(actions.pageTitle.text()).toEqual('Add remote cluster'); + }); + + test('should have a link to the documentation', () => { + expect(actions.docsButtonExists()).toBe(true); + }); + + test('should have a toggle to Skip unavailable remote cluster', () => { + expect(actions.skipUnavailableSwitch.exists()).toBe(true); + + // By default it should be set to "false" + expect(actions.skipUnavailableSwitch.isChecked()).toBe(false); + + actions.skipUnavailableSwitch.toggle(); + + expect(actions.skipUnavailableSwitch.isChecked()).toBe(true); + }); + + describe('on prem', () => { + test('should have a toggle to enable "proxy" mode for a remote cluster', () => { + expect(actions.connectionModeSwitch.exists()).toBe(true); + + // By default it should be set to "false" + expect(actions.connectionModeSwitch.isChecked()).toBe(false); + + actions.connectionModeSwitch.toggle(); + + expect(actions.connectionModeSwitch.isChecked()).toBe(true); + }); + + test('server name has optional label', () => { + actions.connectionModeSwitch.toggle(); + expect(actions.serverNameInput.getLabel()).toBe('Server name (optional)'); + }); + + test('should display errors and disable the save button when clicking "save" without filling the form', async () => { + expect(actions.globalErrorExists()).toBe(false); + expect(actions.saveButton.isDisabled()).toBe(false); + + await actions.saveButton.click(); + + expect(actions.globalErrorExists()).toBe(true); + expect(actions.getErrorMessages()).toEqual([ + 'Name is required.', + // seeds input is switched on by default on prem and is required + 'At least one seed node is required.', + ]); + expect(actions.saveButton.isDisabled()).toBe(true); + }); + + test('renders no switch for cloud url input and proxy address + server name input modes', () => { + expect(actions.cloudUrlSwitch.exists()).toBe(false); + }); + }); + describe('on cloud', () => { + beforeEach(async () => { + await act(async () => { + ({ actions, component } = await setup(true)); + }); + + component.update(); + }); + + test('renders a switch between cloud url input and proxy address + server name input for proxy connection', () => { + expect(actions.cloudUrlSwitch.exists()).toBe(true); + }); + + test('renders no switch between sniff and proxy modes', () => { + expect(actions.connectionModeSwitch.exists()).toBe(false); + }); + test('defaults to cloud url input for proxy connection', () => { + expect(actions.cloudUrlSwitch.isChecked()).toBe(false); + }); + test('server name has no optional label', () => { + actions.cloudUrlSwitch.toggle(); + expect(actions.serverNameInput.getLabel()).toBe('Server name'); + }); + }); + }); + describe('form validation', () => { + describe('remote cluster name', () => { + test('should not allow spaces', async () => { + actions.nameInput.setValue('with space'); + + await actions.saveButton.click(); + + expect(actions.getErrorMessages()).toContain('Spaces are not allowed in the name.'); + }); + + test('should only allow alpha-numeric characters, "-" (dash) and "_" (underscore)', async () => { + const expectInvalidChar = (char: string) => { + if (char === '-' || char === '_') { + return; + } + + try { + actions.nameInput.setValue(`with${char}`); + + expect(actions.getErrorMessages()).toContain( + `Remove the character ${char} from the name.` + ); + } catch { + throw Error(`Char "${char}" expected invalid but was allowed`); + } + }; + + await actions.saveButton.click(); // display form errors + + [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS].forEach(expectInvalidChar); + }); + }); + + describe('proxy address', () => { + beforeEach(async () => { + await act(async () => { + ({ actions, component } = await setup()); + }); + + component.update(); + + actions.connectionModeSwitch.toggle(); + }); + + test('should only allow alpha-numeric characters and "-" (dash) in the proxy address "host" part', async () => { + await actions.saveButton.click(); // display form errors + + const expectInvalidChar = (char: string) => { + actions.proxyAddressInput.setValue(`192.16${char}:3000`); + expect(actions.getErrorMessages()).toContain( + 'Address must use host:port format. Example: 127.0.0.1:9400, localhost:9400. Hosts can only consist of letters, numbers, and dashes.' + ); + }; + + [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS] + .filter(notInArray(['-', '_', ':'])) + .forEach(expectInvalidChar); + }); + + test('should require a numeric "port" to be set', async () => { + await actions.saveButton.click(); + + actions.proxyAddressInput.setValue('192.168.1.1'); + expect(actions.getErrorMessages()).toContain('A port is required.'); + + actions.proxyAddressInput.setValue('192.168.1.1:abc'); + expect(actions.getErrorMessages()).toContain('A port is required.'); + }); + }); + + describe('on prem', () => { + beforeEach(async () => { + await act(async () => { + ({ actions, component } = await setup()); + }); + + component.update(); + + actions.nameInput.setValue('remote_cluster_test'); + }); + + describe('seeds', () => { + test('should only allow alpha-numeric characters and "-" (dash) in the node "host" part', async () => { + await actions.saveButton.click(); // display form errors + + const expectInvalidChar = (char: string) => { + actions.seedsInput.setValue(`192.16${char}:3000`); + expect(actions.getErrorMessages()).toContain( + `Seed node must use host:port format. Example: 127.0.0.1:9400, localhost:9400. Hosts can only consist of letters, numbers, and dashes.` + ); + }; + + [...NON_ALPHA_NUMERIC_CHARS, ...ACCENTED_CHARS] + .filter(notInArray(['-', '_', ':'])) + .forEach(expectInvalidChar); + }); + + test('should require a numeric "port" to be set', async () => { + await actions.saveButton.click(); + + actions.seedsInput.setValue('192.168.1.1'); + expect(actions.getErrorMessages()).toContain('A port is required.'); + + actions.seedsInput.setValue('192.168.1.1:abc'); + expect(actions.getErrorMessages()).toContain('A port is required.'); + }); + }); + + test('server name is optional (proxy connection)', () => { + actions.connectionModeSwitch.toggle(); + actions.saveButton.click(); + expect(actions.getErrorMessages()).toEqual(['A proxy address is required.']); + }); + }); + + describe('on cloud', () => { + beforeEach(async () => { + await act(async () => { + ({ actions, component } = await setup(true)); + }); + + component.update(); + }); + + test('cloud url is required since cloud url input is enabled by default', () => { + actions.saveButton.click(); + expect(actions.getErrorMessages()).toContain('A url is required.'); + }); + + test('proxy address and server name are required when cloud url input is disabled', () => { + actions.cloudUrlSwitch.toggle(); + actions.saveButton.click(); + expect(actions.getErrorMessages()).toEqual([ + 'Name is required.', + 'A proxy address is required.', + 'A server name is required.', + ]); + }); + }); + }); +}); diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/add/special_characters.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/add/special_characters.ts similarity index 100% rename from x-pack/plugins/remote_clusters/__jest__/client_integration/add/special_characters.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/add/special_characters.ts diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.js deleted file mode 100644 index 094fb5056e983..0000000000000 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.js +++ /dev/null @@ -1,34 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { registerTestBed } from '@kbn/test/jest'; - -import { RemoteClusterEdit } from '../../../public/application/sections/remote_cluster_edit'; -import { createRemoteClustersStore } from '../../../public/application/store'; -import { registerRouter } from '../../../public/application/services/routing'; - -export const REMOTE_CLUSTER_EDIT_NAME = 'new-york'; - -export const REMOTE_CLUSTER_EDIT = { - name: REMOTE_CLUSTER_EDIT_NAME, - seeds: ['localhost:9400'], - skipUnavailable: true, -}; - -const testBedConfig = { - store: createRemoteClustersStore, - memoryRouter: { - onRouter: (router) => registerRouter(router), - // The remote cluster name to edit is read from the router ":id" param - // so we first set it in our initial entries - initialEntries: [`/${REMOTE_CLUSTER_EDIT_NAME}`], - // and then we declarae the :id param on the component route path - componentRoutePath: '/:name', - }, -}; - -export const setup = registerTestBed(RemoteClusterEdit, testBedConfig); diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.tsx b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.tsx new file mode 100644 index 0000000000000..2259396bf33f2 --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.helpers.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { registerTestBed, TestBedConfig } from '@kbn/test/jest'; + +import React from 'react'; +import { RemoteClusterEdit } from '../../../public/application/sections'; +import { createRemoteClustersStore } from '../../../public/application/store'; +import { AppRouter, registerRouter } from '../../../public/application/services'; +import { createRemoteClustersActions } from '../helpers'; +import { AppContextProvider } from '../../../public/application/app_context'; + +export const REMOTE_CLUSTER_EDIT_NAME = 'new-york'; + +export const REMOTE_CLUSTER_EDIT = { + name: REMOTE_CLUSTER_EDIT_NAME, + seeds: ['localhost:9400'], + skipUnavailable: true, +}; + +const ComponentWithContext = (props: { isCloudEnabled: boolean }) => { + const { isCloudEnabled, ...rest } = props; + return ( + + + + ); +}; + +const testBedConfig: TestBedConfig = { + store: createRemoteClustersStore, + memoryRouter: { + onRouter: (router: AppRouter) => registerRouter(router), + // The remote cluster name to edit is read from the router ":id" param + // so we first set it in our initial entries + initialEntries: [`/${REMOTE_CLUSTER_EDIT_NAME}`], + // and then we declare the :id param on the component route path + componentRoutePath: '/:name', + }, +}; + +const initTestBed = (isCloudEnabled: boolean) => + registerTestBed(ComponentWithContext, testBedConfig)({ isCloudEnabled }); + +export const setup = async (isCloudEnabled = false) => { + const testBed = await initTestBed(isCloudEnabled); + + return { + ...testBed, + actions: { + ...createRemoteClustersActions(testBed), + }, + }; +}; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.js deleted file mode 100644 index 19dd468cb76c5..0000000000000 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.js +++ /dev/null @@ -1,80 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act } from 'react-dom/test-utils'; - -import { RemoteClusterForm } from '../../../public/application/sections/components/remote_cluster_form'; -import { setupEnvironment } from '../helpers'; -import { setup as setupRemoteClustersAdd } from '../add/remote_clusters_add.helpers'; -import { - setup, - REMOTE_CLUSTER_EDIT, - REMOTE_CLUSTER_EDIT_NAME, -} from './remote_clusters_edit.helpers'; - -describe('Edit Remote cluster', () => { - let component; - let find; - let exists; - - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); - - httpRequestsMockHelpers.setLoadRemoteClustersResponse([REMOTE_CLUSTER_EDIT]); - - beforeEach(async () => { - await act(async () => { - ({ component, find, exists } = setup()); - }); - component.update(); - }); - - test('should have the title of the page set correctly', () => { - expect(exists('remoteClusterPageTitle')).toBe(true); - expect(find('remoteClusterPageTitle').text()).toEqual('Edit remote cluster'); - }); - - test('should have a link to the documentation', () => { - expect(exists('remoteClusterDocsButton')).toBe(true); - }); - - /** - * As the "edit" remote cluster component uses the same form underneath that - * the "create" remote cluster, we won't test it again but simply make sure that - * the form component is indeed shared between the 2 app sections. - */ - test('should use the same Form component as the "" component', async () => { - let addRemoteClusterTestBed; - - await act(async () => { - addRemoteClusterTestBed = setupRemoteClustersAdd(); - }); - - addRemoteClusterTestBed.component.update(); - - const formEdit = component.find(RemoteClusterForm); - const formAdd = addRemoteClusterTestBed.component.find(RemoteClusterForm); - - expect(formEdit.length).toBe(1); - expect(formAdd.length).toBe(1); - }); - - test('should populate the form fields with the values from the remote cluster loaded', () => { - expect(find('remoteClusterFormNameInput').props().value).toBe(REMOTE_CLUSTER_EDIT_NAME); - expect(find('remoteClusterFormSeedsInput').text()).toBe(REMOTE_CLUSTER_EDIT.seeds.join('')); - expect(find('remoteClusterFormSkipUnavailableFormToggle').props()['aria-checked']).toBe( - REMOTE_CLUSTER_EDIT.skipUnavailable - ); - }); - - test('should disable the form name input', () => { - expect(find('remoteClusterFormNameInput').props().disabled).toBe(true); - }); -}); diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.tsx b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.tsx new file mode 100644 index 0000000000000..2913de94bc2dd --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/edit/remote_clusters_edit.test.tsx @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { TestBed } from '@kbn/test/jest'; + +import { RemoteClusterForm } from '../../../public/application/sections/components/remote_cluster_form'; +import { RemoteClustersActions, setupEnvironment } from '../helpers'; +import { setup as setupRemoteClustersAdd } from '../add/remote_clusters_add.helpers'; +import { + setup, + REMOTE_CLUSTER_EDIT, + REMOTE_CLUSTER_EDIT_NAME, +} from './remote_clusters_edit.helpers'; +import { Cluster } from '../../../common/lib'; + +let component: TestBed['component']; +let actions: RemoteClustersActions; +const { server, httpRequestsMockHelpers } = setupEnvironment(); + +describe('Edit Remote cluster', () => { + afterAll(() => { + server.restore(); + }); + + httpRequestsMockHelpers.setLoadRemoteClustersResponse([REMOTE_CLUSTER_EDIT]); + + beforeEach(async () => { + await act(async () => { + ({ component, actions } = await setup()); + }); + component.update(); + }); + + test('should have the title of the page set correctly', () => { + expect(actions.pageTitle.exists()).toBe(true); + expect(actions.pageTitle.text()).toEqual('Edit remote cluster'); + }); + + test('should have a link to the documentation', () => { + expect(actions.docsButtonExists()).toBe(true); + }); + + /** + * As the "edit" remote cluster component uses the same form underneath that + * the "create" remote cluster, we won't test it again but simply make sure that + * the form component is indeed shared between the 2 app sections. + */ + test('should use the same Form component as the "" component', async () => { + let addRemoteClusterTestBed: TestBed; + + await act(async () => { + addRemoteClusterTestBed = await setupRemoteClustersAdd(); + }); + + addRemoteClusterTestBed!.component.update(); + + const formEdit = component.find(RemoteClusterForm); + const formAdd = addRemoteClusterTestBed!.component.find(RemoteClusterForm); + + expect(formEdit.length).toBe(1); + expect(formAdd.length).toBe(1); + }); + + test('should populate the form fields with the values from the remote cluster loaded', () => { + expect(actions.nameInput.getValue()).toBe(REMOTE_CLUSTER_EDIT_NAME); + // seeds input for sniff connection is not shown on Cloud + expect(actions.seedsInput.getValue()).toBe(REMOTE_CLUSTER_EDIT.seeds.join('')); + expect(actions.skipUnavailableSwitch.isChecked()).toBe(REMOTE_CLUSTER_EDIT.skipUnavailable); + }); + + test('should disable the form name input', () => { + expect(actions.nameInput.isDisabled()).toBe(true); + }); + + describe('on cloud', () => { + const cloudUrl = 'cloud-url'; + const defaultCloudPort = '9400'; + test('existing cluster that defaults to cloud url (default port)', async () => { + const cluster: Cluster = { + name: REMOTE_CLUSTER_EDIT_NAME, + mode: 'proxy', + proxyAddress: `${cloudUrl}:${defaultCloudPort}`, + serverName: cloudUrl, + }; + httpRequestsMockHelpers.setLoadRemoteClustersResponse([cluster]); + + await act(async () => { + ({ component, actions } = await setup(true)); + }); + component.update(); + + expect(actions.cloudUrlInput.exists()).toBe(true); + expect(actions.cloudUrlInput.getValue()).toBe(cloudUrl); + }); + + test('existing cluster that defaults to manual input (non-default port)', async () => { + const cluster: Cluster = { + name: REMOTE_CLUSTER_EDIT_NAME, + mode: 'proxy', + proxyAddress: `${cloudUrl}:9500`, + serverName: cloudUrl, + }; + httpRequestsMockHelpers.setLoadRemoteClustersResponse([cluster]); + + await act(async () => { + ({ component, actions } = await setup(true)); + }); + component.update(); + + expect(actions.cloudUrlInput.exists()).toBe(false); + + expect(actions.proxyAddressInput.exists()).toBe(true); + expect(actions.serverNameInput.exists()).toBe(true); + }); + + test('existing cluster that defaults to manual input (proxy address is different from server name)', async () => { + const cluster: Cluster = { + name: REMOTE_CLUSTER_EDIT_NAME, + mode: 'proxy', + proxyAddress: `${cloudUrl}:${defaultCloudPort}`, + serverName: 'another-value', + }; + httpRequestsMockHelpers.setLoadRemoteClustersResponse([cluster]); + + await act(async () => { + ({ component, actions } = await setup(true)); + }); + component.update(); + + expect(actions.cloudUrlInput.exists()).toBe(false); + + expect(actions.proxyAddressInput.exists()).toBe(true); + expect(actions.serverNameInput.exists()).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.ts similarity index 63% rename from x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.ts index 304ec51986aba..3ebe3ab5738d6 100644 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/http_requests.ts @@ -5,25 +5,24 @@ * 2.0. */ -import sinon from 'sinon'; +import sinon, { SinonFakeServer } from 'sinon'; +import { Cluster } from '../../../common/lib'; // Register helpers to mock HTTP Requests -const registerHttpRequestMockHelpers = (server) => { - const mockResponse = (response) => [ +const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { + const mockResponse = (response: Cluster[] | { itemsDeleted: string[]; errors: string[] }) => [ 200, { 'Content-Type': 'application/json' }, JSON.stringify(response), ]; - const setLoadRemoteClustersResponse = (response) => { - server.respondWith('GET', '/api/remote_clusters', [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(response), - ]); + const setLoadRemoteClustersResponse = (response: Cluster[] = []) => { + server.respondWith('GET', '/api/remote_clusters', mockResponse(response)); }; - const setDeleteRemoteClusterResponse = (response) => { + const setDeleteRemoteClusterResponse = ( + response: { itemsDeleted: string[]; errors: string[] } = { itemsDeleted: [], errors: [] } + ) => { server.respondWith('DELETE', /api\/remote_clusters/, mockResponse(response)); }; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.ts similarity index 80% rename from x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.ts index 63084b21e3902..cf859ff6913f5 100644 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/index.ts @@ -7,3 +7,4 @@ export { nextTick, getRandomString, findTestSubject } from '@kbn/test/jest'; export { setupEnvironment } from './setup_environment'; +export { createRemoteClustersActions, RemoteClustersActions } from './remote_clusters_actions'; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_actions.ts b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_actions.ts new file mode 100644 index 0000000000000..ba0c424793838 --- /dev/null +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/remote_clusters_actions.ts @@ -0,0 +1,199 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { TestBed } from '@kbn/test/jest'; +import { act } from 'react-dom/test-utils'; +export interface RemoteClustersActions { + docsButtonExists: () => boolean; + pageTitle: { + exists: () => boolean; + text: () => string; + }; + nameInput: { + setValue: (name: string) => void; + getValue: () => string; + isDisabled: () => boolean; + }; + skipUnavailableSwitch: { + exists: () => boolean; + toggle: () => void; + isChecked: () => boolean; + }; + connectionModeSwitch: { + exists: () => boolean; + toggle: () => void; + isChecked: () => boolean; + }; + cloudUrlSwitch: { + toggle: () => void; + exists: () => boolean; + isChecked: () => boolean; + }; + cloudUrlInput: { + exists: () => boolean; + getValue: () => string; + }; + seedsInput: { + setValue: (seed: string) => void; + getValue: () => string; + }; + proxyAddressInput: { + setValue: (proxyAddress: string) => void; + exists: () => boolean; + }; + serverNameInput: { + getLabel: () => string; + exists: () => boolean; + }; + saveButton: { + click: () => void; + isDisabled: () => boolean; + }; + getErrorMessages: () => string[]; + globalErrorExists: () => boolean; +} +export const createRemoteClustersActions = (testBed: TestBed): RemoteClustersActions => { + const { form, exists, find, component } = testBed; + + const docsButtonExists = () => exists('remoteClusterDocsButton'); + const createPageTitleActions = () => { + const pageTitleSelector = 'remoteClusterPageTitle'; + return { + pageTitle: { + exists: () => exists(pageTitleSelector), + text: () => find(pageTitleSelector).text(), + }, + }; + }; + const createNameInputActions = () => { + const nameInputSelector = 'remoteClusterFormNameInput'; + return { + nameInput: { + setValue: (name: string) => form.setInputValue(nameInputSelector, name), + getValue: () => find(nameInputSelector).props().value, + isDisabled: () => find(nameInputSelector).props().disabled, + }, + }; + }; + + const createSkipUnavailableActions = () => { + const skipUnavailableToggleSelector = 'remoteClusterFormSkipUnavailableFormToggle'; + return { + skipUnavailableSwitch: { + exists: () => exists(skipUnavailableToggleSelector), + toggle: () => { + act(() => { + form.toggleEuiSwitch(skipUnavailableToggleSelector); + }); + component.update(); + }, + isChecked: () => find(skipUnavailableToggleSelector).props()['aria-checked'], + }, + }; + }; + + const createConnectionModeActions = () => { + const connectionModeToggleSelector = 'remoteClusterFormConnectionModeToggle'; + return { + connectionModeSwitch: { + exists: () => exists(connectionModeToggleSelector), + toggle: () => { + act(() => { + form.toggleEuiSwitch(connectionModeToggleSelector); + }); + component.update(); + }, + isChecked: () => find(connectionModeToggleSelector).props()['aria-checked'], + }, + }; + }; + + const createCloudUrlSwitchActions = () => { + const cloudUrlSelector = 'remoteClusterFormCloudUrlToggle'; + return { + cloudUrlSwitch: { + exists: () => exists(cloudUrlSelector), + toggle: () => { + act(() => { + form.toggleEuiSwitch(cloudUrlSelector); + }); + component.update(); + }, + isChecked: () => find(cloudUrlSelector).props()['aria-checked'], + }, + }; + }; + + const createSeedsInputActions = () => { + const seedsInputSelector = 'remoteClusterFormSeedsInput'; + return { + seedsInput: { + setValue: (seed: string) => form.setComboBoxValue(seedsInputSelector, seed), + getValue: () => find(seedsInputSelector).text(), + }, + }; + }; + + const createProxyAddressActions = () => { + const proxyAddressSelector = 'remoteClusterFormProxyAddressInput'; + return { + proxyAddressInput: { + setValue: (proxyAddress: string) => form.setInputValue(proxyAddressSelector, proxyAddress), + exists: () => exists(proxyAddressSelector), + }, + }; + }; + + const createSaveButtonActions = () => { + const click = () => { + act(() => { + find('remoteClusterFormSaveButton').simulate('click'); + }); + + component.update(); + }; + const isDisabled = () => find('remoteClusterFormSaveButton').props().disabled; + return { saveButton: { click, isDisabled } }; + }; + + const createServerNameActions = () => { + const serverNameSelector = 'remoteClusterFormServerNameFormRow'; + return { + serverNameInput: { + getLabel: () => find('remoteClusterFormServerNameFormRow').find('label').text(), + exists: () => exists(serverNameSelector), + }, + }; + }; + + const globalErrorExists = () => exists('remoteClusterFormGlobalError'); + + const createCloudUrlInputActions = () => { + const cloudUrlInputSelector = 'remoteClusterFormCloudUrlInput'; + return { + cloudUrlInput: { + exists: () => exists(cloudUrlInputSelector), + getValue: () => find(cloudUrlInputSelector).props().value, + }, + }; + }; + return { + docsButtonExists, + ...createPageTitleActions(), + ...createNameInputActions(), + ...createSkipUnavailableActions(), + ...createConnectionModeActions(), + ...createCloudUrlSwitchActions(), + ...createSeedsInputActions(), + ...createCloudUrlInputActions(), + ...createProxyAddressActions(), + ...createServerNameActions(), + ...createSaveButtonActions(), + getErrorMessages: form.getErrorsMessages, + globalErrorExists, + }; +}; diff --git a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.ts similarity index 95% rename from x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js rename to x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.ts index 97ad344a63cc4..084552c5e6abe 100644 --- a/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.js +++ b/x-pack/plugins/remote_clusters/__jest__/client_integration/helpers/setup_environment.ts @@ -36,6 +36,8 @@ export const setupEnvironment = () => { notificationServiceMock.createSetupContract().toasts, fatalErrorsServiceMock.createSetupContract() ); + // This expects HttpSetup but we're giving it AxiosInstance. + // @ts-ignore initHttp(mockHttpClient); const { server, httpRequestsMockHelpers } = initHttpRequests(); diff --git a/x-pack/plugins/remote_clusters/public/application/app_context.tsx b/x-pack/plugins/remote_clusters/public/application/app_context.tsx index 7931001c6faee..528ec322f49e1 100644 --- a/x-pack/plugins/remote_clusters/public/application/app_context.tsx +++ b/x-pack/plugins/remote_clusters/public/application/app_context.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { createContext } from 'react'; +import React, { createContext, useContext } from 'react'; export interface Context { isCloudEnabled: boolean; + cloudBaseUrl: string; } export const AppContext = createContext({} as any); @@ -22,3 +23,10 @@ export const AppContextProvider = ({ }) => { return {children}; }; + +export const useAppContext = () => { + const ctx = useContext(AppContext); + if (!ctx) throw new Error('Cannot use outside of app context'); + + return ctx; +}; diff --git a/x-pack/plugins/remote_clusters/public/application/index.d.ts b/x-pack/plugins/remote_clusters/public/application/index.d.ts index 167297cedf556..45f981b5f2bc5 100644 --- a/x-pack/plugins/remote_clusters/public/application/index.d.ts +++ b/x-pack/plugins/remote_clusters/public/application/index.d.ts @@ -12,7 +12,8 @@ export declare const renderApp: ( elem: HTMLElement | null, I18nContext: I18nStart['Context'], appDependencies: { - isCloudEnabled?: boolean; + isCloudEnabled: boolean; + cloudBaseUrl: string; }, history: ScopedHistory ) => ReturnType; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap deleted file mode 100644 index 5f09193be90c2..0000000000000 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/__snapshots__/remote_cluster_form.test.js.snap +++ /dev/null @@ -1,2017 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RemoteClusterForm proxy mode renders correct connection settings when user enables proxy mode 1`] = ` - - -
- - } - fullWidth={true} - title={ - -

- -

-
- } - > -
- -
- -
- - -

- - Name - -

-
-
- -
- -
- - A unique name for the cluster. - -
-
-
-
-
-
- -
- - } - fullWidth={true} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - - } - isInvalid={false} - label={ - - } - labelType="label" - > -
-
- - - -
-
- - -
-
- - - - -
-
-
-
- -
- - Name can only contain letters, numbers, underscores, and dashes. - -
-
-
-
-
-
-
-
-
-
-
- - - - - } - onChange={[Function]} - /> - - - } - fullWidth={true} - title={ - -

- -

-
- } - > -
- -
- -
- - -

- - Connection mode - -

-
-
- -
- -
- - Use seed nodes by default, or switch to proxy mode. - - -
-
- - } - onBlur={[Function]} - onChange={[Function]} - onFocus={[Function]} - > -
- - - - Use proxy mode - - -
-
-
-
-
-
-
-
-
-
-
- -
- - } - fullWidth={true} - hasChildLabel={true} - hasEmptyLabelSpace={false} - helpText={ - - } - isInvalid={false} - label={ - - } - labelType="label" - > -
-
- - - -
-
- - -
-
- - - - -
-
-
-
- -
- - The address to use for remote connections. - -
-
-
-
-
- - - , - } - } - /> - } - isInvalid={false} - label={ - - } - labelType="label" - > -
-
- - - -
-
- - -
-
- - - - -
-
-
-
- -
- - - , - } - } - > - A string sent in the server_name field of the TLS Server Name Indication extension if TLS is enabled. - - - - -
-
-
-
-
- - } - label={ - - } - labelType="label" - > -
-
- - - -
-
- - -
-
- - - - -
-
-
-
- -
- - The number of socket connections to open per remote cluster. - -
-
-
-
-
-
-
-
-
-
-
- -

- - - , - "optionName": - - , - } - } - /> -

- - } - fullWidth={true} - title={ - -

- -

-
- } - > -
- -
- -
- - -

- - Make remote cluster optional - -

-
-
- -
- -
-

- - - , - "optionName": - - , - } - } - > - A request fails if any of the queried remote clusters are unavailable. To send requests to other remote clusters if this cluster is unavailable, enable - - - Skip if unavailable - - - . - - - - -

-
-
-
-
-
-
- -
- -
-
- -
- - - Skip if unavailable - -
-
-
-
-
-
-
-
-
-
-
-
-
- -
- - -
- -
- -
- -
- - - - - -
-
-
-
-
-
- -
- - - -
-
-
-
- -`; - -exports[`RemoteClusterForm renders untouched state 1`] = ` -Array [ -
-
-
-
-

- Name -

-
-
- A unique name for the cluster. -
-
-
-
-
-
- -
-
-
-
- -
-
-
- Name can only contain letters, numbers, underscores, and dashes. -
-
-
-
-
-
-
-
-
-

- Connection mode -

-
-
- Use seed nodes by default, or switch to proxy mode. -
-
-
- - - Use proxy mode - -
-
-
-
-
-
-
-
-
- -
-
- -
-
-
- -
-
-
-
- -
-
-
- The number of gateway nodes to connect to for this cluster. -
-
-
-
-
-
-
-
-
-

- Make remote cluster optional -

-
-
-

- A request fails if any of the queried remote clusters are unavailable. To send requests to other remote clusters if this cluster is unavailable, enable - - Skip if unavailable - - . - -

-
-
-
-
-
-
-
- - - Skip if unavailable - -
-
-
-
-
-
-
, -
, -
-
-
-
- -
-
-
-
- -
-
, -] -`; - -exports[`RemoteClusterForm validation renders invalid state and a global form error when the user tries to submit an invalid form 1`] = ` -Array [ -
-
- -
-
-
-
- -
-
-
- Name is required. -
-
- Name can only contain letters, numbers, underscores, and dashes. -
-
-
, -
-
- -
-
- -
, -
-
-
- - - Skip if unavailable - -
-
-
, -
, -] -`; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/cloud_url_help.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/cloud_url_help.tsx new file mode 100644 index 0000000000000..1d4862ff094ce --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/cloud_url_help.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FunctionComponent, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiLink, EuiPopover, EuiPopoverTitle, EuiText } from '@elastic/eui'; +import { useAppContext } from '../../../../app_context'; + +export const CloudUrlHelp: FunctionComponent = () => { + const [isOpen, setIsOpen] = useState(false); + const { cloudBaseUrl } = useAppContext(); + return ( + + { + setIsOpen(!isOpen); + }} + > + + + + } + isOpen={isOpen} + closePopover={() => setIsOpen(false)} + anchorPosition="upCenter" + > + + + + + + + + ), + elasticsearch: Elasticsearch, + }} + /> + + + ); +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/connection_mode.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/connection_mode.tsx new file mode 100644 index 0000000000000..d06b4f111ec92 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/connection_mode.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FunctionComponent } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiDescribedFormGroup, EuiTitle, EuiFormRow, EuiSwitch, EuiSpacer } from '@elastic/eui'; + +import { SNIFF_MODE, PROXY_MODE } from '../../../../../../common/constants'; +import { useAppContext } from '../../../../app_context'; + +import { ClusterErrors } from '../validators'; +import { SniffConnection } from './sniff_connection'; +import { ProxyConnection } from './proxy_connection'; +import { FormFields } from '../remote_cluster_form'; + +export interface Props { + fields: FormFields; + onFieldsChange: (fields: Partial) => void; + fieldsErrors: ClusterErrors; + areErrorsVisible: boolean; +} + +export const ConnectionMode: FunctionComponent = (props) => { + const { fields, onFieldsChange } = props; + const { mode, cloudUrlEnabled } = fields; + const { isCloudEnabled } = useAppContext(); + + return ( + +

+ +

+ + } + description={ + <> + {isCloudEnabled ? ( + <> + + + + } + checked={!cloudUrlEnabled} + data-test-subj="remoteClusterFormCloudUrlToggle" + onChange={(e) => onFieldsChange({ cloudUrlEnabled: !e.target.checked })} + /> + + + + ) : ( + <> + + + + } + checked={mode === PROXY_MODE} + data-test-subj="remoteClusterFormConnectionModeToggle" + onChange={(e) => + onFieldsChange({ mode: e.target.checked ? PROXY_MODE : SNIFF_MODE }) + } + /> + + + )} + + } + fullWidth + > + {mode === SNIFF_MODE ? : } +
+ ); +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/index.ts b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/index.ts new file mode 100644 index 0000000000000..864385ad0b1a3 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { ConnectionMode } from './connection_mode'; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/proxy_connection.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/proxy_connection.tsx new file mode 100644 index 0000000000000..04e8533a0d2af --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/proxy_connection.tsx @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FunctionComponent } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { EuiFieldNumber, EuiFieldText, EuiFormRow, EuiLink } from '@elastic/eui'; +import { useAppContext } from '../../../../app_context'; +import { proxySettingsUrl } from '../../../../services/documentation'; +import { Props } from './connection_mode'; +import { CloudUrlHelp } from './cloud_url_help'; + +export const ProxyConnection: FunctionComponent = (props) => { + const { fields, fieldsErrors, areErrorsVisible, onFieldsChange } = props; + const { isCloudEnabled } = useAppContext(); + const { proxyAddress, serverName, proxySocketConnections, cloudUrl, cloudUrlEnabled } = fields; + const { + proxyAddress: proxyAddressError, + serverName: serverNameError, + cloudUrl: cloudUrlError, + } = fieldsErrors; + + return ( + <> + {cloudUrlEnabled ? ( + <> + + } + labelAppend={} + isInvalid={Boolean(areErrorsVisible && cloudUrlError)} + error={cloudUrlError} + fullWidth + helpText={ + + } + > + onFieldsChange({ cloudUrl: e.target.value })} + isInvalid={Boolean(areErrorsVisible && cloudUrlError)} + data-test-subj="remoteClusterFormCloudUrlInput" + fullWidth + /> + + + ) : ( + <> + + } + helpText={ + + } + isInvalid={Boolean(areErrorsVisible && proxyAddressError)} + error={proxyAddressError} + fullWidth + > + onFieldsChange({ proxyAddress: e.target.value })} + isInvalid={Boolean(areErrorsVisible && proxyAddressError)} + data-test-subj="remoteClusterFormProxyAddressInput" + fullWidth + /> + + + + ) : ( + + ) + } + helpText={ + + + + ), + }} + /> + } + fullWidth + > + onFieldsChange({ serverName: e.target.value })} + isInvalid={Boolean(areErrorsVisible && serverNameError)} + fullWidth + /> + + + )} + + } + helpText={ + + } + fullWidth + > + onFieldsChange({ proxySocketConnections: Number(e.target.value) })} + fullWidth + /> + + + ); +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/sniff_connection.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/sniff_connection.tsx new file mode 100644 index 0000000000000..063aeb3490aef --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/components/sniff_connection.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { FunctionComponent, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { + EuiComboBox, + EuiComboBoxOptionOption, + EuiFieldNumber, + EuiFormRow, + EuiLink, +} from '@elastic/eui'; + +import { transportPortUrl } from '../../../../services/documentation'; +import { validateSeed } from '../validators'; +import { Props } from './connection_mode'; + +export const SniffConnection: FunctionComponent = ({ + fields, + fieldsErrors, + areErrorsVisible, + onFieldsChange, +}) => { + const [localSeedErrors, setLocalSeedErrors] = useState([]); + const { seeds = [], nodeConnections } = fields; + const { seeds: seedsError } = fieldsErrors; + // Show errors if there is a general form error or local errors. + const areFormErrorsVisible = Boolean(areErrorsVisible && seedsError); + const showErrors = areFormErrorsVisible || localSeedErrors.length !== 0; + const errors = + areFormErrorsVisible && seedsError ? localSeedErrors.concat(seedsError) : localSeedErrors; + const formattedSeeds: EuiComboBoxOptionOption[] = seeds.map((seed: string) => ({ label: seed })); + + const onCreateSeed = (newSeed?: string) => { + // If the user just hit enter without typing anything, treat it as a no-op. + if (!newSeed) { + return; + } + + const validationErrors = validateSeed(newSeed); + + if (validationErrors.length !== 0) { + setLocalSeedErrors(validationErrors); + // Return false to explicitly reject the user's input. + return false; + } + + const newSeeds = seeds.slice(0); + newSeeds.push(newSeed.toLowerCase()); + onFieldsChange({ seeds: newSeeds }); + }; + + const onSeedsInputChange = (seedInput?: string) => { + if (!seedInput) { + // If empty seedInput ("") don't do anything. This happens + // right after a seed is created. + return; + } + + // Allow typing to clear the errors, but not to add new ones. + const validationErrors = + !seedInput || validateSeed(seedInput).length === 0 ? [] : localSeedErrors; + + // EuiComboBox internally checks for duplicates and prevents calling onCreateOption if the + // input is a duplicate. So we need to surface this error here instead. + const isDuplicate = seeds.includes(seedInput); + + if (isDuplicate) { + validationErrors.push( + + ); + } + + setLocalSeedErrors(validationErrors); + }; + return ( + <> + + } + helpText={ + + + + ), + }} + /> + } + isInvalid={showErrors} + error={errors} + fullWidth + > + + onFieldsChange({ seeds: options.map(({ label }) => label) }) + } + onSearchChange={onSeedsInputChange} + isInvalid={showErrors} + fullWidth + data-test-subj="remoteClusterFormSeedsInput" + /> + + + + } + helpText={ + + } + fullWidth + > + onFieldsChange({ nodeConnections: Number(e.target.value) })} + fullWidth + /> + + + ); +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/index.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/index.ts similarity index 100% rename from x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/index.js rename to x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/index.ts diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js deleted file mode 100644 index 325215d08af5f..0000000000000 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.js +++ /dev/null @@ -1,962 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { merge } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { - EuiButton, - EuiButtonEmpty, - EuiCallOut, - EuiComboBox, - EuiDescribedFormGroup, - EuiFieldNumber, - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiForm, - EuiFormRow, - EuiLink, - EuiLoadingKibana, - EuiLoadingSpinner, - EuiOverlayMask, - EuiSpacer, - EuiSwitch, - EuiText, - EuiTitle, - EuiDelayRender, - EuiScreenReaderOnly, - htmlIdGenerator, -} from '@elastic/eui'; - -import { - skippingDisconnectedClustersUrl, - transportPortUrl, - proxySettingsUrl, -} from '../../../services/documentation'; - -import { RequestFlyout } from './request_flyout'; - -import { - validateName, - validateSeeds, - validateProxy, - validateSeed, - validateServerName, -} from './validators'; - -import { SNIFF_MODE, PROXY_MODE } from '../../../../../common/constants'; - -import { AppContext } from '../../../app_context'; - -const defaultFields = { - name: '', - seeds: [], - skipUnavailable: false, - nodeConnections: 3, - proxyAddress: '', - proxySocketConnections: 18, - serverName: '', -}; - -const ERROR_TITLE_ID = 'removeClustersErrorTitle'; -const ERROR_LIST_ID = 'removeClustersErrorList'; - -export class RemoteClusterForm extends Component { - static propTypes = { - save: PropTypes.func.isRequired, - cancel: PropTypes.func, - isSaving: PropTypes.bool, - saveError: PropTypes.object, - fields: PropTypes.object, - disabledFields: PropTypes.object, - }; - - static defaultProps = { - fields: merge({}, defaultFields), - disabledFields: {}, - }; - - static contextType = AppContext; - - constructor(props, context) { - super(props, context); - - const { fields, disabledFields } = props; - const { isCloudEnabled } = context; - - // Connection mode should default to "proxy" in cloud - const defaultMode = isCloudEnabled ? PROXY_MODE : SNIFF_MODE; - const fieldsState = merge({}, { ...defaultFields, mode: defaultMode }, fields); - - this.generateId = htmlIdGenerator(); - this.state = { - localSeedErrors: [], - seedInput: '', - fields: fieldsState, - disabledFields, - fieldsErrors: this.getFieldsErrors(fieldsState), - areErrorsVisible: false, - isRequestVisible: false, - }; - } - - toggleRequest = () => { - this.setState(({ isRequestVisible }) => ({ - isRequestVisible: !isRequestVisible, - })); - }; - - getFieldsErrors(fields, seedInput = '') { - const { name, seeds, mode, proxyAddress, serverName } = fields; - const { isCloudEnabled } = this.context; - - return { - name: validateName(name), - seeds: mode === SNIFF_MODE ? validateSeeds(seeds, seedInput) : null, - proxyAddress: mode === PROXY_MODE ? validateProxy(proxyAddress) : null, - // server name is only required in cloud when proxy mode is enabled - serverName: isCloudEnabled && mode === PROXY_MODE ? validateServerName(serverName) : null, - }; - } - - onFieldsChange = (changedFields) => { - this.setState(({ fields: prevFields, seedInput }) => { - const newFields = { - ...prevFields, - ...changedFields, - }; - return { - fields: newFields, - fieldsErrors: this.getFieldsErrors(newFields, seedInput), - }; - }); - }; - - getAllFields() { - const { - fields: { - name, - mode, - seeds, - nodeConnections, - proxyAddress, - proxySocketConnections, - serverName, - skipUnavailable, - }, - } = this.state; - const { fields } = this.props; - - let modeSettings; - - if (mode === PROXY_MODE) { - modeSettings = { - proxyAddress, - proxySocketConnections, - serverName, - }; - } else { - modeSettings = { - seeds, - nodeConnections, - }; - } - - return { - name, - skipUnavailable, - mode, - hasDeprecatedProxySetting: fields.hasDeprecatedProxySetting, - ...modeSettings, - }; - } - - save = () => { - const { save } = this.props; - - if (this.hasErrors()) { - this.setState({ - areErrorsVisible: true, - }); - return; - } - - const cluster = this.getAllFields(); - save(cluster); - }; - - onCreateSeed = (newSeed) => { - // If the user just hit enter without typing anything, treat it as a no-op. - if (!newSeed) { - return; - } - - const localSeedErrors = validateSeed(newSeed); - - if (localSeedErrors.length !== 0) { - this.setState({ - localSeedErrors, - }); - - // Return false to explicitly reject the user's input. - return false; - } - - const { - fields: { seeds }, - } = this.state; - - const newSeeds = seeds.slice(0); - newSeeds.push(newSeed.toLowerCase()); - this.onFieldsChange({ seeds: newSeeds }); - }; - - onSeedsInputChange = (seedInput) => { - if (!seedInput) { - // If empty seedInput ("") don't do anything. This happens - // right after a seed is created. - return; - } - - this.setState(({ fields, localSeedErrors }) => { - const { seeds } = fields; - - // Allow typing to clear the errors, but not to add new ones. - const errors = !seedInput || validateSeed(seedInput).length === 0 ? [] : localSeedErrors; - - // EuiComboBox internally checks for duplicates and prevents calling onCreateOption if the - // input is a duplicate. So we need to surface this error here instead. - const isDuplicate = seeds.includes(seedInput); - - if (isDuplicate) { - errors.push( - i18n.translate('xpack.remoteClusters.remoteClusterForm.localSeedError.duplicateMessage', { - defaultMessage: `Duplicate seed nodes aren't allowed.`, - }) - ); - } - - return { - localSeedErrors: errors, - fieldsErrors: this.getFieldsErrors(fields, seedInput), - seedInput, - }; - }); - }; - - onSeedsChange = (seeds) => { - this.onFieldsChange({ seeds: seeds.map(({ label }) => label) }); - }; - - onSkipUnavailableChange = (e) => { - const skipUnavailable = e.target.checked; - this.onFieldsChange({ skipUnavailable }); - }; - - resetToDefault = (fieldName) => { - this.onFieldsChange({ - [fieldName]: defaultFields[fieldName], - }); - }; - - hasErrors = () => { - const { fieldsErrors, localSeedErrors } = this.state; - const errorValues = Object.values(fieldsErrors); - const hasErrors = errorValues.some((error) => error != null) || localSeedErrors.length; - return hasErrors; - }; - - renderSniffModeSettings() { - const { - areErrorsVisible, - fields: { seeds, nodeConnections }, - fieldsErrors: { seeds: errorsSeeds }, - localSeedErrors, - } = this.state; - - // Show errors if there is a general form error or local errors. - const areFormErrorsVisible = Boolean(areErrorsVisible && errorsSeeds); - const showErrors = areFormErrorsVisible || localSeedErrors.length !== 0; - const errors = areFormErrorsVisible ? localSeedErrors.concat(errorsSeeds) : localSeedErrors; - - const formattedSeeds = seeds.map((seed) => ({ label: seed })); - - return ( - <> - - } - helpText={ - - - - ), - }} - /> - } - isInvalid={showErrors} - error={errors} - fullWidth - > - - - - - } - helpText={ - - } - fullWidth - > - - this.onFieldsChange({ nodeConnections: Number(e.target.value) || null }) - } - fullWidth - /> - - - ); - } - - renderProxyModeSettings() { - const { - areErrorsVisible, - fields: { proxyAddress, proxySocketConnections, serverName }, - fieldsErrors: { proxyAddress: errorProxyAddress, serverName: errorServerName }, - } = this.state; - - const { isCloudEnabled } = this.context; - - return ( - <> - - } - helpText={ - - } - isInvalid={Boolean(areErrorsVisible && errorProxyAddress)} - error={errorProxyAddress} - fullWidth - > - this.onFieldsChange({ proxyAddress: e.target.value })} - isInvalid={Boolean(areErrorsVisible && errorProxyAddress)} - data-test-subj="remoteClusterFormProxyAddressInput" - fullWidth - /> - - - - ) : ( - - ) - } - helpText={ - - - - ), - }} - /> - } - fullWidth - > - this.onFieldsChange({ serverName: e.target.value })} - isInvalid={Boolean(areErrorsVisible && errorServerName)} - fullWidth - /> - - - - } - helpText={ - - } - fullWidth - > - - this.onFieldsChange({ proxySocketConnections: Number(e.target.value) || null }) - } - fullWidth - /> - - - ); - } - - renderMode() { - const { - fields: { mode }, - } = this.state; - - const { isCloudEnabled } = this.context; - - return ( - -

- -

- - } - description={ - <> - - - - } - checked={mode === PROXY_MODE} - data-test-subj="remoteClusterFormConnectionModeToggle" - onChange={(e) => - this.onFieldsChange({ mode: e.target.checked ? PROXY_MODE : SNIFF_MODE }) - } - /> - - {isCloudEnabled && mode === PROXY_MODE ? ( - <> - - - } - > - - - - ), - searchString: ( - - - - ), - }} - /> - - - ) : null} - - } - fullWidth - > - {mode === PROXY_MODE ? this.renderProxyModeSettings() : this.renderSniffModeSettings()} -
- ); - } - - renderSkipUnavailable() { - const { - fields: { skipUnavailable }, - } = this.state; - - return ( - -

- -

- - } - description={ - -

- - - - ), - learnMoreLink: ( - - - - ), - }} - /> -

-
- } - fullWidth - > - { - this.resetToDefault('skipUnavailable'); - }} - > - - - ) : null - } - > - - -
- ); - } - - renderActions() { - const { isSaving, cancel } = this.props; - const { areErrorsVisible, isRequestVisible } = this.state; - - if (isSaving) { - return ( - - - - - - - - - - - - ); - } - - let cancelButton; - - if (cancel) { - cancelButton = ( - - - - - - ); - } - - const isSaveDisabled = areErrorsVisible && this.hasErrors(); - - return ( - - - - - - - - - - {cancelButton} - - - - - - {isRequestVisible ? ( - - ) : ( - - )} - - - - ); - } - - renderSavingFeedback() { - if (this.props.isSaving) { - return ( - - - - ); - } - - return null; - } - - renderSaveErrorFeedback() { - const { saveError } = this.props; - - if (saveError) { - const { message, cause } = saveError; - - let errorBody; - - if (cause && Array.isArray(cause)) { - if (cause.length === 1) { - errorBody =

{cause[0]}

; - } else { - errorBody = ( -
    - {cause.map((causeValue) => ( -
  • {causeValue}
  • - ))} -
- ); - } - } - - return ( - - - {errorBody} - - - - - ); - } - - return null; - } - - renderErrors = () => { - const { - areErrorsVisible, - fieldsErrors: { name: errorClusterName, seeds: errorsSeeds, proxyAddress: errorProxyAddress }, - localSeedErrors, - } = this.state; - - const hasErrors = this.hasErrors(); - - if (!areErrorsVisible || !hasErrors) { - return null; - } - - const errorExplanations = []; - - if (errorClusterName) { - errorExplanations.push({ - key: 'nameExplanation', - field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputNameErrorMessage', { - defaultMessage: 'The "Name" field is invalid.', - }), - error: errorClusterName, - }); - } - - if (errorsSeeds) { - errorExplanations.push({ - key: 'seedsExplanation', - field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputSeedsErrorMessage', { - defaultMessage: 'The "Seed nodes" field is invalid.', - }), - error: errorsSeeds, - }); - } - - if (localSeedErrors && localSeedErrors.length) { - errorExplanations.push({ - key: 'localSeedExplanation', - field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputLocalSeedErrorMessage', { - defaultMessage: 'The "Seed nodes" field is invalid.', - }), - error: localSeedErrors.join(' '), - }); - } - - if (errorProxyAddress) { - errorExplanations.push({ - key: 'seedsExplanation', - field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputProxyErrorMessage', { - defaultMessage: 'The "Proxy address" field is invalid.', - }), - error: errorProxyAddress, - }); - } - - const messagesToBeRendered = errorExplanations.length && ( - -
- {errorExplanations.map(({ key, field, error }) => ( -
-
{field}
-
{error}
-
- ))} -
-
- ); - - return ( - - - - - - } - color="danger" - iconType="cross" - /> - {messagesToBeRendered} - - ); - }; - - render() { - const { - disabledFields: { name: disabledName }, - } = this.props; - - const { - isRequestVisible, - areErrorsVisible, - fields: { name }, - fieldsErrors: { name: errorClusterName }, - } = this.state; - - return ( - - {this.renderSaveErrorFeedback()} - - - -

- -

- - } - description={ - - } - fullWidth - > - - } - helpText={ - - } - error={errorClusterName} - isInvalid={Boolean(areErrorsVisible && errorClusterName)} - fullWidth - > - this.onFieldsChange({ name: e.target.value })} - fullWidth - disabled={disabledName} - data-test-subj="remoteClusterFormNameInput" - /> - -
- - {this.renderMode()} - - {this.renderSkipUnavailable()} -
- - {this.renderErrors()} - - - - {this.renderActions()} - - {this.renderSavingFeedback()} - - {isRequestVisible ? ( - this.setState({ isRequestVisible: false })} - /> - ) : null} -
- ); - } -} diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js deleted file mode 100644 index 2ae16b8ca7cbf..0000000000000 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.test.js +++ /dev/null @@ -1,53 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { mountWithIntl, renderWithIntl } from '@kbn/test/jest'; -import { findTestSubject, takeMountedSnapshot } from '@elastic/eui/lib/test'; -import { RemoteClusterForm } from './remote_cluster_form'; - -// Make sure we have deterministic aria IDs. -jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ - htmlIdGenerator: (prefix = 'staticGenerator') => (suffix = 'staticId') => `${prefix}_${suffix}`, -})); - -describe('RemoteClusterForm', () => { - test(`renders untouched state`, () => { - const component = renderWithIntl( {}} />); - expect(component).toMatchSnapshot(); - }); - - describe('proxy mode', () => { - test('renders correct connection settings when user enables proxy mode', () => { - const component = mountWithIntl( {}} />); - - findTestSubject(component, 'remoteClusterFormConnectionModeToggle').simulate('click'); - - expect(component).toMatchSnapshot(); - }); - }); - - describe('validation', () => { - test('renders invalid state and a global form error when the user tries to submit an invalid form', () => { - const component = mountWithIntl( {}} />); - - findTestSubject(component, 'remoteClusterFormSaveButton').simulate('click'); - - const fieldsSnapshot = [ - 'remoteClusterFormNameFormRow', - 'remoteClusterFormSeedNodesFormRow', - 'remoteClusterFormSkipUnavailableFormRow', - 'remoteClusterFormGlobalError', - ].map((testSubject) => { - const mountedField = findTestSubject(component, testSubject); - return takeMountedSnapshot(mountedField); - }); - - expect(fieldsSnapshot).toMatchSnapshot(); - }); - }); -}); diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.tsx new file mode 100644 index 0000000000000..9f6eee757c755 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/remote_cluster_form.tsx @@ -0,0 +1,629 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { Component, Fragment } from 'react'; +import { merge } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiButton, + EuiButtonEmpty, + EuiCallOut, + EuiDescribedFormGroup, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiForm, + EuiFormRow, + EuiLink, + EuiLoadingKibana, + EuiLoadingSpinner, + EuiOverlayMask, + EuiSpacer, + EuiSwitch, + EuiText, + EuiTitle, + EuiDelayRender, + EuiScreenReaderOnly, + htmlIdGenerator, + EuiSwitchEvent, +} from '@elastic/eui'; + +import { Cluster } from '../../../../../common/lib'; +import { SNIFF_MODE, PROXY_MODE } from '../../../../../common/constants'; + +import { AppContext, Context } from '../../../app_context'; + +import { skippingDisconnectedClustersUrl } from '../../../services/documentation'; + +import { RequestFlyout } from './request_flyout'; +import { ConnectionMode } from './components'; +import { + ClusterErrors, + convertCloudUrlToProxyConnection, + convertProxyConnectionToCloudUrl, + validateCluster, +} from './validators'; +import { isCloudUrlEnabled } from './validators/validate_cloud_url'; + +const defaultClusterValues: Cluster = { + name: '', + seeds: [], + skipUnavailable: false, + nodeConnections: 3, + proxyAddress: '', + proxySocketConnections: 18, + serverName: '', +}; + +const ERROR_TITLE_ID = 'removeClustersErrorTitle'; +const ERROR_LIST_ID = 'removeClustersErrorList'; + +interface Props { + save: (cluster: Cluster) => void; + cancel?: () => void; + isSaving?: boolean; + saveError?: any; + cluster?: Cluster; +} + +export type FormFields = Cluster & { cloudUrl: string; cloudUrlEnabled: boolean }; + +interface State { + fields: FormFields; + fieldsErrors: ClusterErrors; + areErrorsVisible: boolean; + isRequestVisible: boolean; +} + +export class RemoteClusterForm extends Component { + static defaultProps = { + fields: merge({}, defaultClusterValues), + }; + + static contextType = AppContext; + private readonly generateId: (idSuffix?: string) => string; + + constructor(props: Props, context: Context) { + super(props, context); + + const { cluster } = props; + const { isCloudEnabled } = context; + + // Connection mode should default to "proxy" in cloud + const defaultMode = isCloudEnabled ? PROXY_MODE : SNIFF_MODE; + const fieldsState: FormFields = merge( + {}, + { + ...defaultClusterValues, + mode: defaultMode, + cloudUrl: convertProxyConnectionToCloudUrl(cluster), + cloudUrlEnabled: isCloudEnabled && isCloudUrlEnabled(cluster), + }, + cluster + ); + + this.generateId = htmlIdGenerator(); + this.state = { + fields: fieldsState, + fieldsErrors: validateCluster(fieldsState, isCloudEnabled), + areErrorsVisible: false, + isRequestVisible: false, + }; + } + + toggleRequest = () => { + this.setState(({ isRequestVisible }) => ({ + isRequestVisible: !isRequestVisible, + })); + }; + + onFieldsChange = (changedFields: Partial) => { + const { isCloudEnabled } = this.context; + + // when cloudUrl changes, fill proxy address and server name + const { cloudUrl } = changedFields; + if (cloudUrl) { + const { proxyAddress, serverName } = convertCloudUrlToProxyConnection(cloudUrl); + changedFields = { + ...changedFields, + proxyAddress, + serverName, + }; + } + + this.setState(({ fields: prevFields }) => { + const newFields = { + ...prevFields, + ...changedFields, + }; + return { + fields: newFields, + fieldsErrors: validateCluster(newFields, isCloudEnabled), + }; + }); + }; + + getCluster(): Cluster { + const { + fields: { + name, + mode, + seeds, + nodeConnections, + proxyAddress, + proxySocketConnections, + serverName, + skipUnavailable, + }, + } = this.state; + const { cluster } = this.props; + + let modeSettings; + + if (mode === PROXY_MODE) { + modeSettings = { + proxyAddress, + proxySocketConnections, + serverName, + }; + } else { + modeSettings = { + seeds, + nodeConnections, + }; + } + + return { + name, + skipUnavailable, + mode, + hasDeprecatedProxySetting: cluster?.hasDeprecatedProxySetting, + ...modeSettings, + }; + } + + save = () => { + const { save } = this.props; + + if (this.hasErrors()) { + this.setState({ + areErrorsVisible: true, + }); + return; + } + + const cluster = this.getCluster(); + save(cluster); + }; + + onSkipUnavailableChange = (e: EuiSwitchEvent) => { + const skipUnavailable = e.target.checked; + this.onFieldsChange({ skipUnavailable }); + }; + + resetToDefault = (fieldName: keyof Cluster) => { + this.onFieldsChange({ + [fieldName]: defaultClusterValues[fieldName], + }); + }; + + hasErrors = () => { + const { fieldsErrors } = this.state; + const errorValues = Object.values(fieldsErrors); + return errorValues.some((error) => error != null); + }; + + renderSkipUnavailable() { + const { + fields: { skipUnavailable }, + } = this.state; + + return ( + +

+ +

+ + } + description={ + +

+ + + + ), + learnMoreLink: ( + + + + ), + }} + /> +

+
+ } + fullWidth + > + { + this.resetToDefault('skipUnavailable'); + }} + > + + + ) : null + } + > + + +
+ ); + } + + renderActions() { + const { isSaving, cancel } = this.props; + const { areErrorsVisible, isRequestVisible } = this.state; + + if (isSaving) { + return ( + + + + + + + + + + + + ); + } + + let cancelButton; + + if (cancel) { + cancelButton = ( + + + + + + ); + } + + const isSaveDisabled = areErrorsVisible && this.hasErrors(); + + return ( + + + + + + + + + + {cancelButton} + + + + + + {isRequestVisible ? ( + + ) : ( + + )} + + + + ); + } + + renderSavingFeedback() { + if (this.props.isSaving) { + return ( + + + + ); + } + + return null; + } + + renderSaveErrorFeedback() { + const { saveError } = this.props; + + if (saveError) { + const { message, cause } = saveError; + + let errorBody; + + if (cause && Array.isArray(cause)) { + if (cause.length === 1) { + errorBody =

{cause[0]}

; + } else { + errorBody = ( +
    + {cause.map((causeValue) => ( +
  • {causeValue}
  • + ))} +
+ ); + } + } + + return ( + + + {errorBody} + + + + + ); + } + + return null; + } + + renderErrors = () => { + const { + areErrorsVisible, + fieldsErrors: { + name: errorClusterName, + seeds: errorsSeeds, + proxyAddress: errorProxyAddress, + serverName: errorServerName, + cloudUrl: errorCloudUrl, + }, + } = this.state; + + const hasErrors = this.hasErrors(); + + if (!areErrorsVisible || !hasErrors) { + return null; + } + + const errorExplanations = []; + + if (errorClusterName) { + errorExplanations.push({ + key: 'nameExplanation', + field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputNameErrorMessage', { + defaultMessage: 'The "Name" field is invalid.', + }), + error: errorClusterName, + }); + } + + if (errorsSeeds) { + errorExplanations.push({ + key: 'seedsExplanation', + field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputSeedsErrorMessage', { + defaultMessage: 'The "Seed nodes" field is invalid.', + }), + error: errorsSeeds, + }); + } + + if (errorProxyAddress) { + errorExplanations.push({ + key: 'proxyAddressExplanation', + field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputProxyErrorMessage', { + defaultMessage: 'The "Proxy address" field is invalid.', + }), + error: errorProxyAddress, + }); + } + + if (errorServerName) { + errorExplanations.push({ + key: 'serverNameExplanation', + field: i18n.translate( + 'xpack.remoteClusters.remoteClusterForm.inputServerNameErrorMessage', + { + defaultMessage: 'The "Server name" field is invalid.', + } + ), + error: errorServerName, + }); + } + + if (errorCloudUrl) { + errorExplanations.push({ + key: 'cloudUrlExplanation', + field: i18n.translate('xpack.remoteClusters.remoteClusterForm.inputcloudUrlErrorMessage', { + defaultMessage: 'The "Elasticsearch endpoint URL" field is invalid.', + }), + error: errorCloudUrl, + }); + } + + const messagesToBeRendered = errorExplanations.length && ( + +
+ {errorExplanations.map(({ key, field, error }) => ( +
+
{field}
+
{error}
+
+ ))} +
+
+ ); + + return ( + + + + + + } + color="danger" + iconType="cross" + /> + {messagesToBeRendered} + + ); + }; + + render() { + const { isRequestVisible, areErrorsVisible, fields, fieldsErrors } = this.state; + const { name: errorClusterName } = fieldsErrors; + const { cluster } = this.props; + const isNew = !cluster; + return ( + + {this.renderSaveErrorFeedback()} + + + +

+ +

+ + } + description={ + + } + fullWidth + > + + } + helpText={ + + } + error={errorClusterName} + isInvalid={Boolean(areErrorsVisible && errorClusterName)} + fullWidth + > + this.onFieldsChange({ name: e.target.value })} + fullWidth + disabled={!isNew} + data-test-subj="remoteClusterFormNameInput" + /> + +
+ + + + {this.renderSkipUnavailable()} +
+ + {this.renderErrors()} + + + + {this.renderActions()} + + {this.renderSavingFeedback()} + + {isRequestVisible ? ( + this.setState({ isRequestVisible: false })} + /> + ) : null} +
+ ); + } +} diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.tsx index 4e402b8b55a5b..2bcedc2bce458 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.tsx +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/request_flyout.tsx @@ -24,13 +24,13 @@ import { Cluster, serializeCluster } from '../../../../../common/lib'; interface Props { close: () => void; - name: string; cluster: Cluster; } export class RequestFlyout extends PureComponent { render() { - const { name, close, cluster } = this.props; + const { close, cluster } = this.props; + const { name } = cluster; const endpoint = 'PUT _cluster/settings'; const payload = JSON.stringify(serializeCluster(cluster), null, 2); const request = `${endpoint}\n${payload}`; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.ts b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.ts index 67a5d8f727f3e..6f3956a19f6a0 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.ts +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/index.ts @@ -10,3 +10,10 @@ export { validateProxy } from './validate_proxy'; export { validateSeeds } from './validate_seeds'; export { validateSeed } from './validate_seed'; export { validateServerName } from './validate_server_name'; +export { validateCluster, ClusterErrors } from './validate_cluster'; +export { + isCloudUrlEnabled, + validateCloudUrl, + convertProxyConnectionToCloudUrl, + convertCloudUrlToProxyConnection, +} from './validate_cloud_url'; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.test.ts b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.test.ts new file mode 100644 index 0000000000000..599706ba85b02 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.test.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + isCloudUrlEnabled, + validateCloudUrl, + convertCloudUrlToProxyConnection, + convertProxyConnectionToCloudUrl, + i18nTexts, +} from './validate_cloud_url'; + +describe('Cloud url', () => { + describe('validation', () => { + it('errors when the url is empty', () => { + const actual = validateCloudUrl(''); + expect(actual).toBe(i18nTexts.urlEmpty); + }); + + it('errors when the url is invalid', () => { + const actual = validateCloudUrl('invalid%url'); + expect(actual).toBe(i18nTexts.urlInvalid); + }); + }); + + describe('is cloud url', () => { + it('true for a new cluster', () => { + const actual = isCloudUrlEnabled(); + expect(actual).toBe(true); + }); + + it('true when proxy connection is empty', () => { + const actual = isCloudUrlEnabled({ name: 'test', proxyAddress: '', serverName: '' }); + expect(actual).toBe(true); + }); + + it('true when proxy address is the same as server name and default port', () => { + const actual = isCloudUrlEnabled({ + name: 'test', + proxyAddress: 'some-proxy:9400', + serverName: 'some-proxy', + }); + expect(actual).toBe(true); + }); + it('false when proxy address is the same as server name but not default port', () => { + const actual = isCloudUrlEnabled({ + name: 'test', + proxyAddress: 'some-proxy:1234', + serverName: 'some-proxy', + }); + expect(actual).toBe(false); + }); + it('true when proxy address is not the same as server name', () => { + const actual = isCloudUrlEnabled({ + name: 'test', + proxyAddress: 'some-proxy:9400', + serverName: 'some-server-name', + }); + expect(actual).toBe(false); + }); + }); + describe('conversion from cloud url', () => { + it('empty url to empty proxy connection values', () => { + const actual = convertCloudUrlToProxyConnection(''); + expect(actual).toEqual({ proxyAddress: '', serverName: '' }); + }); + + it('url with protocol and port to proxy connection values', () => { + const actual = convertCloudUrlToProxyConnection('http://test.com:1234'); + expect(actual).toEqual({ proxyAddress: 'test.com:9400', serverName: 'test.com' }); + }); + + it('url with protocol and no port to proxy connection values', () => { + const actual = convertCloudUrlToProxyConnection('http://test.com'); + expect(actual).toEqual({ proxyAddress: 'test.com:9400', serverName: 'test.com' }); + }); + + it('url with no protocol to proxy connection values', () => { + const actual = convertCloudUrlToProxyConnection('test.com'); + expect(actual).toEqual({ proxyAddress: 'test.com:9400', serverName: 'test.com' }); + }); + it('invalid url to empty proxy connection values', () => { + const actual = convertCloudUrlToProxyConnection('invalid%url'); + expect(actual).toEqual({ proxyAddress: '', serverName: '' }); + }); + }); + + describe('conversion to cloud url', () => { + it('empty proxy address to empty cloud url', () => { + const actual = convertProxyConnectionToCloudUrl({ + name: 'test', + proxyAddress: '', + serverName: 'test', + }); + expect(actual).toEqual(''); + }); + + it('empty server name to empty cloud url', () => { + const actual = convertProxyConnectionToCloudUrl({ + name: 'test', + proxyAddress: 'test', + serverName: '', + }); + expect(actual).toEqual(''); + }); + + it('different proxy address and server name to empty cloud url', () => { + const actual = convertProxyConnectionToCloudUrl({ + name: 'test', + proxyAddress: 'test', + serverName: 'another-test', + }); + expect(actual).toEqual(''); + }); + + it('valid proxy connection to cloud url', () => { + const actual = convertProxyConnectionToCloudUrl({ + name: 'test', + proxyAddress: 'test-proxy:9400', + serverName: 'test-proxy', + }); + expect(actual).toEqual('test-proxy'); + }); + }); +}); diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.tsx new file mode 100644 index 0000000000000..1f4862f0113e7 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cloud_url.tsx @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Cluster } from '../../../../../../common/lib'; +import { isAddressValid } from './validate_address'; + +export const i18nTexts = { + urlEmpty: ( + + ), + urlInvalid: ( + + ), +}; + +const CLOUD_DEFAULT_PROXY_PORT = '9400'; +const EMPTY_PROXY_VALUES = { proxyAddress: '', serverName: '' }; +const PROTOCOL_REGEX = new RegExp(/^https?:\/\//); + +export const isCloudUrlEnabled = (cluster?: Cluster): boolean => { + // enable cloud url for new clusters + if (!cluster) { + return true; + } + const { proxyAddress, serverName } = cluster; + if (!proxyAddress && !serverName) { + return true; + } + const portParts = (proxyAddress ?? '').split(':'); + const proxyAddressWithoutPort = portParts[0]; + const port = portParts[1]; + return port === CLOUD_DEFAULT_PROXY_PORT && proxyAddressWithoutPort === serverName; +}; + +const formatUrl = (url: string) => { + url = (url ?? '').trim().toLowerCase(); + // delete http(s):// protocol string if any + url = url.replace(PROTOCOL_REGEX, ''); + return url; +}; + +export const convertProxyConnectionToCloudUrl = (cluster?: Cluster): string => { + if (!isCloudUrlEnabled(cluster)) { + return ''; + } + return cluster?.serverName ?? ''; +}; +export const convertCloudUrlToProxyConnection = ( + cloudUrl: string = '' +): { proxyAddress: string; serverName: string } => { + cloudUrl = formatUrl(cloudUrl); + if (!cloudUrl || !isAddressValid(cloudUrl)) { + return EMPTY_PROXY_VALUES; + } + const address = cloudUrl.split(':')[0]; + return { proxyAddress: `${address}:${CLOUD_DEFAULT_PROXY_PORT}`, serverName: address }; +}; + +export const validateCloudUrl = (cloudUrl: string): JSX.Element | null => { + if (!cloudUrl) { + return i18nTexts.urlEmpty; + } + cloudUrl = formatUrl(cloudUrl); + if (!isAddressValid(cloudUrl)) { + return i18nTexts.urlInvalid; + } + return null; +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cluster.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cluster.tsx new file mode 100644 index 0000000000000..e0fa434f21d5c --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_cluster.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { validateName } from './validate_name'; +import { PROXY_MODE, SNIFF_MODE } from '../../../../../../common/constants'; +import { validateSeeds } from './validate_seeds'; +import { validateProxy } from './validate_proxy'; +import { validateServerName } from './validate_server_name'; +import { validateCloudUrl } from './validate_cloud_url'; +import { FormFields } from '../remote_cluster_form'; + +type ClusterError = JSX.Element | null; + +export interface ClusterErrors { + name?: ClusterError; + seeds?: ClusterError; + proxyAddress?: ClusterError; + serverName?: ClusterError; + cloudUrl?: ClusterError; +} +export const validateCluster = (fields: FormFields, isCloudEnabled: boolean): ClusterErrors => { + const { name, seeds = [], mode, proxyAddress, serverName, cloudUrlEnabled, cloudUrl } = fields; + + return { + name: validateName(name), + seeds: mode === SNIFF_MODE ? validateSeeds(seeds) : null, + proxyAddress: !cloudUrlEnabled && mode === PROXY_MODE ? validateProxy(proxyAddress) : null, + // server name is only required in cloud when proxy mode is enabled + serverName: + !cloudUrlEnabled && isCloudEnabled && mode === PROXY_MODE + ? validateServerName(serverName) + : null, + cloudUrl: cloudUrlEnabled ? validateCloudUrl(cloudUrl) : null, + }; +}; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.ts b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.ts deleted file mode 100644 index a5b3656b36de5..0000000000000 --- a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.ts +++ /dev/null @@ -1,43 +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 - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -import { isAddressValid, isPortValid } from './validate_address'; - -export function validateSeed(seed?: string): string[] { - const errors: string[] = []; - - if (!seed) { - return errors; - } - - const isValid = isAddressValid(seed); - - if (!isValid) { - errors.push( - i18n.translate( - 'xpack.remoteClusters.remoteClusterForm.localSeedError.invalidCharactersMessage', - { - defaultMessage: - 'Seed node must use host:port format. Example: 127.0.0.1:9400, localhost:9400. ' + - 'Hosts can only consist of letters, numbers, and dashes.', - } - ) - ); - } - - if (!isPortValid(seed)) { - errors.push( - i18n.translate('xpack.remoteClusters.remoteClusterForm.localSeedError.invalidPortMessage', { - defaultMessage: 'A port is required.', - }) - ); - } - - return errors; -} diff --git a/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.tsx b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.tsx new file mode 100644 index 0000000000000..4863dff5ec337 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/components/remote_cluster_form/validators/validate_seed.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { isAddressValid, isPortValid } from './validate_address'; + +export function validateSeed(seed?: string): JSX.Element[] { + const errors: JSX.Element[] = []; + + if (!seed) { + return errors; + } + + const isValid = isAddressValid(seed); + + if (!isValid) { + errors.push( + + ); + } + + if (!isPortValid(seed)) { + errors.push( + + ); + } + + return errors; +} diff --git a/x-pack/plugins/remote_clusters/public/application/sections/index.d.ts b/x-pack/plugins/remote_clusters/public/application/sections/index.d.ts new file mode 100644 index 0000000000000..ab0f579c1a415 --- /dev/null +++ b/x-pack/plugins/remote_clusters/public/application/sections/index.d.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ComponentType } from 'react'; + +export declare const RemoteClusterEdit: ComponentType; +export declare const RemoteClusterAdd: ComponentType; +export declare const RemoteClusterList: ComponentType; diff --git a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js index 6ee6bd6d87d58..124d2d42afb78 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js +++ b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_add/remote_cluster_add.js @@ -73,7 +73,7 @@ export class RemoteClusterAdd extends PureComponent { description={ } /> diff --git a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js index c68dd7ab10aa7..18ee2e2b3875d 100644 --- a/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js +++ b/x-pack/plugins/remote_clusters/public/application/sections/remote_cluster_edit/remote_cluster_edit.js @@ -27,10 +27,6 @@ import { getRouter, redirect } from '../../services'; import { setBreadcrumbs } from '../../services/breadcrumb'; import { RemoteClusterPageTitle, RemoteClusterForm, ConfiguredByNodeWarning } from '../components'; -const disabledFields = { - name: true, -}; - export class RemoteClusterEdit extends Component { static propTypes = { isLoading: PropTypes.bool, @@ -202,8 +198,7 @@ export class RemoteClusterEdit extends Component { ) : null} Store; diff --git a/x-pack/plugins/remote_clusters/public/assets/cloud_screenshot.png b/x-pack/plugins/remote_clusters/public/assets/cloud_screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c9302ef76eac6184fad0eb6931558c94980e54 GIT binary patch literal 197089 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 z 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

M|4!~-3cgu7U#8Pr4HL9(7d^4r zeZ+!2DzX2&B??XZ&j38FDKYn!ddtlb$$G;Nrey)hrNQvNG_)CrFf4ckgDLD0wAK^jm^oEXc*>cQi z+XC|659xoN?QaCWhs}V;NKFjoQA7RT2`7pX5DwEi_%S;Tdp<=Q{of}0f8O;ALqNNW zhUj<(y)zmJ^1?3k`)|K^{nk+KwfwjUvgAFAWZLC@PK4dlogMb|V2b_zIPsnuttMMS zx%Md1eWOjsRThwvPrZM;P;HX1`8!nNVpAkf9q?~wc{XJ(9foH3U{gEn4m&h7T@Ff3 zE%&X=+vx8U&s?4~1gzwhY1T!Jrg1l2N&i<*OF++0k>p$`fMim!+Hl}!`ikf6Li=9u zm}jjqfU8Zi=EXl<<~@7tHu)P`EbsxpH{wwS;Njao&6pJivTAnPA5UWe_a5xBBT(-R zl%$!uXt#UbZ%6nwG+u2;d)l-oG?ah&j);DTjzY9V^1r^|;Zy4&3xwCjO4v-kdqLVX zzECx7Je2gTj`@Iu#NIuB5HWg5VBGRNoFPI%hAqnRaL}e!mR*j0T!l6xu8W2hx}| zF(L%w{`ofj&l59=*j5tS+YnZZCh{Ht7a8oAH&DP+2oRine`hx|GABjNtQ6L8{IW;5 zQ28xpIF(h*`_=1b%OOBf7;n?@A`FnX9nigHv0LwiNMhJP1#0;;GiL-7!tb5Fj5|$e zRk=y|KQWpmV^FCHjPi0{6FVqaOpQ}o7#;qEHi_w@vmm*5aPY|6HJUT)PABh3A_r8( z=v~%Osn-bQ<6`N@)DFE68l7e>bEOiRkz}?oNp6&s%qm@Do7lBIoA{e0@K7&49I%u< zO*Wd#|EaHLVamXi+Ws+ERm5@$`F8I3=U8urEmeEI1#*#QmF+g_Pd}WkL`-c6nhm+J|UQoKwEa!Z}P2)t35g()+ic`})+3IdbnaW>qCQH71 z?Xs~kW-`-jXo|L>LMe`a&PA%uHA^F4H+{aulwNieL+-3MgY zrsw*UPbQ18FY&>ojv)-azK{>pcMPu*$$9e1-4b#gdfGf@kR7@Fcv-mA z>j<*Hz*at?$*`k|Iv*p(cG!G5n<)OWT<17c9w0joVw0|DIT)%R;2aqgt4%{_K^@3X zlju;c8~P9`p%QJ%Gt@>g#P&k^`fQtDDl@;Qef-gy0Ya11xYQ*cY_2U&(B2rmJt+7Y zbA;xqH~9DEMa7WUu%q$r<;iGFc^$IIBgb}skNBXC~vuyY~Vs>00`C^ z0v5FolGIvVi)geT8cZY(W3F~-qnwU@a*ZggFSJ_gLWvEX^>3=K%5 z&|S=tuUUDfep-|H&WGx$lUFCKnFoUjWtuHr6_^--4VdpP9cN4*S-YmVE^+P1#j5= zh7y7486$VqSG&dK5vgsmPHM99)0xkCNX=H^gh8%i0ZNhT&xpDYI`fKr4|fhGa>xu4 z;`5)4hT;L=HK7ji&3EPxXu^A+1x+copHnt%9y4Ogyce zq+155m@}nny`wN{IsTSSq{iXwLV=gj-pK*t?--Ed#OOHT=Za`SemckcsfJaDM90U- zl#Kui_*_*1kjdTgX~byMm%Ja_(U$6RFBdr3_cXcGqSsg zqv?MCAZx?6K3V}{&1upXZZB?ojYHl~X1T{JEput8Y*hw*ve?YVtu2e1pcV$n_fiRE zw&tTT+zqjGak0E)lA!Fxn6G*ho4KW|PUdsLrbi8DoZCoe`qVSuhzZ(qt6T&49Me#I zY@HGgFHgMEQq8pU)2z6`1hW!|kl63WvnXZ1XQGM(&(=I8Vi#{u(C;;l@=6PI!!^|X z8J=-CQBI-(lT4Qv<&%|?=q4WcFGiP}WvA^0Q@?8SmbM=yO42Gy$ExUGmnPie-GILG zP{J>Vl}EOVsFRy{bfv`+8y!9{ptD2b#7@l{zMWj}5oE7*^hxL)S^2~ji1e3=9-v?M z-=P!k5t~wrhCTh(cF_UXq#X>#QAwU?uu2!q*_(Jj-SOv+iL@=BkTCvHjWW!ujgbjR zr?W*A)eVE()PZEqnz2M(^4x{=iJTZv#e{D>Eb`$%zx=@3%-%YBx_TprSz-cLU5QxZ zZog84(VSobvypbU_k`>(o+jyCgemoJ9IP|Hxp-JQxGM`gC`ztp; zpuvqVEK9(Z=G6!l2{y427yV zovGr48}riXhkZqE8FJdi!&Zcf9$r&&hcv|Rxw5~zC##JS24a{sGgmz0%NT7wj4}3Q zw0X8XIjjf2$D8PPwC9ZSapLS?suVa?1E#i^0gw zzm$Cp-s?(dOfZK^WGB^l=aWm62axtoGG13{f2GrBw!5}uw3bDxkYh<~rri>F<@LOj zllII7{p*W?#Spi#c#gt%2ksgZR!Mi~1*hnTTCjO;#?HfWl0i8tE!WdzP6C^=KaYQ1 zOCqNaSZ7**&c`gfWYtC#b_9NTt6Y76@o7_-)(+qZjR5V{#wi;rEQo(ETUu)04f?Q# zZdZmc(a_2|bI^Zd)$eZdx>sRFS0-)Zky*Xu7^HhO_-R7c05FvmevZ;+_#C%SbR-l5q?!Bi903+3E+=vY}~n}tQ;NPraLL(k(R+M zO7N|R^RIMbw>-N}U6et!HpG(=`I(8}(6w63ne~-`AriM}4KGQWMc9!9e zm8ETZE}S@@F@xtzD9;#A)(I~6aNNAlJ@1dpBOsu>{dvisDqz|o3E9`?G;1AnG6+{R zV-v{fZKyb9#=~fH!iqFpf2{V^E3pWQclkRUvmM-r&DMC94jAeU@qU;|(E7|lT9z${ zf)kj#_w8^JdP1)hAQ!qj#yaMj4R3$(ibIH^rXfVJB!BR{rN3Q1U@NnTi%nTg-dy!? z)@-YP1wVVbUG2_NLdsnyS!M{H9L3xFyB>S5$|1i@nnYkd^L6>ZYkl0WMOkB-dWtZe zU`t;ksr{yD&CwG7{x0h=Jh_TEw-fcutE@}63sTxUqvLlIdF`p6aU#L%S@u{xV15;p zC<2sZ+NV5M zZqe{u5T0?)`Eue~erp)8@L$u%zsu@7wS;V{ZNmvHm}`RdgyDv(FZ29MOIcW#sA=!> zL*FL+H$>B2Bu$M5YvR@QAArHXpe$<}3>zX`?Rl}oZtWxziow=LcRC7}ygyr3)8e|) ze8Xh33hA=yqyG@5{xd4-8p|4>P1z}B9y?$AWPZi%auVP6_;a-}{Q4^aw$-&o4^{#E z!}xj_Gj6<{Vu{6`d1hvC7{OA@>&cm{gFhdOatA?&NcgrxMcR`~E5G(F0ng^j@1)t$ z3qNCBn{g0|Po@yDsX!=}_T20Jn#h_KiV}-r@UwSvQMN-46CW_Vs!W;npcnabhOp=* z5W^_78Z$Ad5}jd#zeX0=#94?!(;mum_>4w5&j^GT(Pz+KtsT! zhz_gml~2-q+Q1mW*&@8on#%=qM=%P)HncO33@E)XJ>7$&w+-M+PDUceKT2>uqh8s| z%X%vVS8j9ePd8`z(IvTIiFGNsp|&K&lEre7%dN*y0zPl~b%2IFB@p(D*dl-4r4k8#8mJ z-hF2rBEui)q}usD$q2-gf9#5l&rz~J+CF@-dIU8zIGifC={^VW%_b3jI&&&Lnh~ua z)nqyP<-?y!DJBh@pl7sF@5Lub=uWurc8S&Y0hqGd<$mh*`_J!6=ZEE*+Zzx}5$pDA zmf{J@sGyOxs+Z>F+CI!ky*l2NsKt%-Rh$F*;Z>F(uDh(ITNe*=Ylm{&$W7T%-AMgD zZ|TtW*rR6A(G9!24}Dul$V1rdUWtyT#&xRhLpNcyo5}g3@>mo5zR+01>Y10co}MuV zGRd^1QoXcRqUY%e6W?FD*YxQHdL!pkK#so*j5#8*_)%OMc)@sUvTN@?Lx}-6NFo6g zwWd-1;ZWsv4RU9J##`fI_&s7z$0~M$X9U?o?{ify_r^@BJ+FTf3xPOOke|&OSt55|wzPY8F^c~b{XYsj(ly5bLp<9--A@?*-BJM6y4ZwhHXJ1*_@rpqZ z1#MOu&BV9KG6bSPWhH%*{2+5UUwhP+QE#BYePzwrQO~{n3$VzyIb#F`pscT353Z?q z7i)KTu2fz@20xkhpLi^C_FH`>Ec)8fEB2H?w1{=4z7sMwvUbc~%O=(CTJz=A+*(nq zaHyVaO9R!J_=OK_FEiSZCMRFvkgHvH2lK59T2Wdq!Up2?YkXU+{n=};Ry9ROwa%Qg zElf_N+^v$2iP^TkqrBSg!A-4n5}dXB<=@b{ofvw*-qxS8miFwLf*uWYKN~H4RmAV@ zTFR>E5#f3IjRz)}q9F%X$oaND7BvCpR@3$1RWbIIFtm)d6-K?=V1bkBA~Y{0Z1GRH$6MHj z>l|q;CJle&7ID^`nXYB0;=~U1-T1rfuhb=eEK9rU?>rYbJZ^`f z`49o*wN?)WWAh)RZ^=@O#6W}-8?h|RKe5_WM0r3|6&5v73YP$m#JeuT$MJ0NwHVYAcTYLT+hHF^@q!;R zzS;2}eCd?@yps!@syMazKJKU%l|k`R+{*7qhPQR6FC`oZtc(fq{rBi%l*K_Xli3|1 z6{xz$#%OMbOKz9-1H~AH^G6pi?Z|mPeN?iV*XhIhFA3^-8VlQNYslO`{mqz5Xz@P$ z(?|Y49XPfumWPEh%^BaT_{LLdM_d%9RWc)O7A^% z5K%yB(tEE;iS!ymQF;gvdPzV!0Rn^`An)V;u5->>`z-ghzW?VRCCQwb^M3Ammodg1 z!FsW04K!j``nlsXJCew@W~P;n5DX-FvVYKX-d0W(wU3TuJW7Y7<{xw}CF-H#I4YW6 znE0JD)~CfiQt7cwK6GEzPH)(GcW-;+iFwzri|A*4#4CNUG^qkUpE46oB;oGG=1(fk zUTCd^5Fgle|8#l4l&^d8)D13Anh}iz5=g2omugui1Et+}jmu>5Uy(FhOVPT+gRYJd zTccx(HrD3|y@yxrIA`Y5E6vAIGjoyGPKi$$glj?K1)f3Y++qo#u)8^oTg?MQ{K21y zBY)+{>FT5^xR%!rgwzCE*|C-?Ni3FU;rqNi^bO`Jy-$5MEkdPCrH0!p64%oAkU8YW zy0spcDgER92L(!G#2G@Uw=`R76&V4KR$uy>Pw)($L5>48kwxUC-gFp_4q(X0xvUgC z_{D2761fs}>e8pja;MKqxe@*D)GhV;^N|Nu4#V@s6V49HR?TVL+*xpJXH+lN}^>i-t*!7_U9;S4&8-`g8WgjU?%z(K!HbMOZRGO8ZXVZUPAT{c9 z7Rwf#X*;lHy?S?jhzZHpIcp9&rh>%W6Lzc&e%X{s{CMrwleFGv5lCifRf9#InfBuVBKmJjrkg{IO-5lnBRC*umwi?DjN|d}c=j;-U}d@%o`@{xI3WtKne*hJNn+)8 z{%M328;!y9>gV1y4Ow=ONwp&M8ObnZ*w4kGo%1dR?Q}V~=+EdLFMh5bIa_tY;=UZ^ zFjgpFdiQJk$CHQQBU!H_>r!)=Z~U&;BeQbz`^)(-x6ONE9GlPq>q!5bfhU$_hPL$; z)*r1#cX$}Z9$pOr4wl)*pcCiYE*EI$z|Ud#0!LOcA81Vzom&|>IdmUFxXQ#gZt?Iy zc50{|f6i!?Hv7OzGhXsSZDT^i7i&lxMK8$mV})6P#rpPe$UCcEcwGO-A-|e+WKWYW*Y-smzhlJo$=;MJb(W2RTHAw2bnib|Q z0?n{pH>s{8&h!x;m0s5q%dF&lI>9&L_OPED+XV%*ON-BtAmfs3G0wNJio8y;eMi$r z^A)6}RGwm~TYXh&<$ZjkEX6~pn= z2Tl&3V~KUvc*TN0k9S+m;2_JrH^A zitVBNY!=al?ZkE7@Oon_X)s!sf1Y1AyII2sIqI|mMD;hDg~9U`xG9VC9UkNZGv5^4 zql}-VDZ9iEKWHnK)xjL!aXY+NmAULnA6`f&wBI^$Kfjt>!;Cz!xH z?8(OCa1zRRD$@egBHEd_dFF5(F_Rhnu$;xJ1y0=&SH$Fdv z`yVCqOZIuV_=!Ijw0RnKbtEsCHf`#U(JD9z_6@2J3=sLs_&l$0h?TwLLf37@_Z4ap zm%hCIZD3n_oc}D6j3+;H#{g(JSqsOqjD2cCTu@H)_!spmQ!2A$@zX!FT-pK4t=96t zFOcYI%^BTnSEkb-j+E?T zt5z1sUiNW+boI)brVJgIujG_WZPQB2q&=Cb?{sQWaRMn6KG9X__E~!6^4I%e&PGuV5NmoT9~8Y zkQQOa{z;x3L*{u8SY0T}Nv%(`A3?Dio7afd-SS9gRFmN582F|item&HP}_xV*>x&i z&6mlFyh`GW9sm+p$wGb08mc~8Q^)=_FY}<^H1_8$sINh2w=K>?SzkA^YGiF7Hc&y? z4^NYI>7;&IH=-+M9y({WImgeO!_k3tI^|kZgJRi0@7bNtKjE>7(MH;9&5^I2*4FTW z)J(DGzp}=*V8Xc1-_(lKve_JGYTW8l1Z+Q58(9maKgWT}CH)kFMnIc-k4?ut-glu2 z!HjHT8J#7mXv;VyoRj#=Jf20r_Y$HZGZt_f5v9+dEZbc&(*;9&8+T;x&9kHDaKniU z&jKOn&Uap!1N0;7nCFf-mvNu!+Rc3n{Iy~-OdYZw?fE=;RGAun${2WA90dLJNQ+o` z((_cmo#<@xCmvJ}Qr^%chQd&sVlA@olyG4Er!|q8&BNO)tM#gbLi60JmK}cQ8pdh& zX{GodB$mhP*{<4lpY~!w>>BKyxIROj>g!U~_(+ zl3>!aZ$~MhSAJn>*FDryML3*0-MD9*0-il1(V3jceS5l^CksmMDEAw;rG6#2 z4bo8DAuRq8+S&60TF`tDujV3eP^hx1?)HP47I$Xst7IyAluYf+sK$&Ele6=qu<48M-=FD2tRU4s0-={jI7#XT zj#{oeC4azuaUPwC8+W1lu*U+8V&n{wt#kO|wYMS={JQQg*=NThYxL6V2b;I3rxzsr zedE4>it2b%6+76jN}!%(oF6LQR|%2K^12r8@AK~Jv-QLFcZv?ihx{`iNuGm{c!VFh zPmD9BGLFSi*5C)jom-n3#V-{lz`%yiqQUKybX;K)M-fLYM5THdYA!laXXJb)04eY% zE4)lvH<_E@5je29biaHX*2(lvt=eX?%4N$*oUT4QP2YN-(pWysW0wX3-xod}_bTdb zJ1UN_x~HsBd1Nnw+m`$+F`y}ev+Sxv*Kc`|GxYKI&ZS)c&69m8xa4{PGM>7&Q_Gb% z*m0(=zs8n-ZcLc0K|wiDd3(o8&zq$y3TIrTnz_wMC+ZvNfgYc#7CMZV^aCZsrSQ|D zI|aSk7TBb6w_^aC3rGpiq}-EiYDQG1h`8;StnFMf_|-3skPG!BVf-YgjhS(?E&lqe zt1(=U7nFP3x&Vcd;D%1x_pe@A|4cZ{PM?z3NmnKu#A>czX;+SLU`#4;E8G#6M4S!^ z!hC8vc_IbqjJGipyah6sVFcJ3It5EG-L!&u6w?N(M^tB+Ky*&7f}ha^W=}-^b?Bgu z3QLqTX?fb%X=L~%@qJJnU(=dUo%wWg0Ium#JT#kbTOMr6sM|&6I$UhL{J9leukOt1 z!$bMXty47D^35)BlQ&ug?m?kpbp`e?ZkksiO`ka-Z|as7aH_;}A#?8e#c&D9H59yT zNhKu61lJtKtR4&pCb5#v#3!^X03S^wAEtP{(ErKn!U0nV!eX-LkD~*}`#)4~DN?{8 zO}_SfjifrLCzM>4{Iyg(DO8tk+lZ600DuzFJN-fF%dDZ)!`9J3Ni3v8Yphre;lLcr z-i&CN*w6C)xyJ&4mqYX9*v>5n=e}PtwAlVQ-y%J*|5muDXW}S}0u;Y_{xuteoE9oL zcV8Cqc~c2ZZJKy6z@&tq5@ z$#9%2%S7FFwY}Fw_Y7cx%)GjW|n+Zhvi@BF20 zYd57mbci)fn9s$F=Gsrv*S$v_YXR>Why8*dUbyd|@0u4sF^CKDCA_YjdFS1apmeAj zBR;K+|4?kt6zbbA<@JJ%GJMI@ZMla<((q-1^Tn%2095@psZeES;#%FD;d>_4MbcN3 zPNCE#YjjRs_~YTUBP%=oMjwr@Vfu9o**X(5iPLPTuev+YBg+i&XtwR%JTuG_NZ`KI z(dlH<*6PSXuctTvtH}datTkuW@~RNeDv^8%0te-cPp+_!Wl1GofdCNs>P*lft>`WZ zXPUI=Tjp|m3+&($s@LsDT$tXTbORCrBu$5=n*;Wm;iL^!okSaoL};R?C3}m2BPeLMZ9rH$e;@Unw+rHY)P=q z=Ws4)bfy_A{}whc!ndjW;xxT|4?t`IGJ>=Z!S1vQK5vHOpqb30B_@LGj5s>S)_@48 z`iBl#@qVkb%)58O-6xedHuHQ)_JObAC|h1KJTGvq@mJ)u3;C!RyZ;r-@2~ z*`S0j6`(E5wv#UlStBJJZC2ZRv~5Q5Us?bzkKrkt_mE{I!FOv2k1}7V%)X@cD%((> zDAoDi`z`loU`Eq;FY#iua-pzx=8oGIE8GOu1#T zHkc1=lI|f!J=LiX)C^0LxXns$o@j??PET+wJK$G;5-D*RzOw@E^j?{JU^REGmSP%Y z=y4ooHc`gSBqh0yo8Afu2o!SqK$$^p0|_Lb(JzM+ICqg_Bv&MvE)Hz!K9o1d6I>IR zSKxnTq0rl-`RGfnFb#Z<>_E9WSkTuvNiJimY=lOpIKxK?Wz+TvQEwGmA&Jxw@p&>(dO;TZwtEnQ(}vl zt-UXew1V?6s6dI)Gwws86_{`^S^Fm-%Q8i^W7F4QE6Y&hj%_(Uk3Iv|SA#*u5`)eH zvb-@tk`s>8mYH8a5)W$r#-=V4@tNMYUl9(bc@=CK#FIQ$Ix(rgKE2H8C02W#F)Odw zdM#mrIZ)jZn^I;!Q{O};&&I{y3c;1=6H@MiZUM|#>moe8vGm>2Qy5&P#^=$ zpUeShxK&;tyKqOf9NyDI;Gz7!U%X=B9#^oTja+cjEFPq~-d2LY`}f;)!os#C49&(5 zr6G(UOr(LG7}%?z#3UK=disg=53=FGiZ@?KEI+?leat=NATU$MT3hc#6?S>#{yPqF zJuhhQGSB%!t0#tA;z@3&iqT#NW{{V%sl@i+jnrjXdaBp_Z*964JG0>wc(eO+7)N*R z%^?c40l_4LOI_$rn&wmj4^zXyl$L2nYddEz;S!@!pGDIn1lB>^7;>4XZctNt%WHIt z3GY_1_KoU7zB*#|c!lZ&qsU*l7?7VyW{P(l5eLhe?c3 zkGqF+NSr^vowLsVg1^wPp3xV@e|Oz_=cE=dz9fAYTR$Ll6dN>*+lb{^X^8NvuUJy= zev=0%XUf;`k^K0nUommAm@MSld+*Gl&YutD({?|2j-_+hm`Rn^nKu+- z_&jajMT$^Nx`7aGbbaFmauT*}aWny;#=CpZcCGHZ>1G_q5I;URM>%ijl@3%t8NEb+ zaSpTM9F}$-ew})OJ=DSck-a`KP`!OR!P1|@MBAqbWx4XfS9l1e>TG6W3?(r_M(UL%}~O4$!>Q6vvE(tSb~P|WV|0qxzD|p~MJ_WiR=~*Rj0i(iDvMx0wa1{T62E`{O6FCISh_exh{Nz}<9k5lH`tU- z=r*27RpqF@x&?Dqr-ljS9IW|FkWihnG}4qW7NQNCaKvdtZ;7_TA=O@z#aPf{ z^f{js(uy@cbnXJEgNJ|yH`YhVwkN`P>e9ut=iYfp;T)(e6u@XSyn>B>Ehm-NS4vd< z!kolDnP90Awur`yp^Cv?gw7s4k%5ftxX~}GLw+%Hr-M3;!yZj_ zW%?bx8@Y^I^z)XO-C)RuGJ3i_EMfPH#8ZAQi77LI(kNmPo6oY=?)R9V=xA_eFK5yx z(ZHg+5vzYs$09$s~SYTf_pJe+^4~5%!@syZdM=$f}cXuo1uvSVjY` zMJ>T_09)ys`Yz5!Y_vEMGd(hJKj~AiqjT7@9ks486d|3kg?e=1upSjbaR>fG7 zn(h(Yp_VzL-7ty_#+@gpVoP_7^k9`y!7#v{Ke+&_4T@erOfNP2037c$jKwgHuUyAM*b@h=Ls4u$NAnqy1of4WEseEn{3hTS z6OCxEK+5!&JlrQR=Sr)ilOGoGmBGx@x&ajypy5p(p;w9_k{&4x0dBIG-AV-fPUf5S5Yl0ap(`oVL>n0tu;)N$Pjv3TY_yROM%H(J7yre;3ZRFJR_J>wJ7 zCX}v$t!8?ue`@{w{lvnBl>6>R0D&bav3NJ09uiSonT@ltg!5EeMv8 zJCP+BbTMP6Xb;!z?HoG>Pxx##>=Ori*lOwCScTKsAU-G0SrPDfJf;qqF%pl@KD9Dw z3#bh_oZ?8oVw4>F0f52A3aeh-b}S;)ivYbn^?J9lhdUMcyeijo=4u!trp^jQVuC|& zu^HS?Zm|>7A+(ep^4t8_pWb86g8K+!AwPAEy(cEW?z~-zZu-H}1M_nsy@a@bH9ff9 zif!cWCFeQ@jMRc^_o;rMDT-KYIwL4uUJfix+Hq4yfOoara9SkTD0m#@X2M80={avKisHJCNkd&DB`>W_CN~1TIBT_>*>>e1z}lmaORyO(Nh|ogv7@@+MPi=1ObR2- z^K44T5Rxm)Q(Q1582kPK#9D+-*kPQ6RCyRGvpnr2_zdF;QRrZ!-_L_8U0YN%|OJ>8nndsaG2)*2BNdrwxUmww`!gW5j5_62mVot7WRn z`ev9xKQ?W{(q}}1pNM6q%ByWTYkvc+-O?gYH+zP^RBSd=efPJ0IUxdlbN4&ZaY=1? zKUC%xG(BbjbVp&W%BKTKzYH`tgYboyml!>zsM|y6a0b8ieDvJy9}!Bl@T0Y{>Sn6P zn)l7z1?0lH8r_zw;wesyYP?gmH3Y(Tdu-%tL)H<^Vg+}Q?c=4gj65bY9fQPYqtTqd zcKkj>Ui`9j10++2dl@%g<(2+i&0ez`Xkha@OBYKdfd=f&!Y`J2WpD0kIas@u0hO5f z7}|lxv!RT5Ahl3$&td#F?Q;QO)zz)d7W{)TJaaElIYIb3&`5E>GS$HvK{-BNT&zIs zdxTT5qr9DII(p>Be!Uqr2OjU zCyu6y5EqV=_iwE=+n7ax((E(a`>r^$r=p7+<3F|qF_dG;;;*j+x>xX(lJK=ZpH2m@ z{-A+HQhbb~gS#=lvzW}!3?VMHt^0I&bu_M>JS%m>r+Q+yoMorm-rRUUqjXMm<@9;! zto^&lec^Vf4J7T#iX>L`ImcoGF}cYkx6k7osV(+m-?>vJj#?iWXt%u4G)oYA1++$s zIXqPzUT_h}Q3g){Xp5 zo z7e)Mk(SX|4xj!#Au;RdXwu zi9Nm?`>v7vV%KZB)|zJDODf~OIfi+NmslN9MBKjg#@Wa>CaWYWGZMA3RPVpGf7~aqn6ru#s=FMWA zS!+C)>GuIE8CzbV2SbB9nj2M7qv!RTVr#SJO=T_@MpoV*B`DA>_1#LC;yMjz`pM@J zmOEUxS07gc5L2U>%GGb1vtF;cXCa^o^)!P3mr8GayHA}a$Ig#a0_!NlB z|JV(4HgIA~Q06uCB`bhm2{>Hlg-eoN+*tJ~oUna&Qa)$5{fKd|@Kf)rI0I0D%of7B z1K`AGo@?PURVD*^e8$m35~mL1)&WSP-pg9S8&>~;V3>Pj2QL!F{sY8XE)#=&Bi*8^ z@T~@6g1S)OD#zDsOpq+KQ=VGDG**Gs+a}n@4qq;vO7#IL`aav|7xZhM|!( zuuHl6-XrNB6^~*7S%w+fkLYQ1#uVHwpu$#DrXlz;5|e}Qh3k=grtS@Du30&#&&y&( zs2a@pP1y5xk;m(aM+l(hYu-uiU-D5^c)&=&Vj!P=lUi*^#rKm*aawI>dL#3!Z(P=O zTTG!W+i;(9!r}1LZ>hxdI<(iaVlH&>EB?~I%Co`Y*Vha;!DObJ;}fNxkG#@=qHQ=& zutpcRR~62t^fdiJ)8pTwWv|_LaRVCGUE~4SxOczk2QGX65>Mc__|Z|@Y_YroQSTHN zW{=N}6l8_h7Z+a3kRa$RDt8Z!m~sj&O>Girw{0L}L^PAi8nD9k3krWf5D`r{xGg5b zbu6Rp4d=gj>Mlfwj1qsCssb0G<#zf>OhRMfd{%&l1old6dV_(0OuwN?V{YM+kX+^O zv-4Xr^Gh`0rOzWaf9z$?rq$d7jyDl~BGu4B;B){P7*-qQder)&x8=0TRWDC@?UW=u zPB1i>;C`S7s^I>BT~^f#DBe(~CowO_4)q3p%~~l51piV@FcDve)ZdO_Oujo+^&B91 zWyr*Iy^QFqowIwMsC6Z8+KK%?$QcArUIQ=yii7Nr-eAi`e?bLY(r#J^n%hHMwb3MO zHbdPp&j2Q9l4pTde=v6N2*M{#?7kXrXOH`dC_mD5R6c{?GP z=l#F!_-}swt_ui9O!~SD{KMJ20cP_oGVaqqH2ujNw~i?coufm4GyK09#WPi4HsLR{ zDE^_D83JbZ1`QkjhqDO>DDM)mFe>Io?GQ!~h zGy2~??f>WL|K4VP`TYO$^#67m{OQ+QhQXVal6QX_AgD_RN2PmZ2b!iiNB)oTwXv~( z<}%cZjv9G%v+IZO!$n1-3}X6!s8{p;7oB4VHc9x`^Z36b%IC>4UqpPEd5xp2ixCQD z_8s?Do82H;Ld6+8zi8J5>}{B*UnR;U)UMQFCTaCh8Ieq`o?m?(sz#)4&J9+cZ-}+C}x%T2d7IlfFGS}fRF~sZZ-@Bm)*Uzq@ z3o8FIg+DFst*p2F+g{$y-vs}><{3l;yL-+71k&p7B0jMEJwL6jm-7~r^X068cQuUv zGq2!ds_>W~H03cxw%*n9e;7oJPyy?q_J`2#mScqV7SES##DwqRpFc3ThUn)4>I{%A z@=SUa^FJ2-pMLuO1qdu%ec#y7{Q2wtX+8ei*#5u2eNF;iZ+pG+SBCp{vwL3Ow(EiE zjsCN}y6|1IxPYEqKNF#=pqvi>Pt*CIfr)-;rCqua@wcP=uaSe}Wr1`_*lll#&Fy&S zb^XU$yRn45<^F%F19XX?xLU^OYT&HvM35z*q_KVCv-<(xTbR7>wfcMH&|jyaZhbk_ zS2PnYh5FO>|7Mwfy;I#TxMA?vRjXg2a@VllDREdj#x-UrCosSk+44mkPV|p9B;y_s zTW7pqJ%QCD6Jw-L1{_a}y~rN!bdH(*wsiBSM=2Pg2ncMccerP!qYbfBY$yrsv-J4gS*Ba~ye3bf)-h=W2ht1^|=T7({>HUF^18AF-@*U1XVR@u_y0 zX*K>t!^JLWuagX1qNUUu_b8wazBUleC~k>tfm-0A8Gj*x$?i__6e=gi?Jf5yHM&_A z0-8^8(m|~{9QKZKBXN+gi{-NjCkwX9Z-dqwWAI zM86(+7jd@!q~396#VG95xIfiCA5@+e$8S9te$O42R$JvU#W&UJ*z7*XBn~nHu7c;H z?n_Pv#E`?YCN`%uQoCiJZIzJx*06)+Ba*@|Y*9+v5{-qfi=iXA0ftvs=G#LC_W&xq z@_3nko3h*`u)y0_Q8L#EW)&aY&$LR<;FE+bcEuzcUhoe|1_a zB^*hgz0xf=*m7Ew&Xv7$jyp*7!!(M^YrezRwXaYD`jN%iq5WRcB(c)?jN1HEE=**^unX75XD>E2*pm|7&)>Tg8{DNneBcxD>rsv8II4m5%*$3v> z`6nGTt`RhDH`y1w4mp+T*G~6YD3sm%L2KHW-om$bWqqPPh95dbNZ91BgeZx(uC zOjtzzFw9YVYEXwHO7Y(xF5U}nB-7^bWi$yGqjqz}2Wk~6FOLeTdCnmNa7*zTQprp~ zcUgjXOtUuXenim5H)ERQPSY@{0GJ(6`grs=jzZ?_8t1ET&s*_s4~bI9gNxm(gc_-`5*j*78hjw<$|WFV5W4&i49Wt-2f`{lW@XEx!R0Exq9s(&C=8 zuH8XeE%)z~Vme%(Ql{`*XPw}A6-5|KU4J~%sMbZ^F=D4GNua48A!*y55Mili%^ z$94c1O4l#1zPziko0@HD$m|TNMu4&ap1S10m%v?ZmL2BF`q8$J{oodsvA5*SU}8ex z;`L&_(^b=@<>ahnelgIu(x<0J4KA^>UU<0&S2QMXpnP%0!%#&gA5EvbE)e6p)o|dk z?wLE9O}5$zsh152J9~UOQKx3_vy#fH+Lb_$9DA*Xf8rWP(y*JPLn!6&f&TtpTS$yZ zupm$Cj`SDZ@~_6!d&O1(KKPIriy;p12M^WqSA^dC7&&*xmgBSPk^7NvY3EGArQP>} zMu^hRa;j}<<}Luw?0Es)v&QbTv~aa!@DiWfl8w(=Z1+^@3okcgwUR7#!X&lel%1u;Qe;7>)@H=X3rxtZv`Rsk;>{X>(A}+wGWp|n? zn2CNZuh6WWK%Hhr#?-ra1RAh$t%kJ!r=kpA+8-l$S0k9IR1fTWfuAdzs#1nDdH%c_ zmGoW5tmpG0fvOM6Kcej{f^%W|kpH93Bsj8A zZD*V+3?b(5yxx8ACfi!)j6W%F!+upMK&v!8;#T+c9WN7gJ8YEfxN*9pd%UC#@AJb1 ztr=4ttg~kMDpWMBoPG`=JYx_5t`l1y#y(Bux30i{{k(FO{N9F$eU6-n*m z{q^FtZ`?<-xVI&q4c()Qz@wl!xQ^5oDEVVF?=p43sqt;Mp|BtbQ_x&NtX z&-NARvo*@b-4#QGr%5g3oTt%fH05ur*)lEHXT1?yc|lBp$NDXTQHL4t2%I73!R`>! zyWSYK-m+#9N?e6YFw+_3G$>x+v0Oi=tE#!VUPoD;Ncwb}+MGj-)^p+^V+6bi*p z*P=816tWS(EmmXlY&T5Up1(39+Q0YpWoal*ug-yviIz0<_$&ep>tCwxV?o3)l;0-D z56(+{8lRFpKucQk2j1mdzkzp014NT!@yy}j0`W3t-~w2RCx;_^RXf2Z3{pxVelKf{X{u- zN|ErkfMYBpfxMobIR0o;yNEKVxp@n0-YqVB4I~>u11m5OI|Pld@=x;eoX#PG@XXnc zTdIo+q=km{+*++hqHHF44V!@6pFow*;H(c{;F&Xse^s0CaYdukTh+6G3@Ub=9&2Me zeh%F-H@-~o`r#h9E|;MQa=9;&nzT*7$|F@(@G?tqsCgp}demDW-4!Mv@G;um6C31| zT-n8~IlN$RH};i{nnUL^;Z<@GlwKGlRm9cp6HKt=XS@+crM|*gs|?FMg!Suvr1uH$ zGwvuba?o+pSKRp#6^E`4XmgUye!MIZ6LcrzXS1F7AbQxa>q5*xIqCU1Q)Fjo4DXbD z)}ByjX6yEJX<^`b6QDxr!*8KRhV5)nN}@L<<=!QK-?)=^0g#E|TFoFXuOOD+hpZxV zL{mG%j!Ptc+j0 zmpMk_md72ct@rqqbj(s9e@ke+#NHaE+l9~E+?pooY{TBC{+4u+;LB+N|6)q_1F>dJ zwQZn!mc%17Axg%kI zcg>(J!n$WsLt=~4Cchut2zon^DG7VFoisW{1z}i#x=4W|FOJP zjIw;+`*`nryatZwZOLw?7n0f3|H5_1eis#lPgG>`;oMbgpYE5n( zo=arzf4%Kyo~?^^s>H0PHydKqbK~i9!EsfqqED&2 zwFNN{Y>~}Ml$m@82REbu8ZVe{itqOqLtCdku4 z-1FHS4$CBA09@!s^^`pr%0_EEX$ZKgjp|u({s{~AlX*E*4uvsTmWnL|(ZYSEpa@*$5*e4i8+jvozoXZHZ)`GBuZ(={Lc_l9woyKAZ$R(fJPEeO^h`Ob2H zTL+7yQTUX{nAW41QSYfI_)a5Fupg!SQ*CofvhHW=#F zVcUEtqC0{PnkeJ0zssK5)|qqgrau$DAS}Bg^{ZSvSym(LLw_37+V}lp_SHE|Y5jN( zr~#UHMaCa62=x`Ir9bl8p4F;zuw5Tr$8XJD&(T@Lwe1#v$VQQWRJNggWJ~dpChn0| zoG#a=1S&0CJzJC)SCUO-;qz-#PajgeNIEPSajg7-(lW*$`GDQGMft6_2QtO$osI%c zi$u}ltNw!-{O+p(gIE*pG*1z)Z6n(X%)n^E_Dxz&H-)WgE7mMN%TUHadwL^r)L6SP zN_;P@mke^)@45HE=hxjO7xs1e9_w0ebDk4-D?_Kby}Xj=n&T}-d)nQ$8&|!BdA1j# z7=)FwTSFW`3t>gkG0jF*9nLle-`#bt#9K#ntSf*MZ{3Jigsn(Utmz z(*tm_|B1S~yIxHN7Q?mTJ3Kq~0hIaR2f<_V@ej~Zn=6<_Zphu?-YIwOi;peoRl z`4*JN)BYq_N8suh*79VJ`cQa`amD}SV8V3k&{*@rf96q-ZE@yC%X?gzaG{itee~IG zP|)+`KI-MYe*3fZDBp7bI^U?XLmUQ#|EgR5N3zlFlTfwd4v61TZz&k^8hyN+Y`PrT zQJhXPW9i6ZBk6@;r;|h>z8bFjpi#B<^^m|xC&s=Ej+fkD9pL>n8$;+`vse5=Fghto z%(LRN)+3c;lfceUwY^ic^J&pKZV)HcaDHgGToA8Lg>fAX_-c4$hw>c^-|j30b0@;m z>-$XNmm!+%@AA42)9k@hgB zFgI2QuKDcu^FUKn(WL_i0flG#2p+AwNA+3G zW2%dOF#6225wq@TX` z)&*6hg?XCRp5huQn@Gj(!3CL1vb>92O}^(RHL2H;pAD(rvAq&dpcPKVW$;WPhMt?t zpl(;aj%gdYt=GaoQI6{qw+mwm@HR-3WkOO5*t{P5s^L$%tsyNbjUbR74><6Ab$H_- zmDj1}*#=ElGeoTHOFT<76T`~>wqJiC^1xG$R>R$Yl12a5h7{wU4aB@;-nEH+GGUYz`q!MLUUo^%m9Mt@i3U)gm10D+OsZM{Z`T6tcn6`raP-#79w)1HyhN!uXYJi1zc5MExsPQA)S&FYrV>|4?A5i z&YrXNrq*LQL{sKbK?6kw39{zf3+<;KJX?9MoNK!zm zvz>{4KiBj8aK^cASd?NWg&KW4AW$RT-TEtm&sQ{^atbUa<P+sH2 z1!hS2G;#XwE`Re8dwm+IxV(_6UGVh79w@Mn)Qzp307;#(HDr6B>cuqe*{JOy-W`*D z7u33TR*y7biD%K^H*O+N;;7j1nyQEz)sT1s*Nqo;zIQSu&=W(yO#buacu`{jmWNe4 z+SF6R2TIC2-y>m}KsxZ^#JV}CX;6tZd+FxcPL`scX+U8kU1PBgZ@hM$ z(;N$<`0Prg0mc@=bilPZFlt6N7oEyqbR3wI+~)Y| zn@jAP_0TBWVkBN^uxM)aS(bL|C;r#(foC?KMyTC^esgyz9zLB|Yh3lRf2H-)sOQ=H zFI8`TD5E?Whq1;ezxvq`o$bcvcyZ}04Bf8D(Ht%59TBb7Sje`dlwQSG?U@Yg%z$j` zCjE7Y715^hY`h51&!TFMmBGmkeLu%2Gf1<_#z%(!@$s)OJ3&DU#-PO_HRKD_4h=SV zjcd9ssE@7Kn^m51dk-VDacGx(w=+!gj%TJf?a(GEhm^OT?@^PfG8K;#G=ap&MP`yV z&*q?1`-*mQeVHi+zt}6zV{;5({|l^O8?x1ZsG~WN7v!qW=Olku`m_Lg60>Uv zuN*LiA*KZS{mg2~;%sbyZVR*KfN3Frneqf%`7MWBZMXu;CWa2Ot#X#&HG97HHF)vV zue73+yx68QpTE4q_EwC}J#VvcK>TK6Yzqt&5}HYy26q|I_}X2wYBB$;V^8Z3)5T8Sfm>g+?2tu79!j-XJ;>zZUVWtlgZ<2o=t4$ z&HrM5OSlIqztv*3hGk%>4yN4CohbpYLe@1glYvg{H*-s;Tp^`%4EqZiO!Q{URIoRE zZ=M}vV8Dr+dCDwle-6Qs?3^U<1hv{SGz<{mTJxRu>~yU6x(%zMFc1*=-t27mRh9@D zfXK<}R%5m@upB9{bsADERHiQQJx~dlcn9c@r`-SGJj*`FJJpwIzOCwEbkKg1^{q(KL!>)YpvWL8;YOssi}R*?`)jIAi< zDg9el`*dACUsbzNY^cD+bAy&+YRrbvWFe5Ix7t=lCkV2w3fzC%jCbw3%2c-FNmziP zgvBjzb%shkw!5b>%x#(`%w;^KzYwbOUA9Jo>`= z?}UeB1}TS{3l*cX?wk5oj&HYs!rZ))#eb|9J!NpU9?V!qPDxq~Jd0nyf4~ibUE>Q1 z+;G;udoQ`mIOW2~ zt{DqB7*)&7&aNq}&o+kOaA+{}-sjhyiv3ra{4J7$W@pcF^ErX9(JXH7K$yJC^u|pd z$x%hP&))n&?}-Cc(}f;vMjt(M^3wgP5<-|J?9Ax}a==)98V)U&Vkwbf7_7}bJ)t#; ztE;c`5cb1goI4Tb2!TkMgnDReb~|oHSk4}^)uEHu5lpdJl9=kPOM|$ri>&jl(`lDA zRd)_y!roqdIB}Fn)Dk^ao>#0Np-{^dds5mwDQk6j{XNEUCz+aHzqQYoxA_e4Se};0 zl&n$~wAn&i6f*~n_35OJmnK3*izDwy^?-_(B7>R(LwbD?olf~y(G6qAR6HgFgM(`) z+bs$O)^isW%-tV}eQk%|W?p65Wc5YlCqXYx`$3s`!3=gKbj-wLYv!x#()8iO&2Skn z|Gk3BI(sVXjylJgWnjV%dRo=0^I=wmE>+4R{UY#b%~E3q67QUPhPE8zk2aq};;&c~ zU5_5-ylvoNc#!)DGQrq90>#@1v!#9MVv}q_*}r?Y(Ln6$)w~^YubcUWfKC2Fl<=f| zp8MUJ<{Mnoj9o*o^XFhgocE&!4zLN@T6~|;2d2_YqbexyG-Iq#iGAZrn%H6PRHDFR zO%()-aKD=HSbb;ZMZP{j;TfNiECyu7A9JM%yEfAxHlK8=U5Yn>>ZR7D4d-{y45-P{ zZ7oU`znL44J|NXoea zpLQar;@fKdaIeYPbQY_TH^}VRyuB?NvyGmXr=NWV-x^ec`q}cPS=}D7j|p_f5|4Td z^@=GrS$QX`jPkC^cRkcbuG5t=_g4f2He!EH*A2DK*2H08OxI)|)yU%A5%mQ^7sd5! zwB5|c`ysr5tC<_;W4YB~c(^^a%Bbf43Ndes_uNewvCiHy=3Ga`)K=bFj) zoA9tk?&uCdotff0s+w^n`qfQdbz7a=^{BujHTyTMvlaycj+>_V#h2MBJ%^aiucK0p zEz37G>IIPNwxsAVCRv~{`-J>|H)eX82(YRf?vCH14~HV}#`dii_1`F_(7}8guXvOJ zXuquys4V^zH)-3Pn{G00)q<&le&zv}3-oH&so+Y3BEx>T=aW>f^UKhlu40IiM`hMgRQ zK>vGCfx+SaCPWA~9_7gu5aP+OVNtRb{`=A?8Rvn|vE zJGDBx(Espk_D$n<7pM*u3a_`Hm<9p^y&-hagrD|1F^{tuXGHQ9lZlVIG~BN&2z@+6 zVSIUW-b=ml-NtGmn)?}E(W%7z<%Y>4nUT$(t?y^K_f`8Ak?%F$VyZmM$&n}QYSA~{ zF!8J1x}gAWq-2e(n~+{TFYiz0&>JT`95Ul|R8)0V+9#UM48L@VpGfJMtd6HN1kBXG z2T#TJtkbB4c%=(APXTi}sEq;*tmSU|6wG1e?Pk=`X%zi+->XShSQ(07@GTV5 zUw;%&`w=7dMlMc$?(5*E$f+&{5uiU{xSy2+VRb>hTD;3-O?~|Y3IqF^xWVE2vj)o@ zht_?2{vzK`ZHp3t|X)azW36S$v~ zwa0NTp}(O$JB{sxr;fjzg9y7nRG>S0MLd!F{3Oc0%uINP*ApeS_r%khs*>~EGD$}Kw zh^4&;5)UFrPj_n_JY(Ur(>qF+GYybR?Y3mqC;}7)YDgRZ$TUAG%kPnf;6rSw4T!I{ z^MU859VW^CO-HJ&;i&l$cI#63TsMLS|I-vPr%rx!32l_WF9T8GPXO6!dh>)u(?bb4 zLEKFg$z!5&y|5uB{6`SS3-9|bixSia^w9!ZEnBfn@;%oLb#Uv~0XW}h9`QUw!ENVi zLmtW|h+e;J;f6^}+-UwXZMgN5>DCx_o#@JG;!J|X~{2C^P>yC_ex@uc-EoTY(c1mxdOLf=9la}w= zv62X0^9PC`_lFsNF8@4qd44J^)tcPGsLL1kUKJJFA0Jxc@>#9Gr*B;i&{&9%U`XY z_7nWb%&Zff==u=;qAFMfbhnC}S2%V5*ubDitVAuLwQ)l4d{1ba0Oc&c`23~3;!CEK z8_RNMTdgUR6zOp2s`@ZGOZy{X^kDBZ$B_&r>Nk@e=63@Rsu|4pmJQURXoSZl`J2W7 zpNXls1Ope5_s0U`9PsLPT2cMZwSYDQ za+6ru`DK5Lk=ZhJm4=puI`^dLo6BS^HJnYqn_;cR4Govz_M`0m`!BIm@PWr4LClx-jMqQw5M@8b;{vlj4?2g4xL$)XdjYqH@MRpHfr`ea8 zqUK5TcIE^!40-7`be**x{s_??;f&9&tI$fd#7_fsAFMEUB+Uwoo|jz$!xS!(AmGs_ z)NHr|tk5O(&aQ4RY;%&^VkY@BKDM_Gs+kq|jQ29|LzJibh>mc(l^>41)1{ zb~X&#wIATcy<&-d7)djuIs0{GBjbxpb*d9==+Nd(QggMw z)`_0`(`8e`CPNmx!!6gis(AAnhY!;AUGE!Q{PIB}PH0Ro01I>sYD%#(6sdK;NF_$2 zB?2WkzGfsL?IuJ&8>WH{)AaeO-LT|iUvoo0CREKB4nBB~pu6W+1on03UC5-kLvF(W z9Ak?4qwyOx06%`laBZ8i*P$6cp@h`k&9U|JVuc|p5kkw;AH*&u{N#`pZ`|o zk5FR!_wQA?^E`)2{lIbe26K9&snljZWQ%oZST6Q}P#CsP%6Yg%s(zB_R5BVQDN@Zd zXZ^fCrL<4q1ZU&zvP`y&Uia}hKP5?QM_H@e>~)p(jtBJgNk=FM2}FC2j+TQu=6V`^ z?QyAhe&hK#r@khz0_Vfw$^5Te)$m#wd~0ha2eV0moK9Nk1{KIPEfEe??x!sa6Wb8R ziOq!)BdS*C=KNAyLbNj8>wT1j6C}`f`;e;-OG40Bb`Z|Tw7o8+MX>2TiQMoM-!uJ@ z_+njT{|10cyU~&`c-dE+oQ_Tp9!#px#x<4O{0WBw~Rh1 z=sp&MZnze3Ml{-QI>-~=X-kosKeW@4dTa5Jq)2k0J2|aWp5}mHM&5u0y~~5rTLls} zA;P*qgk#x}Xg)!DhI8Ch38sYbO*+vdxr}*OGvxZ5MY%+d7+lDA6vS$z{RWx1plTYx zyjX9lm>bU8z!S(fS-H8|;P0Ks=H(`&5AzT>k-4YU%sp@X$|LS z6?R6J;Q9pzz34GdONx<@33fC))JMV7HgFlA_v@`idHdG@MRDP_8{6ruRp09~mI6iM z_{X!6pVt`DD8P>zo@q+iG2q{zj5s^>R4vO^m!;}NzFM!e-B0x3wO9&tt$$B&eJEe& z*-ZoyRd0R7Ay2{bRO&U3wex<4z*p&n742QygT3_@R(q&w62zGfGX?RPyYmJ)FSb1g zLdBD?4)hc8V;r;=w`ZVWH)3phFAnDQd#-FpvG6+rr^T~N>ojtgrFPTmFDtB=F%4|^ zZZBJJ6pm|(+tU(Z2+wc24;}^dbOz0)g;K+&F&In6rKT*UHfbO7hgyRc^COC_H!Cjy z#?A(rCVNZ?51bF<$B-a0!KOQ$$3-GJ#|PZfpU z18_;!=&eQ1?bVX2_f1ekU3dFO_BJL)iY5k(PHG?%n4@>sDO>}>_g`COI&}b3nmvJZ z`RnW(#615JleWmzl`flpBK80hhMV5uHZS5sVtXYGXJ7Q!;Uoq!x70Vj@}-v4^T@(P zdw91bQ#@DlHu4j;9u}2~v9%|`7vh((3vD2g;G3IOx4d8Sb2KAu!oTtXyX++0$m@{d z0;$Sb8rS{9LTbO!L?xjYH5BsH!syY{hX_^xD@ZN?Vxgdlj>mi{J50xE*U#Ptq3Bhg z+{$&ag!BhkA>1w73$_PTOWG26P$8dPJ1n}9{Y73p9tW6tUfa2+F84kpe`D{yp3yal zv?-fJSJZh|O6+w$?PGuNfhz7g1y97sY~Nb42P&U(Pqei+YD=9v>a{w0x%56|U6#@i zT*lOn3*Njdd<%&nL{JWy7|p9t%uAhb9q_~kQWesZHQzDFIg^? zrE}%EtwwQ>vD_fnwJ~D?$-drQObiFow&iz+L+Kakz0Ulg!NZ(*vEuqObVD7c29~le znDL?N#`Hw)48NqUs9T+?cy8f7KlfQwBAP*zyJOw zE#yF^cS{iB@C6akzaxS68OnW?H*u@x4AMA^vTNkR2F|Y|p zOH}H7Jumg=-JP@!`4|k5j!dUzmQ5m+4FfUY%4V8D|^|l3M#nMcGri{2q_0W9GXY%d_v0buj{hKfnik0Frg@*b;lP(^++i zp4z)TqoVq(F>jnRu~aH5{b|y%|3Hv>0)J1Y8PVD0QGK4W6prU#rFYZxE%yNmbAc3Y zvX)9JCS3A(ER)}e>Tnxv+5gHTJjw^|h2LY%^gAZx{_Wgni`P8>C=|NbqWQ_zhgF=X zuu-~<@L*Z&DeB0o4peO2i&NA6M!e?q?)tnuEe$||&4DELE7&;p51o{$Imy+^V=abj zrs@x!K`-UJYxk_)?I9n}qKZLl%pCTb(6RR#N!8ULZ7}r4`bM*%&-v;3xFJq2(q^6F0s+=e6V@enOxh&j-Mv?lb^sm&HzwaTd*_I2niwR+S+ za3wCwS1q+Yx1W6Sbuoe#v*aMB&E#7o-#lvLSB4MP(!0~7xv6Dn< z`)g7rY&m7$QI`wt?qTllDVQrqD;W^q5JO0=fT$op@BR?pov;o)N^^??hzo|NS_}>& z$Vi~I7%{bob0Q}BnB`h~)w1@)qvJi_K1kP1^h=1NbH{gOlJ>V-%+1SC`EV?dCKVK- ztjBVa9qf2mc8)nbLcUp_fQ_xzSC*Ri9O<-#BrPS~7F>hapQEElS?wFIk@G)N0JNcq z=mb@g6NNhC8l`i5kwOo^T!3*Qrso}4Pgc#5?5mISqF;6g zdN}X3$8s%r(mh8aK2dPIAn10^k;f&!x?hZ=mJFvca_l9?}kStfaY`DFxRejWy3P*LxF&PJMG>kbE*2b1+cU{ag?YA14gars#<*rwzf=dq02*C z(l~~!d8KxYHKkC{#DY?((=b6SitPC0Te>{i&|YhFJGok>jl?w7H!x3PL&F@Hhhp@E zuSdA4()c6mUYw)C8wH?69KD@mY$ULf@9qJOur_Rj9*vslj!L>#`{a4A?`2gWs2n3g zdJux}?4cS|@$+IMWkt5%MOq@#(zLCup>*5_2WyVBmmO?85J(|?R_;P0tuxrq^SJ`I z={7@09v6Q}{?D^Cng?XV`5=41z-bl1%cYrT#G?qr$Bv1R8)&DUxo0~Vh4=2lb|zY? zly!%tMYAY}y7>-txqVa0l#Zqh)+9Bro3gMcp3Pk~hj^VloTN*|X-F4+P2OJ5O30a2oLX>R!A(Be8ziI+mk z{!%QO$qxR3{N$kow{6&r3v+2REm+;p^5F97@uC6`UMrLhBCE>%yIXc^rd&_v4ZI|v zy!GxcR1Z>7u%v-9U0FYJ)2q!Ai_a-0hh*{j7Gp#q|NPy9;j%*h#Ve%zys6%SNId z-abG_eUMUorbfx_-Cra%AdSRQPjNEGyJ32lJTgHulj!WMuA~EGyJxwE!Q?h$*CWKKZ_qs%1&2E@Pt6+9a}<*|GlB0k#U+P(HeJkg`a1%Qj~ zGyKCAd5J$Pv(W&(Ru~MBkM$S~imS3UvQLt2ITlmQU!-23-#cFjh{4&P08%*qMzEk# zr2~e^KKaa{_!2&vI7HAwOy+)qzAWwe_ChxY{CGD)Yaz^*3q2oLIYF8u3mR#UFn7>` zv9QkRm-&R;-AZ*`a;hZ0d$>|iVj1D_ma;AwborKS4NGs^5&bcZ%q&_*u@_f^=B9D= z$y^PxBDOWdld6^Xw{xA|SaU5Q7VewP4ev{rAprq#)sy`+B{mM%_l=*GlN!>R zC#7Suk0`3IAa?~K*}{=RnSQmcwSSV z7n7_!ud&M!NHJ0+Ffys^-|Dl=^hyf(tcnhuoVkiatkE~)#eqjF$_d}#zM-T9ZfHDZ zxr>EGq^hLDdxf<}PeYOwVN)J8Yt!}95-H4IUDoq}DyxvqefgL+x^bjOSxNQPO=I*APCqytQll#d$&Vq6?I?Xo|9$xu`QTv#|FXI%QXx7a35lnED8TOROIE>XY0I}v~CGFcz!!(@wwx2R#IC| zV^Et>-rHAX@il~hNU=OL&+WdG8akUM&qof1`n5;3eBxHnAWni*%k{FBSxebtX%2dZ z?CCZ7H0PYJqGmp8Ix1fVTS-n^tjV)i>$iH z_T*=}wYpayT{>~6E<#PY$Uu;a*!YuaaXb(qUIR4?6~nNr0wTNcY#F6zIU&Jgw>Apy zcLY}G@A1j_R)@+g1{;q8csu928v*sBbvirkA_8_BK*~ z_3#_&O$#2Z-?t@Zm5dI^UFh8^Wz4IwY4W{W6Wxo`UDQ!oPt)F{l~GG6;5)}hTb)}B zL+TGdt~i`~R)?CmhJ=jacU(A?J)r998f_qh?y)hxxkkBxr$yk9>l;;g#I)xR?jaA4 zCy5l*8u{S352Um?=Q*Bl6^X<4IjdIkXGn?w)=Pq`Vjga!&QN!`U&3t~PT`^8bG*!2 zm6|S9*7{Ta#=O~JiLv;6ho~EToU6EMfj$28FvCx0Z&^rsq1&q?X|!ha)EO(0gxT69 z0>4xncRu6kFe$-JdJ{@D>vjWGSDD-I;tsRbas&yocEr}4*sI+G_nw2UmH5A)=Y>V3Sv72QWBJw2fYV>m!7#5 zsLm)NG7jbV;?;YpM)t?xPIHABrGX0H`Nnw7X!h07_fG5dvNaN6FKzQ%A@@8iUT^V`~|in1SEJO`3Z))QKP;sge`S8;}~ACSd8I+z(W5lMt~Gf>`@!J&jK` zySY`dk9t?&Jmn9dk3*olfde|+Y(E^tqCN?h>P{f7;V+92PPtpE{% znswCjv30`6)Lud~T}LdJVU`<0Y^@ksSDr=uF&Jrb_2%72u;^do)u1?0A(&q|;Ry4q1NYfmTv;hD?9{e z)dL4ft-i}DbD;|4edN3=e6-m_v7x<+%4a3%b#J390pYI0#;EV`LEkJ>xkd9O zY%Bu2md*t(Lp3RjEQpC`B>SNQ4tlgZ*!#r)nL}N9Otgs5p+kt$>gq1jLip>x^hbbj@Aah}h4o}qsieXl(%zPgNnPS=XnfUUvd+Z;kVq2NAw=@~HZbKM3 zOy7tMuzTvd^(7746h$q0cp67@gV;B0XCHAWzS<>bzF-1D%Q^2?73vd|yaTAzMbH;B`NS1>1xBk& zb;jWRu#jjyl=a=9RUd_3W@4z?_oGBo)e#9^JVl|kxwbX)?79x14@Z`4RiGYZ0U3t^-^0~dyM_vVB|fs3D`u_2uZ@zRB8A8WQbw?4Fmoae$2Fa+T_>_!L*gF z)AzzwYg~4-=yuYpeSkLRS#CSBS>*FG=$vnP_oUM=NYbLV?Q0_eIYJUD<9Mh`OmMw=N_} zzU+J1kJMh~N>G3t21eW8OCZ~cRAh*Az<9pb$$%$%0BzMzj_p)L6|lQtfNxnbR2i5Z z)EUR)mD#bgeuw#Y(aqoAvnZ9``q@0m`AF3m#14>5HCWUV*@KO}^^<*lz7SE1su+|z z@SwBa#sYq`QataX#r6v=iHpEq8hRmea9MG0+o1g0o9m)(C`Hut7v=>60WUc$isUeM zbS4C-5joEGQ2cOvE2kU{_?*h*`|n|qflWYl|8BR}VPxyvdS%>Ec9uY?MY|mkZImD> z+qHN2olH;0`b{T>QcY(Yx~NTWBoLzGKq;ux2mI1G{pvyqv$vB~N`dMlXWg7IRKDbq zMY)j|2z~^FLh!*s8ldhwnBRWri4SfaHf;tJA8dxMDgjB^Z`qjsFJ3&y$!2Ghd-gMAopA*B1$<>$UA<^)CQd-W#QT~N4rp=2gRRb9mrG-{~Ur#G4PGwf_PF(GH& zekxHNG(wkW^nCu?XMGTM)wIm%J}YZL_l^dbp|nmEI|5yoFLMV<$l7Xh9S;GIi#IZd zInz9c8@1f}t!-F$H1cA*f~<6hB09e-Kbwm)@gYPks_9j3aJYn^gQ25j2A=ysAHjAy zY=2!r^urA-R*UbO5gZ~BFNV$IueowOnCaJ@ZE{ED#(%U`;-h5;^-iYY|5%e%Ns3mbf*ZoUH1B z14vz^v^_1VZ0<0ZRL-*XK+K|>%H+7haq>_(J$wR1As#n*P?ECIHjA=EzdwqGs#$9@^um=r6IBRe7xSb z9?nw?s?kXHUZKV=R5gJ_VPxIe?4mhK}65P-c7-?P`#dNdRcR`u_b}7ft zlR`l`f4XGEInuRy)xpDhyv7u9@O`bybdX8?j;KWhzr*Ci0ee_A!FcWVHj~YGK4i>G z?y_5ADiQ1*KS7UVO|&>}SDa0It}sw_c~wHdF>IZl#WgL?#F*(gupH^&7QDMY$T!lg zfAhb&c7I~2X19emgcBCcGR+=e$XNK@!GH7Y>i4g_!CBWX@*9+&Qt`S+NF8l_y~F?y zm=&@Rpttf+EBz~{`vx@vpQ&hG%IFJ|{k}455_sT4_s4?bYF>L|Bw_VNfhwhHcfxQ6 zSHk>)9c2_Nz3&rIs67L)@e9V}q$H4!)M*;TP;eMLH}+V@N4#P#njc8W85cG7HkAPi zX?l*SOpN3yx!qf=_MNh`7WKoio2LGj-#72cX1?;A)1&+!9_jBtval$gzUby`7hmsg z9$1$uQl$|OpSk;kohP7R0bjKlrL&3Q>v?ETyGX@j@DRv3u@uQ;JkV`Zh5F;AG!hCu_LLj8RNNh}ZFDFA~S=spD)`@=F(^SiR|?4gm%gDeQi`JNj_En-@$*uk2d zLW3i}=lOb#Vx4p&qRcUa>bgQf?C4PSrL%>0azod`{cs_$wC@q%g6=={6G+Tn- zTmVK{@M{K8Py=X*oaORdv=r9=@{_q{ip0v0=?88`iO{N zYfJm{%_M)9p}&jQ-rk;G-@i8H(ohUK-1UAn^o{-6U46eyiF!2E+^MGp#zO#D6O0Ad zH>)Ca!igr_`0@AG&%06HX?U#Y{i(^SaEBfMnh0B{@f%h6r&0gS?tb=MfCp6}SvwA0 z1kZF<1jN!^$bkMNn{m0vE%>5i0Z*T6b9U){lEsdH_r~u~&OaTuf4MgCY`{IORv0wUf^Gg=RaQE!>bBA>-N28`2FFp z-+5m}x*lu&4trv8qBKOBMgJEHPmI!xy|9L6>=E_?5_p0*N_2`L9-I^_CK4P&Jd|VHf7c?S7hkseu5tlB} z9;JK%gxViU9Znr5M71j4UOd=jHvMZ&-7ADkbZ?F`K3CE9ov?bG zDOZ_4jq(O>2CxoaeZ?T-qxOre@l4zG6WRk))c4hMHfpIg*s_o5B((rdIgNxa2uGN5Zv0vdSJ9*;8 zNv~Q#{pYta=3L9P*xO_|Xk(9;Ok|dBAyIr|{TFj+=GwK)E8e%(UR}xc__cv38D~Vo z7IPzob#8SnwE-gLFGc}~3_h623>=BkF7p}t;yT>)?U#pQjEKi$i2GS zGTQixQz_rCgZbCS@*l4vq5#3}Hf2Qw{Qv3xe)bP84pq^_wZG7t{AKcAeAC>0AWU^0 z=(jTYOB?>O6G<}~0!qq}MK@W+{C{(r{>RXPOA%!Nze;pPj_dx#FZ}PGLEDRq6Q`i5 zz2`rM`TI+0jSEpaRyxQ&#jh6rb-@32|Nk}pUz+CD|L>;XJWqQKO;3HVM*j!!r!24W Kq*(UloBsm`DHQVn literal 0 HcmV?d00001 diff --git a/x-pack/plugins/remote_clusters/public/plugin.ts b/x-pack/plugins/remote_clusters/public/plugin.ts index 107d4e127d1b5..540a8b40a6208 100644 --- a/x-pack/plugins/remote_clusters/public/plugin.ts +++ b/x-pack/plugins/remote_clusters/public/plugin.ts @@ -60,13 +60,14 @@ export class RemoteClustersUIPlugin initNotification(toasts, fatalErrors); initHttp(http); - const isCloudEnabled = Boolean(cloud?.isCloudEnabled); + const isCloudEnabled: boolean = Boolean(cloud?.isCloudEnabled); + const cloudBaseUrl: string = cloud?.baseUrl ?? ''; const { renderApp } = await import('./application'); const unmountAppCallback = await renderApp( element, i18nContext, - { isCloudEnabled }, + { isCloudEnabled, cloudBaseUrl }, history ); diff --git a/x-pack/plugins/remote_clusters/tsconfig.json b/x-pack/plugins/remote_clusters/tsconfig.json index 0bee6300cf0b2..9dc7926bd62ea 100644 --- a/x-pack/plugins/remote_clusters/tsconfig.json +++ b/x-pack/plugins/remote_clusters/tsconfig.json @@ -8,10 +8,12 @@ "declarationMap": true }, "include": [ + "__jest__/**/*", "common/**/*", "fixtures/**/*", "public/**/*", "server/**/*", + "../../../typings/**/*", ], "references": [ { "path": "../../../src/core/tsconfig.json" }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a1bb98669cd70..e42b87f388473 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16756,10 +16756,6 @@ "xpack.remoteClusters.addTitle": "リモートクラスターを追加", "xpack.remoteClusters.appName": "リモートクラスター", "xpack.remoteClusters.appTitle": "リモートクラスター", - "xpack.remoteClusters.cloudClusterInformationDescription": "クラスターのプロキシアドレスとサーバー名を見つけるには、デプロイメニューの{security}ページに移動し、{searchString}を検索します。", - "xpack.remoteClusters.cloudClusterInformationTitle": "Elasticsearch Cloudデプロイのプロキシモードを使用", - "xpack.remoteClusters.cloudClusterSearchDescription": "リモートクラスターパラメーター", - "xpack.remoteClusters.cloudClusterSecurityDescription": "セキュリティ", "xpack.remoteClusters.configuredByNodeWarningTitle": "このリモートクラスターはノードの elasticsearch.yml 構成ファイルで定義されているため、編集または削除できません。", "xpack.remoteClusters.connectedStatus.connectedAriaLabel": "接続済み", "xpack.remoteClusters.connectedStatus.notConnectedAriaLabel": "未接続", @@ -16833,7 +16829,6 @@ "xpack.remoteClusters.remoteClusterForm.fieldServerNameRequiredLabel": "サーバー名", "xpack.remoteClusters.remoteClusterForm.fieldSocketConnectionsHelpText": "リモートクラスターごとに開くソケット接続の数。", "xpack.remoteClusters.remoteClusterForm.hideRequestButtonLabel": "リクエストを非表示", - "xpack.remoteClusters.remoteClusterForm.inputLocalSeedErrorMessage": "「シードノード」フィールドが無効です。", "xpack.remoteClusters.remoteClusterForm.inputNameErrorMessage": "「名前」フィールドが無効です。", "xpack.remoteClusters.remoteClusterForm.inputProxyErrorMessage": "「プロキシアドレス」フィールドが無効です。", "xpack.remoteClusters.remoteClusterForm.inputSeedsErrorMessage": "「シードノード」フィールドが無効です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1fa26ba983071..623e127bd84b0 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16981,10 +16981,6 @@ "xpack.remoteClusters.addTitle": "添加远程集群", "xpack.remoteClusters.appName": "远程集群", "xpack.remoteClusters.appTitle": "远程集群", - "xpack.remoteClusters.cloudClusterInformationDescription": "要查找您的集群的代理地址和服务器名称,请前往部署菜单的{security}页面并搜索“{searchString}”。", - "xpack.remoteClusters.cloudClusterInformationTitle": "将代理模式用于 Elastic Cloud 部署", - "xpack.remoteClusters.cloudClusterSearchDescription": "远程集群参数", - "xpack.remoteClusters.cloudClusterSecurityDescription": "安全", "xpack.remoteClusters.configuredByNodeWarningTitle": "您无法编辑或删除此远程集群,因为它是在节点的 elasticsearch.yml 配置文件中定义的。", "xpack.remoteClusters.connectedStatus.connectedAriaLabel": "已连接", "xpack.remoteClusters.connectedStatus.notConnectedAriaLabel": "未连接", @@ -17059,7 +17055,6 @@ "xpack.remoteClusters.remoteClusterForm.fieldServerNameRequiredLabel": "服务器名", "xpack.remoteClusters.remoteClusterForm.fieldSocketConnectionsHelpText": "每个远程集群要打开的套接字数目。", "xpack.remoteClusters.remoteClusterForm.hideRequestButtonLabel": "隐藏请求", - "xpack.remoteClusters.remoteClusterForm.inputLocalSeedErrorMessage": "“种子节点”字段无效。", "xpack.remoteClusters.remoteClusterForm.inputNameErrorMessage": "“名称”字段无效。", "xpack.remoteClusters.remoteClusterForm.inputProxyErrorMessage": "“代理地址”字段无效。", "xpack.remoteClusters.remoteClusterForm.inputSeedsErrorMessage": "“种子节点”字段无效。",