From 3ce8b74c48a0bbee3fcabf6ec9fcae8ab1c88dcc Mon Sep 17 00:00:00 2001 From: Francois-Clement Brossard Date: Sat, 26 Oct 2024 02:43:33 +0900 Subject: [PATCH] [SR] Add tooltips for disabled fields on managed SLM repository and policy (#196565) ## Summary Closes https://github.com/elastic/kibana/issues/173124#issuecomment-2352968634 by adding tooltips details when hovering the disabled SLM repository or policy fields. ### Screenshots **SLM managed repository** ![Screenshot 2024-10-16 at 1 38 19](https://github.com/user-attachments/assets/3bd11ea5-f846-433f-8615-b51de184336b) **SLM managed policy** ![Screenshot 2024-10-16 at 1 37 57](https://github.com/user-attachments/assets/d11757bd-bda5-4b4f-8c1e-e795e01b1fa2) ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels) - [x] This will appear in the **Release Notes** and follow the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> --- .../components/disable_tooltip.tsx | 52 ++++++++++++ .../policy_form/steps/step_logistics.tsx | 83 +++++++++++-------- .../type_settings/azure_settings.tsx | 79 +++++++++++------- .../type_settings/gcs_settings.tsx | 79 +++++++++++------- .../type_settings/s3_settings.tsx | 79 +++++++++++------- 5 files changed, 247 insertions(+), 125 deletions(-) create mode 100644 x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx diff --git a/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx b/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx new file mode 100644 index 0000000000000..8d82705b27022 --- /dev/null +++ b/x-pack/plugins/snapshot_restore/public/application/components/disable_tooltip.tsx @@ -0,0 +1,52 @@ +/* + * 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, { ReactElement } from 'react'; +import { EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export const MANAGED_REPOSITORY_TOOLTIP_MESSAGE = i18n.translate( + 'xpack.snapshotRestore.repositoryForm.disableToolTip', + { + defaultMessage: 'This field is disabled because you are editing a managed repository.', + } +); + +export const MANAGED_POLICY_TOOLTIP_MESSAGE = i18n.translate( + 'xpack.snapshotRestore.policyForm.disableToolTip', + { + defaultMessage: 'This field is disabled because you are editing a managed policy.', + } +); + +interface Props { + isManaged?: boolean; + tooltipMessage: string; + component: ReactElement; +} + +/** + * Component that wraps a given component (disabled field) with a tooltip if a repository + * or policy is managed (isManaged === true). + * + * @param {boolean} isManaged - Determines if the tooltip should be displayed. + * @param {string} tooltipMessage - The message to display inside the tooltip. + * @param {React.ReactElement} component - The component to wrap with the tooltip. + */ +export const DisableToolTip: React.FunctionComponent = ({ + isManaged, + tooltipMessage, + component, +}) => { + return isManaged ? ( + + {component} + + ) : ( + component + ); +}; diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx index 2ad6c88af5f13..36fd8c10f684b 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx @@ -33,6 +33,7 @@ import { useLoadRepositories } from '../../../services/http'; import { linkToAddRepository } from '../../../services/navigation'; import { InlineLoading } from '../..'; import { StepProps } from '.'; +import { DisableToolTip, MANAGED_POLICY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; export const PolicyStepLogistics: React.FunctionComponent = ({ policy, @@ -258,22 +259,28 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ } return ( - ({ - value: name, - text: name, - }))} - hasNoInitialSelection={!doesRepositoryExist} - value={!doesRepositoryExist ? '' : policy.repository} - onBlur={() => setTouched({ ...touched, repository: true })} - onChange={(e) => { - updatePolicy({ - repository: e.target.value, - }); - }} - fullWidth - data-test-subj="repositorySelect" - disabled={policy?.isManagedPolicy && isEditing} + ({ + value: name, + text: name, + }))} + hasNoInitialSelection={!doesRepositoryExist} + value={!doesRepositoryExist ? '' : policy.repository} + onBlur={() => setTouched({ ...touched, repository: true })} + onChange={(e) => { + updatePolicy({ + repository: e.target.value, + }); + }} + fullWidth + data-test-subj="repositorySelect" + disabled={policy?.isManagedPolicy && isEditing} + /> + } /> ); }; @@ -325,25 +332,31 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ } fullWidth > - { - updatePolicy({ - snapshotName: e.target.value, - }); - }} - onBlur={() => setTouched({ ...touched, snapshotName: true })} - placeholder={i18n.translate( - 'xpack.snapshotRestore.policyForm.stepLogistics.policySnapshotNamePlaceholder', - { - defaultMessage: `''`, - description: - 'Example date math snapshot name. Keeping the same syntax is important: ', - } - )} - data-test-subj="snapshotNameInput" - disabled={policy?.isManagedPolicy && isEditing} + { + updatePolicy({ + snapshotName: e.target.value, + }); + }} + onBlur={() => setTouched({ ...touched, snapshotName: true })} + placeholder={i18n.translate( + 'xpack.snapshotRestore.policyForm.stepLogistics.policySnapshotNamePlaceholder', + { + defaultMessage: `''`, + description: + 'Example date math snapshot name. Keeping the same syntax is important: ', + } + )} + data-test-subj="snapshotNameInput" + disabled={policy?.isManagedPolicy && isEditing} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx index da061fa8c2abb..9f33e23a9cb29 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/azure_settings.tsx @@ -18,6 +18,7 @@ import { import { AzureRepository, Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: AzureRepository; @@ -94,16 +95,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -139,16 +146,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.container)} error={settingErrors.container} > - { - updateRepositorySettings({ - container: e.target.value, - }); - }} - data-test-subj="containerInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + container: e.target.value, + }); + }} + data-test-subj="containerInput" + disabled={isManagedRepository} + /> + } /> @@ -184,16 +197,22 @@ export const AzureSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx index 865a628b984b6..75272fec0c7e1 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/gcs_settings.tsx @@ -12,6 +12,7 @@ import { EuiDescribedFormGroup, EuiFieldText, EuiFormRow, EuiSwitch, EuiTitle } import { GCSRepository, Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: GCSRepository; @@ -82,16 +83,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -127,16 +134,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > - { - updateRepositorySettings({ - bucket: e.target.value, - }); - }} - data-test-subj="bucketInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + bucket: e.target.value, + }); + }} + data-test-subj="bucketInput" + disabled={isManagedRepository} + /> + } /> @@ -172,16 +185,22 @@ export const GCSSettings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } /> diff --git a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx index 88398315a327c..dd9953cf93a78 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/repository_form/type_settings/s3_settings.tsx @@ -20,6 +20,7 @@ import { import { Repository, S3Repository } from '../../../../../common/types'; import { RepositorySettingsValidation } from '../../../services/validation'; import { ChunkSizeField, MaxSnapshotsField, MaxRestoreField } from './common'; +import { DisableToolTip, MANAGED_REPOSITORY_TOOLTIP_MESSAGE } from '../../disable_tooltip'; interface Props { repository: S3Repository; @@ -117,16 +118,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.client)} error={settingErrors.client} > - { - updateRepositorySettings({ - client: e.target.value, - }); - }} - data-test-subj="clientInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + client: e.target.value, + }); + }} + data-test-subj="clientInput" + disabled={isManagedRepository} + /> + } /> @@ -162,16 +169,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.bucket)} error={settingErrors.bucket} > - { - updateRepositorySettings({ - bucket: e.target.value, - }); - }} - data-test-subj="bucketInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + bucket: e.target.value, + }); + }} + data-test-subj="bucketInput" + disabled={isManagedRepository} + /> + } /> @@ -207,16 +220,22 @@ export const S3Settings: React.FunctionComponent = ({ isInvalid={Boolean(hasErrors && settingErrors.basePath)} error={settingErrors.basePath} > - { - updateRepositorySettings({ - basePath: e.target.value, - }); - }} - data-test-subj="basePathInput" - disabled={isManagedRepository} + { + updateRepositorySettings({ + basePath: e.target.value, + }); + }} + data-test-subj="basePathInput" + disabled={isManagedRepository} + /> + } />